From 75b94a502521d587272828d81fac36fe43b33f5f Mon Sep 17 00:00:00 2001 From: Zac Gaetano Date: Thu, 21 May 2026 17:08:02 +0000 Subject: [PATCH] web-ui(wave 2): token cleanups from wave-1 code review Promoted 14 new tokens (--accent-hover, --signal-{good,bad,warn}-hover, --accent-bright, --thumb-black, --overlay, --shadow, --ease-out-{quart,expo}, --dur-{fast,normal,slide}, --z-topbar) and substituted every raw oklch / cubic-bezier / hardcoded z-index occurrence in the 12 primitive files. cubic-bezier appearances dropped from 8 files to 0 (only in tokens.css). Bundle byte count: 138 KB -> 139 KB. Visual regression: zero (smoke page still renders identically). --- services/web-ui/src/css/components/button.css | 10 ++++---- .../web-ui/src/css/components/card-asset.css | 8 +++---- .../src/css/components/card-operational.css | 6 ++--- .../web-ui/src/css/components/field-group.css | 4 ++-- .../src/css/components/form-controls.css | 8 +++---- .../web-ui/src/css/components/list-row.css | 2 +- .../web-ui/src/css/components/sidebar.css | 6 ++--- .../web-ui/src/css/components/slide-panel.css | 6 ++--- services/web-ui/src/css/components/toast.css | 2 +- services/web-ui/src/css/components/tokens.css | 23 +++++++++++++++++++ services/web-ui/src/css/components/topbar.css | 2 +- 11 files changed, 50 insertions(+), 27 deletions(-) diff --git a/services/web-ui/src/css/components/button.css b/services/web-ui/src/css/components/button.css index 439e8db..20ceee7 100644 --- a/services/web-ui/src/css/components/button.css +++ b/services/web-ui/src/css/components/button.css @@ -10,9 +10,9 @@ font: 500 13px/1 var(--font); cursor: pointer; user-select: none; - transition: background-color 120ms cubic-bezier(0.25, 1, 0.5, 1), - border-color 120ms cubic-bezier(0.25, 1, 0.5, 1), - color 120ms cubic-bezier(0.25, 1, 0.5, 1); + transition: background-color var(--dur-fast) var(--ease-out-quart), + border-color var(--dur-fast) var(--ease-out-quart), + color var(--dur-fast) var(--ease-out-quart); } .wd-btn:focus-visible { outline: 2px solid var(--accent-subtle); @@ -36,7 +36,7 @@ color: oklch(98% 0.005 266); } .wd-btn--primary:hover:not(:disabled) { - background: oklch(52% 0.20 266); + background: var(--accent-hover); } .wd-btn--secondary { @@ -63,7 +63,7 @@ color: oklch(98% 0.005 25); } .wd-btn--danger:hover:not(:disabled) { - background: oklch(68% 0.22 25); + background: var(--signal-bad-hover); } /* Icon-only (28px square) */ diff --git a/services/web-ui/src/css/components/card-asset.css b/services/web-ui/src/css/components/card-asset.css index c509732..53fcffc 100644 --- a/services/web-ui/src/css/components/card-asset.css +++ b/services/web-ui/src/css/components/card-asset.css @@ -8,7 +8,7 @@ border: 1px solid var(--border-faint); border-radius: 6px; overflow: hidden; - transition: border-color 120ms cubic-bezier(0.25, 1, 0.5, 1); + transition: border-color var(--dur-fast) var(--ease-out-quart); } .wd-card-asset:hover { border-color: var(--border); @@ -18,7 +18,7 @@ position: relative; width: 100%; aspect-ratio: 16 / 9; - background: oklch(0% 0 0); + background: var(--thumb-black); overflow: hidden; } .wd-card-asset-thumb img, @@ -27,7 +27,7 @@ height: 100%; object-fit: cover; display: block; - transition: filter 120ms cubic-bezier(0.25, 1, 0.5, 1); + transition: filter var(--dur-fast) var(--ease-out-quart); } .wd-card-asset:hover .wd-card-asset-thumb img, .wd-card-asset:hover .wd-card-asset-thumb video { @@ -55,7 +55,7 @@ position: absolute; top: 8px; left: 8px; opacity: 0; - transition: opacity 120ms cubic-bezier(0.25, 1, 0.5, 1); + transition: opacity var(--dur-fast) var(--ease-out-quart); } .wd-card-asset:hover .wd-card-asset-checkbox, .wd-card-asset.is-selected .wd-card-asset-checkbox, diff --git a/services/web-ui/src/css/components/card-operational.css b/services/web-ui/src/css/components/card-operational.css index 1118660..43b8114 100644 --- a/services/web-ui/src/css/components/card-operational.css +++ b/services/web-ui/src/css/components/card-operational.css @@ -9,7 +9,7 @@ background: var(--bg-panel); border: 1px solid var(--border-faint); border-radius: 6px; - transition: border-color 120ms cubic-bezier(0.25, 1, 0.5, 1); + transition: border-color var(--dur-fast) var(--ease-out-quart); } .wd-card-op:hover { border-color: var(--border); } .wd-card-op.is-active { border-color: var(--accent-border); } @@ -62,7 +62,7 @@ .wd-mini-bar-fill { height: 100%; background: var(--accent); - transition: width 240ms cubic-bezier(0.16, 1, 0.3, 1); + transition: width var(--dur-slide) var(--ease-out-expo); } .wd-mini-bar-fill--warn { background: var(--signal-warn); } .wd-mini-bar-fill--bad { background: var(--signal-bad); } @@ -79,7 +79,7 @@ position: absolute; inset: 0; width: 100%; - background: linear-gradient(90deg, var(--accent), oklch(70% 0.18 266)); + background: linear-gradient(90deg, var(--accent), var(--accent-bright)); } /* Grid container */ diff --git a/services/web-ui/src/css/components/field-group.css b/services/web-ui/src/css/components/field-group.css index 5d4443b..7f05cd7 100644 --- a/services/web-ui/src/css/components/field-group.css +++ b/services/web-ui/src/css/components/field-group.css @@ -40,8 +40,8 @@ text-transform: uppercase; color: var(--text-tertiary); cursor: pointer; - transition: color 120ms cubic-bezier(0.25, 1, 0.5, 1), - border-color 120ms cubic-bezier(0.25, 1, 0.5, 1); + transition: color var(--dur-fast) var(--ease-out-quart), + border-color var(--dur-fast) var(--ease-out-quart); } .wd-tab:hover { color: var(--text-secondary); } .wd-tab.is-active { diff --git a/services/web-ui/src/css/components/form-controls.css b/services/web-ui/src/css/components/form-controls.css index 1f8bc95..871cf22 100644 --- a/services/web-ui/src/css/components/form-controls.css +++ b/services/web-ui/src/css/components/form-controls.css @@ -18,7 +18,7 @@ border-radius: 4px; font: 400 13px/1 var(--font); color: var(--text-primary); - transition: border-color 120ms cubic-bezier(0.25, 1, 0.5, 1); + transition: border-color var(--dur-fast) var(--ease-out-quart); } .wd-textarea { height: auto; min-height: 80px; padding: 8px 10px; line-height: 1.5; resize: vertical; } .wd-input:focus, .wd-select:focus, .wd-textarea:focus { @@ -71,7 +71,7 @@ background: var(--bg-hover); border: 1px solid var(--border); border-radius: 999px; - transition: background 200ms cubic-bezier(0.25, 1, 0.5, 1); + transition: background 200ms var(--ease-out-quart); } .wd-toggle-track::after { content: ''; @@ -80,8 +80,8 @@ width: 12px; height: 12px; border-radius: 50%; background: var(--text-secondary); - transition: transform 200ms cubic-bezier(0.25, 1, 0.5, 1), - background 200ms cubic-bezier(0.25, 1, 0.5, 1); + transition: transform 200ms var(--ease-out-quart), + background 200ms var(--ease-out-quart); } .wd-toggle input:checked ~ .wd-toggle-track { background: var(--accent); diff --git a/services/web-ui/src/css/components/list-row.css b/services/web-ui/src/css/components/list-row.css index f69a091..4dc4359 100644 --- a/services/web-ui/src/css/components/list-row.css +++ b/services/web-ui/src/css/components/list-row.css @@ -12,7 +12,7 @@ height: 44px; padding: 0 16px; border-bottom: 1px solid var(--border-faint); - transition: background-color 120ms cubic-bezier(0.25, 1, 0.5, 1); + transition: background-color var(--dur-fast) var(--ease-out-quart); } .wd-list-row:hover { background: var(--bg-hover); } .wd-list-row.is-selected { background: var(--bg-surface); } diff --git a/services/web-ui/src/css/components/sidebar.css b/services/web-ui/src/css/components/sidebar.css index cef1e91..cf3f8b8 100644 --- a/services/web-ui/src/css/components/sidebar.css +++ b/services/web-ui/src/css/components/sidebar.css @@ -48,8 +48,8 @@ font: 500 13px/1 var(--font); color: var(--text-secondary); text-decoration: none; - transition: background-color 120ms cubic-bezier(0.25, 1, 0.5, 1), - color 120ms cubic-bezier(0.25, 1, 0.5, 1); + transition: background-color var(--dur-fast) var(--ease-out-quart), + color var(--dur-fast) var(--ease-out-quart); } .wd-nav-item:hover { background: var(--bg-hover); @@ -115,5 +115,5 @@ .wd-sidebar-user-info { flex: 1; min-width: 0; } .wd-sidebar-user-name { font: 500 12px/1.3 var(--font); color: var(--text-primary); } .wd-sidebar-user-role { font: 500 10px/1.3 var(--font); color: var(--text-tertiary); letter-spacing: 0.06em; text-transform: uppercase; } -.wd-sidebar-user-logout { opacity: 0; transition: opacity 120ms cubic-bezier(0.25, 1, 0.5, 1); } +.wd-sidebar-user-logout { opacity: 0; transition: opacity var(--dur-fast) var(--ease-out-quart); } .wd-sidebar-user:hover .wd-sidebar-user-logout { opacity: 1; } diff --git a/services/web-ui/src/css/components/slide-panel.css b/services/web-ui/src/css/components/slide-panel.css index eb992ce..b922fcb 100644 --- a/services/web-ui/src/css/components/slide-panel.css +++ b/services/web-ui/src/css/components/slide-panel.css @@ -6,10 +6,10 @@ position: fixed; inset: 0; z-index: var(--z-overlay); - background: oklch(8% 0.010 266 / 0.65); + background: var(--overlay); opacity: 0; pointer-events: none; - transition: opacity 240ms cubic-bezier(0.25, 1, 0.5, 1); + transition: opacity var(--dur-slide) var(--ease-out-quart); } .wd-slide-overlay.is-open { opacity: 1; @@ -29,7 +29,7 @@ flex-direction: column; overflow: hidden; transform: translateX(100%); - transition: transform 240ms cubic-bezier(0.16, 1, 0.3, 1); + transition: transform var(--dur-slide) var(--ease-out-expo); } .wd-slide-panel.is-open { transform: translateX(0); } diff --git a/services/web-ui/src/css/components/toast.css b/services/web-ui/src/css/components/toast.css index 3b6e332..69e8e49 100644 --- a/services/web-ui/src/css/components/toast.css +++ b/services/web-ui/src/css/components/toast.css @@ -21,7 +21,7 @@ display: flex; flex-direction: column; gap: 4px; - box-shadow: 0 12px 32px -16px oklch(0% 0 0 / 0.7); + box-shadow: 0 12px 32px -16px var(--shadow); } .wd-toast::before { content: ''; diff --git a/services/web-ui/src/css/components/tokens.css b/services/web-ui/src/css/components/tokens.css index a3c500e..eccc362 100644 --- a/services/web-ui/src/css/components/tokens.css +++ b/services/web-ui/src/css/components/tokens.css @@ -55,4 +55,27 @@ --z-overlay: 80; --z-panel: 90; --z-toast: 200; + + /* Hover-darker variants of accent + signals — promoted from + * inline oklch() arithmetic that was duplicated across button.css + * and card-operational.css */ + --accent-hover: oklch(52% 0.20 266); + --accent-bright: oklch(70% 0.18 266); + --signal-bad-hover: oklch(68% 0.22 25); + --signal-good-hover: oklch(74% 0.18 148); + --signal-warn-hover: oklch(84% 0.16 90); + /* Pure-black-ish tinted toward brand hue for thumbnails & overlays. */ + --thumb-black: oklch(0% 0 266); + --overlay: oklch(8% 0.010 266 / 0.65); + --shadow: oklch(0% 0 266 / 0.5); + + /* Motion + ease tokens — promoted from raw cubic-bezier strings */ + --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1); + --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); + --dur-fast: 120ms; + --dur-normal: 180ms; + --dur-slide: 240ms; + + /* Z layers — promoted from sidebar/topbar where 30 was hard-coded */ + --z-topbar: 30; } diff --git a/services/web-ui/src/css/components/topbar.css b/services/web-ui/src/css/components/topbar.css index 20ecbf7..6a0c3f7 100644 --- a/services/web-ui/src/css/components/topbar.css +++ b/services/web-ui/src/css/components/topbar.css @@ -3,7 +3,7 @@ .wd-topbar { position: sticky; top: 0; - z-index: 30; + z-index: var(--z-topbar); height: var(--topbar-h); display: flex; align-items: center;