From 673318c30573d30667aae3c1bc24c3b4cbb99bc0 Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Wed, 29 Jul 2026 09:21:06 +1200 Subject: [PATCH 01/13] Point the site color variables at the design system generic tokens 22 declarations in vars.css now reference generic tokens from @octopusdeploy/design-system-tokens - --colorTextPrimary/Secondary, --colorBorderPrimary/Tertiary, --colorBackgroundPrimaryDefault and SecondaryDefault, and --colorTextLinkDefault. Because those tokens theme themselves, 19 html[data-theme='dark'] overrides become redundant and are deleted, taking the block from 44 entries to 25. This is a visual change. The site's light theme was already close to the design system, so most of the shift is in dark mode: body text #dae2e9 -> #f4f6f8, links #1fc0ff -> #87bfec, header #152b3d -> #111a23, code background #0c1a24 -> #1f303f. Light shifts are small - borders #dae2e9 -> #dee1e6, tinted surfaces going neutral, body text #10212f -> #282f38 - and link colour in light does not change at all. Fixes two latent bugs: --background-default and --background-light had no dark override, so they resolved to white and pale blue in dark mode. Verified by snapshotting all 886 computed custom properties plus the rendered colour, background, border and font of seven elements, in both themes, before and after. 23 values change per theme and every one is accounted for; nothing shifted that wasn't intended or a documented knock-on through an existing alias. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 63 ++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index 2ce70aa32e..8ae58d7c66 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -85,32 +85,32 @@ --font-size-medium: 1rem; --font-size-small: 0.875rem; - --color-base-primary: var(--white); + --color-base-primary: var(--colorBackgroundPrimaryDefault); - --color-text: var(--blue-midnight); - --color-heading: var(--blue-grey-dark); - --color-text-secondary: var(--navy-700); + --color-text: var(--colorTextPrimary); + --color-heading: var(--colorTextPrimary); + --color-text-secondary: var(--colorTextSecondary); - --color-subtitle: var(--navy-600); + --color-subtitle: var(--colorTextSecondary); --font-size-subtitle: var(--font-size-large); --font-size-title: var(--font-size-xxlarge); - --border-color-header: var(--navy-200); + --border-color-header: var(--colorBorderPrimary); - --color-menu-link: var(--navy-600); - --color-menu-link-active: var(--navy-700); - --color-menu-link-alt: var(--blue-500); + --color-menu-link: var(--colorTextSecondary); + --color-menu-link-active: var(--colorTextPrimary); + --color-menu-link-alt: var(--colorTextLinkDefault); --color-menu-marker: var(--navy-300); - --bg-color-menu: var(--blue-qqq); + --bg-color-menu: var(--colorBackgroundSecondaryDefault); --bg-color-menu-open: rgba(13, 128, 216, 0.1); - --border-color-menu-open: var(--navy-200); + --border-color-menu-open: var(--colorBorderPrimary); --gap-menu: 0.6em; --navigation-width: 21.25rem; --bg-color-tab: var(--navy-200); - --border-color-tab: var(--navy-200); - --border-color-tab-active: var(--navy-400); + --border-color-tab: var(--colorBorderPrimary); + --border-color-tab-active: var(--colorBorderTertiary); --color-hint: #124164; --bg-color-hint: var(--lightest-blue); @@ -135,17 +135,17 @@ --duration-default: 300ms; --code-color: var(--color-text); - --code-background: var(--blue-100); + --code-background: var(--colorBackgroundSecondaryDefault); /* Backgrounds TODO - update with design system */ - --background-light: var(--blue-100); - --background-default: var(--white); + --background-light: var(--colorBackgroundSecondaryDefault); + --background-default: var(--colorBackgroundPrimaryDefault); /* Borders TODO - update with design system */ - --border-default-color: var(--blue-200); + --border-default-color: var(--colorBorderPrimary); /* Separator */ - --separator-color: #dae2e9; + --separator-color: var(--colorBorderPrimary); /* Scrollbar */ --scrollbar-color: #a9bbcb; @@ -158,7 +158,7 @@ --icon-tile-shadow: 0px 4px 10px 0px rgba(13, 128, 216, 0.2); /* Article header */ - --header-separator-color: var(--navy-200); + --header-separator-color: var(--colorBorderPrimary); --header-icon-border: var(--border-default-color); --header-icon-background: var(--background-light); @@ -190,7 +190,7 @@ --hamburger-lines-color: var(--blue-grey-light); /* Theme Switcher */ - --theme-switcher-border: var(--navy-200); + --theme-switcher-border: var(--colorBorderPrimary); /* Badge */ --badge-background: rgba(162, 209, 244, 0.2); @@ -204,7 +204,7 @@ /* To be checked and cleaned */ - --octo-blue: var(--blue-500); + --octo-blue: var(--colorTextLinkDefault); --lightest-blue: #e5f4ffff; --octo-blue-lighter: #2f95e3ff; --octo-blue-lightest: #1fc0ffff; @@ -218,7 +218,7 @@ --bold-font: var(--font-family); --code-font: Consolas, monaco, monospace; - --header-bg: var(--white); + --header-bg: var(--colorBackgroundPrimaryDefault); --header-icon-stroke: var(--blue-grey-light); --header-link-color: var(--octo-blue); --header-link-alt: var(--blue-gray-darker); @@ -263,32 +263,18 @@ } html[data-theme='dark'] { - --color-base-primary: #10202e; - --color-menu-link: var(--navy-300); - --color-menu-link-active: var(--navy-100); - --bg-color-menu: #0c1a24; --bg-color-menu-open: var(--blue-grey-dark); - --border-color-menu-open: var(--navy-700); - --header-bg: var(--blue-grey-dark); - --color-text: #dae2e9ff; - --color-heading: var(--white); - --color-subtitle: #f5f6f8; --body-link-alt: var(--white); --search-placeholder-color: var(--navy-400); --search-remove-icon-color: var(--white); --grey-lighter: var(--blue-grey-dark); /* TODO: update this */ --navy-200: #314c62; - --octo-blue: var(--octo-blue-lightest); - --border-color-header: var(--navy-700); /* TODO: update this */ --blue-grey: #dae2e9ff; --header-link-alt: var(--color-text); --grey-light: var(--navy-700); - --color-menu-link-alt: var(--octo-blue-lightest); - --body-link-color: var(--octo-blue-lightest); --octopus-logo-text-color: var(--white); - --theme-switcher-border: var(--navy-700); --color-hint: var(--color-text); --bg-color-hint: rgba(13, 128, 216, 0.1); --color-info: var(--color-text); @@ -296,17 +282,12 @@ html[data-theme='dark'] { --hamburger-lines-color: var(--white); --footer-link-color: var(--color-menu-link); --search-overlay: rgba(12, 26, 36, 0.8); - --header-separator-color: var(--navy-700); --header-icon-border: transparent; --header-icon-background: var(--blue-grey-dark); --badge-background: rgba(31, 192, 255, 0.1); --badge-color: var(--octo-blue-lightest); - --color-text-secondary: #dae2e9; - --icon-tile-background: #132838; --icon-tile-background-hover: #223950; --icon-tile-border: #1c3f59; --icon-tile-border-hover: var(--octo-blue-lightest); --icon-tile-shadow: 0px 6px 20px 0px var(--bg-color-menu); - --separator-color: var(--navy-700); - --code-background: #0c1a24; } From 3206df7ca145cbb692fc9cb224dc2ad6efefee63 Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Wed, 29 Jul 2026 09:43:30 +1200 Subject: [PATCH 02/13] Remove palette variables this change orphaned Once the site's color variables point at generic tokens, five palette entries have no remaining references: --navy-600, --blue-100, --blue-200, --blue-qqq and --blue-midnight. Each was declared once and referenced nowhere, so they are deleted. Verified with the snapshot harness: the five properties disappear from the computed set (886 -> 881) and nothing else changes - zero differences on the seven rendered elements in either theme. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 6 ------ 1 file changed, 6 deletions(-) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index 8ae58d7c66..ad6f54ae0a 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -35,17 +35,12 @@ --white: var(--colorScalesWhite); --navy-700: var(--colorScalesNavy700); - --navy-600: var(--colorScalesNavy600); --navy-400: var(--colorScalesNavy400); --navy-300: var(--colorScalesNavy300); --navy-200: var(--colorScalesNavy200); --navy-100: var(--colorScalesNavy100); --blue-500: var(--colorScalesBlue500); - --blue-200: var(--colorScalesBlue200); - --blue-100: var(--colorScalesBlue100); - /* No scale equivalent */ - --blue-qqq: #fafdff; /* TODO: remove green-400 as it's being used in one place only */ --green-400: var(--colorScalesGreen400); @@ -61,7 +56,6 @@ --blue-midnight-dark: #070e14ff; --blue-midnight-darker: #0a202fff; - --blue-midnight: #10212fff; --blue-midnight-lighter: #22425cff; --blue-grey-dark: #152b3dff; From 52c497717f4c9b6870b40114dc79f0dbbaa8aed6 Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Wed, 29 Jul 2026 10:16:31 +1200 Subject: [PATCH 03/13] Use brand tokens for the three literals that match them exactly An audit of every color in vars.css against the installed token stylesheets found three hardcoded values with an exact equivalent: --blue-grey-medium #113049 -> var(--brandGrey) --border-color-success #00b065 -> var(--brandGreen) --scrollbar-color #a9bbcb -> var(--navy-300) The first two are the only brand tokens the package defines that the site already used as literals; the third duplicated a palette entry. Verified with the snapshot harness: 881 computed properties and seven rendered elements identical in both themes. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index ad6f54ae0a..fae9b1d24b 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -60,7 +60,7 @@ --blue-grey-dark: #152b3dff; --blue-gray-darker: #1f2f3cff; - --blue-grey-medium: #113049ff; + --blue-grey-medium: var(--brandGrey); --blue-grey: var(--navy-700); --blue-grey-light: #274b66ff; /* This is navy 500 in the design system's scale */ @@ -116,7 +116,7 @@ --color-success: #04502f; --bg-color-success: #e8ffeb; - --border-color-success: #00b065; + --border-color-success: var(--brandGreen); --color-warning: #a23623; --bg-color-warning: #fefae9; @@ -142,7 +142,7 @@ --separator-color: var(--colorBorderPrimary); /* Scrollbar */ - --scrollbar-color: #a9bbcb; + --scrollbar-color: var(--navy-300); /* Icon Tile */ --icon-tile-border: var(--border-default-color); From 8b863fe7e87827f68ec1081591ecb44e1be939ad Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Wed, 29 Jul 2026 10:34:40 +1200 Subject: [PATCH 04/13] Map callouts, tabs and icons onto generic tokens Callouts had no dark theming at all: --color-success, --color-warning, --color-problem and their backgrounds and borders carried no dark override, so a success callout rendered as #e8ffeb pale green with #04502f text on a dark page. Backgrounds and borders now use the status tokens, which theme themselves, and the four redundant dark overrides are gone. Callout text maps to --colorTextPrimary rather than the matching --colorText{Info,Success,Warning,Danger}. main.css sets `color` on the whole callout block (.hint, .success and friends), so that is body copy, and the status text tokens are not built for it - #b98f02 on #fff7d9 is 2.8:1, which fails WCAG AA. With --colorTextPrimary every callout lands at 12.5:1 or better in light, up from 6.5-9.5:1, and AA or better in dark. Also maps --bg-color-tab to --colorBackgroundTertiary, --icon-fill to --colorIconSecondary and --hamburger-lines-color to --colorIconPrimary, retiring one more dark override. --border-color-success moves from var(--brandGreen) to var(--colorBorderSuccess), superseding the earlier commit in this branch: the brand token does not theme, the border token does. Removes five variables with no remaining references: --header-icon-stroke, --header-link-alt-bg and --image-bg were already dead, and --lightest-blue became dead when the callout backgrounds stopped using it. Resolves the two "update with design system" TODOs, which are now done, and rewrites the three that remain to say what actually blocks them. The green-400 note claimed one usage where there are two, both icon colors that --colorIconSuccess could take. --navy-200 and --blue-grey are still hand-themed only because main.css consumes those palette entries directly, so both notes now point at the specific rules that need moving. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 60 +++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index fae9b1d24b..c57e27f20a 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -42,7 +42,9 @@ --blue-500: var(--colorScalesBlue500); - /* TODO: remove green-400 as it's being used in one place only */ + /* TODO: --green-400 only colors two icons in main.css (.fa-circle-check and + .fa-heart.green). Those could use --colorIconSuccess instead, which would + retire this entry. */ --green-400: var(--colorScalesGreen400); --green-500: var(--colorScalesGreen500); /* Brand greens, no scale equivalent */ @@ -102,40 +104,40 @@ --navigation-width: 21.25rem; - --bg-color-tab: var(--navy-200); + --bg-color-tab: var(--colorBackgroundTertiary); --border-color-tab: var(--colorBorderPrimary); --border-color-tab-active: var(--colorBorderTertiary); - --color-hint: #124164; - --bg-color-hint: var(--lightest-blue); - --border-color-hint: var(--blue-500); + --color-hint: var(--colorTextPrimary); + --bg-color-hint: var(--colorBackgroundInfo); + --border-color-hint: var(--colorBorderInfo); - --color-info: #124164; - --bg-color-info: var(--lightest-blue); - --border-color-info: var(--blue-500); + --color-info: var(--colorTextPrimary); + --bg-color-info: var(--colorBackgroundInfo); + --border-color-info: var(--colorBorderInfo); - --color-success: #04502f; - --bg-color-success: #e8ffeb; - --border-color-success: var(--brandGreen); + --color-success: var(--colorTextPrimary); + --bg-color-success: var(--colorBackgroundSuccess); + --border-color-success: var(--colorBorderSuccess); - --color-warning: #a23623; - --bg-color-warning: #fefae9; - --border-color-warning: #fc8431; + --color-warning: var(--colorTextPrimary); + --bg-color-warning: var(--colorBackgroundWarning); + --border-color-warning: var(--colorBorderWarning); - --color-problem: #931919; - --bg-color-problem: #fff2ee; - --border-color-problem: #ff4848; + --color-problem: var(--colorTextPrimary); + --bg-color-problem: var(--colorBackgroundDanger); + --border-color-problem: var(--colorBorderDanger); --duration-default: 300ms; --code-color: var(--color-text); --code-background: var(--colorBackgroundSecondaryDefault); - /* Backgrounds TODO - update with design system */ + /* Backgrounds */ --background-light: var(--colorBackgroundSecondaryDefault); --background-default: var(--colorBackgroundPrimaryDefault); - /* Borders TODO - update with design system */ + /* Borders */ --border-default-color: var(--colorBorderPrimary); /* Separator */ @@ -181,7 +183,7 @@ --hamburger-translate-y: calc( var(--hamburger-line-height) + var(--hamburger-line-margin) ); - --hamburger-lines-color: var(--blue-grey-light); + --hamburger-lines-color: var(--colorIconPrimary); /* Theme Switcher */ --theme-switcher-border: var(--colorBorderPrimary); @@ -199,7 +201,6 @@ /* To be checked and cleaned */ --octo-blue: var(--colorTextLinkDefault); - --lightest-blue: #e5f4ffff; --octo-blue-lighter: #2f95e3ff; --octo-blue-lightest: #1fc0ffff; @@ -213,12 +214,9 @@ --code-font: Consolas, monaco, monospace; --header-bg: var(--colorBackgroundPrimaryDefault); - --header-icon-stroke: var(--blue-grey-light); --header-link-color: var(--octo-blue); --header-link-alt: var(--blue-gray-darker); - --header-link-alt-bg: var(--blue-grey-smoke); - --image-bg: var(--blue-grey-smoke); --content-bg: var(--white); --body-link-color: var(--octo-blue); @@ -227,7 +225,7 @@ --footer-link-color: var(--navy-200); --icon-stroke: var(--white); - --icon-fill: var(--blue-grey-light); + --icon-fill: var(--colorIconSecondary); --octopus-logo-text-color: #0f2535; @@ -262,18 +260,16 @@ html[data-theme='dark'] { --search-placeholder-color: var(--navy-400); --search-remove-icon-color: var(--white); --grey-lighter: var(--blue-grey-dark); - /* TODO: update this */ + /* TODO: --navy-200 is still hand-themed because main.css uses it directly for + borders and one background (lines 112, 216, 262, 920, 2539). Point those at + --border-default-color / --bg-color-tab and this override can go. */ --navy-200: #314c62; - /* TODO: update this */ + /* TODO: --blue-grey is hand-themed for .card__description (main.css:1016). + That is secondary text, so --color-text-secondary already covers it. */ --blue-grey: #dae2e9ff; --header-link-alt: var(--color-text); --grey-light: var(--navy-700); --octopus-logo-text-color: var(--white); - --color-hint: var(--color-text); - --bg-color-hint: rgba(13, 128, 216, 0.1); - --color-info: var(--color-text); - --bg-color-info: var(--blue-grey-light); - --hamburger-lines-color: var(--white); --footer-link-color: var(--color-menu-link); --search-overlay: rgba(12, 26, 36, 0.8); --header-icon-border: transparent; From e74aa47060417879eb6b60bc70a5f818d101db88 Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Wed, 29 Jul 2026 10:45:49 +1200 Subject: [PATCH 05/13] Restore the original green-400 TODO wording Keeps the comment as it was on main. The CTA greens keep their original "Brand greens, no scale equivalent" note too - neither value has a token equivalent, and choosing a replacement is a design decision about the button rather than something to resolve here. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index c57e27f20a..5e6f50649f 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -42,9 +42,7 @@ --blue-500: var(--colorScalesBlue500); - /* TODO: --green-400 only colors two icons in main.css (.fa-circle-check and - .fa-heart.green). Those could use --colorIconSuccess instead, which would - retire this entry. */ + /* TODO: remove green-400 as it's being used in one place only */ --green-400: var(--colorScalesGreen400); --green-500: var(--colorScalesGreen500); /* Brand greens, no scale equivalent */ From 908155db9d705ae368418739c5aa83a00473a04b Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Wed, 29 Jul 2026 11:11:51 +1200 Subject: [PATCH 06/13] Keep the dark side navigation hand-themed Mapping --bg-color-menu to --colorBackgroundSecondaryDefault turned the side navigation from a recessed panel into a raised one: it went from #0c1a24, darker than the page, to #1f303f, well above it. The design system's dark backgrounds only step lighter from --colorBackgroundPrimaryDefault (#111A23 -> #1F303F -> #2E475D), so no token describes a surface below the page. The dark override is restored with a comment explaining why. Light mode keeps the token. Measured against production: the nav is #0c1a24 in both, and recessed relative to the page again (#111a23 here, #10202e on live). Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index 5e6f50649f..bcf709f572 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -253,6 +253,11 @@ } html[data-theme='dark'] { + /* The side navigation is a recessed panel, darker than the page. The design + system's dark backgrounds only step lighter from + --colorBackgroundPrimaryDefault (#111A23 -> #1F303F -> #2E475D), so there + is no token for a surface below the page, and this stays hand-themed. */ + --bg-color-menu: #0c1a24; --bg-color-menu-open: var(--blue-grey-dark); --body-link-alt: var(--white); --search-placeholder-color: var(--navy-400); From d64d27dad7d2a2c12d0df079a47f96ed88fedf06 Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Wed, 29 Jul 2026 13:15:31 +1200 Subject: [PATCH 07/13] Rebuild the dark surface ramp from tokens Mapping every background straight onto its token flattened dark mode: the page dropped to --colorBackgroundPrimaryDefault #111A23, which is close enough to the navigation and code wells that the whole page read as one colour, and the recessed surfaces ended up lighter than the page. The site uses three levels of depth in dark, so it now uses three tokens: --colorBackgroundPrimaryDefault #111A23 navigation, code blocks --colorBackgroundSecondaryDefault #1F303F page and header --colorBackgroundTertiary #2E475D icon tiles That means the page takes Secondary rather than Primary in dark, which diverges from the portal's use of Primary as the page, but it reproduces the relationships the docs site already had: nav and code recessed below the page, cards raised above it. Light mode is untouched and keeps Primary. Measured against production, ordered by lightness: sidebar/code #111a23 (was #0c1a24) page/header #1f303f (was #10202e) hint callout #1d384e (was #102a3f) The hint and info callout backgrounds are restored byte-for-byte to their original values - a 10% Octopus Cyan wash and var(--blue-grey-light). The design system has no translucent background token, and the wash is a deliberate effect that a solid #0F4778 fill replaced with a heavy block. Of the 44 overrides originally in this block, 23 resolve to values identical to their tokens, notably seven navy-700 borders collapsing onto --colorBorderPrimary. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index bcf709f572..a921ee71a4 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -253,12 +253,11 @@ } html[data-theme='dark'] { - /* The side navigation is a recessed panel, darker than the page. The design - system's dark backgrounds only step lighter from - --colorBackgroundPrimaryDefault (#111A23 -> #1F303F -> #2E475D), so there - is no token for a surface below the page, and this stays hand-themed. */ - --bg-color-menu: #0c1a24; + /* The page sits mid-ramp; the nav and code wells are recessed below it */ + --color-base-primary: var(--colorBackgroundSecondaryDefault); + --bg-color-menu: var(--colorBackgroundPrimaryDefault); --bg-color-menu-open: var(--blue-grey-dark); + --header-bg: var(--colorBackgroundSecondaryDefault); --body-link-alt: var(--white); --search-placeholder-color: var(--navy-400); --search-remove-icon-color: var(--white); @@ -273,14 +272,19 @@ html[data-theme='dark'] { --header-link-alt: var(--color-text); --grey-light: var(--navy-700); --octopus-logo-text-color: var(--white); + /* No translucent background token exists */ + --bg-color-hint: rgba(13, 128, 216, 0.1); + --bg-color-info: var(--blue-grey-light); --footer-link-color: var(--color-menu-link); --search-overlay: rgba(12, 26, 36, 0.8); --header-icon-border: transparent; --header-icon-background: var(--blue-grey-dark); --badge-background: rgba(31, 192, 255, 0.1); --badge-color: var(--octo-blue-lightest); + --icon-tile-background: var(--colorBackgroundTertiary); --icon-tile-background-hover: #223950; --icon-tile-border: #1c3f59; --icon-tile-border-hover: var(--octo-blue-lightest); --icon-tile-shadow: 0px 6px 20px 0px var(--bg-color-menu); + --code-background: var(--colorBackgroundPrimaryDefault); } From 6ddbf193146aefc2463aa3e79778914398989d8f Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Wed, 29 Jul 2026 14:33:54 +1200 Subject: [PATCH 08/13] Use the callout token family for callouts The design system has a dedicated --colorCallout* family, which is a better fit than the generic background and text tokens these were using: --colorCalloutText{Info,Success,Warning,Danger} --colorCalloutBackground{...}Default --colorCalloutBorder{...} Two reasons it matters. The backgrounds are translucent by design - light is rgb(from #CDE4F7 r g b / 0.5), dark is rgb(from #093051 r g b / 0.8) - which is the same washed effect the site was hand-rolling, so both dark overrides for hint and info are no longer needed and are removed. And the family pairs its text colors with its backgrounds, unlike the generic ones. --colorTextWarning on --colorBackgroundWarning was 2.8:1, failing WCAG AA, which is why callout text was previously mapped to --colorTextPrimary. Measured in a browser, every callout is now AAA in both themes, worst case 9.59:1: light #093051 on #e6f2fb is 11.85:1, dark #cde4f7 on #0b2c48 is 10.98:1. The tokens use CSS Color 4 relative color syntax, which needs Chrome 119, Safari 16.4 or Firefox 128. Chromium resolves it to color(srgb ...) as expected. Older browsers treat the declaration as invalid and drop the fill; the text and left border still render and both stay legible. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 41 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index a921ee71a4..2a22032ce4 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -106,25 +106,25 @@ --border-color-tab: var(--colorBorderPrimary); --border-color-tab-active: var(--colorBorderTertiary); - --color-hint: var(--colorTextPrimary); - --bg-color-hint: var(--colorBackgroundInfo); - --border-color-hint: var(--colorBorderInfo); + --color-hint: var(--colorCalloutTextInfo); + --bg-color-hint: var(--colorCalloutBackgroundInfoDefault); + --border-color-hint: var(--colorCalloutBorderInfo); - --color-info: var(--colorTextPrimary); - --bg-color-info: var(--colorBackgroundInfo); - --border-color-info: var(--colorBorderInfo); + --color-info: var(--colorCalloutTextInfo); + --bg-color-info: var(--colorCalloutBackgroundInfoDefault); + --border-color-info: var(--colorCalloutBorderInfo); - --color-success: var(--colorTextPrimary); - --bg-color-success: var(--colorBackgroundSuccess); - --border-color-success: var(--colorBorderSuccess); + --color-success: var(--colorCalloutTextSuccess); + --bg-color-success: var(--colorCalloutBackgroundSuccessDefault); + --border-color-success: var(--colorCalloutBorderSuccess); - --color-warning: var(--colorTextPrimary); - --bg-color-warning: var(--colorBackgroundWarning); - --border-color-warning: var(--colorBorderWarning); + --color-warning: var(--colorCalloutTextWarning); + --bg-color-warning: var(--colorCalloutBackgroundWarningDefault); + --border-color-warning: var(--colorCalloutBorderWarning); - --color-problem: var(--colorTextPrimary); - --bg-color-problem: var(--colorBackgroundDanger); - --border-color-problem: var(--colorBorderDanger); + --color-problem: var(--colorCalloutTextDanger); + --bg-color-problem: var(--colorCalloutBackgroundDangerDefault); + --border-color-problem: var(--colorCalloutBorderDanger); --duration-default: 300ms; @@ -253,11 +253,11 @@ } html[data-theme='dark'] { - /* The page sits mid-ramp; the nav and code wells are recessed below it */ - --color-base-primary: var(--colorBackgroundSecondaryDefault); + /* Page, header and nav share the darkest background; panels sit above it */ + --color-base-primary: var(--colorBackgroundPrimaryDefault); --bg-color-menu: var(--colorBackgroundPrimaryDefault); --bg-color-menu-open: var(--blue-grey-dark); - --header-bg: var(--colorBackgroundSecondaryDefault); + --header-bg: var(--colorBackgroundPrimaryDefault); --body-link-alt: var(--white); --search-placeholder-color: var(--navy-400); --search-remove-icon-color: var(--white); @@ -272,9 +272,6 @@ html[data-theme='dark'] { --header-link-alt: var(--color-text); --grey-light: var(--navy-700); --octopus-logo-text-color: var(--white); - /* No translucent background token exists */ - --bg-color-hint: rgba(13, 128, 216, 0.1); - --bg-color-info: var(--blue-grey-light); --footer-link-color: var(--color-menu-link); --search-overlay: rgba(12, 26, 36, 0.8); --header-icon-border: transparent; @@ -286,5 +283,5 @@ html[data-theme='dark'] { --icon-tile-border: #1c3f59; --icon-tile-border-hover: var(--octo-blue-lightest); --icon-tile-shadow: 0px 6px 20px 0px var(--bg-color-menu); - --code-background: var(--colorBackgroundPrimaryDefault); + --code-background: var(--colorBackgroundSecondaryDefault); } From 8309e9334b401812932bdc757df032c215435b9b Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Wed, 29 Jul 2026 15:16:19 +1200 Subject: [PATCH 09/13] Drop three dark overrides that repeat their own root value --color-base-primary, --header-bg and --code-background declared the same token in the dark block as in :root, so the override did nothing - the token already themes itself. Verified with the snapshot harness: 877 computed properties and seven rendered elements identical in both themes. That leaves --bg-color-menu as the only surface override, because the navigation is a distinct panel in light and matches the page in dark. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index 2a22032ce4..1de97ad96f 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -253,11 +253,9 @@ } html[data-theme='dark'] { - /* Page, header and nav share the darkest background; panels sit above it */ - --color-base-primary: var(--colorBackgroundPrimaryDefault); + /* The navigation matches the page in dark, unlike light */ --bg-color-menu: var(--colorBackgroundPrimaryDefault); --bg-color-menu-open: var(--blue-grey-dark); - --header-bg: var(--colorBackgroundPrimaryDefault); --body-link-alt: var(--white); --search-placeholder-color: var(--navy-400); --search-remove-icon-color: var(--white); @@ -283,5 +281,4 @@ html[data-theme='dark'] { --icon-tile-border: #1c3f59; --icon-tile-border-hover: var(--octo-blue-lightest); --icon-tile-shadow: 0px 6px 20px 0px var(--bg-color-menu); - --code-background: var(--colorBackgroundSecondaryDefault); } From 94b974f523acaacd68c18ce3da6aea6c6715ef77 Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Thu, 30 Jul 2026 11:21:10 +1200 Subject: [PATCH 10/13] Address review feedback --border-color-tab-active used --colorBorderTertiary, which is byte-identical to --colorBorderDisabled in both themes and so the wrong token for a selected state. It is the only marker on the selected tab and the tabpanel outline, and it had dropped to 1.97:1 in light and 2.65:1 in dark, failing WCAG 1.4.11. --colorBorderSelected gives 4.63:1 and 5.87:1. The dark icon tile had three problems, all caused by putting the fill on --colorBackgroundTertiary, the top of the dark ramp, which left nothing lighter for hover or the border. Dropping the fill a step lets the rest inherit: fill #1f303f inherits --background-light, dark override removed hover #2e475d --colorBackgroundTertiary, so hover lightens again border #2e475d inherits --border-default-color, dark override removed hover #449be1 --colorBorderSelected, replacing off-brand #1fc0ff shadow rgba(0, 0, 0, 0.4), replacing var(--bg-color-menu), which had come to resolve to the page color and so painted nothing Border contrast on the fill is 1.40:1, in line with the original dark tile at 1.37:1 and light at 1.21:1. The blue hover border matches what main already did with --octo-blue-lightest. Verified in a browser: both themes lighten on hover. --header-icon-background pointed at var(--blue-grey-dark) #152b3d, which sits between two ramp steps and belongs to neither. :root already resolves it through --background-light, so the override is removed. Both TODO comments cited line numbers that were already stale. They now name the selectors: code, .image, figure:has(p > img) p, .card and .site-search-results__item for --navy-200, and .card__description for --blue-grey. Takes the dark block from 22 declarations to 18. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index 1de97ad96f..0017e18835 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -104,7 +104,7 @@ --bg-color-tab: var(--colorBackgroundTertiary); --border-color-tab: var(--colorBorderPrimary); - --border-color-tab-active: var(--colorBorderTertiary); + --border-color-tab-active: var(--colorBorderSelected); --color-hint: var(--colorCalloutTextInfo); --bg-color-hint: var(--colorCalloutBackgroundInfoDefault); @@ -260,12 +260,12 @@ html[data-theme='dark'] { --search-placeholder-color: var(--navy-400); --search-remove-icon-color: var(--white); --grey-lighter: var(--blue-grey-dark); - /* TODO: --navy-200 is still hand-themed because main.css uses it directly for - borders and one background (lines 112, 216, 262, 920, 2539). Point those at - --border-default-color / --bg-color-tab and this override can go. */ + /* TODO: --navy-200 is still hand-themed because main.css uses it directly on + code, .image, figure:has(p > img) p, .card and .site-search-results__item. + Point those at --border-default-color / --bg-color-tab and this can go. */ --navy-200: #314c62; - /* TODO: --blue-grey is hand-themed for .card__description (main.css:1016). - That is secondary text, so --color-text-secondary already covers it. */ + /* TODO: --blue-grey is hand-themed for .card__description, which is + secondary text, so --color-text-secondary already covers it. */ --blue-grey: #dae2e9ff; --header-link-alt: var(--color-text); --grey-light: var(--navy-700); @@ -273,12 +273,10 @@ html[data-theme='dark'] { --footer-link-color: var(--color-menu-link); --search-overlay: rgba(12, 26, 36, 0.8); --header-icon-border: transparent; - --header-icon-background: var(--blue-grey-dark); --badge-background: rgba(31, 192, 255, 0.1); --badge-color: var(--octo-blue-lightest); - --icon-tile-background: var(--colorBackgroundTertiary); - --icon-tile-background-hover: #223950; - --icon-tile-border: #1c3f59; - --icon-tile-border-hover: var(--octo-blue-lightest); - --icon-tile-shadow: 0px 6px 20px 0px var(--bg-color-menu); + /* Tiles sit one step above the page so hover has somewhere lighter to go */ + --icon-tile-background-hover: var(--colorBackgroundTertiary); + --icon-tile-border-hover: var(--colorBorderSelected); + --icon-tile-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.4); } From 2b13d6af77b0c9adcfc92c19760fdf88ec29bdf8 Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Thu, 30 Jul 2026 12:22:31 +1200 Subject: [PATCH 11/13] Use the scrollbar token for the scrollbar thumb --scrollbar-color pointed at --navy-300, a palette entry, so it carried one value for both themes. It feeds ::-webkit-scrollbar-thumb, and the package has --colorScrollbarHandle for exactly that. This also fixes a contrast problem: at #a9bbcb on white the thumb was 1.97:1, below the 3:1 that WCAG 1.4.11 asks of a non-text UI component. #959595 gives 3.00:1. Dark moves from 8.91:1 to 3.83:1, which still clears. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index 0017e18835..3c809b93cf 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -142,7 +142,7 @@ --separator-color: var(--colorBorderPrimary); /* Scrollbar */ - --scrollbar-color: var(--navy-300); + --scrollbar-color: var(--colorScrollbarHandle); /* Icon Tile */ --icon-tile-border: var(--border-default-color); From b41cd5279c8ca257ef82a66aad411a0a31b66507 Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Thu, 30 Jul 2026 13:22:25 +1200 Subject: [PATCH 12/13] Address follow-up review: drop the dead shadow, hoist the tile hover border --icon-tile-shadow was declared in both blocks and read nowhere - main.css never references it. The rgba(0, 0, 0, 0.4) in the previous commit therefore changed a variable nothing renders, and pointing it at --shadowMedium would have adopted a token for dead code. Both declarations are removed. --icon-tile-border-hover was equal to --icon-tile-border in light, so the light tile border did not change on hover, while dark had its own override. :root now uses --colorBorderSelected for both themes and the dark override goes. Verified in a browser: light #dee1e6 -> #1a77ca, dark #2e475d -> #449be1, and both themes still lighten the fill. Takes the dark block to 17 declarations. The earlier claim of 18 was wrong - the grep behind it excluded --navy-200 because of the digits in the name. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/vars.css | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/public/docs/css/vars.css b/public/docs/css/vars.css index 3c809b93cf..6307d8c03a 100644 --- a/public/docs/css/vars.css +++ b/public/docs/css/vars.css @@ -146,10 +146,9 @@ /* Icon Tile */ --icon-tile-border: var(--border-default-color); - --icon-tile-border-hover: var(--border-default-color); + --icon-tile-border-hover: var(--colorBorderSelected); --icon-tile-background: var(--background-light); --icon-tile-background-hover: var(--background-default); - --icon-tile-shadow: 0px 4px 10px 0px rgba(13, 128, 216, 0.2); /* Article header */ --header-separator-color: var(--colorBorderPrimary); @@ -277,6 +276,4 @@ html[data-theme='dark'] { --badge-color: var(--octo-blue-lightest); /* Tiles sit one step above the page so hover has somewhere lighter to go */ --icon-tile-background-hover: var(--colorBackgroundTertiary); - --icon-tile-border-hover: var(--colorBorderSelected); - --icon-tile-shadow: 0px 6px 20px 0px rgba(0, 0, 0, 0.4); } From 1555e408f7f78a79398cc7af3c11558d70536700 Mon Sep 17 00:00:00 2001 From: William Laugesen Date: Thu, 30 Jul 2026 14:01:31 +1200 Subject: [PATCH 13/13] Give the tab panel a background [role='tabpanel'] set background: var(--aft), and --aft is defined nowhere in the repo, so the panel had no background at all. The selected tab already uses --color-base-primary for both its fill and its bottom border, so the panel now uses the same variable and the two read as one surface: #ffffff in light, #111a23 in dark. The tabs are built at runtime by public/docs/js/modules/detail-tabs.js, which converts
into a tablist, so none of this markup appears in the static HTML. Verified in a browser on /docs/deployments/custom-scripts. Worth fixing here because moving --border-color-tab-active to --colorBorderSelected draws a 2px blue border around every panel, which made the missing background obvious. Co-Authored-By: Claude Opus 5 (1M context) --- public/docs/css/main.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/docs/css/main.css b/public/docs/css/main.css index 8c59b348a0..eab45d2183 100644 --- a/public/docs/css/main.css +++ b/public/docs/css/main.css @@ -3416,7 +3416,7 @@ img.btn__icon { padding: 1rem; border: 2px solid var(--border-color-tab-active); border-radius: var(--standard-radius); - background: var(--aft); + background: var(--color-base-primary); overflow: auto; }