diff --git a/src/shared/versions.ts b/src/shared/versions.ts
index 895c0cc..492caad 100644
--- a/src/shared/versions.ts
+++ b/src/shared/versions.ts
@@ -1,6 +1,6 @@
export const HARBOR_VERSIONS = Object.freeze({
- macClient: '0.26.3',
- gatewayClient: '0.27.3',
+ macClient: '0.26.4',
+ gatewayClient: '0.27.4',
gatewayBackend: '0.27.0',
});
diff --git a/src/web/features/devices/DevicesFeature.tsx b/src/web/features/devices/DevicesFeature.tsx
index 6d62ac5..a420dc4 100644
--- a/src/web/features/devices/DevicesFeature.tsx
+++ b/src/web/features/devices/DevicesFeature.tsx
@@ -245,11 +245,12 @@ export function DevicesToggle({
;
}
diff --git a/src/web/features/diagnostics/DiagnosticsFeature.tsx b/src/web/features/diagnostics/DiagnosticsFeature.tsx
index df3a00e..044c04a 100644
--- a/src/web/features/diagnostics/DiagnosticsFeature.tsx
+++ b/src/web/features/diagnostics/DiagnosticsFeature.tsx
@@ -60,11 +60,13 @@ export function DiagnosticsToggle({
onClick={onToggle}
>
;
diff --git a/src/web/features/instructions/InstructionsFeature.tsx b/src/web/features/instructions/InstructionsFeature.tsx
index bdd59f3..9303c68 100644
--- a/src/web/features/instructions/InstructionsFeature.tsx
+++ b/src/web/features/instructions/InstructionsFeature.tsx
@@ -249,9 +249,13 @@ export function InstructionsToggle({
onClick={onToggle}
>
;
}
diff --git a/src/web/features/routing/RoutingFeature.tsx b/src/web/features/routing/RoutingFeature.tsx
index 8d094ea..890460d 100644
--- a/src/web/features/routing/RoutingFeature.tsx
+++ b/src/web/features/routing/RoutingFeature.tsx
@@ -832,10 +832,12 @@ export function RoutingToggle({
>
);
diff --git a/src/web/styles/primitives.css b/src/web/styles/primitives.css
index 38f5393..0dc0589 100644
--- a/src/web/styles/primitives.css
+++ b/src/web/styles/primitives.css
@@ -76,16 +76,26 @@
.client-rail-subscription-back,
.client-rail-subscription-front,
-.client-rail-info-ring,
-.client-rail-info-mark,
-.client-rail-device-monitor,
-.client-rail-device-phone,
+.client-rail-book-page-position,
+.client-rail-book-spine,
+.client-rail-device-link,
.client-rail-device-bridge,
+.client-rail-diagnostics-position,
+.client-rail-rule-knob-position {
+ transform-box: fill-box;
+ transform-origin: center;
+ transition: transform var(--client-rail-state-duration) cubic-bezier(0.16, 1, 0.3, 1), opacity 260ms ease, stroke-dasharray var(--client-rail-state-duration) cubic-bezier(0.16, 1, 0.3, 1), stroke-dashoffset var(--client-rail-state-duration) cubic-bezier(0.16, 1, 0.3, 1);
+}
+
+.client-rail-book-page,
.client-rail-diagnostics-glass,
.client-rail-rule-knob {
transform-box: fill-box;
transform-origin: center;
- transition: transform var(--client-rail-state-duration) cubic-bezier(0.16, 1, 0.3, 1), opacity 260ms ease, stroke-dasharray var(--client-rail-state-duration) cubic-bezier(0.16, 1, 0.3, 1), stroke-dashoffset var(--client-rail-state-duration) cubic-bezier(0.16, 1, 0.3, 1);
+}
+
+.client-rail-book-page.is-right {
+ transform-origin: left center;
}
.client-rail-action .client-rail-subscription-card,
@@ -105,17 +115,20 @@
transform: translate(-2px, 1px);
}
-.client-rail-info-ring {
- stroke-dasharray: 1 0;
- stroke-dashoffset: 0.1;
+.client-instructions-toggle.is-open .client-rail-book-page-position.is-left {
+ transform: translateX(-1.25px) rotate(-2.5deg);
}
-.client-instructions-toggle.is-open .client-rail-info-ring {
- stroke-dasharray: 0.9 0.1;
+.client-instructions-toggle.is-open .client-rail-book-page-position.is-right {
+ transform: translateX(1.25px) rotate(2.5deg);
}
-.client-instructions-toggle.is-open .client-rail-info-mark {
- transform: translateY(-1px);
+.client-instructions-toggle.is-open .client-rail-book-spine {
+ transform: scaleY(1.06);
+}
+
+.client-rail-device-link {
+ opacity: 0.68;
}
.client-rail-device-bridge {
@@ -124,10 +137,8 @@
}
.client-rail-subscription-scan,
-.client-rail-info-sweep,
.client-rail-device-packet,
-.client-rail-diagnostics-scan,
-.client-rail-rule-scan {
+.client-rail-diagnostics-scan {
stroke-width: 2.4;
opacity: 0;
stroke-dasharray: 0.18 0.82;
@@ -138,12 +149,8 @@
stroke-dasharray: 0.36 0.64;
}
-.client-devices-toggle.is-open .client-rail-device-monitor {
- transform: translateX(1px);
-}
-
-.client-devices-toggle.is-open .client-rail-device-phone {
- transform: translateX(-1px);
+.client-devices-toggle.is-open .client-rail-device-link {
+ opacity: 1;
}
.client-devices-toggle.is-open .client-rail-device-bridge {
@@ -151,28 +158,42 @@
transform: scaleX(1);
}
-.client-diagnostics-toggle.is-open .client-rail-diagnostics-glass {
- transform: translate(1px, -1px) rotate(-4deg);
+.client-rail-diagnostics-trace {
+ opacity: 0.72;
}
-.client-local-rules-toggle.is-open .client-rail-rule-knob.is-top {
- transform: translateX(2px);
+.client-diagnostics-toggle.is-open .client-rail-diagnostics-position {
+ transform: translate(2px, -1px) rotate(-7deg);
}
-.client-local-rules-toggle.is-open .client-rail-rule-knob.is-bottom {
- transform: translateX(-2px);
+.client-local-rules-toggle.is-open .client-rail-rule-knob-position.is-top {
+ transform: translateX(4px);
+}
+
+.client-local-rules-toggle.is-open .client-rail-rule-knob-position.is-bottom {
+ transform: translateX(-4px);
}
.client-subscription-toggle.is-open .client-rail-subscription-scan,
-.client-instructions-toggle.is-open .client-rail-info-sweep,
.client-devices-toggle.is-open .client-rail-device-packet,
-.client-diagnostics-toggle.is-open .client-rail-diagnostics-scan,
-.client-local-rules-toggle.is-open .client-rail-rule-scan {
+.client-diagnostics-toggle.is-open .client-rail-diagnostics-scan {
animation: client-rail-ambient-trace 10s 1.1s linear infinite;
}
-.client-local-rules-toggle.is-open .client-rail-rule-scan.is-bottom {
- animation: client-rail-ambient-trace 10s 1.32s linear infinite;
+.client-instructions-toggle.is-open .client-rail-book-page.is-right {
+ animation: client-rail-book-turn 10s 1.1s ease-in-out infinite;
+}
+
+.client-diagnostics-toggle.is-open .client-rail-diagnostics-glass {
+ animation: client-rail-glass-scan 10s 1.1s ease-in-out infinite;
+}
+
+.client-local-rules-toggle.is-open .client-rail-rule-knob.is-top {
+ animation: client-rail-rule-tune-top 10s 1.1s ease-in-out infinite;
+}
+
+.client-local-rules-toggle.is-open .client-rail-rule-knob.is-bottom {
+ animation: client-rail-rule-tune-bottom 10s 1.28s ease-in-out infinite;
}
@keyframes client-rail-ambient-trace {
@@ -182,6 +203,28 @@
10%, 100% { opacity: 0; stroke-dashoffset: 0; }
}
+@keyframes client-rail-book-turn {
+ 0%, 2%, 10%, 100% { transform: translateX(0) scaleX(1); }
+ 5% { transform: translateX(-1px) scaleX(0.18); }
+ 7% { transform: translateX(-0.5px) scaleX(0.55); }
+}
+
+@keyframes client-rail-glass-scan {
+ 0%, 2%, 10%, 100% { transform: translateX(0) rotate(0); }
+ 4% { transform: translateX(-3px) rotate(6deg); }
+ 7% { transform: translateX(1.5px) rotate(-3deg); }
+}
+
+@keyframes client-rail-rule-tune-top {
+ 0%, 2%, 10%, 100% { transform: translateX(0); }
+ 6% { transform: translateX(-2px); }
+}
+
+@keyframes client-rail-rule-tune-bottom {
+ 0%, 2%, 10%, 100% { transform: translateX(0); }
+ 6% { transform: translateX(2px); }
+}
+
.client-local-rules-toggle:disabled {
cursor: default;
color: var(--client-muted);
diff --git a/test/web/responsive-layout-contract.test.js b/test/web/responsive-layout-contract.test.js
index eadff38..73c5914 100644
--- a/test/web/responsive-layout-contract.test.js
+++ b/test/web/responsive-layout-contract.test.js
@@ -140,31 +140,34 @@ test('secondary menus share one right rail and switch equal drawers as a vertica
assert.match(disabledRulesLabel, /filter:\s*blur\(5px\)/);
assert.match(styles, /\.client-local-rules-toggle:disabled:hover span\s*\{[\s\S]*opacity:\s*1/);
assert.match(subscription, /client-rail-subscription-back[\s\S]*client-rail-subscription-front[\s\S]*client-rail-subscription-lines[\s\S]*client-rail-subscription-scan/);
- assert.match(instructions, /client-rail-info-ring[\s\S]*client-rail-info-sweep[\s\S]*client-rail-info-mark/);
+ assert.match(instructions, /client-rail-book-page-position is-left[\s\S]*client-rail-book-page is-left[\s\S]*client-rail-book-page-position is-right[\s\S]*client-rail-book-page is-right[\s\S]*client-rail-book-spine/);
assert.match(component, / {
const witnesses = readStyleWitnesses(root);
- assert.equal(witnesses.length, 859);
+ assert.equal(witnesses.length, 863);
assert.equal(witnesses.filter((witness) => witness.unknown || witness.ancestorUnknown).length, 0);
const ledger = createStyleLedger(readStyleSource(root), { witnesses });
assert.deepEqual(ledger.counts, acceptedLedger.counts);
@@ -405,8 +405,8 @@ test('main owns one public stylesheet and the regrouped production CSS is determ
assert.equal((main.match(/import ['"][^'"]+\.css['"]/g) || []).length, 1);
const assets = fs.readdirSync(path.join(root, 'dist/assets')).filter((file) => file.endsWith('.css'));
- assert.deepEqual(assets, ['index-CAi7iXH5.css']);
+ assert.deepEqual(assets, ['index-BlKS5cQQ.css']);
const built = fs.readFileSync(path.join(root, 'dist/assets', assets[0]));
- assert.equal(built.byteLength, 135653);
- assert.equal(sha256(built), '15cb8f4597c16fd8ba119395b1246e3cf9362fc24988aecd6a08a0666fb53d46');
+ assert.equal(built.byteLength, 136693);
+ assert.equal(sha256(built), '3486f1e09a97e1293d7cdd4c7661b994bda1f388c1560518657da1b3a8318d6e');
});