/* Self-hosted SUSE variable fonts - same-origin, no CDN egress; mirrors shells/web/src/styles/fonts.css,
   including its source ORDER: the shell copy under /fonts/ ships on every profile, the brand catalog
   under /catalog/fonts/ only under a pack that has one. Listing the catalog alone (as this did before
   2026-08-10) meant the whole docs site fell back to a system font on the neutral profile. */
@font-face{font-family:'SUSE';src:url('/fonts/SUSE[wght].woff2') format('woff2-variations'),url('/catalog/fonts/webfonts/SUSE[wght].woff2') format('woff2-variations');font-weight:100 900;font-style:normal;font-display:swap}
@font-face{font-family:'SUSE';src:url('/fonts/SUSE-Italic[wght].woff2') format('woff2-variations'),url('/catalog/fonts/webfonts/SUSE-Italic[wght].woff2') format('woff2-variations');font-weight:100 900;font-style:italic;font-display:swap}
@font-face{font-family:'SUSE Mono';src:url('/fonts/SUSEMono[wght].woff2') format('woff2-variations'),url('/catalog/fonts/webfonts/SUSEMono[wght].woff2') format('woff2-variations');font-weight:100 900;font-style:normal;font-display:swap}
@font-face{font-family:'SUSE Mono';src:url('/fonts/SUSEMono-Italic[wght].woff2') format('woff2-variations'),url('/catalog/fonts/webfonts/SUSEMono-Italic[wght].woff2') format('woff2-variations');font-weight:100 900;font-style:italic;font-display:swap}
/* Cinzel (SIL OFL 1.1, see /info/fonts/Cinzel-OFL.txt) - Roman inscriptional capitals,
   the same source Gill drew Perpetua Titling from. Self-hosted, not fetched from
   fonts.gstatic.com: a third-party request on every docs page would contradict what
   server-surface.md tells the reader. Latin subset only, 26 KB, loaded on one page. */
@font-face{font-family:'Cinzel';src:url('/info/fonts/cinzel-latin.woff2') format('woff2-variations');font-weight:400 900;font-style:normal;font-display:swap;unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+2122,U+2212}
:root {
  --safe-top: max(env(safe-area-inset-top, 0px), var(--safe-top-fb, 0px));
  --safe-bottom: max(env(safe-area-inset-bottom, 0px), var(--safe-bottom-fb, 0px));
  --safe-left: max(env(safe-area-inset-left, 0px), var(--safe-left-fb, 0px));
  --safe-right: max(env(safe-area-inset-right, 0px), var(--safe-right-fb, 0px));
}
:root {
  --chrome-h: calc(2.6rem * var(--a11y-fs, 1));   
  --chrome-top: calc(0.5rem + var(--safe-top));    
  --chrome-inset: 2rem;    
  --chrome-grow: calc(2.6rem * (var(--a11y-fs, 1) - 1));
}
:root {
  --grid-gap: 2rem;
  --grid-gap-tight: 12px;
}
@media (max-width: 640px) {
  :root {
    --grid-gap: var(--grid-gap-tight);
  }
}
@media (max-width: 640px) {
  :root {
    --chrome-top: calc(1.25rem + var(--safe-top));
  }
}
@media (pointer: coarse) {
  :root {
    --chrome-h: max(44px, calc(44px * var(--a11y-fs)));
  }
}
@media (pointer: coarse) {
  html[data-a11y-text="large"] {
    --chrome-h: calc(44px * var(--a11y-fs));
  }
}
:root {
  --vf-ai-1: 276 86% 67%;  --vf-ai-2: 262 74% 48%;  --vf-ai: 270 80% 58%;
}
:root {
  --track-rail: hsl(var(--muted) / 0.55);
}
:root {
  --preview-surface: hsl(var(--muted) / 0.6);
  --preview-checker: repeating-conic-gradient(
    hsl(var(--muted-foreground) / .025) 0% 25%,
    transparent 0% 50%) 50% / 14px 14px;
}
:root {
  --track-tier-1: 28%;
  --track-tier-2: 14%;
  --track-tier-3: 8%;
  --track-tier-beyond: 0%;
}
[data-theme="dark"],
[data-theme="brand"] {
  --track-tier-1: 46%;
  --track-tier-2: 26%;
  --track-tier-3: 15%;
}
:root {
  --font-brand: 'SUSE', ui-sans-serif, system-ui, sans-serif;
  --font-mono: 'SUSE Mono', ui-monospace, monospace;
  --edge: inset 0 0 0 1px hsl(var(--border));
  --edge-faint: inset 0 0 0 1px hsl(var(--foreground) / .1);
  --edge-strong: inset 0 0 0 1px hsl(var(--foreground) / .18);
  --shadow-1: 0 1px 3px hsl(0 0% 0% / .13);
  --shadow-2: 0 4px 14px hsl(0 0% 0% / .18);
  --shadow-3: 0 8px 28px hsl(0 0% 0% / .22);
  --shadow-4: 0 12px 36px hsl(0 0% 0% / .26);
  --shadow-5: 0 24px 60px hsl(0 0% 0% / .3);
  --bevel: inset 0 1px hsl(0 0% 100% / .1);
  --ring-focus: 0 0 0 3px hsl(var(--ring) / .15);
  --ring-focus-strong: 0 0 0 2px hsl(var(--primary) / .35);
  --radius-xs: calc(var(--radius) * .25);
  --radius-sm: calc(var(--radius) * .5);
  --radius-md: calc(var(--radius) * .75);
  --radius-lg: var(--radius);
  --radius-pill: calc(var(--radius) * 999);
  --radius-round: calc(var(--radius) * 999);
  --fs-2xs: calc(10px * var(--a11y-fs));
  --fs-xs: calc(11px * var(--a11y-fs));
  --fs-sm: calc(12px * var(--a11y-fs));
  --fs-md: calc(13px * var(--a11y-fs));
  --fs-lg: calc(14px * var(--a11y-fs));
  --fs-xl: calc(16px * var(--a11y-fs));
  --sp-1: calc(var(--space) * .25);
  --sp-2: calc(var(--space) * .5);
  --sp-3: calc(var(--space) * .75);
  --sp-4: var(--space);
  --sp-5: calc(var(--space) * 1.25);
  --sp-6: calc(var(--space) * 1.5);
  --sp-7: calc(var(--space) * 2);
  --sp-8: calc(var(--space) * 3);
  --dur-1: .12s;
  --dur-2: .18s;
  --dur-3: .3s;
  --ease-out: cubic-bezier(.32, .72, 0, 1);
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
  --z-chrome: 20;
  --z-overlay: 50;
  --z-toast: 90;
  --z-max: 100;
  --z-top: 100000;
}
:root {
  --ui-color-text-default: hsl(var(--foreground));
  --ui-color-text-muted: hsl(var(--muted-foreground));
  --ui-color-surface-canvas: hsl(var(--background));
  --ui-color-surface-raised: hsl(var(--card));
  --ui-color-surface-overlay: hsl(var(--popover));
  --ui-color-surface-muted: hsl(var(--muted));
  --ui-color-action-primary: hsl(var(--primary));
  --ui-color-action-on-primary: hsl(var(--primary-foreground));
  --ui-color-selection-surface: hsl(var(--primary) / .12);
  --ui-color-selection-border: hsl(var(--primary));
  --ui-color-border-default: hsl(var(--border));
  --ui-color-focus-ring: hsl(var(--ring));
  --ui-color-syntax-keyword: hsl(var(--primary));
  --ui-color-syntax-string: var(--ui-color-text-default);
  --ui-color-syntax-comment: var(--ui-color-text-muted);
  --ui-color-syntax-number: hsl(var(--primary));
  --ui-color-syntax-function: var(--ui-color-text-default);
  --ui-color-syntax-type: hsl(var(--primary));
  --ui-color-syntax-operator: var(--ui-color-text-muted);
  --ui-color-status-danger: hsl(var(--destructive));
  --ui-color-status-danger-surface: hsl(var(--destructive) / .07);
  --ui-color-status-notice-surface: hsl(var(--primary) / .07);
  --ui-size-target: 44px;
  --ui-size-icon-sm: calc(14px * var(--a11y-fs));
  --ui-size-icon-md: calc(16px * var(--a11y-fs));
  --ui-size-icon-lg: calc(20px * var(--a11y-fs));
  --ui-size-control: calc(30px * var(--a11y-fs));
  --ui-space-section: 64px;
  --ui-space-control-inline: var(--sp-4);
  --ui-space-control-block: var(--sp-3);
  --ui-space-panel: var(--sp-7);
  --ui-space-page: var(--sp-8);
  --ui-radius-control: var(--radius-sm);
  --ui-radius-choice: var(--radius-xs);
  --ui-radius-choice-round: var(--radius-round);
  --ui-radius-surface: var(--radius-lg);
  --ui-radius-card: calc(var(--radius) * 1.25);
  --ui-radius-panel: var(--radius);
  --ui-radius-pill: var(--radius-pill);
  --ui-elevation-control: var(--shadow-1);
  --ui-elevation-panel: var(--shadow-2);
  --ui-elevation-floating: var(--shadow-3);
  --ui-elevation-sheet: var(--shadow-4);
  --ui-elevation-overlay: var(--shadow-5);
  --ui-edge-default: var(--edge);
  --ui-edge-faint: var(--edge-faint);
  --ui-edge-strong: var(--edge-strong);
  --ui-effect-bevel: var(--bevel);
  --ui-effect-focus-halo: var(--ring-focus);
  --ui-effect-selected: inset 0 0 0 1px hsl(var(--primary) / .20);
  --ui-effect-accent-ring: inset 0 0 0 1px hsl(var(--primary) / .20);
  --ui-effect-selection-ring: 0 0 0 2px var(--ui-color-selection-border);
  --ui-effect-selection-ring-hover: 0 0 0 2px color-mix(in srgb, var(--ui-color-selection-border) 40%, transparent);
  --ui-type-display: calc(64px * var(--a11y-fs));
  --ui-type-heading: calc(28px * var(--a11y-fs));
  --ui-type-lead: calc(18px * var(--a11y-fs));
  --ui-type-caption: calc(12px * var(--a11y-fs));
  --ui-type-tracking-label: .06em;
  --ui-type-tracking-tight: -.01em;
  --ui-type-body: var(--fs-md);
  --ui-type-label: var(--fs-sm);
  --ui-type-title: var(--fs-lg);
  --ui-type-ui-family: var(--font-brand);
  --ui-type-mono-family: var(--font-mono);
  --ui-type-band: var(--fs-xs);
  --ui-type-section: var(--fs-md);
  --ui-type-field: var(--fs-2xs);
  --ui-type-help: var(--fs-xs);
  --ui-type-weight-section: 600;
  --ui-type-weight-label: 600;
  --ui-motion-feedback: var(--dur-1);
  --ui-motion-overlay: var(--dur-2);
  --ui-motion-navigation: var(--dur-3);
  --ui-motion-standard: var(--ease-out);
  --ui-layer-chrome: var(--z-chrome);
  --ui-layer-overlay: var(--z-overlay);
  --ui-layer-toast: var(--z-toast);
}
:root,
[data-theme="light"] {
  color-scheme: light;
  --background:             0 0% 100%;
  --foreground:             224 71% 4%;
  --foreground-canvas:      224 71% 4%;
  --card:                   0 0% 99%;
  --card-foreground:        224 71% 4%;
  --popover:                0 0% 100%;
  --popover-foreground:     224 71% 4%;
  --primary:                171 62% 12%;      
  --primary-foreground:     0 0% 100%;
  --secondary:              210 40% 96%;
  --secondary-foreground:   224 71% 4%;
  --muted:                  210 40% 96%;
  --muted-foreground:       215 20% 38%;      
  --accent:                 210 40% 94%;
  --accent-foreground:      224 71% 4%;
  --destructive:            0 72% 51%;
  --destructive-foreground: 0 0% 100%;
  --border:                 214 28% 84%;
  --input:                  214 28% 84%;
  --ring:                   171 62% 12%;
  --store-1:                171 60% 20%;
  --store-2:                166 50% 32%;
  --store-3:                159 46% 43%;
  --store-4:                150 52% 55%;
  --store-5:                140 55% 65%;
  --store-other:            205 10% 62%;
  --radius:                 1rem;
  --space:                  8px;
}
[data-theme="dark"] {
  color-scheme: dark;
  --background:             224 71% 4%;
  --foreground:             213 31% 91%;
  --foreground-canvas:      213 31% 91%;   
  --card:                   222 47% 7%;
  --card-foreground:        213 31% 91%;
  --popover:                222 47% 7%;
  --popover-foreground:     213 31% 91%;
  --primary:                151 57% 46%;      
  --primary-foreground:     0 0% 0%;
  --secondary:              217 33% 14%;
  --secondary-foreground:   213 31% 91%;
  --muted:                  217 33% 14%;
  --muted-foreground:       215 20% 76%;      
  --accent:                 217 33% 18%;
  --accent-foreground:      213 31% 91%;
  --destructive:            0 63% 38%;
  --destructive-foreground: 213 31% 91%;
  --border:                 217 33% 18%;
  --input:                  217 33% 18%;
  --ring:                   151 57% 46%;
  --store-1:                151 57% 46%;
  --store-2:                160 50% 54%;
  --store-3:                170 46% 60%;
  --store-4:                150 58% 70%;
  --store-5:                140 60% 78%;
  --store-other:            215 12% 46%;
  --radius:                 1rem;
  --space:                  8px;
}
[data-theme="brand"] {
  color-scheme: dark;
  --background:             171 62% 12%;      
  --foreground:             160 30% 92%;
  --foreground-canvas:      160 30% 92%;      
  --card:                   171 55% 17%;
  --card-foreground:        160 30% 92%;
  --popover:                171 55% 17%;
  --popover-foreground:     160 30% 92%;
  --primary:                151 57% 46%;      
  --primary-foreground:     0 0% 0%;
  --secondary:              171 48% 21%;
  --secondary-foreground:   160 30% 92%;
  --muted:                  171 48% 20%;
  --muted-foreground:       160 18% 86%;      
  --accent:                 171 48% 22%;
  --accent-foreground:      160 30% 92%;
  --destructive:            0 55% 42%;
  --destructive-foreground: 160 30% 92%;
  --border:                 171 36% 33%;
  --input:                  171 36% 33%;
  --ring:                   151 57% 46%;
  --store-1:                151 57% 52%;
  --store-2:                146 52% 60%;
  --store-3:                160 46% 64%;
  --store-4:                140 58% 72%;
  --store-5:                132 60% 79%;
  --store-other:            171 16% 54%;
  --radius:                 1rem;
  --space:                  8px;
}
:root {
  --job-candy-a: var(--brand-primary, hsl(var(--primary)));
  --job-candy-b: var(--brand-secondary, hsl(var(--accent)));
}
html[data-a11y-contrast="high"] {
  --track-rail: hsl(var(--muted) / 0.9);
}
html[data-a11y-contrast="high"]:not([data-theme="dark"]):not([data-theme="brand"]) {
  --card:                   210 24% 97%;   
  --muted-foreground:       215 32% 22%;   
  --border:                 214 30% 38%;   
  --input:                  214 32% 30%;   
  --ring:                   171 90% 12%;   
  --destructive:            0 80% 34%;     
  --store-1:                171 62% 16%;
  --store-2:                166 55% 27%;
  --store-3:                159 52% 38%;
  --store-4:                150 58% 48%;
  --store-5:                140 60% 57%;
  --store-other:            205 14% 42%;   
}
html[data-a11y-contrast="high"][data-theme="dark"] {
  --primary:                147.6 75% 67.1%; 
  --primary-foreground:     0 0% 0%;         
  --ring:                   147.6 75% 67.1%;
  --foreground:             213 45% 98%;   
  --card:                   222 47% 9%;    
  --card-foreground:        213 45% 98%;
  --popover:                222 47% 11%;   
  --popover-foreground:     213 45% 98%;
  --secondary:              217 33% 20%;   
  --secondary-foreground:   213 45% 98%;
  --muted:                  217 33% 17%;   
  --muted-foreground:       213 35% 86%;   
  --accent:                 217 33% 26%;   
  --accent-foreground:      213 45% 98%;
  --border:                 215 30% 55%;   
  --input:                  215 32% 62%;   
  --ring:                   213 45% 98%;
  --destructive:            0 72% 44%;     
  --destructive-foreground: 213 45% 98%;
  --store-other:            215 16% 66%;   
}
html[data-a11y-contrast="high"][data-theme="brand"] {
  --primary:                147.6 75% 67.1%; 
  --primary-foreground:     0 0% 0%;         
  --foreground:             0 0% 100%;     
  --card-foreground:        0 0% 100%;
  --popover-foreground:     0 0% 100%;
  --secondary-foreground:   0 0% 100%;
  --accent-foreground:      0 0% 100%;
  --muted-foreground:       0 0% 88%;      
  --border:                 0 0% 72%;      
  --input:                  0 0% 80%;      
  --ring:                   147.6 75% 67.1%; 
  --destructive:            0 72% 44%;     
  --destructive-foreground: 0 0% 100%;
  --store-other:            0 0% 68%;      
}
/* Bridge: the docs' legacy token names, expressed in the app's design tokens above, so the
   whole docs stylesheet follows the app's [data-theme] light/dark/brand system and - inside
   the app shell - the active brand. Neutrals/surfaces map cleanly; the ACCENT (--green ->
   --primary) is the one design choice to review: the app's primary is deep teal in light,
   pine green in dark/brand, so light-mode links become teal rather than green. */
:root{
  --page:hsl(var(--background));
  --text:hsl(var(--foreground));
  --muted:hsl(var(--muted-foreground));
  /* These two read their APP twin, not the app token of the same name. Both names
     exist on each side with different meanings: the app's --border and --muted are
     raw HSL triplets (an edge and a muted surface), the docs' are finished colours
     (an edge and muted TEXT). Because this block and the app tokens both land on
     :root, the name the docs define is the only one left in scope, so
     the border read itself and the pale surface wrapped a colour in hsl() again. A cycle and a nonsense value compute the same way: the whole
     declaration is dropped, which painted every table heading, footer, code block
     and the "On this page" panel with no background and no border at all. --input
     and --secondary carry the same values as --border and --muted in every shipped
     theme; the two accessibility themes tune them a shade apart on purpose, and
     there the docs take the stronger edge and the lighter surface. */
  --border:hsl(var(--input));
  --pale:hsl(var(--secondary));
  /* The app's role tokens built on those two shadowed names break here the same way:
     --ui-color-surface-muted is hsl(var(--muted)) and --ui-color-border-default reads
     --border, so on /info both computed as transparent in every theme and anything
     styled with them painted nothing. Re-point them at the same twins, so the shared
     reading components (docs-components.css) look the same here as in the app. */
  --ui-color-surface-muted:hsl(var(--secondary));
  --ui-color-border-default:hsl(var(--input));
  /* The app's type scale multiplies by the a11y text setting (parts/a11y.css), which a
     static page has no control for. Declared at 1 so the app's type tokens resolve here
     at their normal sizes instead of computing as invalid. */
  --a11y-fs:1;
  --green:hsl(var(--primary));
  --dark:hsl(var(--foreground));
  --light:hsl(var(--primary)/0.4);
  --red:hsl(var(--destructive));
  /* The deep, ALWAYS-DARK marketing-band / chrome surface (nav, hero, platform, assure,
     about, everywhere, pathways). It must stay dark in EVERY theme - unlike --background/
     --card which flip light in the light theme, and unlike --primary which goes pine-green
     in dark/brand. Default is the SUSE deep teal (= the old #0c322c); brand-vars.ts will
     override it per active brand in the app shell (M2) so a self-hosted org's dark bands
     carry their brand. Fixes the M1 bug where these bands used var(--dark) (=--foreground),
     which inverted to near-white text-on-band in dark mode. */
  --band-dark:171 62% 12%;
  /* The always-LIGHT ink that rides on --band-dark (headings, nav wordmark, nav/hero/
     platform/assure/everywhere/about/pathways copy). Paired with --band-dark so the
     always-dark chrome is fully brand-reactive: a self-hosted brand overrides BOTH the
     band surface and its on-dark ink. Defaults to white, so the neutral build renders
     byte-identical to the old hardcoded #fff. Crucially it is a dedicated token, NOT
     --primary-foreground: that one flips to BLACK under [data-a11y-contrast=high] in
     dark/brand, which would turn every band's white text black-on-dark. --on-band-dark
     stays light in every theme + contrast mode, so the a11y contract holds. */
  --on-band-dark:0 0% 100%;
  /* The always-BRIGHT accent that rides on --band-dark for CTAs on the dark chrome (the
     nav "Launch App" pill). Band-invariant like the pair above: the nav is dark in every
     theme, so its CTA must POP in every theme - it can't borrow --primary, which goes deep
     teal in the LIGHT theme and would sink the button into the dark band. Default is the
     pine green (= dark/brand --primary, the old bright SUSE green); brand-vars.ts overrides
     it per active brand in the app shell. Paired with --band-dark as its ink (dark-on-green,
     the original CTA look). */
  --band-accent:151 57% 46%;
  --orange:#fe7c3f;--navy:#192072;--blue:#2453ff;
  --col-cap:38rem;
}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
body{font-family:'SUSE',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;color:var(--text);background:var(--page);line-height:1.65}
a{color:var(--green);text-decoration:none}
a:hover{text-decoration:underline}
/* Safety net for inline icon SVGs: every one carries only a viewBox (no width/height),
   so without a scoped size rule it balloons to the CSS default 300×150 - or stretches to
   fill a flex/grid parent - and reads as an unfinished giant glyph. Default them to a
   text-sized square; sized contexts (.icon-*, .assure-card-ic, illustrations, …) override
   this with a more specific selector. Keeps a missing/renamed rule from ever ballooning. */
svg{width:1em;height:1em;flex:none}
code{font-family:var(--brand-font),'SUSE Mono','SF Mono','Fira Code',monospace;font-size:.875em;background:hsl(var(--muted));padding:.15em .35em;border-radius:3px}
/* A long token in running text (a URL, a flag list, an env var, a link whose text is
   an address) breaks where it must rather than widening the page. break-word, not
   anywhere: it breaks only a token that would overflow and leaves table columns their
   natural width, so a wide table keeps scrolling in its own frame. Visual only: a copy
   of the text is unchanged. Code blocks keep their own rules. */
.docs-content :not(pre)>code,.docs-content a{overflow-wrap:break-word}
pre{background:hsl(var(--muted));color:hsl(var(--foreground));padding:1.25rem 1.5rem;border-radius:8px;overflow-x:auto;white-space:pre-wrap;overflow-wrap:anywhere;font-size:.875rem;line-height:1.5;margin-bottom:1.25rem; box-shadow: inset 0 .2rem .4rem #0002, 0 1px #fff2}
pre code{background:none;padding:0;color:inherit;font-size:1em}
h1,h2,h3,h4{line-height:1.25;font-weight:700}
h2{font-size:2rem;letter-spacing:0;font-weight:900;text-transform:uppercase}
p{margin-bottom:2rem}
ul{padding-left:1.25rem;margin-bottom:1rem}
li{margin-bottom:.35rem}
blockquote{border-left:0; box-shadow:0 0 0 1px #30ba7825, inset 0 1px #fff3, inset 0 -1px #0001, 0 .1rem 2.4rem #30ba7855;  border-radius: 2em; padding: 1.5rem 2.25rem;background:var(--pale);margin:4rem 0;transform:scale(1.1)}
/* The desktop scale reaches past the column; on a phone the column is the screen. */
/* The scale needs spare room beside the column; below 800px the column is the screen. */
@media(max-width:800px){blockquote{transform:none}}
blockquote p{margin:0}
hr{border:none;border-top:1px solid var(--border);margin:2rem 0}
strong{font-weight:600}

/* SPDX-License-Identifier: MPL-2.0 */
/* ── Button system (component audit rec 2) - the one shared `.btn` primitive
      plus `.btn--primary` / `.btn--ghost` / `.btn--danger` / `.btn--sm` variants.
      Imported from app.css on the critical path, so every route - including the
      always-eager gallery/catalog/projects landing - gets a real base instead of
      depending on a lazily-loaded view chunk to arrive first (previously the
      `.btn` recipe lived only in tool-chrome.css, a lazy view sheet).

      Several call-sites can't rename their markup this wave (a later wave composes
      the classes onto existing elements), so they alias onto these rules via
      selector lists instead of restating the same declarations locally - each
      hand-rolled "primary fill" recipe below is textually declared exactly ONCE,
      here. Every aliased selector keeps its own file for true deltas (shape,
      size, unique hover treatment); only the shared background/color pair moves.

      Policy (component audit M2, 2026-07-13): new buttons use `.btn` + its
      variants (--primary / --ghost / --danger / --sm / --glass). The legacy
      per-view families - .pro-btn, .save-btn, .copy-btn, .copy-url-btn,
      .render-pill-save, .pro-sess-save, [data-me-saveall] - are FROZEN: no new
      members, no new modifiers, no new call-sites. Their primary-fill recipes
      already alias .btn--primary below; migrate a family to `.btn` only when
      its view gets rewritten wholesale. */

/* Base - outline/neutral button. Also covers any plain <button> inside
   .tool-actions (the export panel), which predates the .btn class and still
   needs the identical look without every call-site adding the class by hand. */
.btn,
.tool-actions button:not(.btn),
.docs-listen, .docs-edition {                     /* docs/build.ts - /info's Listen and print-edition controls */
  text-decoration: none;
  padding: 5px 14px;
  background: var(--ui-color-surface-canvas);
  color: var(--ui-color-text-default);
  border: transparent;
  border-radius: var(--ui-radius-panel);
  font: inherit;
  font-size: var(--ui-type-body);
  cursor: pointer;
  box-shadow: var(--ui-effect-bevel), var(--ui-elevation-control);
  transition: background var(--ui-motion-feedback), border-color var(--ui-motion-feedback), color var(--ui-motion-feedback);
  white-space: nowrap;
}
/* Hover/disabled stay scoped to .tool-actions button (its historical reach) -
   many bare-.btn call-sites (gallery footer, catalog bulk bar, …) define their
   own hover locally, so a blanket `.btn:hover` here would change their look. */
.tool-actions button:not(.btn):hover:not(:disabled) {
  background: hsl(var(--accent));
  border-color: var(--ui-color-border-default);
}
.btn:disabled,
.tool-actions button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.btn:focus-visible {
  outline: 2px solid var(--ui-color-focus-ring);
  outline-offset: 2px;
}

/* Small size - folds brand-studio's .be-btn--sm/.be-add--sm, a byte-identical
   duplicate (this was previously just a comment claiming the generalisation;
   the declaration itself hadn't actually been merged). */
.btn--sm,
.be-btn--sm, .be-add--sm {                        /* brand-studio.css */
  padding: .25rem .6rem;
  font-size: calc(.72rem * var(--a11y-fs));
}

/* Ghost - the shape brand-studio's .be-btn composes onto (component audit rec 1). */
.btn--ghost {
  background: var(--ui-color-surface-canvas);
  color: var(--ui-color-text-default);
  border-color: var(--ui-color-border-default);
}
.btn--ghost:hover:not(:disabled),
.be-btn:hover:not(:disabled), .be-add:hover:not(:disabled) {   /* brand-studio.css - identical hover */
  border-color: hsl(var(--primary) / .55);
}
.btn--ghost:hover:not(:disabled) { background: var(--ui-color-surface-muted); }

/* Primary - the fill recipe that used to be re-typed with no base class in
   ~10 places. This selector list is its ONLY declaration app-wide; every
   call-site below keeps just its own delta (border, shape, unique hover) in
   its own file. */
.btn--primary,
.toast-action,                                    /* tool-chrome.css */
.tool-actions [data-action="copy"].copy-armed,    /* tool-chrome.css */
.share-copy-btn,                                  /* dialogs.css */
.unsaved-save,                                    /* dialogs.css */
.modal .modal-primary,                            /* dialogs.css */
.projects-render.btn,                             /* projects.css */
.profile-view .profile-btn-primary,               /* profile.css */
.cropper-btn--primary,                            /* profile.css */
.pro-btn--primary,                                /* pro/pro.css */
.pro-addrow .pro-btn,                             /* pro/pro.css */
.me-primary,                                      /* multi-edit.css */
.cat-act-fav.is-fav,                              /* assets.css */
.cat-tp-btn.cat-tp-play,                          /* asset-shared.css - audio transport play/pause */
.anim-transport-play,                             /* tool.css - animation transport play/pause */
.view-seg-btn[aria-pressed="true"],               /* gallery.css - canonical segmented control */
.gallery-pill.active,                             /* gallery.css - category/sort pill */
.tmpl-chooser-filter.is-active,                   /* template-chooser.css - tag-filter chip */
.fc-frames-empty-add,                             /* editor.css - Artboards empty-state "Draw an artboard" */
.plat-pill,                                       /* platform.css - inline qualifier badge */
.skip-link:focus,                                 /* base.css - a11y skip-nav, revealed on focus */
.not-found-home,                                  /* notfound.css - 404 "Browse all tools" CTA */
.script-audio-generate,                           /* script-audio.css - TTS Generate/Save pair */
.script-audio-save,                               /* script-audio.css */
.upscale-run,                                     /* upscale.css - on-device AI upscale Run */
.rt-actions .rt-run,                              /* retouch.css - content-aware fill/save primary */
.fmt-chip[aria-pressed="true"],                   /* tool-chrome.css - export format picker chosen chip */
.be-cta {                                         /* brand-studio.css */
  background: var(--ui-color-action-primary);
  color: var(--ui-color-action-on-primary);
}
.btn--primary {
  border: 1px solid var(--ui-color-action-primary);
}
/* Identical `filter: brightness(1.08)` hover, folded the same way - call-sites
   with a genuinely different hover (opacity fade, background-only, a different
   brightness value) keep that locally instead of joining this list. */
.btn--primary:hover:not(:disabled),
.toast-action:hover,
.modal .modal-primary:hover,
.projects-render.btn:hover,
.profile-view .profile-btn-primary:hover,
.cropper-btn--primary:hover {
  filter: brightness(1.08);
}

/* Danger - solid destructive fill (confirm-dialog "Delete", etc). The lighter
   outline-style destructive buttons (.cat-bulk-danger, .projects-bulk-danger)
   are a deliberately quieter treatment and stay local, not aliased here. */
.btn--danger,
.modal .modal-danger {   /* dialogs.css */
  background: hsl(var(--destructive, 0 70% 50%));
  color: #fff;
}
.btn--danger {
  border: 1px solid hsl(var(--destructive, 0 70% 50%));
}
.btn--danger:hover:not(:disabled),
.modal .modal-danger:hover {
  filter: brightness(0.94);
}

/* Glass - the translucent "glass pill" recipe. Used to live ONLY on the combined
   .tools-home.home-full selector (tool.css); every other back/topbar pill either
   hand-typed its own approximation or had no blur at all. Andy's exact recipe,
   textually declared once here - composable with .btn or standalone via this
   selector list, same pattern as .btn--primary above. Call-sites keep only real
   shape deltas (box size, border, hover tint) in their own file. */
.btn--glass,
.tools-home,                                      /* components.css - the shared back pill */
.profile-link,                                    /* components.css - top-right profile pill */
.filter-fab,                                      /* gallery.css - sort/filter & view-options FAB */
.history-fab,                                     /* utilities.css/topbar.css - saved-sessions FAB */
.projects-back,                                   /* projects.css - folder breadcrumb back square */
.me-back,                                         /* multi-edit.css - multi-edit header back square */
.home-fab,                                         /* topbar.css - the always-home FAB (nav-less views) */
.theme-fab,                                        /* topbar.css - the theme-cycle FAB (nav-less views) */
.lang-fab {                                       /* topbar.css - language FAB */
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  /* The muted surface at 45%, through its role token: the same colour here, and
     the one name /info re-points, where the raw --muted slot means muted text. */
  background: color-mix(in srgb, var(--ui-color-surface-muted) 45%, transparent);
  text-shadow: 0 1px hsl(var(--secondary) / .5);
  color: hsl(var(--on-primary));
  transition: background var(--ui-motion-feedback), box-shadow var(--ui-motion-feedback);
}

/* SPDX-License-Identifier: MPL-2.0 */
/* ── Docs chrome shared by both readers (plan 277 step 3c) ──────────────────
   docs/build.ts reads this file verbatim into the /info stylesheet, after the
   app's buttons.css, and the in-app reader (views/docs.ts) imports it ahead of
   docs.css. It holds the pieces the two readers show the same way:

     - the round top-row button (.site-fab on /info, .docs-top-btn in the app),
       sized on the top-row height (--chrome-h), so it is exactly as tall as
       the home pill and the app's own back pill beside it;
     - the pathways strip (Welcome and the five documentation sections), which
       /info builds and the in-app reader adopts from the fetched page;
     - the compact lists inside the two disclosures (the section's pages and On
       this page): the in-app reader's phone navigation and the /info menu.

   Built from the app's token roles (tokens.css) only. /info's bridge re-points
   the two roles its legacy names shadow (surface-muted, border-default), so a
   role reads the same on both surfaces. Placement stays with each surface:
   the band, the bar and the sheet in docs/build.ts, the reader's slots in
   docs.css. */

/* ── Round top-row button ───────────────────────────────────────────────────
   Language, Theme, GitHub, Search and Menu on /info; Wide, Theme and the
   profile link in the in-app reader. A glass circle on the canvas with one
   hairline, the glyph on the type multiplier. */
.site-fab,
.docs-top-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  box-sizing: border-box;
  width: var(--chrome-h);
  height: var(--chrome-h);
  padding: 0;
  border: 1px solid var(--ui-color-border-default);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--ui-color-surface-canvas) 85%, transparent);
  color: var(--ui-color-text-default);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  font: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--ui-motion-feedback), border-color var(--ui-motion-feedback), transform var(--ui-motion-feedback);
}
.site-fab:hover,
.docs-top-btn:hover {
  background: var(--ui-color-surface-muted);
  border-color: color-mix(in srgb, var(--ui-color-text-default) 25%, transparent);
  text-decoration: none;
}
.site-fab:active,
.docs-top-btn:active { transform: scale(0.94); }
.site-fab:focus-visible,
.docs-top-btn:focus-visible { outline: 2px solid var(--ui-color-focus-ring); outline-offset: 2px; }
.site-fab svg,
.docs-top-btn svg { width: calc(18px * var(--a11y-fs, 1)); height: calc(18px * var(--a11y-fs, 1)); }
@media (prefers-reduced-motion: reduce) {
  .site-fab,
  .docs-top-btn { transition: none; }
  .site-fab:active,
  .docs-top-btn:active { transform: none; }
}

/* ── Pathways strip ─────────────────────────────────────────────────────────
   Text tabs. The current section takes the full-strength text colour, its weight
   and a 2px underline in the primary: a line under a tab, never an edge on a
   rounded shape. The label stays in the foreground role because the primary is
   too light for small text on the Brand theme's band (4.2:1); as the underline, a
   non-text marker, it needs 3:1 and has it in every theme. */
.docs-pathways {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.4rem;
}
.docs-pathway {
  font: 600 calc(0.95rem * var(--a11y-fs, 1)) / 1.4 var(--font-brand, system-ui, sans-serif);
  color: var(--ui-color-text-muted);
  text-decoration: none;
  padding: 0.2rem 0;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.docs-pathway:hover { color: var(--ui-color-text-default); text-decoration: none; }
.docs-pathway.active {
  color: var(--ui-color-text-default);
  border-bottom-color: var(--ui-color-action-primary);
}
.docs-pathway:focus-visible { outline: 2px solid var(--ui-color-focus-ring); outline-offset: 2px; }
/* On a phone the strip keeps one line and scrolls. lib/docs-strip.ts marks which
   edges have tabs beyond them (data-strip-edges) and each marked edge fades, so a
   cut label never reads as a whole word; it also brings the current tab into view.
   Without that script only the end fades, a hint that the row goes on. The width is
   in em so the strip folds earlier when the reader's browser text is larger. */
@media (max-width: 40em) {
  .docs-pathways {
    --strip-fade-start: 0px;
    --strip-fade-end: 2.5rem;
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    gap: 0.3rem 1.1rem;
    padding-block-end: 2px;
    -webkit-mask-image: linear-gradient(to right, transparent, black var(--strip-fade-start), black calc(100% - var(--strip-fade-end)), transparent);
    mask-image: linear-gradient(to right, transparent, black var(--strip-fade-start), black calc(100% - var(--strip-fade-end)), transparent);
  }
  .docs-pathways::-webkit-scrollbar { display: none; }
  .docs-pathways[data-strip-edges] { --strip-fade-end: 0px; }
  .docs-pathways[data-strip-edges~="start"] { --strip-fade-start: 2.5rem; }
  .docs-pathways[data-strip-edges~="end"] { --strip-fade-end: 2.5rem; }
  [dir="rtl"] .docs-pathways {
    -webkit-mask-image: linear-gradient(to left, transparent, black var(--strip-fade-start), black calc(100% - var(--strip-fade-end)), transparent);
    mask-image: linear-gradient(to left, transparent, black var(--strip-fade-start), black calc(100% - var(--strip-fade-end)), transparent);
  }
}

/* ── Compact lists inside the navigation disclosures ────────────────────────
   The disclosure itself is the shared reading component (docs-components.css);
   these are the rows inside it: the section's pages, with their group labels,
   and the page's own headings. */
.docs-compact-list,
.docs-compact-list :is(ul, ol) { list-style: none; margin: 0; padding: 0; }
.docs-compact-list :is(.docs-sidebar-group, h2, h3, .sidebar-head, .sidebar-label) {
  margin: 0.9rem 0 0.3rem;
  font-size: calc(0.72rem * var(--a11y-fs, 1));
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ui-color-text-muted);
}
.docs-compact-list a {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  min-height: 40px;
  padding: 0.35rem 0.5rem;
  border-radius: var(--ui-radius-control, 6px);
  color: var(--ui-color-text-default);
  text-decoration: none;
  font-size: calc(0.95rem * var(--a11y-fs, 1));
  line-height: 1.35;
}
.docs-compact-list a:hover { background: var(--ui-color-surface-muted); text-decoration: none; }
.docs-compact-list a:focus-visible { outline: 2px solid var(--ui-color-focus-ring); outline-offset: -2px; }
/* The current page: the chosen tint behind full-strength text, its glyph in the
   primary as the marker (the primary as small text fails on Brand, 4.0:1). */
.docs-compact-list a.active,
.docs-compact-list a[aria-current] { color: var(--ui-color-text-default); font-weight: 600; background: var(--ui-color-selection-surface); }
.docs-compact-list a.active svg,
.docs-compact-list a[aria-current] svg { color: var(--ui-color-action-primary); opacity: 1; }
.docs-compact-list a.is-h3 { padding-inline-start: 1.5rem; }
.docs-compact-list .docs-toc-list { border: 0; }
.docs-compact-list .docs-toc-link { border: 0; margin: 0; }
.docs-compact-list svg { width: 16px; height: 16px; flex: none; }

/* ── Forced colours (Windows High Contrast) ─────────────────────────────────
   The system repaints a transparent border in the link colour, which would draw
   the current tab's underline under every tab, and it drops the chosen tint. So
   the idle tabs take the canvas colour, the current tab the highlight, and the
   current page an outline in the highlight. */
@media (forced-colors: active) {
  .docs-pathway { border-bottom-color: Canvas; }
  .docs-pathway.active { border-bottom-color: Highlight; }
  .docs-compact-list a.active,
  .docs-compact-list a[aria-current] { outline: 2px solid Highlight; outline-offset: -2px; }
}


/* ── The site bar (buildNav) ──────────────────────────────────────────────────
   The app's top row on the app's canvas (plan 277 step 3c, decision D14). Every
   control is --chrome-h tall and the gutter is --chrome-inset (tokens.css), and
   the ground is the one the app's bottom bar paints (the canvas at 82%, a blur,
   one hairline) in every theme. The ground is drawn by ::before, not by the bar,
   so the bar sets no backdrop filter of its own and the search results and the
   language menu, both position:fixed inside it, still place themselves against
   the viewport. --site-bar-h is the one height everything below the bar clears:
   the sticky rail, the band, the landing's quicknav and anchor scroll margins. */
:root{--site-bar-h:calc(var(--chrome-h) + 2 * var(--sp-4) + var(--safe-top) + 1px);--site-bar-inset:var(--chrome-inset)}
.site-bar{position:fixed;inset-block-start:0;inset-inline:0;z-index:100;display:flex;align-items:center;gap:var(--sp-5);box-sizing:border-box;min-height:var(--site-bar-h);padding:calc(var(--sp-4) + var(--safe-top)) var(--site-bar-inset) calc(var(--sp-4) + 1px);color:var(--ui-color-text-default)}
.site-bar::before{content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;background:color-mix(in srgb,var(--ui-color-surface-canvas) 82%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-bottom:1px solid var(--ui-color-border-default);transition:opacity var(--ui-motion-overlay)}
/* The landing: over its hero the bar is its controls alone, like the app's
   floating top row, and it takes its ground once the hero has scrolled away
   (NAV_SOLID_JS adds .site-bar--solid). A translucent light ground over the dark
   hero read as a grey stripe. The hero is dark in every theme, so in Light the
   home pill and Launch App take the canvas surface the round buttons already
   have: light controls on the dark hero, and the primary fill again once the
   bar has its ground. Every control carries its own surface, so the hero can
   scroll under the bar on a phone too. */
.site-bar--over-hero:not(.site-bar--solid)::before{opacity:0}
[data-theme="light"] .site-bar--over-hero:not(.site-bar--solid) :is(.site-home,.site-launch){background:color-mix(in srgb,var(--ui-color-surface-canvas) 90%,transparent);color:var(--ui-color-text-default);border-color:transparent}
/* The hero carries its own Launch App in the same words and glyph, so while the
   hero is on screen the bar's copy steps aside; it returns once the hero's buttons
   have passed under the bar (NAV_SOLID_JS adds .site-bar--past-hero). */
.site-bar--over-hero:not(.site-bar--past-hero)>.site-launch{display:none}
@media(prefers-reduced-motion:reduce){.site-bar::before{transition:none}}
/* Skip to content: the app's skip link (base.css .skip-link), hidden with a clip
   until it takes focus, then pinned to the start corner above the bar. Its fill is
   the primary, from buttons.css's alias list. It targets the page's <main>. */
.skip-link{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
/* The fixed bar would cover the article's first line after the jump. */
#docs-main{scroll-margin-top:var(--site-bar-h)}
.skip-link:focus{position:fixed;top:0;inset-inline-start:0;z-index:200;width:auto;height:auto;clip-path:none;padding:8px 16px;font-size:var(--fs-lg);font-weight:600;border-end-end-radius:var(--radius);overflow:visible;text-decoration:none}
main[tabindex="-1"]:focus{outline:none}
/* On-page quick nav - a sticky jump bar under the top bar, on the landing only. */
html{scroll-behavior:smooth}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
section[id]{scroll-margin-top:calc(var(--site-bar-h) + 2.65rem)}
/* Home: the app's back pill (components.css .tools-home) in the shared glass
   (buttons.css .btn--glass), holding the app's mark, the name and, on English
   pages, a quiet Beta chip. It pushes the rest of the row to the inline end. */
.site-home{display:inline-flex;align-items:center;gap:var(--sp-4);flex:none;margin-inline-end:auto;box-sizing:border-box;min-height:var(--chrome-h);padding-block:0;padding-inline:var(--sp-3) var(--sp-7);border:1px solid transparent;border-radius:calc(var(--radius) * 1.5);font-size:var(--fs-md);font-weight:600;line-height:1;color:var(--ui-color-text-default);text-decoration:none;white-space:nowrap;box-shadow:inset 0 -.1em 1em 1px hsl(var(--primary) / .22),0 .1em .3em #0002}
.site-home:hover{background:hsl(var(--primary) / .16);box-shadow:inset 0 0 0 1px hsl(var(--primary) / .34);text-decoration:none}
.site-home:focus-visible{outline:2px solid var(--ui-color-focus-ring);outline-offset:2px}
.site-home img{display:block;width:calc(26px * var(--a11y-fs));height:calc(26px * var(--a11y-fs));border-radius:var(--radius-round)}
/* Beta: English pages only (see buildNav) and deliberately not a t() key, so it
   comes straight back out once the docs are no longer a draft. The tint the app
   gives a chosen row, not an alarm red. */
.site-beta{font-size:var(--fs-2xs);font-weight:700;letter-spacing:.04em;text-transform:uppercase;padding:2px 7px;border-radius:var(--ui-radius-pill);background:var(--ui-color-selection-surface);color:var(--ui-color-action-primary)}
:is([data-theme="dark"],[data-theme="brand"]) .site-beta{color:var(--ui-color-text-default)}
/* The round buttons are the shared .site-fab (docs-chrome.css). Language keeps
   its own glyph a little larger; Theme shows the active theme's glyph. */
.lang-fab-wrap{display:contents}
.site-fab--lang svg{width:calc(20px * var(--a11y-fs));height:calc(20px * var(--a11y-fs))}
.site-fab--theme .icon-moon,.site-fab--theme .icon-brand{display:none}
[data-theme="dark"] .site-fab--theme .icon-sun,[data-theme="brand"] .site-fab--theme .icon-sun{display:none}
[data-theme="dark"] .site-fab--theme .icon-moon,[data-theme="brand"] .site-fab--theme .icon-brand{display:block}
.site-fab--search{display:none}
/* Pressed and current states the system colours would otherwise flatten. */
@media(forced-colors:active){.site-sheet .profile-menu-seg[aria-pressed="true"]{outline:2px solid Highlight;outline-offset:-2px}.site-sheet .site-sheet-sections .docs-pathway.active{outline:2px solid Highlight;outline-offset:-2px}.docs-listen,.docs-edition{border:1px solid ButtonText}}
/* Launch App: the app's primary button (buttons.css .btn.btn--primary, the shape
   of the bottom bar's Verify) with the app's arrow, mirrored for right-to-left. */
.site-launch{display:inline-flex;align-items:center;justify-content:center;gap:6px;flex:none;box-sizing:border-box;min-height:var(--chrome-h);font-weight:600}
.site-launch:hover{text-decoration:none}
.site-launch svg{width:calc(15px * var(--a11y-fs));height:calc(15px * var(--a11y-fs))}
[dir="rtl"] .site-launch svg{transform:scaleX(-1)}

/* Language menu: the app's language popover (topbar.css .lang-menu, the same
   role tokens), a raised card with the sort tabs and one column of languages.
   LANG_PICKER_SCRIPT places it under whichever button opened it. */
.lang-menu{position:fixed;z-index:120;box-sizing:border-box;width:min(272px,calc(100vw - 16px));max-height:70vh;overflow:hidden;padding:6px;display:flex;flex-direction:column;gap:2px;background:var(--ui-color-surface-raised);color:var(--ui-color-text-default);border:1px solid var(--ui-color-border-default);border-radius:var(--ui-radius-card);box-shadow:var(--ui-elevation-floating)}
.lang-menu[hidden]{display:none}
@media(prefers-reduced-motion:no-preference){.lang-menu:not([hidden]){animation:site-pop-in var(--ui-motion-overlay) var(--ui-motion-standard) both}}
@keyframes site-pop-in{from{opacity:0;transform:translateY(-6px) scale(.98)}to{opacity:1;transform:none}}
.lang-sort-tabs{display:flex;gap:2px;padding:3px;margin-bottom:4px;flex:none;background:color-mix(in srgb,var(--ui-color-surface-muted) 50%,transparent);border-radius:var(--ui-radius-pill)}
.lang-sort-tab{flex:1 1 auto;white-space:nowrap;padding:4px 8px;border:0;cursor:pointer;background:transparent;color:var(--ui-color-text-muted);font-family:var(--font-mono);font-size:calc(10.5px * var(--a11y-fs));letter-spacing:.04em;border-radius:var(--ui-radius-pill);transition:background var(--ui-motion-feedback),color var(--ui-motion-feedback)}
.lang-sort-tab:hover{color:var(--ui-color-text-default)}
.lang-sort-tab[aria-selected=true]{background:var(--ui-color-surface-raised);color:var(--ui-color-text-default);font-weight:700;box-shadow:var(--ui-elevation-control)}
.lang-sort-tab:focus-visible{outline:2px solid var(--ui-color-focus-ring);outline-offset:1px}
.lang-menu-list{display:flex;flex-direction:column;gap:2px;flex:1 1 auto;min-height:0;overflow-y:auto}
.lang-menu-item{display:flex;align-items:center;gap:10px;width:100%;padding:8px 10px;border:0;border-radius:var(--ui-radius-panel);background:transparent;color:var(--ui-color-text-default);font:inherit;font-size:calc(13.5px * var(--a11y-fs));font-weight:500;text-align:start;cursor:pointer}
.lang-menu-flags{flex:0 0 auto;display:inline-flex;align-items:center;place-content:flex-end;gap:3px;min-width:4em;font-size:var(--fs-xl);line-height:1;filter:drop-shadow(0 1px 1.5px rgba(0,0,0,.35))}
.lang-menu-name{flex:1 1 auto;min-width:0}
.lang-menu-item:hover{background:var(--ui-color-surface-muted)}
.lang-menu-item:focus-visible{outline:2px solid var(--ui-color-focus-ring);outline-offset:-2px}
.lang-menu-item[aria-pressed=true]{background:var(--ui-color-selection-surface);color:var(--ui-color-action-primary);font-weight:700}

/* ── The phone menu (buildNav's <details class="site-menu">) ─────────────────
   A native disclosure, so it opens without JavaScript. Its sheet is the app's
   profile menu (topbar.css .profile-menu and its rows, the same role tokens),
   navigation first: the documentation sections, then this section's pages and
   this page's headings as the shared disclosures, then the theme segment,
   Language with the current language as a badge and GitHub, and Launch App at
   the foot. Shown below 48em, where the rail folds away; between 40em and 48em
   the bar still shows the theme, Language, GitHub and Launch App, so the sheet
   leaves them out and no control appears twice. HAMBURGER_SCRIPT closes it on
   Escape, an outside tap, a link tap, or focus moving out of it. */
.site-menu{position:relative;display:none;flex:none}
.site-menu>summary{list-style:none}
.site-menu>summary::-webkit-details-marker{display:none}
.site-menu>summary::marker{content:''}
.site-menu>summary>span{display:flex}
.site-menu[open]>summary .site-menu-open,.site-menu:not([open])>summary .site-menu-close{display:none}
/* scroll-padding keeps a row that takes focus clear of the sticky Launch App
   (WCAG technique C43), so keyboard focus is never drawn under it. */
.site-sheet{position:absolute;inset-inline-end:0;top:calc(100% + var(--sp-5));z-index:110;box-sizing:border-box;width:min(340px,calc(100vw - 24px));max-height:calc(100vh - var(--site-bar-h) - 16px);max-height:calc(100dvh - var(--site-bar-h) - 16px);overflow-y:auto;overscroll-behavior:contain;scroll-padding-block-end:calc(var(--chrome-h) + 1.5rem);padding:8px;display:flex;flex-direction:column;gap:4px;background:var(--ui-color-surface-raised);color:var(--ui-color-text-default);border:1px solid var(--ui-color-border-default);border-radius:var(--ui-radius-card);box-shadow:var(--ui-elevation-floating)}
@media(prefers-reduced-motion:no-preference){.site-menu[open] .site-sheet{animation:site-pop-in var(--ui-motion-overlay) var(--ui-motion-standard) both;transform-origin:top right}[dir="rtl"] .site-menu[open] .site-sheet{transform-origin:top left}}
.site-sheet .profile-menu-theme{display:flex;gap:2px;padding:3px;margin-bottom:4px;border:1px solid var(--ui-color-border-default);border-radius:var(--ui-radius-pill);background:color-mix(in srgb,var(--ui-color-surface-muted) 50%,transparent)}
.site-sheet .profile-menu-seg{flex:1;display:flex;align-items:center;justify-content:center;padding:8px 6px;border:0;border-radius:var(--ui-radius-pill);background:transparent;color:var(--ui-color-text-muted);font:inherit;line-height:1.2;cursor:pointer;transition:background var(--ui-motion-feedback),color var(--ui-motion-feedback)}
.site-sheet .profile-menu-seg svg{width:calc(18px * var(--a11y-fs));height:calc(18px * var(--a11y-fs))}
.site-sheet .profile-menu-seg:hover{color:var(--ui-color-text-default)}
.site-sheet .profile-menu-seg[aria-pressed="true"]{background:var(--ui-color-surface-raised);color:var(--ui-color-text-default);box-shadow:var(--ui-elevation-control)}
.site-sheet .profile-menu-seg:focus-visible{outline:2px solid var(--ui-color-focus-ring);outline-offset:2px}
.site-sheet .profile-menu-item{display:flex;align-items:center;justify-content:space-between;gap:12px;box-sizing:border-box;width:100%;min-height:var(--ui-size-target);padding:11px 12px;border:0;border-radius:var(--ui-radius-panel);background:transparent;color:var(--ui-color-text-default);font:inherit;font-size:var(--fs-lg);font-weight:500;line-height:1.3;text-align:start;text-decoration:none;cursor:pointer}
.site-sheet .profile-menu-item:hover{background:var(--ui-color-surface-muted);text-decoration:none}
.site-sheet .profile-menu-item:focus-visible{outline:2px solid var(--ui-color-focus-ring);outline-offset:-2px}
.site-sheet .profile-menu-item svg{flex:none;width:calc(15px * var(--a11y-fs));height:calc(15px * var(--a11y-fs));color:var(--ui-color-text-muted)}
[dir="rtl"] .site-sheet .profile-menu-item svg{transform:scaleX(-1)}
.site-sheet .profile-menu-count{min-width:calc(20px * var(--a11y-fs));height:calc(18px * var(--a11y-fs));padding:0 6px;display:inline-flex;align-items:center;justify-content:center;font-size:var(--fs-xs);font-weight:700;line-height:1;color:var(--ui-color-action-on-primary);background:var(--ui-color-action-primary);border-radius:var(--ui-radius-panel);white-space:nowrap}
.site-sheet-rule{border:0;border-top:1px solid var(--ui-color-border-default);margin:4px}
.site-sheet .docs-compact-nav{display:grid;gap:4px}
.site-sheet .docs-compact-nav .doc-details{margin:0}
.site-sheet .docs-compact-nav .doc-details-body{padding-block:0 8px;padding-inline:8px}
/* The sections open the sheet, as rows: the chosen tint behind the current one
   and a 2px primary line under its label (under the words, not an edge on the
   rounded row). The label keeps the text colour, for contrast on every theme. */
.site-sheet-sections{display:flex;flex-direction:column;gap:2px}
.site-sheet .docs-pathway{display:flex;align-items:center;min-height:40px;padding:.35rem .75rem;border:0;border-radius:var(--ui-radius-control);color:var(--ui-color-text-default);font-weight:500}
.site-sheet .docs-pathway:hover{background:var(--ui-color-surface-muted)}
.site-sheet .docs-pathway.active{background:var(--ui-color-selection-surface);font-weight:600;text-decoration:underline 2px var(--ui-color-action-primary);text-underline-offset:.4em}
.site-sheet-tools{display:flex;flex-direction:column;gap:4px}
/* Launch App closes the sheet and stays in reach at its foot while a long page
   list scrolls under it, with a band of the sheet's own surface around it. */
.site-sheet .site-launch{position:sticky;bottom:0;z-index:1;width:100%;margin-block-start:4px;box-shadow:var(--ui-effect-bevel),var(--ui-elevation-control),0 0 0 8px var(--ui-color-surface-raised)}
/* A short window (a phone on its side, 400% zoom): a pinned footer would take too
   much of it, so Launch App scrolls with the list. */
@media(max-height:500px){.site-sheet{scroll-padding-block-end:0}.site-sheet .site-launch{position:static}}

/* The row folds the app's way, in three steps: the search field becomes a round
   button, the menu arrives as the rail goes, then the theme, Language, GitHub and
   Launch App move into the menu and the Beta chip goes. The mark goes last. The
   steps are in em (62.5, 48, 40 and 22.5em are 1000, 768, 640 and 360px at the
   default text size), so a reader who raised the browser's text size gets the
   folded row early instead of a row that runs past the window. */
@media(max-width:62.5em){
  .site-bar .docs-search{display:none}
  .site-fab--search{display:inline-flex}
  .site-bar.is-searching .docs-search{display:flex;position:absolute;inset-inline:var(--site-bar-inset);inset-block:calc(var(--sp-4) + var(--safe-top)) calc(var(--sp-4) + 1px);z-index:2}
  .site-bar.is-searching .docs-search-input{inline-size:100%}
}
@media(max-width:48em){.site-menu{display:block}}
@media(min-width:40.0625em){.site-sheet-tools,.site-sheet .site-launch{display:none}}
@media(max-width:40em){
  :root{--site-bar-inset:var(--sp-6)}
  .site-bar{gap:var(--sp-4)}
  .site-fab--theme,.site-fab--lang,.site-fab--github,.site-bar>.site-launch,.site-beta{display:none}
}
@media(max-width:22.5em){.site-home img{display:none}.site-home{padding-inline:var(--sp-7)}}

/* Band rhythm (plans/168 WP-2, 2026-08-28): every band's vertical padding here was cut
   by roughly a third to a half. The landing measured 15,768px on desktop and 28,641px on
   a phone, and the middle third read as empty screens at a normal scrolling pace. NOTHING
   was deleted - the cut is whitespace only, so every message, card and mascot survives.
   If you are about to make a band airier again, check the page height first: the numbers
   above are what "generous everywhere" adds up to over nineteen bands. */
.quicknav{position:sticky;top:var(--site-bar-h);z-index:90;background:hsl(var(--background) / 0.9);border-bottom:1px solid var(--border);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}
html[data-theme="dark"] .quicknav{background:rgba(9,26,21,.9)}
.quicknav-inner{max-width:1180px;margin:0 auto;display:flex;gap:.15rem;padding:0 1.5rem;overflow-x:auto;scrollbar-width:none}
.quicknav-inner::-webkit-scrollbar{display:none}
.quicknav a{flex:none;padding:.72rem .8rem;font-size:.82rem;font-weight:600;color:var(--muted);text-decoration:none;border-bottom:2px solid transparent;white-space:nowrap;transition:color .12s}
.quicknav a:hover{color:var(--green)}
.quicknav a.is-current{color:var(--green);border-bottom-color:var(--green)}
/* The one off-page door in the strip (plans/168 WP-5): the brand journey, which had no
   landing entrance at all. Pushed to the inline end so it never reads as a section
   anchor, and it carries no .is-current state - QUICKNAV_JS only tracks ids on THIS page,
   and an app hash resolves to no element, so it is filtered out of the scroll-spy. */
.quicknav .quicknav-app{margin-inline-start:auto;color:var(--green);font-weight:700}
.quicknav .quicknav-app:hover{color:var(--dark)}
/* Overflow affordance (plans/168 WP-6): the strip scrolls with its scrollbar hidden, so
   below ~900px the last pills are cut off with nothing saying there is more. A fade on
   the inline end is the hint. On the container, not the scroller - it has to stay put
   while the pills move under it. */
@media(max-width:900px){
  /* Trailing room so the last pill can scroll CLEAR of the fade - without it the fade
     sits permanently over the brand door, which is the one pill worth reaching. */
  .quicknav-inner{padding-inline-end:3.25rem}
  .quicknav::after{content:'';position:absolute;inset-block:0;inset-inline-end:0;width:2.75rem;pointer-events:none;
    background:linear-gradient(to right,transparent,hsl(var(--background)))}
  html[dir="rtl"] .quicknav::after{background:linear-gradient(to left,transparent,hsl(var(--background)))}
  html[data-theme="dark"] .quicknav::after{background:linear-gradient(to right,transparent,#091a15)}
  html[data-theme="dark"][dir="rtl"] .quicknav::after{background:linear-gradient(to left,transparent,#091a15)}
}
.section-more-row{text-align:center;margin-top:1.25rem}
.section-more{display:inline-flex;align-items:center;gap:.4em;font-size:.92rem;font-weight:700;color:var(--green);text-decoration:none}
.section-more:hover{text-decoration:underline}
.section-more span{transition:transform .15s}
.section-more:hover span{transform:translateX(3px)}
/* Hero */
/* Hero + pathways share one canvas backdrop: the animated chips drift up through
   both, and a single vertical gradient blends the hero green (#1c4a2e) into the
   pathways dark (--dark) so the two bands read as one continuous surface. */
/* The hero ground derives from the ACTIVE brand primary (Andy, 2026-09-02): a dark
   oklab blend, so /info wears the Lolly green and #/docs/index recolours with the
   loaded design system. The fallback pair keeps old engines on the green. */
/* The wrap holds the hero AND the covers band, so the one chip field (#heroCanvas,
   absolute inset:0) runs on behind both. Two background layers: the hero's gradient,
   sized to the hero alone through --hero-h (NAV_SOLID_JS measures it; with scripts
   stripped, the in-app reader, it spans the wrap), over the flat colour the covers
   band always had. The gradient's end colour IS that flat colour, so the seam is
   invisible either way. */
.hero-wrap{position:relative;overflow:hidden;background:linear-gradient(180deg,#1c4a2e 0%,#0c3226 100%) top/100% var(--hero-h,100%) no-repeat,#0c3226;background:linear-gradient(180deg,color-mix(in oklab,hsl(var(--primary)) 34%,#0b1512) 0%,color-mix(in oklab,hsl(var(--primary)) 15%,#0a120f) 100%) top/100% var(--hero-h,100%) no-repeat,color-mix(in oklab,hsl(var(--primary)) 15%,#0a120f)}
.hero{background:transparent;color:hsl(var(--on-band-dark));padding:4.5rem 1.5rem 3.5rem;text-align:center;position:relative;z-index:1;user-select:none;-webkit-user-select:none}
/* Double-clicking the hero backdrop shouldn't highlight the heading/subtitle/trust copy; buttons keep normal selection. */
.hero .hero-btn{user-select:auto;-webkit-user-select:auto; }
.hero::before{content:'';position:absolute;inset:0;background:radial-gradient(ellipse 90% 55% at 50% -5%,rgba(48,186,120,.13) 0%,transparent 65%);pointer-events:none}
#heroCanvas{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;mix-blend-mode:color-dodge;opacity:.6}
.hero h1{font-size:clamp(2.75rem,6vw,5rem);line-height:1.05;margin-bottom:1.5rem;color:hsl(var(--on-band-dark));position:relative;padding-left:.3em;font-weight:200}
/* The hero's headline statement - the page's single h1, above the pilot pill in the
   details column. Displayed in SUSE Mono, uppercased in CSS ONLY: the DOM text stays
   title case, so screen readers read it naturally and the non-Latin locales (whose
   scripts neither SUSE Mono nor text-transform:uppercase touch) fall back cleanly to a
   system face in normal case. The generic .hero h1 rule above still supplies its
   responsive text-align (start on desktop, centre on mobile), so this qualified rule
   (0,2,0) only sets the display treatment (and clears that rule's padding-left, written
   for the old logo h1). break-word + hyphens keep a long single-word translation (e.g.
   German Inhaltssouveränität) inside its column. */
.hero .hero-statement{text-transform:uppercase;font-size:clamp(2.5rem,7vw,5.25rem);font-weight:800;max-width:90%; line-height:1.03;padding-left:0;margin:0 0 1.5rem;color:hsl(var(--on-band-dark));text-wrap:balance;overflow-wrap:break-word;hyphens:auto}
/* Radius + shadow live on the img itself - on the link they trace its layout box,
   which sits a hair off the rendered image edge and shows as a seam. */
/* The slot exists so the verify badge can position against the LOGO rather than
   against the full-width heading - without it a percentage offset resolves against
   the whole line and the badge lands out at the viewport edge. It carries the width
   the link used to own (the link now fills it). The logo is no longer the page's h1
   (that is the hero statement above now), so it is a plain mark; the badge stays a
   SIBLING of the logo link, not inside it, so "Verify this logo's credentials" is not
   folded into the logo link's accessible name. The reset just clears default box
   metrics on the mark. */
.hero-logo-slot{position:relative;width:clamp(180px,32vw,340px);margin:0 auto 1.5rem}
.hero .hero-logo-mark{margin:0;padding:0;line-height:0;position:relative}
.hero-logo-link{display:block;width:100%;aspect-ratio:1/1;border-radius:50%;cursor:pointer;transition:transform .2s ease}
/* The square is pinned on the BOX, not left to the image: before icon.svg has
   arrived (it carries a C2PA manifest and is the first thing the hero loads),
   or if it ever fails, an auto-height <img> collapses to a text line and the
   absolutely-placed still overlay stretches into a thin streak - the "squashed
   lolly" (Andy, 2026-09-02). With the aspect on the link the mark stays a
   circle of the right size from the first paint. */
.hero-logo-link:hover,.hero-logo-link:focus-visible{ outline:none}
.hero-logo-link:hover .hero-logo,.hero-logo-link:focus-visible .hero-logo{}
.hero-logo-link:active{transform:translateY(-1px) scale(1.0)}
.hero-logo{display:block;width:100%;height:100%;aspect-ratio:1/1;object-fit:contain;position:relative;border-radius:50%;filter:hue-rotate(-15deg);transition:box-shadow .2s ease}
.hero-logo:hover{filter: hue-rotate(-25deg) saturate(1.5) brightness(1.01)}
/* The mark idles STILL until hover (Andy, 2026-08-17). The swirl animation lives
   INSIDE the signed icon.svg, which an <img> embeds as its own document - page CSS
   cannot pause it and the signed file is never edited. So a static raster sits on
   top and lifts on hover/focus to let the swirl run. That raster is hero-still.png
   (`npm run icons`), derived from the 3-D icon-primary.svg - its OWN derivative,
   never one of the PWA rasters: the hero regressed to the flat mark the day
   icon-512.png switched sources (2026-08-28), which is what this decoupling fixes.
   Under reduced motion - the OS preference or the app's a11y switch - the still
   never lifts. */
.hero-logo-link{position:relative}
.hero-logo-still{position:absolute;inset:0;width:100%;height:100%;border-radius:50%;filter:hue-rotate(-15deg);transition:opacity .25s ease;pointer-events:none}
.hero-logo-link:hover .hero-logo-still,.hero-logo-link:focus-visible .hero-logo-still{opacity:0}
@media (prefers-reduced-motion: reduce){
  .hero-logo-link:hover .hero-logo-still,.hero-logo-link:focus-visible .hero-logo-still{opacity:1}
}
html[data-a11y-motion="reduce"] .hero-logo-link:hover .hero-logo-still,
html[data-a11y-motion="reduce"] .hero-logo-link:focus-visible .hero-logo-still{opacity:1}
/* The verify badge. Sits ON the circle's lower-right diagonal (a circle inscribed in
   the slot meets that diagonal at 50%+35.4%), small enough that the mark is still the
   thing you see - the badge is an offer, not a second logo. Its own hit area is 44px
   at the smallest hero size, and it never grows past the point where it would read as
   part of the artwork. line-height on .hero-logo-mark is 0, hence the explicit box. */
.hero-verify{position:absolute;left:82%;top:82%;transform:translate(-50%,-50%);
  display:flex;align-items:center;justify-content:center;
  width:clamp(2.75rem,6vw,3.25rem);height:clamp(2.75rem,6vw,3.25rem);
  border-radius:50%;background:var(--green,#30ba78);color:hsl(var(--on-band-dark));
  box-shadow:0 .25em .6em #0005,0 0 0 .18em rgba(12,50,44,.55);
  transition:transform .2s ease,box-shadow .2s ease}
.hero-verify>span{display:flex;width:52%;height:52%}
.hero-verify svg{width:100%;height:100%;display:block}
.hero-verify:hover,.hero-verify:focus-visible{transform:translate(-50%,-50%) scale(1.08);
  box-shadow:0 .35em .8em #0006,0 0 0 .22em rgba(255,255,255,.75);outline:none}
@media(prefers-reduced-motion:reduce){.hero-verify{transition:none}
  .hero-verify:hover,.hero-verify:focus-visible{transform:translate(-50%,-50%)}}
.hero .subtitle{font-size:clamp(.9375rem,1.8vw,1.125rem);max-width:560px;margin:0 auto 2.75rem; margin-left:color:hsl(var(--on-band-dark) / .5);font-weight:300;line-height:1.85;position:relative}
.hero-cta{display:flex;gap:1rem;justify-content:center;flex-wrap:wrap;position:relative;margin-bottom:2.5rem}
.hero-trust{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:.5rem;position:relative}
.hero-trust span{font-size:.8rem;line-height:1;color:hsl(var(--on-band-dark) / .5);letter-spacing:0}
.trust-dot{color:hsl(var(--on-band-dark) / .18)!important}
/* The landing's big call-to-action pill. Its own class, not .btn: /info reads the
   app's buttons.css for its top bar (plan 277 step 3c), and there .btn is the
   app's small bevelled button. */
.hero-btn{display:inline-flex;align-items:center;gap:.45em;padding:2rem 3rem;border-radius:1rem;font-weight:700;font-size:1rem;transition:all .18s ease;box-shadow:0 .2em 1em #0002}
/* The primary CTA wears the brand's primary, and its ink is whichever of black or
   white reads on that fill: --hero-cta-ink is measured off the PAINTED button by
   fitHeroCtaInk (lib/docs-landing.ts) once the fragment is in the DOM, so a near-black
   brand primary (the ink-and-paper starter) gets white text and a bright one black.
   The static /info site runs no such script and its brand is the fixed green, so the
   fallback stays black, exactly what it painted before. No plus-lighter blend any
   more: it ADDED the fill to the always-dark band, so a dark primary contributed
   nothing and the button and its cut-out label both went out (Andy, 2026-09-03). The
   hairline keeps a dark fill readable as a button on the dark band. */
/* The static /info page defines no --brand-primary at all (only the app shell's
   chrome injects it), so the fill falls back to --green, the site's own primary
   (docs.css: hsl(var(--primary)), Pine Green on /info): a brand-green pill under the
   black default label, the same green as the nav's Launch App pill. A white pill
   here read as a blank (Andy, 2026-09-03). In the app the reader bridges --green to
   the active brand too, and an injected --brand-primary still wins. */
.btn-primary{background:var(--green);color:var(--hero-cta-ink);
  box-shadow:0 .2em 1em #0002,inset 0 0 0 1px rgba(255,255,255,.16)}
/* Hover lightens the BRAND fill rather than painting a fixed lighter Pine Green
   (which turned every other brand's button SUSE mint on hover). An engine without
   color-mix() drops the two declarations and keeps the rest fill; the lift and the
   hairline still say "hover". */
.btn-primary:hover{text-decoration:none;transform:translateY(-2px);
  background:color-mix(in oklab,var(--brand-primary,var(--green)) 82%,#fff);
  box-shadow:0 8px 32px color-mix(in oklab,var(--brand-primary,var(--green)) 45%,transparent),inset 0 0 0 1px rgba(255,255,255,.24)}
/* The secondary pill owns its legibility. Its ground is a dark translucency, not
   a near-clear white: white ink over a near-clear fill only reads while the
   backdrop behind it is dark, and a backdrop-filter that fails to paint (seen in
   Chromium: the pill rendered a blank white box at rest and only recovered on the
   hover transform) left white text on white. A dark fill of its own keeps the
   words readable over anything the backdrop turns into. */
.btn-secondary{background:rgba(6,20,14,.42);color:hsl(var(--on-band-dark));border:0;position:relative}
.btn-secondary:hover{background:rgba(6,20,14,.28);text-decoration:none;transform:translateY(-1px)}
/* Glass baseline - frosted blur so the buttons read as glass even where the JS
   liquid-displacement filter can't render. The buildGlass script overrides this
   inline with the refractive filter on the PRIMARY button only: the secondary
   pill's white ink cannot survive a backdrop that paints blank, so it keeps this
   plain, reliable blur and never takes the SVG displacement. */
.btn-primary,.btn-secondary{-webkit-backdrop-filter:blur(3px) saturate(1.45);backdrop-filter:blur(3px) saturate(1.45)}


/* ── Hero download rail ───────────────────────────────────────────────────────
   The five packaged builds, inside the hero so they are above the fold on a
   1280x720 laptop. Everything here sits on the dark hero band only, so the
   colours are the on-band-dark tokens and there is no light-theme twin to keep
   in step.

   The tile is a CARD, not a row, because a row cannot hold this content at this
   width: five tiles across the hero's text column is ~190px each, and "Phone and
   tablet" beside a mark and a file-type badge truncates at that size. Stacking
   gives the name the tile's full width and leaves the badge a corner of its own.

   `--dl-accent` is the ONE per-tile variable: each tile sets it from its own
   [data-dl] and every hover effect below reads it, so adding a sixth platform is
   one line of colour rather than a sixth copy of the hover rules. The accents are
   each project's own mark colour - the tile is recognised by the mark first and
   read second, and a hover that lights up in the wrong green undoes that.

   Motion is opt-out, not opt-in: the reduced-motion query at the end drops the
   travel and keeps the colour and border changes, which are the part that
   carries the meaning.                                                         */
/* The hero's stack (statement, subtitle, CTA pair) clears 720px, the shortest
   laptop viewport this page is designed for. The download rail closed the hero
   until 2026-09-02; it now has its own band (.downloads-section, between the
   persona device and lolly.work), so these gaps are the hero's own. Nothing here
   resizes the buttons or the H1. */
.hero .subtitle{margin-bottom:1.9rem}
.hero-cta{margin-bottom:1.6rem}
/* ── beat 4a: get the app - the rail on the hero's dark surface ──────────── */
.downloads-section{padding:0 1.5rem 3.5rem}
.downloads-inner{max-width:1120px;margin:0 auto;padding:1.6rem 1.6rem 1.5rem;border-radius:14px;color:hsl(var(--on-band-dark));background:linear-gradient(180deg,color-mix(in oklab,hsl(var(--primary)) 34%,#0b1512) 0%,color-mix(in oklab,hsl(var(--primary)) 15%,#0a120f) 100%)}
.hero-downloads{position:relative;margin:0}
.dl-head{display:flex;align-items:baseline;gap:.6rem;flex-wrap:wrap;margin:0 0 .7rem}
.dl-label{font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.14em;
  color:hsl(var(--on-band-dark) / .85)}
.dl-lead{font-size:.8rem;color:hsl(var(--on-band-dark) / .45);font-weight:300}
/* auto-fit rather than repeat(5,1fr): five across the hero column, and the same
   rule reflows to 3+2 and then 2+2+1 without a breakpoint per step. */
.dl-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(9rem,1fr));gap:.55rem}

.dl-tile{--dl-accent:#30ba78;
  position:relative;display:flex;flex-direction:column;gap:.3rem;isolation:isolate;
  padding:.75rem .8rem .7rem;border-radius:.85rem;overflow:hidden;text-decoration:none;
  background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.14);
  color:hsl(var(--on-band-dark));
  -webkit-backdrop-filter:blur(3px) saturate(1.45);backdrop-filter:blur(3px) saturate(1.45);
  box-shadow:0 .15em .6em #0003;
  transition:transform .22s cubic-bezier(.2,.9,.3,1.2),border-color .22s ease,
             background-color .22s ease,box-shadow .22s ease}
.dl-tile[data-dl="apple"]{--dl-accent:#e8eef2}
.dl-tile[data-dl="opensuse"]{--dl-accent:#73ba25}
.dl-tile[data-dl="flatpak"]{--dl-accent:#4a90d9}
.dl-tile[data-dl="android"]{--dl-accent:#3ddc84}

/* The wash: an accent-tinted glow that grows from behind the mark on hover. Sits
   under the content (the tile is an isolation root), so it never touches the
   text contrast. */
.dl-tile::before{content:'';position:absolute;z-index:0;left:-30%;top:-40%;width:110%;aspect-ratio:1;
  transform:scale(.25);border-radius:50%;opacity:0;pointer-events:none;
  background:radial-gradient(circle,color-mix(in oklab,var(--dl-accent) 55%,transparent) 0%,transparent 70%);
  transition:transform .45s cubic-bezier(.2,.9,.3,1),opacity .35s ease}
/* The sheen: one pass of a skewed highlight, left to right, on hover only. */
.dl-tile::after{content:'';position:absolute;z-index:1;inset:0 auto 0 -60%;width:45%;
  pointer-events:none;transform:skewX(-18deg) translateX(0);
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.16),transparent);
  opacity:0;transition:transform .6s ease,opacity .2s ease}
.dl-tile>*{position:relative;z-index:2}

.dl-top{display:flex;align-items:center;gap:.35rem;margin-bottom:.15rem}
.dl-mark{display:flex;flex:0 0 auto;width:1.55rem;height:1.55rem;margin-inline-end:auto;
  color:hsl(var(--on-band-dark) / .8);
  transition:color .22s ease,transform .3s cubic-bezier(.2,.9,.3,1.4),filter .22s ease}
/* The shared `.doc-logo` rule sizes marks for INLINE use in body text (1.1em with
   a 1.35em ceiling, dimmed, with a trailing margin). None of that applies in a
   tile, where the mark is the tile's own subject - so all five of those
   properties are reset rather than fought with. */
.dl-mark .doc-logo{display:flex;width:100%;height:100%;
  max-width:none;max-height:none;margin-inline-end:0;opacity:1;vertical-align:baseline}
.dl-mark svg{width:100%;height:100%;display:block}
/* The download glyph keeps its slot at rest (invisible, not absent), so revealing
   it on hover cannot shift the badge beside it by a pixel. */
.dl-go{display:flex;flex:0 0 auto;width:.95rem;height:.95rem;color:var(--dl-accent);
  opacity:0;transform:translateX(-.35rem);
  transition:opacity .22s ease,transform .35s cubic-bezier(.2,.9,.3,1.5)}
.dl-go svg{width:100%;height:100%;display:block}
.dl-ext{flex:0 0 auto;font-size:.55rem;font-weight:700;letter-spacing:.07em;
  padding:.18rem .34rem;border-radius:.3rem;
  color:hsl(var(--on-band-dark) / .55);border:1px solid rgba(255,255,255,.16);
  background:transparent;
  transition:color .22s ease,background-color .22s ease,border-color .22s ease}

.dl-name{font-size:.92rem;font-weight:600;line-height:1.15;color:hsl(var(--on-band-dark))}
.dl-meta{display:flex;align-items:baseline;gap:.3rem;font-size:.66rem;line-height:1.3;
  min-width:0}
.dl-os{flex:0 0 auto;font-weight:700;text-transform:uppercase;letter-spacing:.08em;
  color:hsl(var(--on-band-dark) / .5);transition:color .22s ease}
.dl-os::after{content:'\00b7';margin-inline-start:.3rem;color:hsl(var(--on-band-dark) / .25)}
.dl-note{font-weight:300;color:hsl(var(--on-band-dark) / .38);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:color .22s ease}

.dl-tile:hover,.dl-tile:focus-visible{outline:none;text-decoration:none;
  transform:translateY(-3px);
  background:rgba(255,255,255,.09);
  border-color:color-mix(in oklab,var(--dl-accent) 60%,transparent);
  box-shadow:0 .7em 1.6em #0005,0 0 0 1px color-mix(in oklab,var(--dl-accent) 35%,transparent),
             0 .5em 2.2em -.4em color-mix(in oklab,var(--dl-accent) 45%,transparent)}
.dl-tile:hover::before,.dl-tile:focus-visible::before{opacity:.45;transform:scale(1)}
.dl-tile:hover::after,.dl-tile:focus-visible::after{opacity:1;transform:skewX(-18deg) translateX(360%)}
.dl-tile:hover .dl-mark,.dl-tile:focus-visible .dl-mark{color:var(--dl-accent);
  transform:scale(1.14) rotate(-5deg);
  filter:drop-shadow(0 0 .5em color-mix(in oklab,var(--dl-accent) 55%,transparent))}
.dl-tile:hover .dl-go,.dl-tile:focus-visible .dl-go{opacity:1;transform:translateX(0)}
/* The badge fills with the accent and takes dark text - the one high-contrast
   moment in the tile, so the file you are about to get names itself loudest. */
.dl-tile:hover .dl-ext,.dl-tile:focus-visible .dl-ext{
  background:var(--dl-accent);border-color:var(--dl-accent);color:#06170f}
.dl-tile:hover .dl-os,.dl-tile:focus-visible .dl-os{color:var(--dl-accent)}
.dl-tile:hover .dl-note,.dl-tile:focus-visible .dl-note{color:hsl(var(--on-band-dark) / .6)}
.dl-tile:active{transform:translateY(-1px) scale(.99)}
/* Keyboard focus needs a ring of its own: the hover treatment is a glow, and a
   glow is not a focus indicator. */
.dl-tile:focus-visible{box-shadow:0 0 0 2px hsl(var(--on-band-dark)),
  0 0 0 4px color-mix(in oklab,var(--dl-accent) 70%,transparent),0 .7em 1.6em #0005}

.dl-more,.dl-verify{display:inline-flex;align-items:center;gap:.35rem;margin-top:.6rem;
  font-size:.76rem;font-weight:600;color:hsl(var(--on-band-dark) / .55);
  transition:color .18s ease,gap .18s ease}
/* The verify link sits on its own row under the tiles; a hair more top gap sets it
   apart from the grid, and the shield glyph tracks the text size. */
.dl-verify{display:flex}
.dl-verify svg{width:.95em;height:.95em;flex:0 0 auto}
/* Not var(--light) - see the .btn-primary:hover note. On this always-dark band that
   token resolves to a near-black teal at 40% in the light theme, which is a hover
   state you cannot see. */
.dl-more:hover,.dl-more:focus-visible,
.dl-verify:hover,.dl-verify:focus-visible{color:#5fd79b;text-decoration:none;gap:.6rem}

/* Phones. "Above the fold" is the whole point of putting the rail in the hero, and
   on a 430x860 phone the hero's own stack spent 808px before the rail started - so
   the rail was the one thing that could not be seen. The height comes back from
   three places, none of which is the rail itself:

     1. the CTA pair stops stacking. Two full-width buttons at 2rem of vertical
        padding are ~195px of hero on a phone; side by side at phone padding they
        are ~60px, and they read better as a pair besides.
     2. the lollipop's floor drops from 180px to 130px. It is the brand mark, not
        the message, and it is the largest single block above the words.
     3. the hero's own top padding halves.

   The tile turns back into a ROW here, because two columns of ~200px is enough
   width for a horizontal layout and a row is 50px tall where the card is 92px.
   The note line goes: it is the least of the four facts, the install page carries
   all of them, and the tile's aria-label still says every one to a screen reader. */
@media(max-width:600px){
  /* 4rem, not less: the top nav is fixed and ~60px tall, so a smaller pad slides
     the lollipop under it. The height comes out of the slot's own bottom margin
     and its floor instead, which costs nothing a reader can see. */
  .hero{padding-top:4rem}
  .hero-logo-slot{width:clamp(120px,32vw,340px);margin-bottom:.5rem}
  .hero .subtitle{margin-bottom:1.2rem}
  .hero-cta{margin-bottom:1.2rem;flex-wrap:nowrap;gap:.6rem}
  .hero-cta .hero-btn{flex:1 1 0;min-width:0;justify-content:center;padding:1.05rem .75rem;
    font-size:.9375rem;border-radius:.85rem}

  .dl-head{margin-bottom:.5rem}
  /* The lead is a grace note, and at this width it wraps to a second line that
     costs more height than the sentence is worth. The label carries the meaning. */
  .dl-lead{display:none}
  .dl-grid{grid-template-columns:repeat(2,1fr);gap:.5rem}
  /* A tile is never centred: a name centred over a left-hand mark reads as two
     unrelated things sharing a box. */
  .dl-tile{text-align:start}
  /* The name gets BOTH text columns and the badge drops to the line below it. At
     two columns of ~167px, a badge beside the name leaves it ~80px, which is not
     enough for "Apple silicon"; under the name it costs nothing, because the row
     it shares with the OS label was half empty. */
  .dl-tile{gap:.5rem;padding:.55rem .6rem;
    display:grid;grid-template-columns:auto 1fr auto;
    grid-template-areas:'mark name name' 'mark meta ext'}
  .dl-top{display:contents}
  .dl-mark{grid-area:mark;width:1.4rem;height:1.4rem;margin-inline-end:0;align-self:center}
  .dl-ext{grid-area:ext;align-self:center;justify-self:end}
  .dl-go{display:none}
  /* One line, always: a name that wraps takes every tile in its row with it, so a
     single long label would add a row's worth of height to the whole grid. */
  .dl-name{grid-area:name;font-size:.84rem;align-self:end;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
  .dl-meta{grid-area:meta;align-self:start;font-size:.62rem}
  .dl-note{display:none}
  .dl-os::after{content:none}
  .dl-more{margin-top:.4rem}
}
@media(prefers-reduced-motion:reduce){
  /* Colour and border still change - that is the affordance. Only travel goes. */
  .dl-tile{transition:border-color .22s ease,background-color .22s ease}
  .dl-tile:hover,.dl-tile:focus-visible,.dl-tile:active{transform:none}
  .dl-tile::after{display:none}
  .dl-tile::before{transition:opacity .2s ease;transform:scale(1)}
  .dl-mark,.dl-go{transition:opacity .2s ease,color .2s ease}
  .dl-tile:hover .dl-mark,.dl-tile:focus-visible .dl-mark{transform:none}
  .dl-tile:hover .dl-go,.dl-tile:focus-visible .dl-go{transform:none}
  .dl-more:hover,.dl-more:focus-visible{gap:.35rem}
}

/* Three-door pathways band - sits directly under the hero on the landing page. */
.pathways-section{background:transparent;position:relative;z-index:1;padding:3rem 1.5rem}
.pathways-inner{max-width:1080px;margin:0 auto;text-align:center}
.pathways-head{display:flex;align-items:center;justify-content:center;gap:2.5rem;flex-wrap:wrap;margin:0 0 1.75rem;text-align:start}
.pathways-headtext{max-width:38rem}
.pathways-title{color:hsl(var(--on-band-dark));font-size:2rem;margin:0 0 .5rem}
.pathways-mascot{width:clamp(160px,20vw,300px);flex-shrink:0}
.pathways-lead{color:hsl(var(--on-band-dark) / .7);font-size:1.0625rem;margin:0}
.pathways-lead a{color:var(--light);font-weight:600}
.pathways-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:1.25rem;text-align:start}
@media(max-width:1020px){.pathways-grid{grid-template-columns:repeat(2,1fr)}}
.pathway-card{    backdrop-filter: blur(5px);display:flex;flex-direction:column;gap:.5rem;padding:1.75rem;border-radius:14px;background:rgba(255,255,255,.05);border:0;    box-shadow: inset 0 1px #fff1, 0 .2em .5em #0002;transition:transform .18s ease,border-color .18s ease,background .18s ease}
.pathway-card:hover{text-decoration:none;transform:translateY(-3px);border-color:var(--green);background:rgba(255,255,255,.08)}
.pathway-ic{align-self:flex-start;display:inline-flex;align-items:center;justify-content:center;width:2.75rem;height:2.75rem;margin-bottom:.35rem;border-radius:12px;color:hsl(var(--on-band-dark));background:linear-gradient(163deg,hsl(150 66% 51%),hsl(154 58% 33%));border:1px solid hsl(0 0% 100% / .3);box-shadow:inset 0 1px 0 hsl(0 0% 100% / .45),0 6px 16px -6px hsl(151 57% 40% / .75);transition:box-shadow .18s ease,transform .18s ease}
.pathway-ic svg{width:1.45rem;height:1.45rem}
.pathway-card:hover .pathway-ic{transform:translateY(-1px);box-shadow:inset 0 1px 0 hsl(0 0% 100% / .5),0 9px 22px -6px hsl(151 57% 40% / .9)}
.pathway-eyebrow{font-size:.75rem;text-transform:uppercase;letter-spacing:.1em;font-weight:700;color:hsl(var(--on-band-dark));}
.pathway-name{font-size:1.375rem;font-weight:200;color:var(--green)}
.pathway-desc{font-size:.9375rem;line-height:1.55;color:hsl(var(--on-band-dark) / .68);flex:1}
.pathway-go{font-size:.9375rem;font-weight:600;color:var(--light);margin-top:.5rem}
@media(max-width:820px){.pathways-grid{grid-template-columns:1fr}}

/* Audience section */
.audience-section{}
.audience-header{background:linear-gradient(180deg,var(--pale) 0%,#fff 100%)}
.audience-title{font-size:2.5rem;color:var(--dark);margin:0}
.audience-sub{color:var(--muted);font-size:.9375rem;margin-top:.5rem;margin-bottom:0}
/* CSS-only tabs (plan 123 D1 final form). The radios are visually hidden but stay
   focusable - the native radio group IS the keyboard interface, and the focus ring is
   painted onto the paired pill below. Never display:none them. */
.aud-radio{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.audience-tabs{display:flex;flex-wrap:wrap;justify-content:center;gap:.5rem;padding:.875rem 1.5rem 1.25rem;background:hsl(var(--background));border-bottom:2px solid var(--border);max-width:1400px;margin:0 auto}
.audience-tab{display:inline-flex;align-items:center;gap:.45rem;padding:.5rem .95rem;border:2px solid var(--border);background:hsl(var(--card));cursor:pointer;border-radius:999px;color:var(--muted);transition:all .15s;font-family:'SUSE',inherit}
.audience-tab .tab-icon{width:1.05rem;height:1.05rem}
.audience-tab .tab-icon svg{width:100%;height:100%}
.audience-tab .tab-label{font-size:.62rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;white-space:nowrap}
.audience-tab:hover{border-color:var(--green);color:var(--dark);background:var(--pale)}

/* Audience panels. Layout and visibility are kept apart on purpose: the card's layout
   lives in the base rule (and flips to a flex column in the phone media block via
   --aud-card-display), while visibility is the radio pairing below - so the mobile
   override never has to out-specify the show rule. The machines band's cards are never
   gated: the hide rule anchors on a preceding .aud-radio sibling, which only the
   tabbed section has. */
.audience-panels{display:block;margin-bottom:2em}
.audience-card{
  --aud-card-display:grid;
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1.4fr);
  gap:2.5rem 5rem;
  align-items:start;
  padding:2.5rem 3.5rem;
  max-width:1400px;
  margin:0 auto;
  scroll-margin-top:5rem;
}
.aud-radio ~ .audience-panels > .audience-card{display:none}
/* An old #slug deep link opens its card without any radio involvement. */
.aud-radio ~ .audience-panels > .audience-card:target{display:var(--aud-card-display,grid)}
/* Index-matched pairing: radio N shows card N, styles pill N. Nine slots so a new
   audience section never silently falls off the end (seven are in use today). */
.aud-radio:nth-of-type(1):checked ~ .audience-panels > .audience-card:nth-child(1),
.aud-radio:nth-of-type(2):checked ~ .audience-panels > .audience-card:nth-child(2),
.aud-radio:nth-of-type(3):checked ~ .audience-panels > .audience-card:nth-child(3),
.aud-radio:nth-of-type(4):checked ~ .audience-panels > .audience-card:nth-child(4),
.aud-radio:nth-of-type(5):checked ~ .audience-panels > .audience-card:nth-child(5),
.aud-radio:nth-of-type(6):checked ~ .audience-panels > .audience-card:nth-child(6),
.aud-radio:nth-of-type(7):checked ~ .audience-panels > .audience-card:nth-child(7),
.aud-radio:nth-of-type(8):checked ~ .audience-panels > .audience-card:nth-child(8),
.aud-radio:nth-of-type(9):checked ~ .audience-panels > .audience-card:nth-child(9){display:var(--aud-card-display,grid)}
.aud-radio:nth-of-type(1):checked ~ .audience-tabs > .audience-tab:nth-child(1),
.aud-radio:nth-of-type(2):checked ~ .audience-tabs > .audience-tab:nth-child(2),
.aud-radio:nth-of-type(3):checked ~ .audience-tabs > .audience-tab:nth-child(3),
.aud-radio:nth-of-type(4):checked ~ .audience-tabs > .audience-tab:nth-child(4),
.aud-radio:nth-of-type(5):checked ~ .audience-tabs > .audience-tab:nth-child(5),
.aud-radio:nth-of-type(6):checked ~ .audience-tabs > .audience-tab:nth-child(6),
.aud-radio:nth-of-type(7):checked ~ .audience-tabs > .audience-tab:nth-child(7),
.aud-radio:nth-of-type(8):checked ~ .audience-tabs > .audience-tab:nth-child(8),
.aud-radio:nth-of-type(9):checked ~ .audience-tabs > .audience-tab:nth-child(9){background:hsl(var(--band-dark));color:hsl(var(--on-band-dark));border-color:hsl(var(--band-dark));box-shadow:0 3px 12px rgba(12,50,44,.2)}
.aud-radio:nth-of-type(1):focus-visible ~ .audience-tabs > .audience-tab:nth-child(1),
.aud-radio:nth-of-type(2):focus-visible ~ .audience-tabs > .audience-tab:nth-child(2),
.aud-radio:nth-of-type(3):focus-visible ~ .audience-tabs > .audience-tab:nth-child(3),
.aud-radio:nth-of-type(4):focus-visible ~ .audience-tabs > .audience-tab:nth-child(4),
.aud-radio:nth-of-type(5):focus-visible ~ .audience-tabs > .audience-tab:nth-child(5),
.aud-radio:nth-of-type(6):focus-visible ~ .audience-tabs > .audience-tab:nth-child(6),
.aud-radio:nth-of-type(7):focus-visible ~ .audience-tabs > .audience-tab:nth-child(7),
.aud-radio:nth-of-type(8):focus-visible ~ .audience-tabs > .audience-tab:nth-child(8),
.aud-radio:nth-of-type(9):focus-visible ~ .audience-tabs > .audience-tab:nth-child(9){outline:2px solid var(--green);outline-offset:2px}
.card-main{min-width:0;overflow:hidden}
.card-icon{width:2.5rem;height:2.5rem;color:var(--green);margin-bottom:1.25rem}
.card-icon svg{width:100%;height:100%}
.card-audience{font-size:.6875rem;text-transform:uppercase;letter-spacing:.14em;color:var(--green);font-weight:700;margin-bottom:.375rem}
.card-tagline{font-size:1.5rem;font-weight:800;color:var(--dark);margin-bottom:.75rem;line-height:1.2}
.card-intro{font-size:.9375rem;color:var(--muted);line-height:1.75;margin-bottom:1.5rem}
.card-main pre{font-size:.8rem;margin-top:0;margin-bottom:0;white-space:pre-wrap;overflow-wrap:anywhere;box-sizing:border-box}
.card-main pre::-webkit-scrollbar{display:none}
.card-benefits{display:grid;grid-template-columns:1fr 1fr;gap:1.5em 4em;padding-left:0;list-style:none;margin:0;padding-top:.25rem}
.card-benefits li{display:flex;align-items:flex-start;gap:.75rem;font-size:.9375rem;line-height:1.6;color:var(--text)}
.card-benefits li:last-child{margin-bottom:0}
.bullet-icon{width:2.25em;height:2.25em;display:block;margin:.15em 0;color:var(--green);flex-shrink:0}
.bullet-icon svg{width:100%;height:100%}
.card-benefits strong{font-weight:700;color:var(--dark)}

/* Platform + What's a tool - side by side on desktop */
.platform-whats-wrap{position:relative;display:flex;align-items:stretch}
/* The try-now callout straddles this wrap's bottom seam (absolute, translateY 50%), so
   BOTH sides of the seam reserve room for its halves: the columns carry enough bottom
   padding that the top half never covers their last lines, and the teaser that follows
   the wrap clears the bottom half the same way. Copy growth eats headroom, not text. */
.platform-whats-wrap .platform-section,.platform-whats-wrap .whats-a-tool{flex:1;min-width:0;padding-bottom:5rem}
.platform-whats-wrap+.teaser-section{padding-top:4.5rem}
/* The floating section eyebrow at the band junction. The band-dark PAIR, not loose
   tokens: the previous background:var(--muted) was a FOREGROUND ink used as a ground,
   with a surface token as its text - two mid-tones in every theme. The pair is
   theme-stable, brand-reactive, and matches the selected tab pills. */
.whats-label{position:absolute;top:0;left:50%;transform:translate(-50%,-50%);z-index:10;border-radius:3rem;padding:.85rem 2rem;font-weight:700;font-size:1.0625rem;white-space:nowrap;box-shadow:0 6px 20px rgba(0,0,0,.18);background:hsl(var(--band-dark));color:hsl(var(--on-band-dark))}

/* Platform */
.platform-section{background:linear-gradient(20deg,#0c322c 0%,#008657 100%);color:hsl(var(--on-band-dark));padding:3rem 3.5rem}
.platform-inner{max-width:var(--col-cap);margin-left:auto;margin-right:0}
.platform-header{text-align:center;margin-bottom:1.75rem}
.platform-section h2{margin-bottom:.5rem}
.platform-tagline{color:hsl(var(--on-band-dark) / .8);font-size:1.0625rem;margin:0;letter-spacing:.01em}
.platform-features{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;background:rgba(0,0,0,.4);border:1px solid rgba(255,255,255,.08);border-radius:14px;overflow:hidden;margin-bottom:1.75rem}
.platform-feature{background:rgba(255,255,255,.025);padding:1.625rem 1.5rem;display:flex;flex-direction:column;gap:.5rem;transition:background .15s}
.platform-feature:hover{background:#00000033}
.platform-feature-icon{width:1.75rem;height:1.75rem;color:var(--green);margin-bottom:.375rem}
.platform-feature-icon svg{width:100%;height:100%}
.platform-feature strong{font-size:.9375rem;font-weight:700;line-height:1.3}
.platform-feature p{color:hsl(var(--on-band-dark) / .45);font-size:.85rem;margin:0;line-height:1.6}
.platform-feature:last-child:nth-child(odd){grid-column:1 / -1}
.rt-mark{font-family:'SUSE',sans-serif;font-weight:700;letter-spacing:0;margin-right:.32em;line-height:1}
.rt-inline{color:var(--green);font-weight:600;white-space:nowrap}
.rt-inline .rt-mark{margin-right:.1em}
/* ── Block 2: make something, right now (plan 117) ──────────────────────────
   Three worked examples, each a plain link into the app carrying the example's
   own inputs. The picture is the tool's own preview of that exact look, so the
   card cannot promise a look the click does not deliver. Cards are <a>, so the
   whole tile is the hit area and keyboard focus lands on it once. */
.make-section{background:hsl(var(--background));padding:3rem 1.5rem}
.make-inner{max-width:1180px;margin:0 auto}
.make-head{max-width:44rem;margin:0 auto 1.75rem;text-align:center}
.make-head h2{color:var(--dark);margin:0 0 .75rem}
html[data-theme="dark"] .make-head h2{color:hsl(var(--foreground))}
.make-lead{color:var(--muted);font-size:1.05rem;line-height:1.7;margin:0}
.make-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.25rem}
@media(max-width:900px){.make-grid{grid-template-columns:1fr;max-width:26rem;margin:0 auto}}
.make-card{display:flex;flex-direction:column;background:hsl(var(--card));border:1px solid var(--border);border-radius:16px;padding:1rem 1rem 1.15rem;color:inherit;text-decoration:none;transition:transform .15s,box-shadow .15s,border-color .15s}
.make-card:hover,.make-card:focus-visible{transform:translateY(-3px);box-shadow:0 .8rem 2rem rgba(12,50,44,.13);border-color:var(--green);text-decoration:none}
.make-card:focus-visible{outline:2px solid var(--green);outline-offset:3px}
.make-shot{display:block;background:var(--pale);border-radius:11px;overflow:hidden;aspect-ratio:4/3;margin-bottom:.95rem}
.make-shot img{width:100%;height:100%;object-fit:contain;display:block}
.make-scene{font-size:1.0625rem;font-weight:700;color:var(--dark);line-height:1.3}
html[data-theme="dark"] .make-scene{color:hsl(var(--foreground))}
.make-line{color:var(--muted);font-size:.9rem;line-height:1.6;margin-top:.35rem;flex:1}
.make-go{margin-top:.9rem;font-size:.875rem;font-weight:700;color:var(--green);display:inline-flex;align-items:center;gap:.4em}
.make-card:hover .make-go span{transform:translateX(3px)}
.make-go span{transition:transform .15s}

/* ── Block 3: the sovereignty statement ─────────────────────────────────────
   The one full statement of internet-optionality on the page, and deliberately
   the quietest band on it: no cards, no icons, no illustration - one paragraph
   on the always-dark chrome surface, with two receipt links under it. */
.sovereign-section{background:hsl(var(--band-dark));color:hsl(var(--on-band-dark));padding:3.25rem 1.5rem}
.sovereign-inner{max-width:52rem;margin:0 auto;text-align:center}
.sovereign-statement{font-size:clamp(.9rem,2.2vw,1rem);line-height:1.75;margin:0;color:hsl(var(--on-band-dark) / .78);text-wrap:pretty}
.sovereign-statement strong{color:hsl(var(--on-band-dark));font-weight:700}
.sovereign-receipts{margin-top:1.35rem;display:flex;align-items:center;justify-content:center;gap:.75rem;font-size:.875rem}
.sovereign-receipts a{color:hsl(var(--on-band-dark) / .62);text-decoration:underline;text-underline-offset:.25em}
.sovereign-receipts a:hover{color:hsl(var(--on-band-dark))}
.sovereign-dot{color:hsl(var(--on-band-dark) / .35)}

/* ── Block 5: AI, on your terms ─────────────────────────────────────────────
   Three short answers, no illustration: this block exists to remove worry, and
   a decorated one would read as a pitch. */
.ai-section{background:hsl(var(--background));padding:3rem 1.5rem;border-top:1px solid var(--border)}
.ai-inner{max-width:1000px;margin:0 auto}
.ai-head{max-width:42rem;margin:0 auto 1.75rem;text-align:center}
.ai-head h2{color:var(--dark);margin:0 0 .75rem}
html[data-theme="dark"] .ai-head h2{color:hsl(var(--foreground))}
.ai-lead{color:var(--muted);font-size:1.05rem;line-height:1.7;margin:0}
.ai-points{display:grid;grid-template-columns:repeat(3,1fr);gap:1.75rem}
@media(max-width:820px){.ai-points{grid-template-columns:1fr;max-width:30rem;margin:0 auto}}
.ai-point strong{display:block;font-size:1rem;color:var(--dark);margin-bottom:.4rem}
html[data-theme="dark"] .ai-point strong{color:hsl(var(--foreground))}
.ai-point p{color:var(--muted);font-size:.9375rem;line-height:1.7;margin:0}

/* ── Block 7: who is behind this, and why ───────────────────────────────────
   The progressive-disclosure turn, low on the page and once. One paragraph in a
   narrow measure - the only place on the landing where "we" is the subject. */
.behind-section{background:var(--pale);padding:3rem 1.5rem}
.behind-inner{max-width:66rem;margin:0 auto;text-align:start}
/* Two columns, left-aligned (Andy, 2026-08-17): the sceptic paragraph and the assurance
   side by side, with the founded-by badge anchoring the foot row once. */
.behind-cols{display:grid;grid-template-columns:1fr 1fr;gap:2rem 3.5rem;align-items:start}
.behind-foot{display:flex;align-items:center;justify-content:space-between;gap:1.5rem;flex-wrap:wrap;margin-top:1.75rem}
/* Moved here from build.ts (2026-08-17) so the reader gets it too: founded-by.svg is
   viewBox-only (no intrinsic width), and without the explicit width the inline anchor
   and the intrinsically-unsized image collapse to 0x0 together - which is exactly what
   happened in-app while these rules lived only in the static blob. */
.founded-badge{display:inline-block;line-height:0}
.founded-badge img{display:block;width:15em;max-width:100%;height:auto}
.behind-foot .behind-links{margin-top:0;justify-content:flex-start}
@media(max-width:800px){.behind-cols{grid-template-columns:1fr}}
.behind-eyebrow{display:inline-block;font-size:.6875rem;text-transform:uppercase;letter-spacing:.14em;font-weight:700;color:var(--green);margin-bottom:1.1rem}
.behind-para{font-size:1.0625rem;line-height:1.85;color:var(--muted);margin:0}
.behind-para strong{color:var(--dark);font-weight:700}
html[data-theme="dark"] .behind-para strong{color:hsl(var(--foreground))}
.behind-assure{margin-top:0}
/* One paragraph since 2026-09-02: a readable measure, left-aligned like the columns were. */
.behind-para--solo{max-width:70ch}
/* The refusal band (plan 122 block 11): the trio + the visible vote, reusing the
   tool-feature card grid so the beats read as one set. */
.refusal-section{padding:3rem 1.5rem;background:var(--page)}
.refusal-section .assure-inner{max-width:1080px;margin:0 auto}
.refusal-title{text-align:center;font-size:1.75rem;margin:0 0 1.25rem}
.refusal-beats{margin-top:0}
/* The quokka rides beside the 2x2 beats, at ease - a calm mascot for a section
   that promises nothing is taken. Beats flex-grow; the mascot holds its width. */
.refusal-row{display:flex;align-items:center;justify-content:center;gap:2.25rem}
.refusal-row .refusal-beats{flex:1 1 auto;min-width:0;margin-bottom:0}
.refusal-mascot{width:clamp(160px,22vw,320px);flex-shrink:0;filter:drop-shadow(0 14px 34px rgba(0,0,0,.4))}
@media(max-width:820px){.refusal-row{flex-direction:column;gap:1.75rem}.refusal-mascot{width:min(52vw,240px)}}
/* The machines band sits directly under the human tabs: two sections, two
   deliberately CONTRASTING treatments (plan 123). The agents card is a deep split
   panel - the prompt is the hero, framed as a terminal pane - and the security card
   is a light ruled audit sheet, one claim per row. Both escape the audience radio
   gating entirely (no .audience-card class). */
.machines-section{padding-top:0}
.machines-band{max-width:1400px;margin:0 auto 1.5rem;padding:0 3.5rem;display:flex;flex-direction:column;gap:2rem}
.machine-card{border-radius:16px;scroll-margin-top:5rem}
.mc-eyebrow{display:inline-flex;align-items:center;gap:.5rem;font-size:.6875rem;text-transform:uppercase;letter-spacing:.14em;font-weight:700;color:var(--green)}
.mc-ic{display:inline-flex}
.mc-ic svg{width:1.25rem;height:1.25rem}
.machine-card .bullet-icon{flex:none;color:var(--green)}
.machine-card .bullet-icon svg{width:1.25rem;height:1.25rem}
.mc-title{font-size:1.5rem;font-weight:800;margin:.5rem 0 .75rem;line-height:1.2;text-transform:none}
.mc-intro{font-size:.9375rem;line-height:1.65;margin:0 0 1.25rem;max-width:56ch}

.machine-card--agents{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:2.5rem;align-items:center;background:hsl(var(--band-dark));color:hsl(var(--on-band-dark));padding:2.75rem 3rem}
/* On the deep band, var(--green) is the LIGHT theme's dark teal - invisible ink here.
   The band-accent pair is the theme-stable bright accent made for this ground. */
.machine-card--agents .mc-eyebrow,
.machine-card--agents .bullet-icon,
.machine-card--agents .mc-points a{color:hsl(var(--band-accent))}
.machine-card--agents .mc-title{color:hsl(var(--on-band-dark))}
.machine-card--agents .mc-intro{color:hsl(var(--on-band-dark)/.75)}
.machine-card--agents .mc-points{list-style:none;padding:0;margin:0;display:grid;grid-template-columns:1fr 1fr;gap:.9rem 1.5rem}
.machine-card--agents .mc-points li{display:flex;gap:.6rem;font-size:.8125rem;line-height:1.55;color:hsl(var(--on-band-dark)/.82)}
.machine-card--agents .mc-points strong{color:hsl(var(--on-band-dark))}
.machine-card--agents .mc-points a{color:var(--green)}
.machine-card--agents .mc-term{background:#071512;border:1px solid hsl(0 0% 100%/.08);border-radius:12px;overflow:hidden;box-shadow:0 14px 40px -18px rgba(0,0,0,.6)}
.machine-card--agents .mc-term pre{margin:0;background:none;box-shadow:none;padding:1.25rem 1.4rem;font-size:.8125rem;line-height:1.7;color:#7fe7b4;white-space:pre-wrap}
.machine-card--agents .mc-term pre code{background:none;color:inherit}

.machine-card--audit{background:hsl(var(--card));border:1px solid var(--border);padding:2.75rem 3rem}
.machine-card--audit .mc-title{color:var(--dark)}
.machine-card--audit .mc-intro{color:var(--muted);margin-bottom:0}
.machine-card--audit .mc-audit{list-style:none;margin:1.75rem 0 0;padding:0;display:grid;grid-template-columns:1fr 1fr;gap:0 3rem}
.machine-card--audit .mc-audit li{display:flex;gap:.75rem;padding:1rem 0;border-top:1px solid var(--border);font-size:.875rem;line-height:1.6;color:var(--muted)}
.machine-card--audit .mc-audit strong{color:var(--dark)}

@media(max-width:900px){
  .machines-band{padding:0 1.25rem}
  .machine-card--agents{grid-template-columns:minmax(0,1fr);padding:2rem 1.5rem}
  .machine-card--audit{padding:2rem 1.5rem}
  .machine-card--audit .mc-audit{grid-template-columns:1fr}
  .machine-card--agents .mc-points{grid-template-columns:1fr}
}
.machines-title{font-size:clamp(1.5rem,2.6vw,2.25rem)!important;-webkit-text-stroke:0;letter-spacing:0}
.assure-status{font-size:.9375rem; max-width:64ch;margin:1.5rem auto 0;text-align:center}
/* Dark-band contrast repairs (2026-08-16 review): these elements inherit the deep
   green --dark ink while sitting ON a deep green band, which reads as empty boxes.
   Explicit paint, appended last so it wins the cascade. */
.matrix-head--new{color:#fff}
.pathway-name{color:#fff}
.pathways-section .pathway-card .pathway-go{color:#30ba78;opacity:1}
.pathways-section .pathway-card:hover .pathway-go{color:#fff}
.everywhere-section .section-more{color:#fff;text-decoration:underline;text-underline-offset:3px}
.platform-feature a{color:#fff;text-decoration:underline;text-underline-offset:2px}
.behind-links{margin-top:1.6rem;display:flex;align-items:center;justify-content:center;gap:.75rem;font-size:.875rem;font-weight:600}
.behind-dot{color:var(--muted);opacity:.5}

/* ── Block 9: the teaser a moved band leaves behind ─────────────────────────
   One line and one link. The reference content itself lives on its own page,
   with the layout that made it readable (formatsSection / importBand). */
.teaser-section{background:hsl(var(--background));padding:2.25rem 1.5rem;border-top:1px solid var(--border)}
.teaser-inner{max-width:46rem;margin:0 auto;text-align:center}
.teaser-line{font-size:1.05rem;line-height:1.7;color:var(--muted);margin:0 0 .6rem}

/* The two moved bands, rendering inside a docs article column rather than
   full-bleed on the landing: drop the band padding the column already supplies,
   and let the import band sit flush under the masthead as the page's opener. */
.docs-content .import-section{background:none;padding:0 0 2.5rem;margin-bottom:2.5rem;border-bottom:1px solid var(--border)}
.docs-content .import-section h2{border-top:none;padding-top:0;margin-top:0}
.docs-content .import-inner{max-width:none}
.docs-content .import-lede{margin-bottom:2rem}
.page-formats .formats-section{padding:2.5rem 0 0;border-top:none;background:none}
.page-formats .formats-inner{max-width:none}
.page-formats .formats-head{margin-bottom:1.25rem}

/* Formats - ONE three-zone table: import-only (left) · round-trip (centre) · export-only (right) */
.formats-section{background:hsl(var(--background));padding:5.5rem 2rem;border-top:1px solid var(--border)}
html[data-theme="dark"] .formats-section{background:hsl(var(--background));border-top-color:hsl(var(--border))}
.formats-inner{max-width:1340px;margin:0 auto}
.formats-head{margin-bottom:2rem}
.formats-head h2{color:var(--dark);font-size:2rem;margin:0 0 .6rem}
html[data-theme="dark"] .formats-head h2{color:hsl(var(--foreground))}
.formats-head p{color:var(--muted);font-size:1.05rem;line-height:1.65;margin:0;max-width:44rem}
.formats-hint{font-size:.9rem;margin-top:.7rem !important;color:var(--green) !important;font-weight:600}
.fmt-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
/* Grid with a FIXED centre and flexible sides: 'both' is an auto track (never wraps,
   sits at the true row centre); import / export are 1fr and wrap only when full. Given
   the wide .formats-inner below, that keeps most rows on one line while guaranteeing the
   round-trip set is never broken across lines. Hard start / centre / end aligned. */
.fmt-table{display:grid;grid-template-columns:[cat]minmax(3.5rem,auto)[in]1fr[both]auto[out]1fr;align-items:center;column-gap:1.25rem;row-gap:.55rem;min-width:660px;padding-bottom:.5rem}
.fmt-row{display:contents}
.fmt-cat{grid-column:cat;display:flex;flex-direction:column;align-items:flex-start;gap:.35rem}
.fmt-cat svg{width:27px;height:27px;color:var(--green);opacity:.9}
.fmt-cat-label{font-size:.64rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);white-space:nowrap}
.fmt-zone{display:flex;flex-wrap:wrap;gap:.4rem;align-content:center;min-width:0}
.fmt-zone--in{grid-column:in;justify-content:flex-start}
.fmt-zone--both{grid-column:both;justify-content:center}
.fmt-zone--out{grid-column:out;justify-content:flex-end}
.fmt-zonelabel{font-size:.6rem;font-weight:800;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);display:inline-flex;align-items:center;gap:.45em;white-space:nowrap}
.fmt-zonelabel .rt-mark{margin:0;color:var(--green)}
.fmt-zonelabel b{color:var(--green);background:rgba(48,186,120,.12);padding:.15em .5em;border-radius:1em;font-family:'SUSE Mono','SF Mono',monospace;font-size:.92em;font-weight:700}
.fmt-divider{grid-column:1/-1;height:0;border-bottom:2px solid var(--border);margin:.15rem 0 .35rem}
.fmt-rowsep{grid-column:1/-1;height:0;border-top:1px solid var(--border);margin:.15rem 0}
.fmt-chip{display:inline-flex;align-items:center;background:rgba(48,186,120,.1);color:#127a45;font-size:.74rem;font-family:'SUSE Mono','SF Mono',monospace;font-weight:700;padding:.3em .64em;border-radius:1em;letter-spacing:.03em;border:1px solid transparent;cursor:pointer;transition:transform .1s,box-shadow .12s,background .12s,color .12s;white-space:nowrap;-webkit-appearance:none;appearance:none}
.fmt-chip:hover{transform:translateY(-1px);box-shadow:0 3px 10px rgba(12,50,44,.16)}
.fmt-chip:focus-visible{outline:2px solid var(--green);outline-offset:2px}
.fmt-chip--both{background:var(--green);color:hsl(var(--on-band-dark))}
.fmt-chip .rt-mark{margin-right:.3em}
html[data-theme="dark"] .fmt-chip,html[data-theme="brand"] .fmt-chip{background:rgba(48,186,120,.16);color:#7fe7b4}
html[data-theme="dark"] .fmt-chip--both,html[data-theme="brand"] .fmt-chip--both{background:var(--green);color:#04140c}
/* Educational dialog */
.fmt-dialog{border:0;border-radius:18px;padding:0;width:min(94vw,38rem);max-height:88vh;overflow:auto;margin:auto;color:var(--dark);background:hsl(var(--popover));box-shadow:0 30px 80px rgba(12,50,44,.34)}
.fmt-dialog::backdrop{background:rgba(8,20,15,.5);backdrop-filter:blur(3px)}
html[data-theme="dark"] .fmt-dialog{background:hsl(var(--popover));color:hsl(var(--foreground))}
.fmt-dialog-inner{padding:1.75rem 1.75rem 1.6rem;position:relative}
.fmt-dialog-x{position:absolute;top:.7rem;right:.7rem;border:0;background:var(--pale);width:1.9rem;height:1.9rem;border-radius:50%;cursor:pointer;color:var(--muted);font-size:.82rem;line-height:1}
.fmt-dialog-x:hover{background:var(--border)}
.fmt-dialog-dir{display:inline-block;font-size:.62rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--green);background:rgba(48,186,120,.14);padding:.3em .7em;border-radius:1em;margin-bottom:.7rem}
.fmt-dialog h3{margin:0;color:inherit;font-size:1.55rem;line-height:1.1}
.fmt-dialog-head{display:flex;align-items:flex-start;gap:.9rem;padding-right:1.8rem}
.fmt-dialog-icon{flex:none;place-self:end;width:2.9rem;height:2.9rem;color:var(--green);margin-top:.1rem}
.fmt-dialog-icon svg{stroke-width:.5px;width:100%;height:100%;display:block}
.fmt-dialog-icon:empty{display:none}
.fmt-dialog-headtext{min-width:0}
.fmt-dialog-full{margin:.15rem 0 0;color:var(--muted);font-size:.9rem;font-weight:600}
.fmt-dialog-desc{margin:.9rem 0 0;color:inherit;font-size:.95rem;line-height:1.65;opacity:.92}
.fmt-dialog-specs{list-style:none;margin:1.1rem 0 0;padding:0;display:grid;grid-template-columns:1fr 1fr;gap:.45rem .9rem}
.fmt-dialog-specs:empty{margin:0}
.fmt-dialog-specs li{font-size:.82rem;line-height:1.3;color:inherit;display:flex;align-items:flex-start;gap:.45em;opacity:.95}
.fmt-dialog-specs li::before{content:'✓';color:var(--green);font-weight:800;flex:none;margin-top:.02em}
@media(max-width:520px){.fmt-dialog-specs{grid-template-columns:1fr}}
.fmt-dialog-feats{list-style:none;margin:1.15rem 0 0;padding:0;display:flex;flex-wrap:wrap;gap:.4rem}
.fmt-dialog-feats:empty{margin:0}
.fmt-dialog-feats li{font-size:.72rem;font-weight:700;color:inherit;background:var(--pale);border:1px solid var(--border);padding:.32em .68em;border-radius:1em;display:inline-flex;align-items:center;gap:.4em}
.fmt-dialog-feats li::before{content:'';width:.5em;height:.5em;border-radius:50%;background:var(--green);flex:none}
/* The format's metadata claims (plans/144 O1): what Lolly reads and writes in
   its own metadata containers, and what survives a round trip. Empty when a row
   carries no block, so the margin collapses with it. */
.fmt-dialog-meta{margin:1.1rem 0 0;font-size:.78rem;line-height:1.55;color:inherit;opacity:.8}
.fmt-dialog-meta:empty{margin:0}
.fmt-dialog-unsup{margin:1.2rem 0 0;padding:.85rem 1rem;border-radius:12px;background:rgba(254,124,63,.1)}
.fmt-dialog-unsup[hidden]{display:none}
.fmt-dialog-unsup-label{display:block;font-size:.62rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--orange);margin-bottom:.5rem}
.fmt-dialog-unsup-list{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:1fr 1fr;gap:.4rem .9rem}
.fmt-dialog-unsup-list li{font-size:.82rem;line-height:1.3;display:flex;align-items:flex-start;gap:.45em;opacity:.9}
.fmt-dialog-unsup-list li::before{content:'-';color:var(--orange);font-weight:800;flex:none}
@media(max-width:520px){.fmt-dialog-unsup-list{grid-template-columns:1fr}}
html[data-theme="dark"] .fmt-dialog-unsup{background:rgba(254,124,63,.13)}
@media(max-width:760px){
.formats-section{padding:4rem 1.25rem}
.fmt-table{min-width:0;display:block}
.fmt-row{display:block;padding:.6rem 0;border-bottom:1px solid var(--border)}
.fmt-row--head{display:none}
.fmt-divider,.fmt-rowsep{display:none}
.fmt-cat{flex-direction:row;align-items:center;gap:.5rem;margin-bottom:.5rem}
.fmt-cat svg{width:20px;height:20px}
.fmt-zone{justify-content:flex-start!important;margin:.2rem 0}
.fmt-zone:empty{display:none}
.fmt-zone:not(:empty)::before{flex-basis:100%;font-size:.56rem;font-weight:800;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin-bottom:.15rem}
.fmt-zone--in:not(:empty)::before{content:'Import only'}
.fmt-zone--both:not(:empty)::before{content:'⇄ Both ways'}
.fmt-zone--out:not(:empty)::before{content:'Export only'}
}

/* QoL pair - sound + bulk, side by side */
.qol-section{background:var(--pale);padding:3.25rem 2rem}
.qol-inner{max-width:2480px;margin:0 auto;display:grid;grid-template-columns:1fr 1fr 1fr 1fr 1fr;gap:1rem}
.qol-panel{background:hsl(var(--card));border:1px solid var(--border);border-radius:20px;padding:2rem  1rem;box-shadow:0 4px 20px rgba(12,50,44,.06);display:flex;flex-direction:column;gap:1.5rem}
.qol-panel h3{color:var(--dark);     font-size: 1rem;  margin: 1rem 0;    font-weight: 500;}
.qol-panel p{color:var(--muted);font-size:.8rem;line-height:1.5;margin:0}
.qol-panel p strong{color:var(--dark);font-weight:700}
@media(max-width:768px){.qol-inner{grid-template-columns:1fr;gap:1.25rem}.qol-section{padding:2.5rem 1.25rem}}

/* Assurance / provenance - the trust band */
.assure-section{background:linear-gradient(155deg,#061816 0%,#0c322c 55%,#0a3b30 100%);color:hsl(var(--on-band-dark));padding:4rem 2rem}
.assure-inner{max-width:1080px;margin:0 auto}
.assure-lede-row{display:flex;align-items:flex-start;justify-content:space-between;gap:2.5rem;margin-bottom:2.25rem}
.assure-lede{max-width:46rem}
/* The magpie fills the gutter right of the lede. The section is literally about Content
   Credentials, so a signed genAI animal here is the argument in the flesh - curiosity by
   design. Contained (in flow, not absolute), stacks under the copy on narrow screens. */
.assure-mascot{width:clamp(120px,25vw,300px);flex-shrink:0;filter:drop-shadow(0 14px 34px rgba(0,0,0,.45))}
@media(max-width:820px){.assure-lede-row{flex-direction:column}.assure-mascot{width:min(42vw,180px);align-self:flex-start}}
.assure-eyebrow{display:inline-block;font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.12em;color:var(--light);margin-bottom:1rem}
.assure-section h2{font-size:2.5rem;line-height:1.08;color:hsl(var(--on-band-dark));margin:0 0 1.25rem}
.assure-lead{font-size:1.12rem;line-height:1.75;color:hsl(var(--on-band-dark) / .72);margin:0}
.assure-lead strong{color:hsl(var(--on-band-dark));font-weight:700}
.assure-lead a{color:var(--light);text-decoration:underline;text-underline-offset:2px}
.assure-main{max-width:46rem;margin-bottom:2.25rem}
.assure-checks{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:1.5rem}
.assure-checks li{display:flex;gap:1rem;align-items:flex-start}
.assure-check-ic{width:1.7rem;height:1.7rem;flex-shrink:0;color:var(--green);margin-top:.05rem}
.assure-check-ic svg{width:100%;height:100%}
.assure-checks strong{display:block;color:hsl(var(--on-band-dark));font-size:1.05rem;font-weight:700;margin-bottom:.25rem}
.assure-checks li>div>span{color:hsl(var(--on-band-dark) / .6);font-size:.92rem;line-height:1.55;display:block}
/* auto-fit rather than a fixed 3: the "Made on your device" card retired into the
   sovereignty statement (plan 117 block 3), so this grid now carries two cards in
   English and three in the locales that still ship the old JSON. */
.assure-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1px;background:rgba(0,0,0,.35);border:1px solid rgba(255,255,255,.08);border-radius:14px;overflow:hidden;margin-bottom:2.25rem}
.assure-card{background:rgba(255,255,255,.03);padding:1.9rem 1.6rem;transition:background .15s}
.assure-card:hover{background:rgba(255,255,255,.06)}
.assure-card-ic{display:block;width:1.7rem;height:1.7rem;color:var(--light);margin-bottom:.85rem}
.assure-card-ic svg{width:100%;height:100%}
.assure-card strong{display:block;color:hsl(var(--on-band-dark));font-size:1rem;margin-bottom:.45rem}
.assure-card p{color:hsl(var(--on-band-dark) / .55);font-size:.88rem;line-height:1.6;margin:0}
.assure-cta a{color:var(--green);font-weight:700;text-decoration:none;font-size:1.02rem}
.assure-cta a:hover{text-decoration:underline}
/* Hand-off to the docs. The section above makes claims; these are where the
   reasoning and the caveats actually live, so they read as a quiet index rather
   than five more marketing cards - small caps label, hairline separators, no fill
   until you hover. */
.assure-docs{margin-top:1.75rem;padding-top:1.5rem;border-top:1px solid rgba(255,255,255,.1)}
.assure-docs-label{display:block;font-size:.6875rem;text-transform:uppercase;letter-spacing:.12em;
  font-weight:700;color:hsl(var(--on-band-dark) / .45);margin-bottom:1.1rem}
.assure-docs-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:.5rem}
.assure-doc{display:block;padding:.9rem 1rem;border-radius:12px;border:1px solid transparent;
  text-decoration:none;transition:background .15s,border-color .15s}
.assure-doc:hover{background:rgba(255,255,255,.045);border-color:hsl(var(--on-band-dark) / .12);text-decoration:none}
.assure-doc-ic{display:block;width:1.15rem;height:1.15rem;color:var(--green);margin-bottom:.55rem}
.assure-doc-ic svg{width:100%;height:100%}
.assure-doc strong{display:block;color:hsl(var(--on-band-dark));font-size:.9375rem;margin-bottom:.3rem}
.assure-doc-desc{display:block;color:hsl(var(--on-band-dark) / .55);font-size:.8125rem;line-height:1.5}
@media(max-width:768px){.assure-section{padding:3rem 1.25rem}.assure-section h2{font-size:1.95rem}.assure-grid{grid-template-columns:1fr}}
[data-theme="dark"] .qol-section{background:hsl(var(--background))}
[data-theme="dark"] .qol-panel{background:rgba(255,255,255,.035);border-color:hsl(var(--on-band-dark) / .1);box-shadow:none}
[data-theme="dark"] .qol-panel h3,[data-theme="dark"] .qol-panel p strong{color:hsl(var(--on-band-dark))}
[data-theme="dark"] .qol-panel p{color:hsl(var(--on-band-dark) / .6)}

/* Everywhere section */
.everywhere-section{padding:3.25rem 2rem;background:hsl(var(--band-dark));color:hsl(var(--on-band-dark))}
.everywhere-inner{display:flex;flex-direction:column;gap:1.5rem;max-width:1400px;margin:0 auto;text-align:start}
/* Mascot beside the TITLE only (per the brief), bigger than before; copy + chips run full
   width on their own lines below. */
.everywhere-head{display:flex;align-items:center;justify-content:space-between;gap:2.5rem}
.everywhere-head h2{margin:0;flex:1 1 auto}
.everywhere-mascot{width:clamp(240px,26vw,420px);flex-shrink:0}
.everywhere-section h2{color:hsl(var(--on-band-dark))}
.everywhere-copy{font-size:1.125rem;line-height:1.75;color:hsl(var(--on-band-dark) / .65);margin:0 0 1rem}
.everywhere-chips{display:flex;flex-wrap:wrap;justify-content:flex-start;gap:1rem}
@media(max-width:768px){.everywhere-head{flex-direction:column;align-items:flex-start;gap:1.25rem}.everywhere-mascot{width:min(82vw,440px)}}
.everywhere-chip{display:inline-flex;flex-direction:column;align-items:center;gap:.625rem;padding:1.25rem 1.75rem;background:rgba(255,255,255,.05);border-radius:14px;color:hsl(var(--on-band-dark));font-size:.95rem;font-weight:700;min-width:7rem;transition:background .2s}
.everywhere-chip:hover{background:rgba(255,255,255,.09)}
.everywhere-chip svg{width:2rem;height:2rem;color:var(--green);flex-shrink:0}
.everywhere-chip span{letter-spacing:.02em}
.everywhere-models{max-width:1400px;margin:4rem auto 0}
.everywhere-models-intro{text-align:center;color:hsl(var(--on-band-dark));font-size:1rem;margin:0 0 2rem}
.everywhere-models-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem}
.everywhere-model{position:relative;display:flex;align-items:stretch;gap:1.5rem;padding:3.5rem 1.75rem 2rem;background:rgba(255,255,255,.05);border-radius:18px;transition:background .2s,border-color .2s}
.everywhere-model:hover{background:rgba(255,255,255,.08);border-color:hsl(var(--on-band-dark) / .16)}
.everywhere-model-main{flex:0 0 2em;min-width:0}
.everywhere-model-num{position:absolute;top:-1rem;left:50%;transform:translateX(-50%);ox-shadow: inset 0 0 0 .25px #0002, inset 0 1px 1.5px #fff9, 0 .2rem .4rem #0002;
    text-shadow: 0 1px .5px #fff2;width:fit-content;font-size:.75rem;font-weight:800;text-transform:uppercase;letter-spacing:.08em;color:var(--dark);background:rgba(48,186,120,1.14);padding:.32rem .7rem;border-radius:999px;margin:0}
.everywhere-model-icon{width:2.25rem;height:2.25rem;color:var(--green);display:block;margin-bottom:.9rem}
.everywhere-model h3{color:var(--green);font-size:1.2rem;margin:0;}
.everywhere-model p{flex:1;min-width:0;font-size:.95rem;line-height:1.65;color:hsl(var(--on-band-dark) / .6);margin:0;padding-left:1.5rem}
@media(max-width:768px){.everywhere-models-grid{grid-template-columns:1fr;gap:2rem}.everywhere-models{margin-top:2.5rem}}

/* What's a tool */
.whats-a-tool{padding:3rem 3.5rem;background:var(--border)}
.whats-inner{max-width:var(--col-cap);margin-right:auto;margin-left:0}
.whats-a-tool .whats-inner>h2{color:var(--dark);font-size:2rem;margin-bottom:.625rem;text-align:center}
.tool-lead{max-width:100%;margin:0 0 2rem;font-size:1.0625rem;line-height:1.8;color:var(--muted);text-align:center}
.tool-anatomy{display:flex;flex-wrap:wrap;gap:.75rem;max-width:100%;margin:0 0 2rem;justify-content:center;align-items:center}
.tool-part{background:hsl(var(--card));border:1px solid var(--border);border-radius:12px;padding:1rem 1.25rem;text-align:center;flex:1;min-width:110px;box-shadow:0 2px 8px rgba(12,50,44,.07);transition:box-shadow .15s}
.tool-part:hover{box-shadow:0 4px 16px rgba(12,50,44,.12)}
.tool-part-file{font-family:'SUSE Mono','SF Mono',monospace;font-size:.75rem;background:hsl(var(--muted));color:var(--dark);padding:.2em .55em;border-radius:4px;display:inline-block;margin-bottom:.5rem;font-weight:600}
.tool-part-name{font-weight:700;color:var(--dark);font-size:.8125rem;margin-bottom:.2rem}
.tool-part-desc{font-size:.73rem;color:var(--muted);line-height:1.45}
.tool-plus{font-size:1.5rem;color:var(--border);font-weight:300;flex-shrink:0;align-self:center}
.tool-features{display:grid;grid-template-columns:repeat(2,1fr);gap:.75rem;margin-bottom:1.75rem}
.tool-feature{background-color:hsl(var(--on-band-dark) / .14);border:1px solid var(--border);border-radius:12px;padding:1.25rem 1.375rem;display:flex;flex-direction:column;gap:.35rem;transition:box-shadow .15s}
.tool-feature:hover{box-shadow:0 4px 16px rgba(12,50,44,.1)}
.tool-feature-icon{width:1.375rem;height:1.375rem;color:var(--green);margin-bottom:.25rem;flex-shrink:0}
.tool-feature-icon svg{width:100%;height:100%}
.tool-feature strong{font-size:.9rem;color:var(--dark);font-weight:700;line-height:1.25}
.tool-feature p{font-size:.8rem;color:var(--muted);line-height:1.55;margin:0}
/* Floats at the bottom seam where the two columns meet (relative to .platform-whats-wrap). */
.try-now-callout{position:absolute;left:50%;bottom:0;transform:translate(-50%,50%);z-index:10;width:min(92%,640px);background:#01564a;border-radius:14px;padding:1.5rem 1.75rem;display:flex;align-items:center;gap:1.5rem;flex-wrap:wrap;box-shadow: 0 10px 30px rgba(0,0,0,.2), inset 0 .06rem .1rem #fff2}
.try-now-text{flex:1;min-width:0}
.try-now-text strong{        color: hsl(var(--on-band-dark));font-size:.9375rem;display:block;margin-bottom:.35rem;font-weight:700}
.try-now-text p{color:hsl(var(--on-band-dark));font-size:.85rem;line-height:1.6;margin:0}

/* Design import segment ("bring your existing files") */
.import-section{background:linear-gradient(180deg,#fff 0%,var(--pale) 100%);padding:7rem 2rem 5rem}
.import-inner{max-width:1080px;margin:0 auto}
.import-lede{display:flex;align-items:center;justify-content:center;gap:2.5rem;max-width:64rem;margin:0 auto 3rem;text-align:start}
.import-lede-text{max-width:46rem}
.import-mascot{width:clamp(180px,22vw,340px);flex-shrink:0}
@media(max-width:820px){.import-lede{flex-direction:column;text-align:center}}
.import-eyebrow{display:inline-block;font-size:.6875rem;text-transform:uppercase;letter-spacing:.14em;font-weight:700;color:var(--green);background:rgba(48,186,120,.1);padding:.4em .9em;border-radius:2em;margin-bottom:1.25rem}
.import-section h2{color:var(--dark);margin-bottom:1.25rem}
.import-lead{font-size:1.0625rem;line-height:1.8;color:var(--muted);margin:0}
.import-lead strong{color:var(--dark);font-weight:700}
.import-sources{display:grid;grid-template-columns:repeat(5,1fr);gap:1rem;margin-bottom:1.75rem}
.import-source{display:flex;flex-direction:column;align-items:center;text-align:center;gap:.5rem;background:hsl(var(--card));border:0;    box-shadow: 0 .3rem 1rem #00000016;border-radius:14px;padding:1.5rem 1rem;transition:box-shadow .15s,transform .15s}
.import-source:hover{box-shadow:0 8px 24px rgba(12,50,44,.1);transform:translateY(-2px)}
.import-badge{display:inline-flex;align-items:center;box-shadow:inset 0 0 0 1px #0002, inset 0 1.25px 2px #fff9,  0 .2rem .4rem #0002;justify-content:center;width:2.75rem;height:2.75rem;border-radius:12px;background:var(--b,#30ba78);color:hsl(var(--on-band-dark));font-weight:800;font-size:.9rem}
.import-source strong{color:var(--dark);font-size:.95rem;font-weight:700}
.import-fmt{font-family:'SUSE Mono','SF Mono',monospace;font-size:.72rem;color:var(--muted);letter-spacing:.02em}
.import-flow{display:flex;align-items:stretch;gap:.5rem;margin-bottom:2.75rem}
.import-step{flex:1;min-width:0;background:var(--border);border:1px solid var(--border);border-radius:14px;padding:1.5rem 1.25rem;text-align:center}
.import-step-icon{width:1.75rem;height:1.75rem;color:var(--muted); margin:0 auto .75rem}
.import-step-icon svg{width:100%;height:100%; stroke-width:1.5px}
.import-step strong{display:block;color:var(--dark);font-size:.9rem;margin-bottom:.35rem}
.import-step p{font-size:.8rem;color:var(--muted);line-height:1.55;margin:0}
.import-arrow{align-self:center;color:var(--green);flex-shrink:0;font-size:1.4rem;font-weight:300;line-height:1}
.import-points{display:grid;grid-template-columns:repeat(3,1fr);gap:1.25rem;margin-bottom:2.5rem}
.import-point{background:hsl(var(--card));border:1px solid var(--border);border-radius:14px;padding:1.75rem 1.5rem}
.import-point-icon{width:2rem;height:2rem;color:var(--green);margin-bottom:.9rem}
.import-point-icon svg{width:100%;height:100%}
.import-point strong{display:block;color:var(--dark);font-size:1rem;margin-bottom:.5rem}
.import-point p{font-size:.875rem;color:var(--muted);line-height:1.65;margin:0}
.import-cta-row{text-align:center}
.import-more{display:inline-flex;align-items:center;gap:.4rem;font-weight:700;color:var(--green);font-size:.95rem}
.import-more:hover{text-decoration:none;color:var(--dark)}
@media(max-width:820px){
  .import-sources{grid-template-columns:repeat(2,1fr)}
  .import-points{grid-template-columns:1fr}
  .import-flow{flex-direction:column}
  .import-arrow{transform:rotate(90deg)}
}
@media(max-width:480px){
  .import-section{padding:4.5rem 1.25rem 3.5rem}
}
/* A landing mascot wrapped with its Content Credential. The mascot's sizing class
   (.about-mascot / .audience-mascot / .everywhere-mascot: width, flex-shrink, drop-shadow)
   rides on THIS span, so it stays the flex child it was; the img just fills it, and the
   corner credential positions against it. NOT .asset-cred (that is width:100%, for the
   full-column docs hero). */
.mascot-cred{position:relative;display:block;flex-shrink:0}
.mascot-cred>img{display:block;width:100%;height:auto;margin:0}
/* Keep a landing mascot's credit INSIDE its box (the brief), unlike a screenshot's
   caption which deliberately overhangs the artwork edge. Clamp the line to the mascot's
   own width and let the pills WRAP into a compact stack rather than run off the side. The
   glyph stays bottom-anchored; the expanded line grows upward within the box. */
.mascot-cred .shot-cred{max-width:calc(100% - 1rem)}
.mascot-cred .shot-cred-line{max-width:100%}
.mascot-cred .shot-cred-row{flex-wrap:wrap}
/* Narrow columns stack the line and its glyph (the docs stylesheet's max-width:640px
   rule). Keep the glyph at the BOTTOM and stack the collapsed line above it - the
   line keeps its height while hidden, and with the glyph on top it was pushed clear
   off a small floated mascot into whatever sat above. */
@media(max-width:640px){.mascot-cred .shot-cred{flex-direction:column-reverse}}
.audience-header{display:flex;align-items:center;justify-content:center;gap:2rem;padding:2.75rem 3rem 1.5rem}
.audience-header-text{text-align:start}
.audience-mascot{width:clamp(200px,26vw,430px);flex-shrink:0;filter:drop-shadow(0 6px 20px rgba(12,50,44,.18))}
@media(max-width:900px){.audience-mascot{width:clamp(160px,22vw,280px)}}
@media(max-width:600px){.audience-header{flex-direction:column;gap:1rem;padding:2rem 1.25rem 1rem}.audience-header-text{text-align:center}.audience-mascot{width:clamp(140px,44vw,220px)}}
.hero-founded{margin-top:2rem; max-width:15em;}
/* About section */
.about-section{padding:3.25rem 1.5rem;background:hsl(var(--band-dark));color:hsl(var(--on-band-dark))}
.about-inner{max-width:960px;margin:0 auto}
.about-header{display:flex;align-items:center;gap:3rem;margin-bottom:2.25rem}
.about-header-text{flex:1;min-width:0}
.about-mascot{width:clamp(200px,26vw,360px);flex-shrink:0;filter:drop-shadow(0 16px 40px rgba(0,0,0,.5))}
/* A second, smaller animal opposite the koala - the About section IS the "adorable
   Australian animals" section, so a companion here is on-theme, not clutter. */
.about-mascot-2{width:clamp(120px,15vw,190px);flex-shrink:0;filter:drop-shadow(0 12px 30px rgba(0,0,0,.45))}
.about-section h2{color:hsl(var(--on-band-dark));margin-bottom:1rem}
.about-section h3{font-size:.75rem;font-weight:800;color:hsl(var(--on-band-dark) / .5);text-transform:uppercase;letter-spacing:.16em;margin:2rem 0 1rem;text-align:center}
.about-lead{font-size:1.0625rem;color:hsl(var(--on-band-dark) / .7);line-height:1.85;margin:0}
.about-items{display:grid;grid-template-columns:1fr 1fr;gap:1.25rem}
.about-item{background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:2rem 1.75rem;display:flex;flex-direction:row;align-items:flex-start;gap:1.125rem}
.about-item-icon{width:3.25rem;height:3.25rem;flex-shrink:0;color:var(--green)}
.about-item-icon svg{width:100%;height:100%}
.about-item p{color:hsl(var(--on-band-dark) / .6);line-height:1.8;font-size:.9375rem;margin:0}
.about-item strong{color:hsl(var(--on-band-dark));font-weight:700}
/* FAQ */
.faq-section{padding:3.25rem 2rem;background:hsl(var(--background))}
.faq-inner{margin:0 auto; max-width: calc(var(--col-cap) * 1.4);}
.faq-section h1,.faq-section h2{text-align:center;margin-bottom:.5rem}
.faq-lead{text-align:center;color:var(--muted);font-size:1.0625rem;margin-bottom:1.75rem}
.faq-list{display:flex;flex-direction:column;gap:.75rem}
.faq-item{border:1px solid var(--border);border-radius:12px;background:var(--pale);overflow:hidden;transition:box-shadow .15s,border-color .15s}
.faq-item[open]{box-shadow:0 6px 20px rgba(12,50,44,.12)}
.faq-q{display:flex;align-items:center;justify-content:space-between;gap:1.25rem;padding:1.25rem 1.5rem;font-weight:700;color:var(--dark);font-size:1.0625rem;line-height:1.4;cursor:pointer;list-style:none}
.faq-q::-webkit-details-marker{display:none}
.faq-q:hover{color:var(--green)}
.faq-chevron{flex-shrink:0;width:1.25rem;height:1.25rem;color:var(--green);transition:transform .2s}
.faq-chevron svg{width:100%;height:100%}
.faq-item[open] .faq-chevron{transform:rotate(180deg)}
.faq-a{padding:0 1.5rem 1.4rem;color:var(--muted);line-height:1.75}
.faq-a p{margin-bottom:.75rem}
.faq-a p:last-child{margin-bottom:0}
/* Screenshots inside an FAQ answer. faq.md is the one .md that renders into the
   LANDING accordion rather than an /info/*.html docs page, so it never picks up
   the .docs-content img rules above - and a shot baseline carries an intrinsic
   width="1440", which without this would render at full size and push the whole
   landing page sideways. Same framing as the docs-page treatment, capped to the
   answer column. */
.faq-a img{max-width:100%;height:auto;display:block;margin:.9rem 0 0;border-radius:10px}
.faq-a img[src*="/info/shots/"]{border:1px solid hsl(var(--border));box-shadow:0 6px 24px #0002}
@media(max-width:800px){
  .about-header{flex-direction:column;text-align:center;gap:1.75rem}
  .about-mascot{width:clamp(160px,44vw,260px)}
  .about-items{grid-template-columns:1fr}
}
/* Hero entrance */
@keyframes heroUp{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}
.hero-heading{animation:heroUp .7s ease both .22s}
.hero .subtitle{animation:heroUp .65s ease both .38s}
.hero-cta{animation:heroUp .65s ease both .52s}
.hero-trust{animation:heroUp .65s ease both .65s}
.hero-inner{display:flex;align-items:center;gap:4rem;max-width:1400px;margin:0 auto;width:100%}
.hero-heading{margin-bottom:1.5rem;position:relative}
.hero h1{margin-bottom:0;text-align:start;letter-spacing:0;font-weight:100}
.hero-details{flex:1 1 0;min-width:0;text-align:start}
/* Tablet: the H1 steps down so the longest claim ("sovereignty", "inclusive") fits
   the column whole instead of hyphenating; the <=600px block below re-sizes it
   again for the stacked layout. */
@media(max-width:1000px){.hero .hero-statement{font-size:clamp(2rem,6vw,4rem)}}
/* min-width:0 is load-bearing: a flex item's default minimum is its min-content
   width, and the cycling H1 word (.cycle-word is width:max-content) made that the
   unwrapped width of whichever claim was showing - so at tablet widths the column
   grew past the viewport on "available offline", the CTAs and download tiles
   reflowed on every swap, and the rail was cut off at the edge (Andy, 2026-09-02).
   With the minimum released the column is the space that is left, and the word
   wraps inside it. */
.hero .subtitle{margin-left:.5rem;max-width:none}
.hero-cta{justify-content:flex-start}
.hero-trust{justify-content:flex-start}
@media(max-width:600px){.hero-inner{flex-direction:column;text-align:center}.hero-heading{flex-direction:column;gap:1rem;align-items:center}.hero h1{text-align:center;font-size:clamp(2rem,10vw,4rem)}.hero-details{text-align:center}.hero-cta{justify-content:center}.hero-trust{justify-content:center}}
/* Scroll reveal */
/* 300ms, both widths (plans/168 WP-3). The old .55s desktop fade ran longer than the
   scroll that triggered it, so a band was still arriving as the reader passed it. */
.reveal{opacity:0;transform:translateY(22px);transition:opacity .3s ease,transform .3s ease}
.reveal.visible{opacity:1;transform:none}
.reveal-1{transition-delay:.05s}
.reveal-2{transition-delay:.15s}
.reveal-3{transition-delay:.25s}
.reveal-4{transition-delay:.35s}
.reveal-5{transition-delay:.45s}
.reveal-6{transition-delay:.55s}
/* Mobile: drop the stagger too - one column means the "cards arriving in sequence"
   the delays paint reads as lag rather than choreography. */
@media(max-width:768px){
  .reveal-1,.reveal-2,.reveal-3,.reveal-4,.reveal-5,.reveal-6{transition-delay:0s}
}
@media(prefers-reduced-motion:reduce){
  .hero h1,.hero .subtitle,.hero-cta,.hero-trust{animation:none}
  .reveal,.reveal.visible{opacity:1;transform:none;transition:none}
}
[data-theme="dark"] .audience-section{border-bottom-color:var(--border)}
[data-theme="dark"] .audience-header{background:linear-gradient(180deg,#0a1f16 0%,#061816 100%)}
[data-theme="dark"] .audience-title{color:var(--text)}
[data-theme="dark"] .audience-tabs{background:hsl(var(--background));border-bottom-color:var(--border)}
[data-theme="dark"] .audience-tab{background:hsl(var(--card))}
[data-theme="dark"] .audience-tab:hover{color:var(--green);background:hsl(var(--card))}
[data-theme="dark"] .card-tagline{color:var(--text)}
[data-theme="dark"] .card-intro{color:var(--muted)}
[data-theme="dark"] .faq-section{background:hsl(var(--background))}
[data-theme="dark"] .faq-section h1,[data-theme="dark"] .faq-section h2{color:var(--text)}
[data-theme="dark"] .faq-item{background:hsl(var(--muted))}
[data-theme="dark"] .faq-q{color:var(--text)}
[data-theme="dark"] .card-benefits strong{color:var(--text)}
[data-theme="dark"] .tool-part{background:hsl(var(--card))}
[data-theme="dark"] .tool-part-file{background:hsl(var(--muted))}
[data-theme="dark"] .tool-part-name{color:var(--text)}
[data-theme="dark"] .whats-a-tool .whats-inner>h2{color:var(--text)}
[data-theme="dark"] .tool-feature{background:hsl(var(--card))}
[data-theme="dark"] .tool-feature strong{color:var(--text)}
[data-theme="dark"] .import-section{background:linear-gradient(180deg,#061816 0%,var(--pale) 100%)}
[data-theme="dark"] .import-section h2{color:var(--text)}
[data-theme="dark"] .import-source,[data-theme="dark"] .import-step{background:hsl(var(--card))}
[data-theme="dark"] .import-point{background:hsl(var(--card))}
[data-theme="dark"] .import-source strong,[data-theme="dark"] .import-step strong,[data-theme="dark"] .import-point strong{color:var(--text)}
/* ── Why we built Lolly + old-way vs Lolly-way matrix ─────────────────────── */
.why-section{padding:3rem 1.5rem;background:var(--lolly-coin-glow)}
.why-inner{max-width:1080px;margin:0 auto}
.why-lede{display:flex;align-items:center;justify-content:center;gap:2.5rem;max-width:62rem;margin:0 auto 1.75rem;text-align:start}
.why-lede-text{max-width:44rem}
.why-mascot{width:clamp(180px,22vw,340px);flex-shrink:0}
@media(max-width:820px){.why-lede{flex-direction:column;text-align:center}}
.why-eyebrow{display:inline-block;font-size:.75rem;font-weight:800;text-transform:uppercase;letter-spacing:.14em;color:var(--green);margin-bottom:.75rem}
.why-section h2{font-size:clamp(1.8rem,4vw,2.5rem);color:var(--dark);line-height:1.12;margin-bottom:1rem}
.why-lead{color:var(--muted);font-size:1.0625rem;line-height:1.7}
.why-frustrations{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem;margin-bottom:1.75rem}
.why-frustration{background:hsl(var(--card));border:0; box-shadow: inset 0 1px #fff1, 0 .2em .5em #0002;border-radius:14px;padding:1.5rem 1.375rem;text-align:center}
.why-frustration-ic{display:inline-flex;width:2.75rem;height:2.75rem;align-items:center;justify-content:center;border-radius:50%;background:rgba(254,124,63,.12);color:var(--orange);margin-bottom:.75rem}
.why-frustration-ic svg{width:1.4rem;height:1.4rem}
.why-frustration strong{display:block;color:var(--dark);margin-bottom:.35rem;font-size:1.0625rem}
.why-frustration p{color:var(--muted);font-size:.9rem;line-height:1.55}
.matrix{display:grid;grid-template-columns:1fr 1fr;gap:.75rem;align-items:stretch}
.matrix-head{font-weight:800;text-transform:uppercase;letter-spacing:.08em;font-size:.8rem;padding:.85rem 1.1rem;border-radius:10px;text-align:center}
/* One step up from var(--muted) (plans/168 WP-6): the old-way column is meant to read
   dimmer than the Lolly-way column, but "dim by design" had been taken past comfortable
   reading. An alpha on the page's own ink keeps the rhetoric - still visibly quieter
   than .matrix-cell--new's full var(--text) - in both themes with one value. */
.matrix-head--old{background:rgba(90,112,103,.14);color:hsl(var(--foreground) / .74)}
.matrix-head--new{background:var(--green);color:#fff}
.matrix-cell{display:flex;gap:.7rem;align-items:flex-start;padding:1rem 1.15rem;border-radius:12px;font-size:.95rem;line-height:1.5}
.matrix-cell--old{background:hsl(var(--card) / .7);border:0;color:hsl(var(--foreground) / .74)}
.matrix-cell--new{background:rgba(48,186,120,.08);color:var(--text);box-shadow:0 2px 12px rgba(48,186,120,.12)}
.matrix-mark{flex-shrink:0;width:1.35rem;height:1.35rem;display:inline-flex;align-items:center;justify-content:center;border-radius:50%;font-size:.78rem;font-weight:800;margin-top:.05rem}
.matrix-cell--old .matrix-mark{background:hsl(var(--card) / 1 );color:var(--muted)}
.matrix-cell--new .matrix-mark{        background: hsl(var(--accent-foreground) / .1);    color: var(--accent-foreground);}
@media(max-width:720px){.why-frustrations{grid-template-columns:1fr}.matrix{grid-template-columns:1fr;gap:.5rem}.matrix-head{display:none}.matrix-cell--old{margin-top:.5rem}}
/* Dark-theme surfaces for the pale Why section. */
[data-theme="dark"] .why-section{background:hsl(var(--background))}
[data-theme="dark"] .why-section h2{color:var(--text)}
[data-theme="dark"] .why-frustration{background:hsl(var(--card))}
[data-theme="dark"] .why-frustration strong{color:var(--text)}
[data-theme="dark"] .matrix-cell--old{background:hsl(var(--card))}
[data-theme="dark"] .matrix-cell--new{background:hsl(var(--card))}

/* ═══ plans/177: the five-beat door ═══════════════════════════════════════════
   New bands: the hero cycle, the covers carousel, what/why, the persona device.
   Colours come only from the token set (--green, --text, --band-dark, …), which
   the static /info page pins to the Lolly green and the in-app reader resolves
   from the ACTIVE DESIGN SYSTEM's brand vars - Andy's 2026-09-02 directive: the
   #/docs landing inherits the brand fully; /info stays green. */

/* ── beat 1: the cycling H1 ─────────────────────────────────────────────── */
.hero-statement--cycle{display:block}
.hero-statement--cycle .cycle-lead{display:block;font-weight:900}
.hero-statement--cycle .cycle-word{display:block;max-width:100%;color:var(--brand-primary);text-decoration:none;font-weight:500;overflow-wrap:break-word;line-height:1.15}
.hero .hero-statement--cycle .cycle-word:hover{text-decoration:none}
.hero-statement--cycle .cycle-word span{display:block;overflow-wrap:break-word;hyphens:auto;text-transform:none; font-style:italic;transition: transform .24s ease,opacity .24s ease}
/* block, not inline-block: an inline-block is an atomic box whose content never
   breaks with the parent's overflow-wrap, so "SOVEREIGNTY" ran past a tablet-width
   column. A block span wraps inside the anchor's max-width and still transforms. */
.hero-statement--cycle .cycle-word.is-swapping span{transform:translateY(.5em);opacity:0}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
@media (prefers-reduced-motion: reduce){.hero-statement--cycle .cycle-word span{transition:none}}

/* ── beat 2: the covers ─────────────────────────────────────────────────────
   Base form is a scroll-snap FILMSTRIP: native swipe and drag on touch, wheel
   and scrollbar elsewhere, and fully working with scripts stripped (the in-app
   reader). COVERS_JS upgrades it to the 3-D fan at every width and adds pointer
   drag, dots, arrows and the slow autoplay. */
/* No background of its own: the band sits inside .hero-wrap, which paints the
   surface, and the chip field lies between that surface and this content
   (position + z-index lift the covers above the canvas, as .hero does). */
.covers-section{position:relative;z-index:1;color:hsl(var(--on-band-dark));padding:2.5rem 1.5rem 2rem;overflow:hidden}
.covers-inner{max-width:1180px;margin:0 auto}
/* The fan is full-bleed (Andy, 2026-09-03: "the full width of the viewport, not
   cropped"): the filmstrip keeps the 1180px reading column, but once the 3-D fan
   is on, the strip runs edge to edge so the tucked covers reach the viewport's
   sides instead of being cut at a column that has nothing to do with them. The
   section's overflow:hidden still clips at the viewport, never the page. */
.covers-section.covers--fan{padding-left:0;padding-right:0}
.covers--fan .covers-inner{max-width:none}
.covers{outline:none;border-radius:10px}
/* Keyboard ring only: a focus the fan took for itself after a pointer drag is marked data-focus-by=pointer (lib/covers-flow.ts). */
.covers:focus-visible:not([data-focus-by="pointer"]){outline:2px solid hsl(var(--primary));outline-offset:6px}
/* The strip is a scroll box, so it clips its own overflow: the card shadow reaches
   ~52px below the card (0 24px 48px -20px) and was cut at the strip's bottom edge as a
   hard line. Pad past the shadow and pull the flow back with a negative margin, so
   the nav below sits where it did. Both strip forms (filmstrip, fan) carry it. */
.covers-strip{display:flex;gap:14px;overflow-x:auto;scroll-snap-type:x mandatory;padding:1rem 2px 4rem;margin-bottom:-2.75rem;-webkit-overflow-scrolling:touch}
.cover-card{position:relative;flex:0 0 min(520px,82vw);aspect-ratio:4/3;scroll-snap-align:center;border-radius:12px;overflow:hidden;background-color:transparent;box-shadow:0 24px 48px -20px rgba(0,0,0,.55);text-decoration:none;color:inherit}
.cover-card img,.cover-card video{width:100%;height:100%;object-fit:cover;object-position:left top;display:block}
.cover-cap{position:absolute;left:0;right:0;bottom:0;display:flex;flex-direction:column;gap:2px;padding:1.6rem .85rem .65rem;background:linear-gradient(transparent,rgba(0,0,0,.72));color:#fff}
.cover-cap b{font-size:.95rem;font-weight:700}
.cover-cap i{font-style:normal;font-size:.78rem;opacity:.85}
/* fan mode (script-applied, from 720px): the app gallery's Cover Flow - a real
   horizontal scroller whose covers are transformed per frame from scroll
   position by lib/covers-flow.ts, which OWNS the horizontal axis (drag, flick,
   wheel spin, settle). Native scroll-snap is off here on purpose: a snap area
   is the transformed box, so native snap chased the tuck and fought the settle.
   touch-action pan-y leaves vertical to the page. */
.covers--fan .covers-strip{gap:0;overflow:hidden;perspective:1500px;perspective-origin:50% 45%;padding:2.25rem calc(50% - min(520px,58vw)/2) 4rem;margin-bottom:-2.75rem;scroll-snap-type:none;scroll-behavior:auto;touch-action:pan-y;overscroll-behavior-x:contain;scrollbar-width:none}
.covers--fan .covers-strip::-webkit-scrollbar{display:none}
.covers--fan .cover-card{flex:0 0 min(520px,58vw);width:min(520px,58vw);will-change:transform;backface-visibility:hidden;pointer-events:none;user-select:none;-webkit-user-select:none}
/* Phones run the fan too (Andy, 2026-09-03). A 58vw card is a thumbnail at 390px, so
   under 720px the centred cover takes 78vw and the strip's centring pad follows; the
   tuck still shows the neighbours' edges either side. */
@media(max-width:719px){
  .covers--fan .covers-strip{padding-left:calc(50% - 39vw);padding-right:calc(50% - 39vw)}
  .covers--fan .cover-card{flex-basis:78vw;width:78vw}
}
/* The loop's clones (lib/covers-flow.ts): pixel copies of the edge covers so the
   fan never shows an end. The filmstrip is finite and hides them. */
.covers-section:not(.covers--fan) .cover-card.is-clone{display:none}
/* Fingers: a lighter shadow. The 48px blur under sixteen 3-D layers is what an
   iPad drops frames on, and at arm's length the difference is invisible. */
@media (pointer:coarse){
  .covers--fan .cover-card{box-shadow:0 12px 24px -14px rgba(0,0,0,.5)}
  .covers--fan .cover-card.is-cur{box-shadow:0 18px 36px -18px rgba(0,0,0,.6),0 0 0 1px hsl(var(--primary) / .4) inset}
}
.covers--fan .covers-strip{cursor:grab}
.cover-card img,.cover-card video{user-select:none;-webkit-user-select:none;-webkit-user-drag:none;pointer-events:none}
.covers--fan .cover-card .cover-cap{opacity:0;transition:opacity .3s ease}
.covers--fan .cover-card.is-cur .cover-cap{opacity:1}
.covers--fan .cover-card.is-cur{box-shadow:0 34px 70px -24px rgba(0,0,0,.7),0 0 0 1px hsl(var(--primary) / .4) inset}
.covers--dragging .covers-strip{cursor:grabbing}
/* The one Open button: OUTSIDE the fan's 3D context (a z-translated cover is
   not hit-testable - the app's featured-go precedent), floating over the
   centred cover and appearing once it has rested there for a moment. */
.covers{position:relative}
/* In flow BELOW the cards (Andy, 2026-09-02: over the card it sat on the
   caption), between the strip and the dots; it reserves its row so the fan
   never jumps when it fades in. Fan-only - the filmstrip cards are their own
   links. */
.covers-open-btn{display:none;width:max-content;margin:.4rem auto 0;opacity:0;transform:translateY(6px);transition:opacity .25s ease,transform .25s ease;pointer-events:none;background:hsl(var(--primary));color:hsl(var(--primary-foreground,0 0% 100%));border-radius:999px;padding:.55rem 1.1rem;font-weight:700;font-size:.875rem;white-space:nowrap;box-shadow:0 10px 28px rgba(0,0,0,.35);text-decoration:none}
.covers--fan .covers-open-btn{display:flex;align-items:center;gap:.35em}
.covers-open-btn.is-on{opacity:1;transform:none;pointer-events:auto; position:relative; z-index:9}
.covers-open-btn:hover{text-decoration:none;filter:brightness(1.07)}
@media (prefers-reduced-motion: reduce){.covers-open-btn{transition:none}}
.covers-nav{display:flex;align-items:center;justify-content:center;gap:14px;margin-top:.5rem}
.covers-btn{width:36px;height:36px;border-radius:50%;border:1px solid hsl(var(--on-band-dark) / .3);background:transparent;color:hsl(var(--on-band-dark));cursor:pointer;font-size:1.1rem;line-height:1}
.covers-btn:hover{border-color:hsl(var(--primary))}
.covers-dots{display:flex;gap:6px}
.covers-dot{width:8px;height:8px;border-radius:50%;background:hsl(var(--on-band-dark) / .3);border:0;padding:0;cursor:pointer;transition:all .2s ease}
.covers-dot[aria-current="true"]{background:hsl(var(--primary));width:22px;border-radius:4px}
@media (prefers-reduced-motion: reduce){.covers--fan .cover-card{transition:none}}

/* ── beat 3: what / why ─────────────────────────────────────────────────── */
.whatwhy-section{padding:4rem 1.5rem 2.5rem}
.whatwhy-inner{max-width:1120px;margin:0 auto;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr));gap:2.5rem 3.5rem}
.whatwhy-eyebrow{font-size:.6875rem;text-transform:uppercase;letter-spacing:.12em;color:color-mix(in oklab,hsl(var(--primary)) 70%,var(--text));font-weight:700}
.whatwhy-big{font-size:1.6rem;letter-spacing:0;text-transform:none;font-weight:800;margin:.5rem 0 .75rem;text-wrap:balance}
.whatwhy-body{color:var(--muted);max-width:52ch;margin:0 0 1rem}
.whatwhy-maxim{margin:0 0 1rem;max-width:52ch}
.whatwhy-stats{display:flex;gap:1.6rem;flex-wrap:wrap;margin:.5rem 0 1rem;  }
.whatwhy-stat{display:flex;flex-direction:column;gap:2px;text-decoration:none;color:inherit; text-align:center;}
.whatwhy-stat b{font-family:'SUSE Mono','SF Mono',monospace;font-size:1.7rem;font-weight:600;line-height:1;font-variant-numeric:tabular-nums;color:color-mix(in oklab,hsl(var(--primary)) 70%,var(--text));}
.whatwhy-stat span{font-size:.6875rem;color:var(--muted);letter-spacing:.06em;text-transform:uppercase}
.whatwhy-stat:hover b{color:color-mix(in oklab,hsl(var(--primary)) 70%,var(--text))}
.whatwhy-receipts{font-size:.875rem;margin-bottom:1rem}
.whatwhy-receipts a{color:var(--muted);text-decoration:underline}
.whatwhy-receipts a:hover{color:var(--green)}
.whatwhy-more{font-weight:700;color:color-mix(in oklab,hsl(var(--primary)) 70%,var(--text));text-decoration:none}
.whatwhy-more:hover{text-decoration:underline}

/* ── beat 4: the persona device (CSS-only: radios + nth-matched pairing) ── */
.persona-section{padding:1.5rem 1.5rem 4rem}
.persona-inner{max-width:1120px;margin:0 auto;position:relative}
.persona-title{margin-bottom:1.25rem;text-align:center; color:color-mix(in oklab,var(--green) 30%,var(--page)) }
.persona-radio,.lane-radio{position:absolute;opacity:0;pointer-events:none;width:1px;height:1px}
.persona-tabs{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
.persona-tab{display:flex;flex-direction:column;gap:4px;padding:1rem 1.15rem;border:1px solid var(--border);border-radius:12px;background:var(--page);cursor:pointer;position:relative;transition:border-color .2s ease,transform .2s ease;padding-right:4.4rem}
.persona-mascot{position:absolute;right:.7rem;top:50%;transform:translateY(-50%);width:8.5em;height:8.5em;object-fit:contain;pointer-events:none}
/* The platypus is a wide animal: in the 8.5em square it read as a smudge (Andy, 2026-09-03: 12em). */
.persona-mascot[src$="platypus.webp"]{width:12em;height:12em; margin-top:-1.5em}
.persona-tab:hover{border-color:var(--muted);transform:translateY(-2px)}
.persona-name{font-family:'SUSE Mono',monospace;font-weight:600;font-size:1.1rem}
.persona-sub{font-size:.8125rem;color:var(--muted)}
#door-creators:checked ~ .persona-tabs label[for="door-creators"],
#door-builders:checked ~ .persona-tabs label[for="door-builders"],
#door-operators:checked ~ .persona-tabs label[for="door-operators"]{border-color:var(--green);background:color-mix(in oklab,var(--green) 30%,var(--page))}
.persona-tabs img{transition: all .5s ease; filter:drop-shadow( 0 1px 14px color-mix(in oklab,var(--green) 86%,var(--page)))}
#door-creators:not(:checked) ~ .persona-tabs label[for="door-creators"] img,
#door-builders:not(:checked) ~ .persona-tabs label[for="door-builders"] img,
#door-operators:not(:checked) ~ .persona-tabs label[for="door-operators"] img{filter:grayscale(.6) brightness(1.3) contrast(1.16) ; opacity:.2; transition: all .5s ease; transform:scale(.8) translate(2em, -5em)}
#door-creators:checked ~ .persona-tabs label[for="door-creators"] .persona-sub,
#door-builders:checked ~ .persona-tabs label[for="door-builders"] .persona-sub,
#door-operators:checked ~ .persona-tabs label[for="door-operators"] .persona-sub{color:var(--text)}
#door-creators:focus-visible ~ .persona-tabs label[for="door-creators"],
#door-builders:focus-visible ~ .persona-tabs label[for="door-builders"],
#door-operators:focus-visible ~ .persona-tabs label[for="door-operators"]{outline:2px solid var(--green);outline-offset:3px}
.persona-pane{display:none;margin-top:1.5rem;padding:1.5rem;border:1px solid var(--green);border-radius:12px;background:var(--page);position:relative}
#door-creators:checked ~ .persona-panes .persona-pane:nth-child(1),
#door-builders:checked ~ .persona-panes .persona-pane:nth-child(2),
#door-operators:checked ~ .persona-panes .persona-pane:nth-child(3){display:block}
.lane-cols{display:grid;grid-template-columns:200px minmax(0,1fr);gap:.5rem 1.8rem;align-items:start}
.lane-tabs{display:flex;flex-direction:column;gap:2px}
.lane-tab{text-align:start;padding:.65rem .85rem;border-inline-start:2px solid var(--border);cursor:pointer;font-size:.9rem;font-weight:600;color:var(--muted);transition:color .15s ease,border-color .15s ease,background .15s ease}
.lane-tab:hover{color:var(--text)}
/* A lane's mascot (persona.json `mascot`) sits figure-sized beside the copy at
   the inline end - the import band's kookaburra treatment, not a tab glyph. It
   comes FIRST in the markup so the phone rule below can float it and wrap the
   copy around it; `order` moves it to the end of the desktop flex row. Wide art
   (the eagle) and tall art (the possum) share one width, so their heights differ
   and the row centres either against the copy. */
.lane-pane{display:none;min-height:150px;gap:1rem 2rem;align-items:center}
.lane-copy{flex:1 1 auto;min-width:0}
.lane-mascot{width:clamp(150px,22vw,240px);flex-shrink:0;order:1}
/* The eagle is a wingspan: at the shared width it is a third the height of the
   others and reads as an ornament, so it gets a third more room. */
.lane-mascot[data-shot$="wedge-tailed-eagle.webp"]{width:clamp(200px,28vw,320px)}
/* The whale is wider than it is tall, so the lane column has to be wider too. */
.lane-mascot[data-shot$="whale.webp"]{width:clamp(260px,34vw,400px)}
/* The lorikeet stands tall on its stick, so it hangs 5em below the pane instead
   of stretching the row (Andy, 2026-09-03). */
.lane-mascot[data-shot$="lorikeet.webp"]{margin-bottom:-5em}
.lane-mascot[data-shot$="pelican.webp"]{margin:-4em 0}
.lane-mascot[data-shot$="bin-chicken.webp"]{margin-bottom:-3.6em}
.lane-pane h3{font-family:'SUSE Mono',monospace;font-size:1.05rem;font-weight:600;text-transform:none;letter-spacing:.02em;margin-bottom:.4rem}
.lane-pitch{color:var(--muted);max-width:56ch;margin:0 0 .9rem;font-size:.95rem}
.lane-links{list-style:none;margin:0 0 1rem;padding:0;display:flex;flex-direction:column;gap:6px;max-width:520px}
.lane-links a{display:flex;justify-content:space-between;gap:10px;text-decoration:none;padding:.6rem .75rem;border-radius:var(--radius);background:color-mix(in oklab,var(--green) 20%,var(--page));border:1px solid var(--border);font-size:.875rem;color:var(--text)}
.lane-links a:hover{border-color:var(--green);text-decoration:none}
.lane-links code{font-family:'SUSE Mono',monospace;font-size:.75rem;color:var(--muted);background:none;padding:0}
.lane-cta{display:flex;gap:1rem;align-items:center;flex-wrap:wrap}
/* Self-contained button styling: the lane CTAs must not depend on the
   landing's own .hero-btn below or the app chrome's .btn
   (whose light-theme pairing painted them blank - Andy, 2026-09-02). The
   brand token PAIR (--primary + --primary-foreground) keeps the label
   legible whatever design system is loaded. */
.lane-cta .hero-btn{display:inline-flex;align-items:center;gap:.4em;background:hsl(var(--primary));color:hsl(var(--primary-foreground,0 0% 100%));border:1px solid transparent;border-radius:999px;padding:.55rem 1.1rem;font-size:.875rem;font-weight:700;text-decoration:none;backdrop-filter:none;-webkit-backdrop-filter:none;mix-blend-mode:normal;box-shadow:none}
.lane-cta .hero-btn:hover{background:hsl(var(--primary));filter:brightness(1.07);text-decoration:none;transform:none;box-shadow:none}
.btn-compact{padding:.55rem 1.1rem;font-size:.875rem}
/* The app's arrow on the Launch App pill, mirrored for right-to-left. */
.hero-btn svg{flex:none;width:1em;height:1em}
[dir="rtl"] .hero-btn svg{transform:scaleX(-1)}
.lane-doc{font-weight:700;color:color-mix(in oklab,hsl(var(--primary)) 70%,var(--text));text-decoration:none;font-size:.875rem}
.lane-doc:hover{text-decoration:underline}
/* nth-matched lane pairing, up to the six operator lanes */
.lane-radio:nth-of-type(1):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(1),
.lane-radio:nth-of-type(2):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(2),
.lane-radio:nth-of-type(3):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(3),
.lane-radio:nth-of-type(4):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(4),
.lane-radio:nth-of-type(5):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(5),
.lane-radio:nth-of-type(6):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(6){display:flex}
.lane-radio:nth-of-type(1):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(1),
.lane-radio:nth-of-type(2):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(2),
.lane-radio:nth-of-type(3):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(3),
.lane-radio:nth-of-type(4):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(4),
.lane-radio:nth-of-type(5):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(5),
.lane-radio:nth-of-type(6):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(6){color:var(--text);border-inline-start-color:var(--green);background:hsl(var(--primary) / .08)}
.lane-radio:nth-of-type(1):focus-visible ~ .lane-cols .lane-tabs .lane-tab:nth-child(1),
.lane-radio:nth-of-type(2):focus-visible ~ .lane-cols .lane-tabs .lane-tab:nth-child(2),
.lane-radio:nth-of-type(3):focus-visible ~ .lane-cols .lane-tabs .lane-tab:nth-child(3),
.lane-radio:nth-of-type(4):focus-visible ~ .lane-cols .lane-tabs .lane-tab:nth-child(4),
.lane-radio:nth-of-type(5):focus-visible ~ .lane-cols .lane-tabs .lane-tab:nth-child(5),
.lane-radio:nth-of-type(6):focus-visible ~ .lane-cols .lane-tabs .lane-tab:nth-child(6){outline:2px solid var(--green);outline-offset:2px}
@media (max-width:719px){
  .persona-tabs{grid-template-columns:1fr}
  .lane-cols{grid-template-columns:1fr}
  .lane-tabs{flex-direction:row;overflow-x:auto;padding-bottom:4px}
  .lane-tab{border-inline-start:0;border-bottom:2px solid var(--border);white-space:nowrap}
  .lane-radio:nth-of-type(1):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(1),
  .lane-radio:nth-of-type(2):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(2),
  .lane-radio:nth-of-type(3):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(3),
  .lane-radio:nth-of-type(4):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(4),
  .lane-radio:nth-of-type(5):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(5),
  .lane-radio:nth-of-type(6):checked ~ .lane-cols .lane-tabs .lane-tab:nth-child(6){border-inline-start:0;border-bottom-color:var(--green)}
  /* Phones: the active pane goes back to flow, so the mascot floats at the
     inline end with the heading and first lines beside it, and the copy takes
     the full width once past it. */
  .lane-radio:nth-of-type(1):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(1),
  .lane-radio:nth-of-type(2):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(2),
  .lane-radio:nth-of-type(3):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(3),
  .lane-radio:nth-of-type(4):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(4),
  .lane-radio:nth-of-type(5):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(5),
  .lane-radio:nth-of-type(6):checked ~ .lane-cols .lane-panes .lane-pane:nth-child(6){display:block}
  .lane-mascot{float:inline-end;width:6.5rem;margin-inline-start:1rem;margin-block-end:.5rem}
  .lane-mascot[data-shot$="wedge-tailed-eagle.webp"]{width:9.5rem}
  .lane-mascot[data-shot$="whale.webp"]{width:12rem}
  /* The float already clears the copy past the bird here; the desktop hangs (the
     lorikeet's, pelican's and ibis's negative margins above) would run a tail over the
     first link row or pull the bird out of the pane. Same specificity as those rules,
     later in the file, so every lane mascot sits in flow on a phone. */
  .lane-mascot[data-shot]{margin:0;margin-inline-start:1rem;margin-block-end:.5rem}
}

/* ── beat 4b: the lolly.work band ───────────────────────────────────────── */
.work-section{padding:0 1.5rem 3.5rem}
.work-inner{max-width:1120px;margin:0 auto;padding:1.5rem 1.6rem;border:1px solid var(--border);border-radius:14px;background:color-mix(in oklab,var(--green) 36%,var(--page))}
.work-eyebrow{display:block;font-family:'SUSE Mono',monospace;font-size:.75rem;letter-spacing:.08em;color:color-mix(in oklab,hsl(var(--primary)) 70%,var(--text));margin-bottom:.35rem}
.work-cols{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:1rem 2rem;align-items:center}
.work-heading{font-size:1.25rem;font-weight:800;text-transform:none;letter-spacing:0;margin:0 0 .4rem;text-wrap:balance}
.work-body{margin:0;color:var(--band-primary);max-width:62ch;font-size:.95rem}
.work-links{display:flex;flex-direction:column;gap:.6rem;align-items:flex-start}
.work-links .hero-btn{display:inline-flex;align-items:center;gap:.4em;background:hsl(var(--primary));color:hsl(var(--primary-foreground,0 0% 100%));border:1px solid transparent;border-radius:999px;padding:.55rem 1.1rem;font-size:.875rem;font-weight:700;text-decoration:none;white-space:nowrap;backdrop-filter:none;-webkit-backdrop-filter:none;mix-blend-mode:normal}
.work-links .hero-btn:hover{filter:brightness(1.07);text-decoration:none;transform:none;box-shadow:none}
.work-link{font-weight:700;font-size:.875rem;color:color-mix(in oklab,hsl(var(--primary)) 70%,var(--text));text-decoration:none;white-space:nowrap}
.work-link:hover{text-decoration:underline}
@media(max-width:719px){.work-cols{grid-template-columns:minmax(0,1fr)}.work-links{flex-direction:row;flex-wrap:wrap}.work-links .hero-btn,.work-link{white-space:normal}.work-heading{overflow-wrap:break-word;hyphens:auto}}

/* ── beat 5: behind, additions ──────────────────────────────────────────── */
.behind-quiet{margin:1rem 0 0;font-size:.8125rem;color:var(--muted);text-align:center}

/* ── faq as its own page ────────────────────────────────────────────────── */
.faq-page{padding-top:1rem}

/* Tenets share this stylesheet in the app reader and the static info site. */
.tn-band{position:relative;isolation:isolate;overflow:hidden;container-type:inline-size;padding:clamp(3rem,7vw,6rem) clamp(1.25rem,5vw,4rem);background:var(--page);color:var(--text);font-family:var(--font-brand,sans-serif)}
.tn-band--dark{background:hsl(var(--band-dark));color:hsl(var(--on-band-dark))}
.tn-inner{position:relative;z-index:1;width:100%;max-width:1120px;margin:0 auto}
.tn-band .tn-label{display:flex;align-items:center;gap:.8rem;font-family:inherit;font-size:.8125rem;font-weight:700;line-height:1.3;letter-spacing:.16em;text-transform:uppercase;color:var(--green);margin:0 0 2.5rem;padding:0;border:0}
.tn-label::before{content:'';display:block;width:1.6rem;height:2px;background:currentColor}
.tn-band--dark .tn-label{color:hsl(var(--band-accent))}
.tn-hero{padding-block:clamp(3rem,7vw,6rem);background:radial-gradient(ellipse at 100% 90%,hsl(var(--band-accent)/.16),transparent 65%),hsl(var(--band-dark))}
.tn-hero-grid{display:grid;grid-template-columns:minmax(0,1.22fr) minmax(0,1fr);gap:clamp(2rem,4vw,3.5rem);align-items:center}
.tn-hero .tn-label{margin-bottom:1.25rem}
.tn-band .tn-vision{font-family:inherit;font-size:clamp(2.375rem,6cqi,4.375rem);font-weight:750;line-height:1.06;letter-spacing:0;text-transform:none;text-wrap:balance;margin:0;color:hsl(var(--on-band-dark));border:0;padding:0}
.tn-vision-end{display:block}
.tn-gloss{font-size:clamp(1.0625rem,1.9cqi,1.35rem);line-height:1.55;color:hsl(var(--on-band-dark)/.8);margin:1.75rem 0 0;max-width:40ch;text-wrap:pretty}
.tn-gloss strong{display:block;font-weight:650;color:hsl(var(--on-band-dark));margin-bottom:.5rem}
/* Native radios keep the medium switch usable without scripts on either surface. */
.tn-samples{min-width:0;width:100%;margin:0;padding:0;border:0;position:relative}
.tn-sample-radio{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
.tn-sample-tabs{display:flex;justify-content:center;gap:1.5rem;margin-bottom:1rem}
.tn-sample-tabs label{display:flex;align-items:center;min-height:2.75rem;padding:.35rem .2rem;border-bottom:2px solid transparent;cursor:pointer;font-size:.8125rem;font-weight:600;color:hsl(var(--on-band-dark)/.65)}
.tn-sample-tabs label:hover{color:hsl(var(--on-band-dark))}
#tenet-print:checked ~ .tn-sample-tabs label[for="tenet-print"],#tenet-screen:checked ~ .tn-sample-tabs label[for="tenet-screen"],#tenet-motion:checked ~ .tn-sample-tabs label[for="tenet-motion"],#tenet-vector:checked ~ .tn-sample-tabs label[for="tenet-vector"]{color:hsl(var(--on-band-dark));border-color:hsl(var(--band-accent))}
#tenet-print:focus-visible ~ .tn-sample-tabs label[for="tenet-print"],#tenet-screen:focus-visible ~ .tn-sample-tabs label[for="tenet-screen"],#tenet-motion:focus-visible ~ .tn-sample-tabs label[for="tenet-motion"],#tenet-vector:focus-visible ~ .tn-sample-tabs label[for="tenet-vector"]{outline:2px solid hsl(var(--band-accent));outline-offset:4px}
.tn-sample-panel{display:none;margin:0;padding:0}
#tenet-print:checked ~ .tn-sample-panels .tn-sample--print,#tenet-screen:checked ~ .tn-sample-panels .tn-sample--screen,#tenet-motion:checked ~ .tn-sample-panels .tn-sample--motion,#tenet-vector:checked ~ .tn-sample-panels .tn-sample--vector{display:block}
.tn-sample-stage{height:clamp(13rem,28cqi,21rem);display:flex;align-items:center;justify-content:center}
.tn-sample-stage img,.tn-sample-stage video{display:block;max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain}
.tn-sample--print img{box-shadow:0 8px 25px #0003}
.tn-sample-actions{display:flex;align-items:center;justify-content:flex-end;gap:.5rem;margin-top:1.25rem;font-size:.75rem;line-height:1.3}
.tn-sample-actions a{display:inline-flex;align-items:center;justify-content:center;gap:.45rem;min-height:2.75rem;padding:.4rem .6rem;color:hsl(var(--on-band-dark)/.8);text-decoration:none;border-radius:.35rem}
.tn-sample-actions a:first-child{margin-inline-end:auto;text-decoration:underline;text-underline-offset:4px}
.tn-sample-actions a:hover{color:hsl(var(--on-band-dark));background:hsl(var(--on-band-dark)/.06)}
.tn-sample-actions a:focus-visible{outline:2px solid hsl(var(--band-accent));outline-offset:2px}
.tn-sample-actions svg{width:1.2rem;height:1.2rem;flex:none}
/* Signed Design-tool exports; the badge opens verification of the original file. */
.tn-art-credentials{position:absolute;inset-block-end:-1.75rem;inset-inline-end:0;z-index:2;display:flex;align-items:center;gap:.35rem;font-size:.6875rem;line-height:1.3;pointer-events:auto}
.tn-art-credentials a{display:inline-flex;align-items:center;gap:.4rem;min-height:2rem;padding:.4rem .6rem;border-radius:999px;background:hsl(var(--band-dark));color:hsl(var(--on-band-dark)/.8);border:1px solid hsl(var(--on-band-dark)/.2);text-decoration:none}
.tn-art-credentials a:hover{color:hsl(var(--on-band-dark));border-color:hsl(var(--on-band-dark)/.65)}
.tn-art-credentials a:focus-visible{outline:2px solid hsl(var(--band-accent));outline-offset:3px}
.tn-art-credentials svg{width:1.1rem;height:1.1rem;flex:none}
.tn-values .md-cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0;margin:0}
.tn-values .md-col{min-width:0;padding:0 2rem;border-inline-start:1px solid var(--border)}
.tn-values .md-col:first-child{padding-inline-start:0;border:0}
.tn-values .md-col:last-child{padding-inline-end:0}
.tn-col-icon{position:relative;display:flex;width:5.5rem;height:5.5rem;align-items:center;justify-content:center;background:hsl(var(--primary)/.08);color:var(--green);margin:0 0 2rem;border-radius:50%}
.tn-col-icon::after{content:'';position:absolute;inset:7px;border:1px solid hsl(var(--primary)/.22);border-radius:inherit}
.tn-values .md-col:nth-child(2) .tn-col-icon{border-radius:20%}
.tn-values .md-col:nth-child(3) .tn-col-icon{border-radius:50% 50% 18% 18%}
.tn-col-icon svg{width:2.25rem;height:2.25rem}
.tn-values .md-col h3{font-family:inherit;font-size:clamp(1.8rem,3.3cqi,2.75rem);font-weight:750;letter-spacing:0;line-height:1.1;margin:0 0 1rem;color:var(--text)}
.tn-values .md-col p{font-size:1.125rem;line-height:1.5;margin:0;max-width:25ch;color:var(--muted);text-wrap:pretty}
.tn-mission{padding-block:clamp(3.5rem,7vw,5.5rem);border-top:2px solid hsl(var(--band-accent))}
.tn-mission .tn-prose>.tn-label,.tn-mission-line,.tn-mission .tn-prose>p{position:relative;z-index:1}
.tn-band .tn-mission-line{font-family:inherit;font-size:clamp(2.5rem,6cqi,5rem);font-weight:650;line-height:1.06;letter-spacing:0;text-transform:none;text-wrap:balance;margin:0;max-width:18ch;color:hsl(var(--on-band-dark))}
.tn-mission .tn-prose>p{font-size:clamp(1.0625rem,2cqi,1.4rem);line-height:1.5;margin:2rem 0 0;max-width:38ch;color:hsl(var(--on-band-dark)/.8);text-wrap:pretty}
.tn-art--infinity{position:absolute;inset:0;pointer-events:none}
.tn-art--infinity>img{position:absolute;width:42%;max-width:26rem;height:auto;right:-2%;top:0;opacity:.16;transform:rotate(-24deg)}
.tn-art--infinity .tn-art-credentials{inset-block-end:-2rem;inset-inline-end:0}
/* A quiet closing statement, set in the same brand face as the other tenets. */
.tn-mantra{padding-block:clamp(2.5rem,5vw,4rem);border-bottom:1px solid var(--border);background:linear-gradient(135deg,hsl(var(--primary)/.07),transparent 70%),var(--page)}
.tn-mantra .tn-inner{display:grid;grid-template-columns:1fr 3fr;gap:2rem;align-items:baseline}
.tn-mantra .tn-label{margin:0}
.tn-mantra blockquote{font-family:inherit;font-style:normal;font-size:clamp(2rem,4.5cqi,3.75rem);font-weight:450;line-height:1.15;letter-spacing:0;text-wrap:balance;color:var(--text);max-width:22ch;margin:0;padding:0;border:0;border-radius:0;background:none;box-shadow:none;transform:none}
.tn-mantra blockquote p{font:inherit;margin:0;color:inherit}
.tn-mantra blockquote strong{font-weight:750;color:var(--green)}
.tn-mission .tn-prose>.tn-author{font-size:.8125rem;line-height:1.4;margin:2.5rem 0 0}
.tn-author a{display:inline-flex;align-items:center;gap:.6rem;min-height:2.75rem;color:hsl(var(--on-band-dark)/.7);text-decoration:none}
.tn-author a:hover{color:hsl(var(--on-band-dark))}
.tn-author svg{width:1.1rem;height:1.1rem}
@container (max-width:720px){
  .tn-mantra .tn-inner{grid-template-columns:1fr;gap:1.5rem}
  .tn-hero-grid{grid-template-columns:1fr;gap:2rem}
  .tn-band .tn-vision{font-size:clamp(2.125rem,10cqi,4rem)}
  .tn-samples{max-width:28rem;justify-self:center}
  .tn-sample-stage{height:14rem}
  .tn-sample-tabs{margin-bottom:.75rem}
  .tn-sample-actions{margin-top:.75rem}
  .tn-values .md-cols{grid-template-columns:1fr;gap:2rem}
  .tn-values .md-col{position:relative;padding:2rem 0 0 6rem;border-inline-start:0;border-top:1px solid var(--border)}
  .tn-values .md-col:first-child{padding:0 0 0 6rem}
  .tn-col-icon{position:absolute;inset-inline-start:0;width:4.5rem;height:4.5rem;margin:0}
  .tn-values .md-col h3{font-size:2rem;margin-bottom:.65rem}
  .tn-values .md-col p{max-width:32ch}
  .tn-art--infinity>img{width:65%;right:-15%;top:20%;opacity:.1}
}
@media (max-width:420px){
  .tn-values .md-col,.tn-values .md-col:first-child{padding-inline-start:4.5rem}
  .tn-col-icon{width:3.25rem;height:3.25rem}
  .tn-col-icon svg{width:1.6rem;height:1.6rem}
}


/* Docs layout */
.docs-wrap{display:grid;grid-template-columns:220px 1fr;max-width:1180px;margin:0 auto;min-height:calc(100vh - 3.5rem - 60px)}
.docs-sidebar{padding:2rem 1.25rem;border-right:1px solid var(--border);position:sticky;top:var(--site-bar-h);height:calc(100vh - var(--site-bar-h));overflow-y:auto}
/* Format / convert side-door pages (plan 116 workstream A). */
.sidedoor-eyebrow{display:flex;align-items:center;gap:.5rem;font-size:.75rem;text-transform:uppercase;letter-spacing:.1em;font-weight:700;color:var(--green);margin-bottom:.75rem}
.sidedoor-eyebrow svg{width:1.25rem;height:1.25rem}
.sidedoor .sidedoor-full{color:var(--muted);font-size:1.0625rem;margin:-1rem 0 1.25rem}
.sidedoor-dir{font-weight:600;margin:0 0 1rem}
.sidedoor-lead{font-size:1.0625rem;line-height:1.7;margin-bottom:1.5rem}
.sidedoor-contrast{color:var(--muted);font-size:.9375rem;line-height:1.65;border-inline-start:3px solid var(--green);padding-inline-start:.85rem;margin:0 0 1.5rem}
.sidedoor-promise{list-style:none;padding:0;display:flex;flex-wrap:wrap;gap:.5rem .75rem;margin:0 0 1.5rem}
.sidedoor-promise li{display:inline-flex;align-items:center;gap:.4em;background:hsl(var(--card));border:1px solid var(--border);border-radius:999px;padding:.3rem .85rem;font-size:.875rem;font-weight:600}
.sidedoor-promise li::before{content:"✓";color:var(--green);font-weight:700}
.sidedoor-cta{display:inline-flex;align-items:center;gap:.4em;background:var(--green);color:#fff;text-decoration:none;font-weight:700;padding:.7rem 1.4rem;border-radius:.6rem;margin-bottom:.5rem}
.sidedoor-cta:hover{filter:brightness(1.05)}
.sidedoor-convert-cols{display:flex;flex-wrap:wrap;align-items:stretch;gap:1rem;margin:0 0 1.5rem}
.sidedoor-col{flex:1 1 15rem;background:hsl(var(--card));border:1px solid var(--border);border-radius:.75rem;padding:1rem 1.15rem}
.sidedoor-col-label{display:block;font-size:.6875rem;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:700;margin-bottom:.35rem}
.sidedoor-col strong{display:block;font-size:1.35rem;margin-bottom:.5rem}
.sidedoor-col p{margin:0;font-size:.9375rem;color:var(--muted);line-height:1.6}
.sidedoor-convert-arrow{align-self:center;color:var(--green);font-size:1.6rem;font-weight:700}
.sidedoor-detail{margin-top:2rem;padding-top:1.5rem;border-top:1px solid var(--border)}
.sidedoor-feats{list-style:none;padding:0;display:flex;flex-wrap:wrap;gap:.5rem;margin:0 0 1rem}
.sidedoor-feats li{background:hsl(var(--card));border:1px solid var(--border);border-radius:.5rem;padding:.3rem .75rem;font-size:.8125rem}
.sidedoor-carry{color:var(--muted);margin:.5rem 0;line-height:1.6}
.sidedoor-prov{font-weight:600;margin:.5rem 0}
.sidedoor-offline{color:var(--muted);margin:.25rem 0 0}
.sidedoor-foot{margin-top:2.5rem;padding-top:1.5rem;border-top:1px solid var(--border)}
.sidedoor-foot-why{margin:0 0 .5rem}
.sidedoor-foot-links{display:flex;flex-wrap:wrap;gap:.5rem 1.5rem}
.sidedoor-foot-link{font-weight:700;text-decoration:none;color:var(--green)}
.sidedoor-foot-link:hover{text-decoration:underline}
/* The rail has three tiers and they have to be told apart at a glance: the
   PATHWAY is a name (17px, bold, full ink, on a rule), a GROUP LABEL is an
   eyebrow over a run of links (11px, uppercase, tracked, muted, one weight step
   lighter so it never competes with the name), and a LINK is the thing you click
   (14px, regular). The pathway used to be 15px against 14px links, which is not
   a tier, and the eyebrow shared the name's 700. See buildSidebar for the other
   half of this: a first group whose label only repeats the pathway is dropped. */
.sidebar-label{font-size:.6875rem;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:600;margin:2rem 0 .5rem}
.sidebar-label:first-child{margin-top:0}
.sidebar-home{display:block;font-size:.8125rem;color:var(--muted)!important;margin-bottom:1rem;padding:0!important}
.sidebar-home:hover{color:var(--green)!important;background:none!important}
/* Docs search - in the TOPBAR, not the rail. It sits with the other whole-site
   controls (language, theme, launch) because it acts on the whole site: the rail
   answers "what is there", the box answers "where is the thing I already know I
   want", and that second question does not belong inside the first question's list.
   It is also where readers look for it.

   Logical properties throughout so the Arabic build mirrors without a second rule
   set. The field is the app's own search field (gallery.css .gallery-search: its
   padding, type size, canvas fill, hairline and focus colour, and its magnifier),
   as tall as every other control in the bar. Below 1000px it folds into a round
   button that opens it over the bar (the site bar block above, DOCS_SEARCH_SCRIPT). */
.docs-search{position:relative;flex:none;display:flex;align-items:center}
.docs-search-icon{position:absolute;inset-inline-start:11px;top:50%;transform:translateY(-50%);display:flex;color:var(--ui-color-text-muted);pointer-events:none}
.docs-search-icon svg{width:var(--fs-xl);height:var(--fs-xl)}
.docs-search-input{inline-size:15rem;box-sizing:border-box;min-height:var(--chrome-h);padding:8px 34px;font:inherit;font-size:var(--fs-md);
  color:var(--ui-color-text-default);background:var(--ui-color-surface-canvas);border:1px solid var(--ui-color-border-default);border-radius:var(--radius);
  outline:none;transition:border-color var(--ui-motion-feedback)}
.docs-search-input::placeholder{color:var(--ui-color-text-muted);opacity:1}
.docs-search-input:focus{border-color:var(--ui-color-focus-ring)}
/* The app restores a 2px ring on its own field for keyboard readers (a11y.css:
   the tinted 1px border alone is too faint), and so does this one. */
.docs-search-input:focus-visible{outline:2px solid var(--ui-color-focus-ring);outline-offset:2px}
/* The app's clear control (gallery.css .gallery-search-clear) in place of the
   browser's own glyph. Below 1000px, with the field open over the bar, it stays
   visible and closes the field when there is nothing to clear. */
.docs-search-input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none;display:none}
.docs-search-clear{position:absolute;inset-inline-end:6px;top:50%;transform:translateY(-50%);width:calc(24px * var(--a11y-fs));height:calc(24px * var(--a11y-fs));display:inline-flex;align-items:center;justify-content:center;padding:0;border:0;border-radius:var(--radius-round);background:transparent;color:var(--ui-color-text-muted);font:inherit;font-size:var(--fs-md);line-height:1;cursor:pointer;transition:background var(--ui-motion-feedback),color var(--ui-motion-feedback)}
.docs-search-clear[hidden]{display:none}
.docs-search-clear:hover{background:var(--ui-color-surface-muted);color:var(--ui-color-text-default)}
.docs-search-clear:focus-visible{outline:2px solid var(--ui-color-focus-ring);outline-offset:1px}
/* FIXED, not absolute, so the panel is never clipped by the bar and can be wider
   than the field it hangs from. Fixed escapes the bar because nothing on the
   ancestor chain establishes a containing block (no transform, no filter, and the
   bar's blur is drawn by its ::before, not by the bar), and the script positions
   it from the input's rect on scroll and resize.

   Width: wide enough for a result to read as three lines of prose rather than a
   column of single words. It is a floating overlay anchored to the field, so it is
   free to be wider than whatever it hangs from. */
.docs-search-results{position:fixed;z-index:110;inline-size:min(30rem,calc(100vw - 2rem));max-height:min(60vh,28rem);overflow-y:auto;background:hsl(var(--popover));border:1px solid var(--border);border-radius:10px;box-shadow:0 10px 34px #00000026;padding:.25rem}
/* A hit is explicitly a flex COLUMN rather than a block. It used to be a block that
   had to out-specify the rail's .docs-sidebar a{display:flex} - and when that
   fight was lost the three spans became flex items in a ROW, so every result was
   three narrow columns of one-word-per-line text. The panel no longer lives in the
   rail, but declaring the axis means the layout cannot be decided by whichever
   ancestor rule happens to win a specificity contest later. */
.docs-search-hit{display:flex;flex-direction:column;align-items:stretch;padding:.5rem .6rem;border-radius:7px;color:var(--text)}
.docs-search-hit .hit-h{font-size:.875rem;font-weight:600;color:var(--dark);line-height:1.35}
.docs-search-hit .hit-c{font-size:.6875rem;color:var(--green);margin-top:.1rem}
.docs-search-hit .hit-x{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:.8125rem;color:var(--muted);margin-top:.25rem;line-height:1.45}
.docs-search-hit:hover,.docs-search-hit.is-active{background:var(--pale);text-decoration:none}
.docs-search-empty{padding:.6rem .55rem;font-size:.8125rem;color:var(--muted)}
[data-theme="dark"] .docs-search-results{background:hsl(var(--popover));box-shadow:0 10px 34px #0000008c}
/* --dark is NOT remapped by the [data-theme="dark"] theme (it overrides --text/--muted/--border
   /--pale only), so every var(--dark) foreground is near-black on the dark panel.
   The docs headings solve it the same way one block up: repoint to --text. */
[data-theme="dark"] .docs-search-hit .hit-h{color:var(--text)}
/* The specification rail (docs/spec-pages.ts): the chapter list a reader gets in
   place of the pathway rail, and the current chapter's headings under it. It wears
   .docs-sidebar, so everything but the number column and the heading list is
   already settled by the rules above and below. */
.spec-rail .spec-n{flex:none;width:1.5em;font-size:.75rem;font-variant-numeric:tabular-nums;color:var(--muted);padding-top:.15em}
.spec-rail a.active .spec-n{color:inherit;opacity:.8}
.spec-heads{list-style:none;margin:.15rem 0 .6rem 1.25rem;padding-left:.6rem;border-left:1px solid var(--border)}
.spec-heads a{font-size:.8125rem;color:var(--muted);padding:.2rem .5rem}
.spec-heads a.is-sub{padding-left:1.1rem}
.sidebar-pathway{font-size:1.0625rem;font-weight:700;color:var(--dark);margin-top:2rem; margin-bottom:.75rem;padding-bottom:.75rem;border-bottom:1px solid var(--border)}
.docs-sidebar a{display:flex;align-items:flex-start;gap:.5rem;padding:.3rem .5rem;font-size:.875rem;color:var(--text);border-radius:5px}
.docs-sidebar a:hover{color:var(--green);background:var(--pale);text-decoration:none}
.docs-sidebar a.active{color:var(--green);font-weight:600;background:var(--pale)}
/* Sidebar glyphs. Quiet by default so the LABEL still leads and the icon is the
   second cue rather than a competing one; they take the link's colour on hover and
   when active, so the row reads as one object. Fixed 1.05em box + flex-start keeps
   a two-line label aligned to the glyph's first line, not centred against it. */
.docs-sidebar a .sidebar-ic{flex:none;width:1.05em;height:1.05em;margin-top:.12em;color:var(--muted);opacity:.75}
.docs-sidebar a .sidebar-ic svg{width:100%;height:100%;display:block}
.docs-sidebar a:hover .sidebar-ic,.docs-sidebar a.active .sidebar-ic{color:inherit;opacity:1}
/* Two pages keep a hue of their own (see buildSidebar): AI and Inclusive Design.
   It is carried by a SOFT TINTED ROW, not a bright glyph - a saturated purple or
   pink sitting next to SUSE green read as two brands arguing rather than one
   system with an accent. The tint does the signalling, the glyph just picks it up,
   and both hues are desaturated toward the palette's own muted register so the
   column still reads green-first. Same landmark, no fight. */
.docs-sidebar a:has(.sidebar-ic.is-ai){background:#f5f2fd}
.docs-sidebar a:has(.sidebar-ic.is-inclusive){background:#fdf1f7}
.docs-sidebar a .sidebar-ic.is-ai{color:#6f5cc6;opacity:1}
.docs-sidebar a .sidebar-ic.is-inclusive{color:#c14b83;opacity:1}
/* Hover and active keep the row in its own hue instead of snapping to green -
   a landmark that changes colour when you touch it stops being a landmark. */
.docs-sidebar a:hover:has(.sidebar-ic.is-ai),.docs-sidebar a.active:has(.sidebar-ic.is-ai){background:#ece6fb;color:#5b4aab}
.docs-sidebar a:hover:has(.sidebar-ic.is-inclusive),.docs-sidebar a.active:has(.sidebar-ic.is-inclusive){background:#fbe3ef;color:#a83c6f}
.docs-sidebar a:hover .sidebar-ic.is-ai,.docs-sidebar a.active .sidebar-ic.is-ai{color:#5b4aab}
.docs-sidebar a:hover .sidebar-ic.is-inclusive,.docs-sidebar a.active .sidebar-ic.is-inclusive{color:#a83c6f}
/* Dark mode: a tint, not a fill - low-alpha over the near-black page so the row
   glows rather than becoming a slab, and the glyph lifts to stay legible. */
/* AI/inclusive sidebar chips: the base rules paint a light lilac/pink chip with
   dark ink, which on a dark ground (dark AND brand) would be light-link-text on
   a light chip. Brand has no overrides of its own, so it takes the dark chip
   treatment too. */
[data-theme="dark"] .docs-sidebar a:has(.sidebar-ic.is-ai),[data-theme="brand"] .docs-sidebar a:has(.sidebar-ic.is-ai){background:rgba(139,124,246,.13)}
[data-theme="dark"] .docs-sidebar a:has(.sidebar-ic.is-inclusive),[data-theme="brand"] .docs-sidebar a:has(.sidebar-ic.is-inclusive){background:rgba(244,114,182,.12)}
[data-theme="dark"] .docs-sidebar a .sidebar-ic.is-ai,[data-theme="brand"] .docs-sidebar a .sidebar-ic.is-ai{color:#b9a8f7}
[data-theme="dark"] .docs-sidebar a .sidebar-ic.is-inclusive,[data-theme="brand"] .docs-sidebar a .sidebar-ic.is-inclusive{color:#f2a9c9}
[data-theme="dark"] .docs-sidebar a:hover:has(.sidebar-ic.is-ai),[data-theme="dark"] .docs-sidebar a.active:has(.sidebar-ic.is-ai),[data-theme="brand"] .docs-sidebar a:hover:has(.sidebar-ic.is-ai),[data-theme="brand"] .docs-sidebar a.active:has(.sidebar-ic.is-ai){background:rgba(139,124,246,.2);color:#cbbdff}
[data-theme="dark"] .docs-sidebar a:hover:has(.sidebar-ic.is-inclusive),[data-theme="dark"] .docs-sidebar a.active:has(.sidebar-ic.is-inclusive),[data-theme="brand"] .docs-sidebar a:hover:has(.sidebar-ic.is-inclusive),[data-theme="brand"] .docs-sidebar a.active:has(.sidebar-ic.is-inclusive){background:rgba(244,114,182,.19);color:#ffc2dd}
[data-theme="dark"] .docs-sidebar a:hover .sidebar-ic.is-ai,[data-theme="dark"] .docs-sidebar a.active .sidebar-ic.is-ai,[data-theme="brand"] .docs-sidebar a:hover .sidebar-ic.is-ai,[data-theme="brand"] .docs-sidebar a.active .sidebar-ic.is-ai{color:#cbbdff}
[data-theme="dark"] .docs-sidebar a:hover .sidebar-ic.is-inclusive,[data-theme="dark"] .docs-sidebar a.active .sidebar-ic.is-inclusive,[data-theme="brand"] .docs-sidebar a:hover .sidebar-ic.is-inclusive,[data-theme="brand"] .docs-sidebar a.active .sidebar-ic.is-inclusive{color:#ffc2dd}
/* Icon bullet lists (the <!--i:key--> md marker - policy pages). Logical
   properties so the Arabic build mirrors correctly. */
.docs-content ul.icon-list{list-style:none;padding-inline-start:0;display:flex;flex-direction:column;gap:.9rem}
.docs-content ul.icon-list>li.ic{display:flex;align-items:flex-start;gap:.75rem}
/* The text column may shrink below its longest word, so a long link or code token
   breaks instead of pushing the page sideways (a flex item keeps its min-content). */
.docs-content ul.icon-list>li.ic>span:not(.li-icon){min-width:0}
/* Technology marks (the <!--l:key--> md marker - docs/logos.ts). Sized in em so a
   mark tracks whatever text it sits in, capped so it cannot become an illustration,
   and nudged onto the baseline the way an inline image needs to be. Muted by default
   at the same weight the sidebar glyphs use: these are landmarks for the eye, not a
   second reading of the sentence. Slightly OVER 1em (1.1) on purpose - these marks
   are dense little pictures, and at exactly the type size they read as smudges.

   HEADINGS CARRY NO MARKS. A heading is the page's own name for a section and the
   thing a reader scans to navigate by; a glyph in front of it competes for that job.
   Where a section really is about a technology, the marks go ABOVE it as a block
   (.doc-logo-block) instead, and the heading keeps its line to itself.

   Colour is deliberately just currentColor at reduced opacity - no per-brand fills.
   The site colours exactly two glyph families on purpose (the AI and inclusive-design
   sidebar rows); twenty brand palettes down a build page would be a carnival, and
   every mark here is someone else's trademark, which is not ours to restyle. If one
   ever earns its colour, it is one rule against [data-logo="key"]. */
.doc-logo{display:inline-block;width:1.1em;height:1.1em;max-width:1.35em;max-height:1.35em;vertical-align:-.18em;margin-inline-end:.3em;opacity:.75}
.doc-logo svg{width:100%;height:100%;display:block}
/* A mark inside a table cell carries the row, so it keeps full presence. */
.docs-content td .doc-logo{opacity:.85}
/* The block form (<!--lb:a b--> on its own line, before a major heading): the same
   marks given air and scale, so scrolling past one reads as arriving somewhere.
   Centred, generous margin above and below, and still monochrome - the size is what
   makes it an event, not colour. Sized in px rather than em: this row belongs to the
   PAGE's rhythm, not to the type around it, and every block should be the same size
   on every page. */
.doc-logo-block{display:flex;justify-content:center;align-items:center;gap:1.5rem;margin:2.5rem 0 1.75rem;padding-top:2.5rem;border-top:1px solid var(--border);color:var(--muted)}
.doc-logo-block>.doc-logo-mark{opacity:.55}
/* The row opens its section, so the section's rule sits above the row, not between
   the row and the heading it introduces. */
.docs-content .doc-logo-block+h2{border-top:0;padding-top:0;margin-top:0}
.doc-logo-mark{display:block;width:44px;height:44px}
.doc-logo-mark svg{width:100%;height:100%;display:block}
@media(max-width:600px){.doc-logo-block{gap:1.1rem;margin:2rem 0 1.25rem;padding-top:2rem}.doc-logo-mark{width:36px;height:36px}}
/* Two columns from a ::: cols fence. The pairing IS the argument on
   /info/status-quo - what happened on the left, what it cost on the right - so the
   two read together rather than one after the other. Below 900px they stack, which
   keeps the reading order intact because the source order is already correct. */
.md-cols{display:grid;grid-template-columns:1fr 1fr;gap:1.75rem 3rem;margin:2rem 0 2.5rem}
.md-cols .md-col>h2:first-child{margin-top:0;font-size:1.25rem}
.md-cols .md-col>ul{margin-bottom:0}
.md-cols .md-col li{font-size:.9375rem}
@media(max-width:900px){.md-cols{grid-template-columns:1fr;gap:2.25rem}}
/* A ::: timeline fence draws its icon list as a sequence: a rail joining each step,
   the way the change history in Verify draws a file's steps. Same visual grammar for
   the same idea - things that happened, in order. Used for the frictions we all
   accumulated, and for the rogue-agent scenario walked step by step. Sequences only:
   a set of causes or commitments stays a plain icon list, because a rail between
   unordered things says something untrue about them. */
.md-timeline .icon-list{position:relative;gap:1.35rem}
.md-timeline .icon-list>li.ic{position:relative;padding-bottom:.1rem}
.md-timeline .icon-list>li.ic .li-icon{position:relative;z-index:1;
  width:2rem;height:2rem;flex:none;display:grid;place-items:center;border-radius:999px;
  background:var(--pale);border:1.5px solid var(--border);color:var(--muted)}
.md-timeline .icon-list>li.ic .li-icon svg{width:1rem;height:1rem}
/* The rail: drawn from each item down to the next, so it stops cleanly at the last
   one instead of trailing into whitespace. */
.md-timeline .icon-list>li.ic:not(:last-child)::before{content:'';position:absolute;
  left:1rem;top:2rem;bottom:-1.35rem;width:1.5px;background:var(--border)}
@media(max-width:640px){.md-timeline .icon-list>li.ic .li-icon{width:1.75rem;height:1.75rem}
  .md-timeline .icon-list>li.ic:not(:last-child)::before{left:.875rem;top:1.75rem}}
.li-icon{flex-shrink:0;width:1.35rem;height:1.35rem;margin-top:.2rem;color:var(--green)}
.li-icon svg{width:100%;height:100%;display:block}
.docs-content{padding:2.75rem 3.5rem 6rem;min-width:0}
/* No band (a page with no h1 at all): the column clears the fixed bar by itself. */
.docs-content.no-mast{padding-top:calc(var(--site-bar-h) + 2.25rem)}
/* ── Article masthead (docsMasthead + DOCS_MASTHEAD_SCRIPT) ───────────────────
   The page's own h1 over the chip field, FULL VIEWPORT WIDTH: the band is a sibling
   of .docs-wrap, so the sidebar rail and the article both begin underneath it. That
   is the landing page's own grammar (its hero spans the window and the content
   starts below), and a band inset to one column would have read as an illustration
   inside the article rather than as the top of the page.

   The heading is left-aligned ON THE CONTENT GRID rather than centred: the landing
   hero sets its h1 to text-align:start inside a centred max-width box, and lining
   this one up with the column the article is about to start in makes the band feel
   structural instead of pasted on. Logical padding, so an RTL locale mirrors it.

   isolation:isolate keeps the canvas's blend mode inside the band - without it the
   dark theme's color-dodge would reach the page behind. */
.docs-masthead{position:relative;isolation:isolate;overflow:hidden;padding:calc(var(--site-bar-h) + 2.25rem) 0 2.25rem;min-height:clamp(14rem,30vh,20rem);display:flex;flex-direction:column;justify-content:flex-end;background:linear-gradient(180deg,var(--pale) 0%,var(--page) 100%)}
/* The dark plate stays a PLATE - a green a couple of steps up from the page - because
   color-dodge divides by the backdrop: over near-black (#061816) the chips resolve to
   near-black too and the field disappears. The gradient's last stop still reaches the
   page colour, so the band ends where the article begins. */
[data-theme="dark"] .docs-masthead,[data-theme="dark"] .docs-strip-band:not(.docs-strip-band--flow){background:linear-gradient(180deg,#16482f 0%,#0b2b21 58%,var(--page) 100%)}
/* Same box as .docs-wrap, then indented past the rail: the h1 starts exactly where
   the article's text will. Below 768px the rail is gone and so is the indent. It
   holds two rows (plan 277 step 3c): the pathways strip, then the title row. */
.docs-mast-inner{position:relative;z-index:2;max-width:1180px;width:100%;margin:0 auto;padding-inline:calc(220px + 3.5rem) 3.5rem;display:flex;flex-direction:column;gap:1.4rem}
.docs-mast-canvas{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:0;opacity:.55}
/* The chips are decoration under the title; the bar and the pathways strip above it
   carry words, so the field fades in only below them. The banked art takes the same
   line. --mast-clear sits on the band: MAST_CLEAR_SCRIPT sets it to the strip's own
   foot, which moves with the band's height and the title's length; the values here
   are the estimate a reader without JavaScript gets. */
.docs-masthead{--mast-clear:calc(var(--site-bar-h) + 5rem)}
@media(max-width:768px){.docs-masthead{--mast-clear:calc(var(--site-bar-h) + 4rem)}}
.docs-mast-canvas,.docs-mast-art{
  -webkit-mask-image:linear-gradient(180deg,transparent 0,transparent var(--mast-clear),#000 calc(var(--mast-clear) + 3rem));
  mask-image:linear-gradient(180deg,transparent 0,transparent var(--mast-clear),#000 calc(var(--mast-clear) + 3rem))}
/* Dark reuses the landing's own recipe (color-dodge over a dark plate); light gets
   a normal blend, because dodging on a near-white band blows the chips out to
   invisible white. Blend and opacity live here rather than in the JS: they are how
   the field MEETS the page, and the page's own theme rules already know that. */
[data-theme="dark"] .docs-mast-canvas{mix-blend-mode:color-dodge;opacity:.6}
/* Two scrims, both above the canvas and below the h1 (::before/::after are z-index 1,
   the heading is 2). The first is legibility insurance - the heading is currentColor,
   so decoration must never be allowed to eat its contrast; the second melts the band
   into the page it sits on, which at full bleed is the whole difference between a
   masthead and a banner. */
.docs-masthead::before{content:'';position:absolute;inset:0;z-index:1;pointer-events:none;background:radial-gradient(ellipse 70% 60% at 30% 88%,var(--mast-scrim) 0%,transparent 72%)}
[dir="rtl"] .docs-masthead::before{background:radial-gradient(ellipse 70% 60% at 70% 88%,var(--mast-scrim) 0%,transparent 72%)}
.docs-masthead::after{content:'';position:absolute;left:0;right:0;bottom:0;height:50%;z-index:1;pointer-events:none;background:linear-gradient(180deg,transparent 0%,var(--page) 94%)}
:root{--mast-scrim:rgba(255,255,255,.82)}
[data-theme="dark"]{--mast-scrim:rgba(6,24,22,.72)}
/* Brand theme is a dark-teal ground: without an override it fell back to the white
   :root scrim, washing the glow white. Ride the brand primary so the halo is the
   active brand's own colour (pine green for SUSE, the mounted brand's primary else). */
[data-theme="brand"]{--mast-scrim:hsl(var(--primary) / .4)}
/* Qualified with .docs-content (0,2,1) on purpose: the article rule .docs-content h1
   is (0,1,1) and gives every page heading a bottom rule and 2rem of padding. Inside a
   band that rule is a second horizontal line under a heading that already sits on
   one, so it has to be out-specified rather than tied with. */
.docs-masthead h1{margin:0;padding:0;border-bottom:0;color:var(--dark);font-size:clamp(2.25rem,3.4vw,3rem);font-weight:300;line-height:1.15}
/* The title row: the page's h1 (the in-app reader's title size and weight) with
   Listen beside it as an app button, on the title's last line rather than over
   the article's first. On a phone Listen wraps under the title. */
.mast-title{display:flex;align-items:flex-end;justify-content:space-between;flex-wrap:wrap;gap:1rem 2rem}
.mast-title h1{flex:1 1 18rem;min-width:0}
.mast-title .listen-bar{margin:0 0 .35rem}
/* The pathways strip at the top of the band (docs-chrome.css, which also makes it
   one scrolling line on a phone, with its edge fades). */
.docs-mast-inner .docs-pathways{margin:0}
@media(max-width:640px){
  .mast-title{gap:.75rem}
  .mast-title .listen-bar{margin:0}
}
/* ── The strip band (wrapPage, pathwaysBand) ─────────────────────────────────
   A page with no masthead (a format or conversion page, a specification chapter,
   an immersive page, the landing) still opens its documentation sections with the
   same strip: a slim band with the masthead's ground and no art or title. At the
   top of a page it clears the fixed bar; on the landing it sits between the dark
   hero and the first light band, where it does not compete with the hero. */
.docs-strip-band{position:relative;padding:calc(var(--site-bar-h) + 1.75rem) 0 1.25rem;background:linear-gradient(180deg,var(--pale) 0%,var(--page) 100%)}
.docs-strip-band .docs-pathways{margin:0}
.docs-strip-band .docs-mast-inner{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:.75rem 2rem}
.docs-strip-band .docs-pathways{flex:1 1 auto;min-width:0}
.docs-strip-band .listen-bar{margin:0}
.docs-strip-band--flow{padding-block:1.75rem .5rem;background:var(--page)}
.docs-strip-band--wide .docs-mast-inner{max-width:calc(1120px + 3rem);padding-inline:1.5rem}
@media(max-width:768px){.docs-strip-band{padding-top:calc(var(--site-bar-h) + 1.25rem)}.docs-strip-band--flow{padding-top:1.25rem}}
/* The article under a strip band no longer clears the bar by itself. */
.docs-strip-band+.docs-wrap .docs-content.no-mast{padding-top:2rem}
[data-theme="dark"] .docs-masthead h1{color:var(--text)}
@media(max-width:768px){.docs-masthead{padding:calc(var(--site-bar-h) + 1.5rem) 0 1.5rem;min-height:9rem}.docs-mast-inner{padding-inline:1rem}}
/* ── Banked masthead art (MASTHEADS + docs-art.ts) ────────────────────────────
   A signed artifact inlined in place of the chip canvas. SAME BAND: same padding,
   min-height, scrims and hoisted h1 - the only thing that changes is what is painted
   behind the heading, so a page that gains banked art does not also silently gain a
   different top. The art takes the canvas's z-index (0), under both scrims, so the
   heading's contrast is protected by the same two layers whatever the artwork does.

   width/height 100% on an SVG artifact's root rather than its own attributes: the
   band's height is the band's decision (it is furniture on a page, not a picture), and
   an SVG that keeps its own preserveAspectRatio then fills it the way it was drawn to.
   A fragment (markup + script) sizes ITSELF inside this box - it brought its own CSS,
   and a blanket rule here would fight it. */
.docs-mast-art{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none}
.docs-mast-art>svg{display:block;width:100%;height:100%}
/* The credential is a mark on the ARTWORK, so it hangs off the band's own corner like a
   screenshot's does - but the band is full-bleed, so it is inset to the same gutter the
   footer and nav use rather than sitting against the window edge. Above both scrims
   (z-index 3) or the melt gradient would fade the one line on the band that must stay
   legible; pointer-events are restored by .shot-cred-btn/.shot-cred-line themselves. */
.docs-masthead--art .shot-cred--mast{inset-block-end:.8rem;inset-inline-end:1.2rem;z-index:3}
/* A banked masthead carries a full claim - signer, file, kind, date, an AI pill and its
   model, plus all three actions - which is far more than the one short row .shot-cred-row's
   nowrap was written for, so on the mast the line overflows its padded card and the facts
   row lands adrift. Same fix the asset/mascot/figure marks use: give the card room and let
   the row WRAP into a compact stack inside it, right-aligned to the anchored corner. */
.docs-masthead--art .shot-cred--mast .shot-cred-line{max-width:min(30rem,calc(100vw - 3rem))}
.docs-masthead--art .shot-cred--mast .shot-cred-row{flex-wrap:wrap}
/* ── Figures (::: figure - a banked artifact in the text flow) ────────────────
   Content, not decoration: it sits in the column with the prose that argues with it,
   and its caption is a real caption (the showcase's, which this deliberately matches -
   two inlined-vector blocks that read differently would be two grammars for one idea).
   The credential rides INSIDE the figcaption rather than on the artwork's corner: a
   figure's provenance is part of what the caption says. */
.docs-figure{position:relative;margin:2.5rem auto;max-width:100%;min-width:0}
.docs-figure-art{position:relative;border-radius:1.2em;overflow:hidden}
.docs-figure-art>svg{display:block;width:100%;height:auto}
.docs-figure figcaption{margin-top:.9rem;font-size:.8125rem;color:var(--muted);text-align:center;
  display:flex;flex-direction:column;align-items:center;gap:.5rem}
.docs-figure figcaption p{margin:0}
/* In the flow, not anchored: .shot-cred is absolutely positioned for the corner-mark
   case, and inside a caption that would drop it onto the artwork above. Static, centred,
   and the glyph BEFORE the line (row, not row-reverse) so it reads left-to-right as a
   caption does. */
.docs-figure figcaption .shot-cred{position:static;flex-direction:row;align-items:center;
  justify-content:center;width:auto;max-width:100%}
/* Open at rest, like the AI-stance hero's and for the same reason: in a caption a mark
   that only appears on hover is a caption hiding half of itself, and a figure's own
   origin is frequently the point the surrounding page is making. */
.shot-cred--figure .shot-cred-line{opacity:1;pointer-events:auto;transform:none}
.docs-figure figcaption .shot-cred-line{align-items:center;max-width:100%}
.docs-figure figcaption .shot-cred-row{flex-wrap:wrap;justify-content:center}
/* "Copy signed source" is a BUTTON among two links (it does something to the reader's
   machine rather than going somewhere), so it is stripped back to look like them -
   the alternative, a link with a click handler, would lie to the keyboard and to the
   status bar about where it goes. */
button.shot-cred-copy{border:0;background:none;padding:.1em .35em;font:inherit;font-size:.6875rem;
  font-weight:600;color:inherit;cursor:pointer}
.shot-cred-copy-label{pointer-events:none}
/* The model pill's entity chip sits tight against its label, like the signer's. */
.prov-model .prov-entity{margin-inline:.18em 0}
.docs-content img{height:auto;    max-width: min(100%, 40em);    height: auto;   margin: 0 auto; display: block;}
/* App screenshots (docs/shots.json captures) read at full column width, framed like a window. */
.docs-content img[src*="/info/shots/"]{max-width:100%;min-width:50%;border-radius:1.2em;
  /* The <img> carries hardcoded width/height attrs to reserve layout space (no
     settle shift). Let CSS win over them so a tall PORTRAIT shot (the mobile
     /verify captures) is bounded by HEIGHT and shrinks its width to match, rather
     than filling the column and running metres down the page. object-fit keeps the
     aspect ratio while width/height are auto. */
  object-fit:contain;width:auto;height:auto;max-height:50em;
  box-shadow: inset 0 0 0 1px hsl(var(--border)), 0 3px 6px #0002, 0 6px 2em #00000014}
/* The frame ring is INK, so it has to invert: a black hairline is invisible on a
   near-black page, which is why the shots read as unframed in dark mode. Light
   ring, slightly stronger (a 1px white line at 6% disappears against a screenshot
   whose own edges are light), plus a deeper drop so the card still sits ON the
   page rather than in it. */
[data-theme="dark"] .docs-content img[src*="/info/shots/"]{
  box-shadow: inset 0 0 0 1px hsl(var(--border)), 0 3px 8px #00000073, 0 6px 2em #0000004d}

/* ── Screenshot settle ──────────────────────────────────────────────────────
   Every shot enters lifted, with a wide diffuse shadow, then lands: the shadow
   tightens under it as it rises the last 30px into place. Read as a sheet being
   set down on the page.

   fit-content, not 100%: the wrapper must hug the IMAGE, because the credential
   line is positioned against this box. A portrait shot in a wide column would
   otherwise strand its credential in the empty margin.

   NO scale, on purpose: an <img> of an SVG is rasterised by Blink at the
   composited scale, so a transform-SCALED shot goes soft DURING the motion and
   snaps crisp only at rest. Since the whole point of these shots is that they are
   vector - razor-sharp at any size - the settle only translates and fades; it
   never scales, so the artwork stays crisp through the entire motion. The
   showcase block below makes the vector argument outright (it animates real
   geometry). */
.shot{display:block;position:relative;width:fit-content;max-width:100%;margin:0 auto}
/* The frame takes its screenshot's final size before the image loads: the width the
   image will have (its own width, capped by the column and by the 50em height limit at
   its ratio), from the size the renderer records on the wrapper. The image then fills
   it. The screenshot rule's width:auto gave an unloaded image no size at all, so pages
   grew as images arrived and section links landed far short of their heading. */
.shot[style*="--shot-w"]{width:min(calc(var(--shot-w) * 1px),100%,calc(50em * var(--shot-w) / var(--shot-h)))}
.shot[style*="--shot-w"]>img{width:100%}
.shot>img{margin:0}
/* The hidden start state is gated on .shots-motion, which the pre-paint script in
   <head> adds. A shot must NEVER be able to strand itself at opacity 0: with no
   JS (or a script that failed to parse) the class is absent, no rule below
   matches, and every screenshot is simply visible. The gate is set before first
   paint rather than by the observer at end-of-body, or a long page would paint
   the shots once and then blink them out to animate them back in. */
@media(prefers-reduced-motion:no-preference){
  .shots-motion .shot{opacity:0;transform:translateY(30px);
    transition:opacity .5s ease,transform .75s cubic-bezier(.16,.84,.3,1)}
  /* Every rule that undoes the start state carries the SAME .shots-motion
     qualifier, so it matches the (0,2,0) above. A bare .shot--in here is
     (0,1,0) and loses to the hidden state - which would leave every screenshot
     on the site invisible forever. */
  .shots-motion .shot--in{opacity:1;transform:none}
  .shots-motion .shot>img{transition:box-shadow .75s cubic-bezier(.16,.84,.3,1)}
  .shots-motion .shot:not(.shot--in)>img{box-shadow:inset 0 0 0 1px hsl(var(--border)), 0 28px 60px #00000030}
  [data-theme="dark"] .shots-motion .shot:not(.shot--in)>img{box-shadow:inset 0 0 0 1px hsl(var(--border)), 0 28px 60px #00000073}
}

/* ── Screenshot credential line ─────────────────────────────────────────────
   A photo-credit that can be checked. At rest: one imprint glyph in the corner at
   low opacity. On hover, keyboard focus or tap it becomes a line of provenance
   pills plus two actions.

   NO JavaScript is required for the reveal, and that is a deliberate a11y choice.
   The line is never display:none - it is opacity 0 with pointer-events off - so it
   stays in the accessibility tree and in tab order, and :focus-within brings it
   into view the instant a keyboard reaches one of its links. A hidden-until-JS
   popover would have had to lie about aria-expanded in the no-JS case; this cannot.
   The script only adds tap-to-open and Escape-to-close, which hover cannot do. */
/* width:max-content is doing real work. An absolutely positioned box shrink-to-fits
   against its containing block, so on a 247px-wide shot the line was squeezed until
   even "signed by Lolly" broke across three lines. Given intrinsic width and an
   inline-end anchor with no inline-start, it lays out at its natural size and grows
   LEFTWARDS across (and past) the artwork, like a caption.

   pointer-events are handed to the children, not the container: the closed line
   still occupies its full box, and a transparent 350px strip that opens on hover
   would fire whenever the pointer crossed the bottom of the shot. */
/* align-items:flex-END, not center: the line is a flex SIBLING of the glyph and is
   opacity-0 (never display:none), so it keeps its box in the layout at rest. Under
   center a taller line - which is exactly what the second, anatomy row makes it -
   would re-centre the glyph upward off its anchored corner, on every shot, expanded or
   not. Bottom-aligning pins the glyph to inset-block-end regardless of how tall the
   invisible line beside it is, so the resting mark is identical whether or not a shot
   has a readable second row. */
.shot-cred{position:absolute;inset-block-end:.55rem;inset-inline-end:.7rem;z-index:2;
  display:flex;align-items:flex-end;justify-content:flex-end;gap:.4rem;flex-direction:row-reverse;
  width:max-content;max-width:min(28rem,calc(100vw - 3rem));pointer-events:none}
/* Quiet by COLOUR and size, never by transparency. This mark used to rest at
   opacity:.34, which faded the glyph's strokes along with its puck - so the ripple
   path dissolved into whatever the screenshot's own corner happened to be and, at
   1.4rem, read as a smudge rather than a mark. A credential nobody can make out is
   not discreet, it is decoration.

   So: the puck stays opaque enough to GUARANTEE the glyph's contrast whatever sits
   behind it (screenshot corners are unpredictable - a white card, a dark timeline, a
   photo), and the glyph is muted against that puck instead of against the shot. Rest
   is legible; hover only sharpens it. */
.shot-cred-btn{display:grid;place-items:center;width:1.4rem;height:1.4rem;flex:none;padding:0;
  border:0;border-radius:50%;cursor:pointer;color:var(--muted);background:hsl(var(--popover) / 0.9);
  box-shadow:0 1px 3px #00000024;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);pointer-events:auto;
  transition:color .2s ease,background .2s ease,box-shadow .2s ease}
.shot-cred-btn svg{width:.9rem;height:.9rem;display:block}
/* Approaching the shot at all sharpens it; it never shouts. */
.shot:hover .shot-cred-btn,.showcase:hover .shot-cred-btn{color:var(--dark)}
.shot-cred-btn:hover,.shot-cred-btn:focus-visible{color:var(--dark);background:hsl(var(--popover));box-shadow:0 2px 6px #0003}
/* Sized against the VIEWPORT, never the shot. Some shots are a 236px-wide crop of
   one control, and a line clamped to that width wraps into a stack taller than the
   artwork. Because .shot-cred is anchored to the inline-end and nothing on the way
   up clips, a wider line simply extends back across the shot (and past its edge on
   a small one), which is how a caption behaves rather than how a box does. */
.shot-cred-line{display:flex;flex-direction:column;align-items:flex-end;gap:.16rem;
  max-width:min(26rem,calc(100vw - 3rem));padding:.28rem .45rem;border-radius:.9rem;
  background:hsl(var(--popover) / 0.87);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  box-shadow:0 2px 10px #0000001f, inset 0 0 0 1px hsl(var(--border));
  opacity:0;pointer-events:none;transform:translateX(.4rem);
  transition:opacity .22s ease,transform .22s ease}
/* Hover is keyed off the GLYPH (and then the line itself, so the pointer can travel
   onto it without it closing) rather than off the container, which is
   pointer-events:none for the reason given above. */
.shot-cred-btn:hover + .shot-cred-line,.shot-cred-btn:focus-visible + .shot-cred-line,
.shot-cred-line:hover,.shot-cred:focus-within .shot-cred-line,
.shot-cred[data-open] .shot-cred-line{opacity:1;pointer-events:auto;transform:none}
/* The "try it" offer under a shot. In the FLOW and OUTSIDE the .shot wrapper, not in
   the overlay: the credential is a mark on the artwork, this is a line of the page, and
   they must not compete. Outside matters structurally too - .shot-cred is anchored to
   the wrapper's bottom edge, so a link inside it pushes that edge down and the mark
   lifts off the artwork's corner onto the caption. Centred under the picture (the shot
   itself is a centred fit-content box), quiet until approached. */
.shot-try{display:block;margin-block-start:.5rem;text-align:center;
  font-size:.8125rem;font-weight:600;color:var(--muted)}
.shot-try::after{content:' →'}
.shot-try:hover,.shot-try:focus-visible{color:var(--green);text-decoration:underline}
.docs-diagram{display:block;max-width:40em;margin:1.5em auto}
.diagram-actions{text-align:center; width:100%;display:flex;align-items:center;justify-content:center;gap:.35rem;margin-top:.5rem; font-size:var(--ui-type-help)}
.docs-diagram>img{border-radius: var(--radius-lg);    box-shadow: var(--shadow-3);display:block;max-width:100%;height:auto;margin:0 auto}
.diagram-actions{display:flex;align-items:center;justify-content:center;gap:.35rem;margin-top:.5rem; font-size:.8125rem;font-weight:600;color:var(--muted)}
.diagram-actions a{color:inherit}
.diagram-verify{display:grid;place-items:center;flex:none;width:2.25rem;height:2.25rem;border-radius:50%}
.diagram-verify svg{width:1.1rem;height:1.1rem}
.diagram-open{padding:.5rem .25rem}
.diagram-open::after{content:' →'}
/* A diagram with a dark twin (.docs-diagram--dual) carries both files, and the
   reader's own theme picks one, the same way a dual screenshot does. */
.docs-diagram--dual>img.diagram-alt{display:none}
[data-theme="dark"] .docs-diagram--dual>img:not(.diagram-alt),[data-theme="brand"] .docs-diagram--dual>img:not(.diagram-alt){display:none}
[data-theme="dark"] .docs-diagram--dual>img.diagram-alt,[data-theme="brand"] .docs-diagram--dual>img.diagram-alt{display:block}
.diagram-actions a:hover{color:var(--green)}
.diagram-actions a:focus-visible{outline:2px solid var(--green);outline-offset:3px}
/* A PAGE ASSET's credential (the AI stance hero): open at rest, because the file's
   history is what the surrounding page is arguing about rather than a footnote to a
   screenshot. Same mark, same line, same two links - only the resting state differs,
   so a reader who never hovers still sees who signed the picture they are looking at. */
.shot-cred--asset .shot-cred-line{opacity:1;pointer-events:auto;transform:none}
/* Full column width, and nothing else: page artwork sizes itself (the hero is
   width:100% a few rules down), so the wrapper only has to be a positioned box the
   mark can hang off. An image that wants 100% of a fit-content parent resolves to
   zero, which is the other reason this is not a .shot. */
.asset-cred{display:block;position:relative;width:100%}
.asset-cred>img{display:block;width:100%;height:auto;margin:1em auto}
/* A page-asset credential rests OPEN on a full-width hero, so - unlike a screenshot's
   caption, which deliberately overhangs a narrow crop (see the .shot-cred notes above) -
   it must stay INSIDE the frame: there is a whole column of room, so a spill past the
   edge like the one on /input-not-impersonation is just a bug. Same fix the mascot credit
   uses a few rules down: clamp the line to the artwork, and let the rows WRAP into a
   compact stack rather than run off the side. The glyph stays anchored; the line grows
   within the box. */
.asset-cred .shot-cred{max-width:calc(100% - 1.4rem)}
.asset-cred .shot-cred-line{max-width:18em}
.asset-cred .shot-cred-row{flex-wrap:wrap}
/* not-a-pipe keeps the DEFAULT centred, 40em-capped image (see .docs-content img above),
   so its .asset-cred wrapper is the full column - wider than the picture - and a mark
   anchored to the wrapper's edge hangs off into the margin. Hug the wrapper to the same cap
   so the credential aligns to the artwork's real edge. (the-flood escapes this only because
   it overrides its image to width:100% further down, filling the wrapper.) */
.asset-cred[data-shot="/info/not-a-pipe.webp"]{max-width:min(100%,40em);margin-inline:auto}
/* Its caption "Ceci n'est pas une pipe" runs along the bottom edge, and that writing is the
   whole point of the picture - so this hero's mark sits mid-height rather than in the bottom
   corner where it would cover the words it is arguing about. */
.asset-cred[data-shot="/info/not-a-pipe.webp"] .shot-cred{inset-block-end:50%}
/* The line is a stack of ROWS, and a shot with no readable file has exactly one of
   them - so the column above is byte-identical to the single row it replaced. The
   second row (what the file is made of) only ever appears inside the expanded line,
   which is the only state the line has: at rest the whole thing is opacity 0. The
   glyph itself does not move when the second row is present, because .shot-cred
   bottom-anchors it (align-items:flex-end) rather than centring it against the line.

   nowrap on the ROW, not on the line: the row still refuses to break "signed by
   Lolly" across lines, and a stack of two short rows is shorter than the four-row
   wrap the one-row rule was written to prevent. */
.shot-cred-row{display:flex;align-items:center;gap:.3rem;flex-wrap:nowrap;justify-content:flex-end}
/* The line's pills are chips on a chip, so they sit a step quieter than the ones
   the prose uses - and they must not inherit the docs paragraph line-height, which
   would make the row twice as tall as the glyph beside it. */
.shot-cred-row>*{flex:none}
.shot-cred-line .prov-pill{font-size:.6875rem;line-height:1.3;padding:.1em .5em;margin:0;white-space:nowrap}
.shot-cred-line .prov-seal{width:.8em;height:.8em}
.shot-cred-do{font-size:.6875rem;font-weight:600;white-space:nowrap;padding:.1em .35em;border-radius:.6em}
.shot-cred-do:hover{background:var(--pale);text-decoration:underline}
/* An AI declaration is not a detail to be discovered - if a shot ever carries one,
   its mark arrives already at full contrast and wearing the brand ring, so it reads
   as a statement rather than as the same quiet glyph every other shot has. */
.shot-cred--ai .shot-cred-btn{color:hsl(var(--on-band-dark));background:hsl(var(--band-dark));box-shadow:0 0 0 2px var(--green)}
/* Dark mode: same contract, inverted. The puck is near-opaque for the same reason -
   a dark screenshot's corner is not reliably darker than the puck - and the glyph is
   a muted PALE against it, not a full-white one, so it stays quiet without becoming
   the invisible stroke this used to be. */
[data-theme="dark"] .shot-cred-btn{color:#93a8a0;background:hsl(var(--popover) / 0.9);box-shadow:0 1px 3px #0006}
[data-theme="dark"] .shot:hover .shot-cred-btn,[data-theme="dark"] .showcase:hover .shot-cred-btn{color:var(--pale)}
[data-theme="dark"] .shot-cred-btn:hover,[data-theme="dark"] .shot-cred-btn:focus-visible{color:var(--pale);background:hsl(var(--popover));box-shadow:0 2px 6px #0008}
[data-theme="dark"] .shot-cred--ai .shot-cred-btn{color:var(--dark);background:var(--light)}
[data-theme="dark"] .shot-cred-line{background:hsl(var(--popover) / 0.93);box-shadow:0 2px 10px #0007, inset 0 0 0 1px hsl(var(--border))}
[data-theme="dark"] .shot-cred-do:hover{background:hsl(var(--foreground) / 0.08)}
@media(prefers-reduced-motion:reduce){.shot-cred-line{transition:none;transform:none}}
/* Narrow columns: the line stacks above the glyph instead of beside it. The box
   stays anchored to the inline-END corner only and grows toward inline-start, the
   side a page never scrolls to (left in LTR, right in RTL). Pinning the start edge
   as well used to stretch the box toward the scrolling side: on a small crop the
   mark left its artwork and the page gained a sideways scroll, open or closed.
   SHOT_CRED_SCRIPT sets --cred-shift on open so a long line stays on screen; the
   independent translate property composes with the open/close transform. */
@media(max-width:640px){
  .shot-cred{flex-direction:column;align-items:flex-end}
  .shot-cred-line{max-width:min(26rem,calc(100vw - 2rem));transform:translateY(.4rem);translate:var(--cred-shift,0px) 0}
}

/* ── Geometry showcase (::: showcase - one inlined vector shot) ─────────────
   Scroll drives --p from 0 to 1. Everything that moves is geometry:

     camera  the svg viewBox is lerped from a centre crop out to full extent (JS -
             viewBox is an attribute, not a CSS property). The captured strokes are
             non-scaling-stroke, so they stay hairline all the way in. No re-raster,
             no blur, at any zoom - the whole point of the block.
     ink     grayscale(1 - p): the drawing arrives as ink and takes on its colour.
             A filter function list CAN transition, unlike the url() case above.
     order   each leaf shape appears when p passes its share of the paint order, so
             the map assembles itself layer by layer (water, then road classes by
             weight) instead of fading in as one flat picture.

   --p is set by JS, so with no JS the fallbacks below (p:1) render the finished
   artwork at full extent, in colour, every layer visible. */
.showcase{--p:1;margin:2.5rem auto;max-width:100%;width:fit-content}
/* The radius lives on the artwork, NOT as overflow:hidden on the stage - the stage
   also holds the credential line, which is allowed to extend past the artwork's
   edge, and a clipping stage would cut it off. */
.showcase-stage{position:relative;border-radius:1.2em;
  box-shadow:inset 0 0 0 1px hsl(var(--border)), 0 3px 6px #0002, 0 6px 2em #00000014}
[data-theme="dark"] .showcase-stage{
  box-shadow:inset 0 0 0 1px hsl(var(--border)), 0 3px 8px #00000073, 0 6px 2em #0000004d}
/* The <img> the build emits, and the live SVG that replaces it, must occupy the
   same box - the swap happens under the reader's eyes and any size change would
   read as a jump rather than an upgrade, and moves every heading below it. The
   fallback is a shot, so the screenshot rule above sizes it (width auto, capped at
   the column and 50em tall); the art follows the same rule, from the width and
   height the showcase script copies over from the image. */
.showcase-fallback,.showcase-art{display:block;height:auto;margin:0;border-radius:1.2em}
.showcase-art{width:auto;max-width:100%;max-height:50em}
.showcase-art{filter:grayscale(calc(1 - var(--p)))}
/* The stagger. Each leaf gets --i (its paint-order index) and the root gets --n
   (the total) from the showcase script; ×2.2 fades each shape over a fraction of
   the scroll rather than all of it, so the layers overlap into one motion.

   The +1 is what makes this read as drawing rather than loading: it puts the FIRST
   leaf (the sheet the artwork sits on) on screen at p=0, so the block opens as
   blank paper and the ink arrives onto it. Without it every layer including the
   background starts at zero, and the opening frame is an empty box that looks like
   a screenshot that failed to load. */
.showcase-art [data-sc-i]{opacity:clamp(0,calc((var(--p) * var(--n) - var(--i) + 1) * 2.2),1)}
.showcase figcaption{margin-top:.9rem;font-size:.8125rem;color:var(--muted);text-align:center;
  max-width:34em;margin-inline:auto}
.showcase figcaption p{margin:0}
@media(prefers-reduced-motion:reduce){
  /* No camera, no ink phase, no stagger - the finished artwork, still. */
  .showcase{--p:1 !important}
  .showcase-art{filter:none}
  .showcase-art [data-sc-i]{opacity:1}
}

/* ── Theme twin: two committed files, one shown ────────────────────────────
   A "dark=1" recipe ships a second baseline captured with the app pinned dark, and
   the reader's own toggle decides which one is on screen. NOT a <picture> with a
   prefers-color-scheme source: the site's dark mode is a CLASS the reader flips,
   so a media-query source would follow the OS and contradict the toggle.

   Ungated (no .shots-motion, no media query) so it holds with JS off, and scoped
   to .shot--dual so a shot with no twin is byte-identical to before. Each twin
   carries its OWN credential line - two separately signed files. */
/* Every img rule here is qualified with the ELEMENT as well as the class: the base
   .docs-content img rule sets display:block at (0,1,1), so a bare .shot-alt (0,1,0)
   loses and BOTH twins render, one under the other. */
.shot--dual>img.shot-alt,.shot--dual .shot-cred--alt{display:none}
[data-theme="dark"] .shot--dual>img:not(.shot-alt),[data-theme="dark"] .shot--dual .shot-cred:not(.shot-cred--alt){display:none}
[data-theme="dark"] .shot--dual>img.shot-alt{display:block}
[data-theme="dark"] .shot--dual .shot-cred--alt{display:flex}

/* Provenance pills (the typed markers authors write in the markdown - see inline()).
   A provenance line reads as
   data tags in sentence order, so the hierarchy is carried by weight and fill, not
   by size: ACTORS solid and darkest, SIGNATURES outlined with a seal, then the
   mechanical detail (actions, filenames, sizes) quiet enough to skim past.
   The paragraph stays ordinary inline text - a flex row would make every word
   between the pills its own flex item and strand the connecting commas. */
.prov-pill{display:inline-block;border-radius:999px;padding:.16em .62em;font-size:.8125rem;
  line-height:1.4;margin:0 .08em;vertical-align:baseline}
/* Every surface below is a THEME TOKEN, never a literal - the tokens flip with
   [data-theme="dark"], a hex does not. A hardcoded light fill under light-on-dark text is how
   these pills went unreadable in dark mode the first time. */
.prov-entity{background:hsl(var(--band-dark));color:hsl(var(--on-band-dark));font-weight:700;letter-spacing:.01em}
[data-theme="dark"] .prov-entity{background:#12463a}  /* lifted off the near-black page so the chip still reads as a chip */
.prov-sig{color:var(--text);font-weight:600;background:rgba(48,186,120,.14)}
/* An actor inside a signature is WHITE ON GREEN in both themes - a signature is the
   one claim that must look identical wherever it is read. The fill is a deepened
   brand green rather than --green itself: white on #30ba78 is about 2.2:1, which
   fails for 13px text, and a signature nobody can read is worse than an off-swatch
   one. This keeps the hue and clears 4.5:1. */
.prov-sig .prov-entity{background:#14784d;color:hsl(var(--on-band-dark));margin-inline:.18em 0}
/* Inline, not a flex child: the pill's baseline must be its TEXT baseline so it
   sits on the same line as the prose around it. The glyph is nudged optically. */
/* The seal is the one glyph in the pill that must read at a glance, and --green
   on --pale is the weakest pairing in the set (a mid-green on a tinted background
   in BOTH themes). It takes the theme's ink instead: near-black on the light pill,
   white on the dark one. The literal #fff is safe here because it lives inside
   [data-theme="dark"], so it flips with the theme rather than surviving it. */
.prov-seal{width:.95em;height:.95em;margin-inline-end:.34em;vertical-align:-.14em;color:var(--dark)}
[data-theme="dark"] .prov-seal{color:hsl(var(--on-band-dark))}
.prov-act{background:var(--pale);color:var(--text);font-weight:550;border:1px solid transparent}
[data-theme="dark"] .prov-act{border-color:var(--border)}
/* A filename wraps rather than truncating - it is evidence the caption is naming,
   so hiding its tail hides the point. NOTE: never give this overflow:hidden -
   on an inline-block that moves the baseline to the bottom margin edge (CSS 2.1
   10.8.1) and the pill visibly drops below the line it sits in. */
.prov-file{background:var(--pale);color:var(--muted);border:1px solid var(--border);
  font-family:'SUSE Mono','SF Mono',monospace;font-size:.75rem;
  white-space:normal;overflow-wrap:anywhere;max-width:100%}
.prov-detail{color:var(--muted);font-variant-numeric:tabular-nums;font-size:.8125rem}
/* The caption sits under the hero as a caption, not as body copy. The extra
   leading is what keeps a wrapped chain of padded pills off the rows above and
   below - with normal leading the pill boxes collide even though the text does not. */
.docs-content p:has(.prov-pill){margin-top:.9rem;font-size:.9375rem;line-height:2.15;color:var(--muted)}

/* The AI-stance hero photo carries a three-manifest C2PA chain (Google's two as
   ingredients, Lolly's own on top) that readers are invited to verify, so its
   bytes are exactly what Lolly exported - never re-encode it in a build step.
   Full column width: it is the page's one image and the argument's evidence. */
.docs-content img[src*="the-flood"]{width:100%;max-width:100%;border-radius:1.2em;box-shadow:0 3px 6px #0002, 0 6px 2em #0001}
.docs-content h2{font-size:1.5rem;font-weight:700;letter-spacing:normal;text-transform:none;border-top:1px solid var(--border);padding-top:2rem;margin-top:2.5rem;margin-bottom:.75rem;color:var(--dark)}
.docs-content h2:first-of-type{border-top:none;padding-top:0;margin-top:0}
.docs-content h3{font-size:1.15rem;margin-top:1.75rem;margin-bottom:.5rem;color:var(--dark)}
.docs-content h4{font-size:1rem;margin-top:1.25rem;margin-bottom:.35rem;color:var(--muted)}
/* The top bar is fixed, so a heading reached by an #anchor (the jump nav below, a
   search result, a shared deep link) would otherwise sit UNDER it. Same idea as
   section[id] on the landing page, with room for the heading's rule. */
.docs-content h2[id],.docs-content h3[id],.docs-content h4[id]{scroll-margin-top:calc(var(--site-bar-h) + 1.75rem)}
.docs-content ul,.docs-content ol{margin-bottom:1rem}
/* ── "On this page" jump nav (long docs pages only - pageJumpNav) ─────────────
   Bottom-right, deliberately quiet: a 2.25rem disc that reads as page furniture
   until you want it. Logical inset so the Arabic build puts it in the corner an RTL
   reader reaches for. Tokens only (--text/--muted/--border/--pale, all redefined by
   .dark) so dark mode needs no second palette here. */
.doc-jump{position:fixed;bottom:1rem;inset-inline-end:1rem;z-index:88}
.doc-jump-btn{display:flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border-radius:999px;border:1px solid var(--border);background:var(--pale);color:var(--muted);cursor:pointer;box-shadow:0 2px 10px #0c322c1f;transition:color .12s,border-color .12s}
.doc-jump-btn svg{width:1.1rem;height:1.1rem}
.doc-jump-btn:hover,.doc-jump-btn[aria-expanded="true"]{color:var(--green);border-color:var(--green)}
/* The first six declarations are RESETS, not choices. A bare nav element selector
   used to be the site's top bar (fixed, full-width, flex) and landed on any <nav>
   on the page; the bar is its own .site-bar now, and the resets stay so no element
   rule can ever lay this panel out as a strip across the bottom of the window. */
.doc-jump-nav{position:absolute;display:block;top:auto;width:auto;height:auto;overflow-x:hidden;transition:none;bottom:calc(100% + .5rem);inset-inline-end:0;min-width:14rem;max-width:min(20rem,calc(100vw - 2rem));max-height:min(60vh,26rem);overflow-y:auto;padding:.4rem;background:var(--pale);border:1px solid var(--border);border-radius:10px;box-shadow:0 10px 34px #0c322c26}
.doc-jump-nav[hidden]{display:none}
.doc-jump-title{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin:.15rem .5rem .35rem}
.doc-jump-nav a{display:block;padding:.32rem .5rem;border-radius:6px;font-size:.875rem;line-height:1.35;color:var(--text);text-decoration:none}
.doc-jump-nav a:hover{background:#30ba7818;color:var(--green);text-decoration:none}
.doc-jump-top{margin-top:.25rem;border-top:1px solid var(--border);padding-top:.45rem;color:var(--muted)}
/* The docs player dock owns this corner while it is open (html.ldp-open, fixed at
   the same 16px). One control per corner - the reader is listening, not scanning. */
html.ldp-open .doc-jump{display:none}
@media(prefers-reduced-motion:reduce){.doc-jump-btn{transition:none}}
@media print{.doc-jump{display:none}}
.docs-content h1{font-size:3rem;color:var(--dark);line-height:1.15;margin-bottom:2rem;padding-bottom:2rem;border-bottom:1px solid var(--border); font-weight:300;}

/* Table */
.table-wrap{overflow-x:auto;margin-bottom:2rem;box-shadow: 0 0 0 1px hsl(var(--border)), 0 .2rem .4rem #00000018; border-radius: 1.5em;}
table{border-collapse:collapse;width:100%;font-size:.875rem}
thead tr th:first-child{border-radius: 1em 0 0 0}
thead tr th:last-child{border-radius: 0 1em 0 0}
th,td{padding:.55rem .9rem;text-align:start;border:1px solid var(--border)}
th{background:var(--pale);font-weight:600;color:var(--dark)}
tr:nth-child(even) td{background:hsl(var(--muted) / 0.4)}

/* Mascots */
.social-proof-mascot{position:absolute;right:4%;top:50%;transform:translateY(-50%);width:clamp(90px,12vw,180px);pointer-events:none;filter:drop-shadow(0 8px 20px rgba(12,50,44,.18))}
.footer-inner{display:flex;align-items:center;justify-content:center;gap:1rem}
.footer-mascot{width:2.75rem;flex-shrink:0;filter:drop-shadow(0 2px 6px rgba(0,0,0,.18))}
@media(max-width:768px){
  .social-proof-mascot{display:none}
}

/* Social proof */
.social-proof{padding:4rem 0 3rem;background:hsl(var(--background));overflow:hidden;position:relative}
.social-proof-inner{text-align:center;padding:0 1.5rem 2.5rem;max-width:50rem;margin:0 auto}
.social-proof h2{font-size:2rem;color:var(--dark);margin-bottom:.375rem}
.social-proof-date{font-size:.8125rem;color:var(--green);font-weight:600;margin-bottom:.625rem;letter-spacing:.02em;text-transform:uppercase}
.social-proof-desc{color:var(--muted);font-size:.9375rem;line-height:1.6}
/* "Founded by SUSE" badge - same size everywhere it appears (hero, social proof, footer) */
.social-proof-founded{margin:1.5rem 0 0;text-align:center}
.social-proof-credit{text-align:center;color:var(--muted);font-size:.875rem;margin-top:1.75rem;padding:0 1.5rem}
.social-proof-credit a{color:var(--green);font-weight:600;text-decoration:none}
.social-proof-credit a:hover{text-decoration:underline}

.opensource-section{padding:5rem 2rem;background:var(--pale);text-align:center}
.opensource-inner{max-width:720px;margin:0 auto}
.opensource-section h2{margin-bottom:1.25rem}
.opensource-section p{color:var(--muted);font-size:1.0625rem;line-height:1.8}

.quokka{max-width:320px;}
@media(max-width:768px){.quokka{max-height:260px;width:auto;max-width:60vw}}
/* Footer */
footer{border-top:1px solid var(--border);padding:2rem 1.5rem;text-align:center;color:var(--muted);font-size:.8125rem;background:var(--pale)}
footer a{color:var(--muted);text-decoration:underline}
footer a:hover{color:var(--dark)}
.sitemap-disclosure{grid-column:1/-1;text-align:start}
.sitemap-disclosure>summary{width:fit-content;margin:0 auto;cursor:pointer;font-weight:600;padding:.5rem}
.sitemap-expanded{display:grid;grid-template-columns:repeat(auto-fit,minmax(10rem,1fr));gap:2rem;margin-top:2rem}
footer .founded-badge{margin-top:.5rem}
/* Footer sitemap - the whole docs set, ten columns (see FOOTER_SECTIONS).
   auto-fit is right for a handful of columns and wrong for ten: it maximises the
   count, so 1180px yields seven and the last three sit alone on a second row under
   four empty tracks. Explicit counts instead - 2 on a phone, 3 on a tablet, then 5.
   Ten divides by both 2 and 5, so the phone and the desktop layouts are exactly
   full (5 rows of two; 2 rows of five). The tablet band is the one that cannot be:
   ten in threes leaves a single column on a fourth row, and the alternative (four
   columns, 4+4+2) trades that for a half-empty row at a narrower column width.
   align-items:start keeps a short column's links at the top of its row
   rather than stretched down it. Columns read left-aligned inside a centred footer,
   which is what makes them scannable as lists rather than as prose. Titles take
   var(--text), not var(--dark), because --dark keeps its value in the dark theme
   and would go invisible there. */
.footer-sitemap{display:grid;grid-template-columns:repeat(2,1fr);align-items:start;gap:1.25rem 1.5rem;max-width:1180px;margin:0 auto 1.75rem;padding-bottom:1.75rem;border-bottom:1px solid var(--border);text-align:start}
@media(min-width:34rem){.footer-sitemap{grid-template-columns:repeat(3,1fr)}}
@media(min-width:64rem){.footer-sitemap{grid-template-columns:repeat(5,1fr)}}
.footer-sitemap a{display:flex;align-items:flex-start;gap:.45em;color:var(--muted);text-decoration:none;padding:.15rem 0 .15rem;line-height:2;min-width:0;overflow-wrap:anywhere;hyphens:auto}
.footer-sitemap a:hover{color:var(--green);text-decoration:underline}
/* Every sitemap link opens with the SAME glyph the docs sidebar gives that page
   (SIDEBAR_ICON - one page→icon mapping, both navs), so the landmark a reader
   learned on the rail keeps working down here. Decorative: aria-hidden spans,
   sized in em to the footer's own text so rows and the smaller uppercase headings
   each get a matching icon from one rule. margin-top holds the 1.5em glyph on the
   FIRST line of the 2-line-height row when a label wraps. */
.footer-sitemap .sitemap-ic{flex:none;width:1.5em;height:1.5em;margin-top:.22em;opacity:.6;color:var(--green)}
.footer-sitemap .sitemap-ic svg{width:100%;height:100%;display:block}
.footer-sitemap a:hover .sitemap-ic{opacity:1}
/* The column heading is a LINK to its pathway's main page. That is what pays for
   the full enumeration: the overview never costs a row of its own, and the two or
   three columns a long pathway is split across all point their heading at the same
   hub. It keeps the heading's own weight and colour rather than the muted link
   treatment two rules above - declared AFTER them so it wins without a specificity
   fight - and takes the underline only on hover, so it reads as a heading first and
   a destination second. footer a{text-decoration:underline} is the rule overridden. */
.sitemap-title{font-size:.6875rem;text-transform:uppercase;letter-spacing:.1em;color:var(--text);font-weight:700;margin-bottom:.5rem;text-decoration:none}
.footer-sitemap a.sitemap-title{color:var(--text)}
.footer-sitemap a.sitemap-title:hover{color:var(--green);text-decoration:underline}
.sitemap-title .sitemap-ic{ width:2em; height:2em; color:var(--text);}

/* Mobile */
@media(max-width:900px){
  .platform-whats-wrap{flex-direction:column}
  .whats-label{display:none}
  .platform-section{padding:4rem 2rem}
  .whats-a-tool{padding:4rem 2rem}
  .platform-inner,.whats-inner{max-width:760px;margin:0 auto}
  .tool-lead{max-width:640px;margin:0 auto 2rem}
  .tool-anatomy{max-width:720px;margin:0 auto 2rem}
  .platform-features{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:768px){
  .docs-wrap{grid-template-columns:1fr}
  /* The rail goes away rather than stacking above the article: as a static block it
     put a screenful of nav in front of the first sentence of every short page. Its
     links reappear inside the phone menu (.site-menu), which the same breakpoint
     shows. */
  .docs-sidebar{display:none}
  /* Top padding must still clear the FIXED bar - collapsing it with the side
     padding slid every page's h1 underneath the bar on phones. */
  .docs-content{padding:1.75rem 1rem 1.5rem}
  .docs-content.no-mast{padding-top:calc(var(--site-bar-h) + 1.5rem)}
  .audience-card{
    --aud-card-display:flex;
    display:flex;flex-direction:column;
    gap:2rem;padding:2.5rem 1.25rem;
  }
  .audience-header{padding:3rem 1rem 1.25rem}
  .audience-title{font-size:1.875rem}
  .audience-tabs{gap:.375rem;padding:.625rem .75rem .875rem}
  .audience-tab{padding:.4rem .7rem}
  .tool-anatomy{gap:.5rem}
  .tool-plus{display:none}
  .tool-part{min-width:110px}
}
@media(max-width:480px){
  .platform-features{grid-template-columns:1fr}
  .tool-features{grid-template-columns:1fr}
  .card-benefits{grid-template-columns:1fr}
  .try-now-callout{position:static;transform:none;width:auto;margin-top:1.75rem;flex-direction:column;align-items:stretch}
  .try-now-callout .hero-btn{text-align:center;justify-content:center}
}



/* Dark mode. The token redefinitions that used to live here are gone: the DOCS_BRIDGE
   above maps --text/--muted/--border/--pale/--page onto the app's [data-theme]-driven
   slots, so dark mode falls out of tokens.css. The component rules below only restyle
   the few places that carry a hardcoded colour of their own. */
[data-theme="dark"] body{background:var(--page)}
[data-theme="dark"] .social-proof{background:hsl(var(--background))}
[data-theme="dark"] .social-proof h2{color:var(--text)}
[data-theme="dark"] .social-proof-desc{color:var(--muted)}
[data-theme="dark"] tr:nth-child(even) td{background:hsl(var(--muted) / 0.4)}
[data-theme="dark"] footer{border-top-color:var(--border)}
[data-theme="dark"] .docs-content h1,[data-theme="dark"] .docs-content h2,[data-theme="dark"] .docs-content h3{color:var(--text)}
[data-theme="dark"] th{color:var(--text)}
/* Code on a dark ground (dark AND brand - brand is a dark-teal theme with no
   [data-theme="brand"] overrides of its own, so it inherits the base rules; the
   base pre now uses hsl(var(--foreground)) so it is already legible, and these
   add the dark box + border for parity). Give inline code a dark surface + light
   text, and the pre block a dark box. The last rule keeps code inside pre
   background-free - [data-theme="dark"] .docs-content code would otherwise
   out-specify the base "pre code background none" reset. */
[data-theme="dark"] .docs-content code,[data-theme="brand"] .docs-content code{background:hsl(var(--muted));color:var(--text)}
[data-theme="dark"] .docs-content pre,[data-theme="brand"] .docs-content pre{background:hsl(var(--muted));color:var(--text);border:1px solid var(--border)}
/* The Warde page sets its two verse blocks as an inscription rather than as code.
   Scoped to the page so no other fenced block is touched. Centred and letterspaced
   because that is what the 1932 broadside and the 1940 bronze both do - the poem was
   cut in capitals for a titling face, and reading it as a listing loses the shape. */
.page-beatrice-warde .docs-content pre{font-family:'Cinzel',Georgia,serif;font-size:1.0625rem;line-height:2.05;letter-spacing:.055em;text-align:center;background:linear-gradient(#fbfaf7,#f4f2ec);color:#25313a;padding:2.5rem 1.5rem;border-radius:10px;box-shadow:inset 0 0 0 1px #0000000f,0 1px 2px #0000000a;white-space:pre-wrap;text-wrap:balance}
.page-beatrice-warde .docs-content pre code{font-family:inherit;font-size:inherit;background:none;padding:0}
[data-theme="dark"] .page-beatrice-warde .docs-content pre,[data-theme="brand"] .page-beatrice-warde .docs-content pre{background:linear-gradient(#12271d,#0d2016);color:#e8f0ea;box-shadow:inset 0 0 0 1px #ffffff14}
/* Shoulders of giants reads as a long editorial piece. Prose keeps a measure near
   seventy characters; the Newton epigraph stands unboxed over a standfirst with a drop
   cap; the Jefferson quotation keeps the house quotation style; the closing motto is
   set in Cinzel, as Warde's own broadside is on its page; and the appendix of credits
   drops to a quieter size. Figures keep the width they were drawn at, and on a phone
   they show at that size in a sideways scroll rather than shrinking their labels
   below reading size. */
.page-shoulders-of-giants .docs-content>:is(p,ul,h2,h3,blockquote,.doc-logo-block){max-width:38rem;margin-inline:auto}
.page-shoulders-of-giants .docs-content p,.page-shoulders-of-giants .docs-content li{text-wrap:pretty}
.page-shoulders-of-giants .docs-content blockquote p{font-size:1.1875rem;line-height:1.6;text-wrap:balance}
.page-shoulders-of-giants .docs-content blockquote p+p{font-size:.875rem;line-height:1.5;color:var(--muted);margin-top:.9rem;letter-spacing:.01em;text-wrap:pretty}
.page-shoulders-of-giants .docs-content blockquote:first-of-type{background:none;box-shadow:none;transform:none;border-radius:0;padding:0;margin:.5rem auto 2.75rem;max-width:30rem;text-align:center}
.page-shoulders-of-giants .docs-content blockquote:first-of-type p{font-size:1.375rem;line-height:1.45;font-style:italic}
.page-shoulders-of-giants .docs-content blockquote:first-of-type p+p{font-style:normal;font-size:.75rem;letter-spacing:.08em;text-transform:uppercase;margin-top:.8rem}
.page-shoulders-of-giants .docs-content blockquote:first-of-type+p{font-size:1.1875rem;line-height:1.7}
.page-shoulders-of-giants .docs-content blockquote:first-of-type+p::first-letter{float:left;font-size:3.35em;line-height:.86;font-weight:800;margin:.06em .1em 0 0;color:var(--green)}
.page-shoulders-of-giants .docs-content blockquote:last-of-type{background:none;box-shadow:none;transform:none;border-radius:0;padding:0;margin:3rem auto 4.5rem;text-align:center}
.page-shoulders-of-giants .docs-content blockquote:last-of-type::before{content:'';display:block;width:3rem;height:1px;background:var(--border);margin:0 auto 2.25rem}
.page-shoulders-of-giants .docs-content blockquote:last-of-type p{font-family:'Cinzel',Georgia,serif;font-size:1.75rem;font-weight:500;letter-spacing:.05em;line-height:1.35;color:var(--dark)}
.page-shoulders-of-giants .docs-content .docs-diagram{margin:3.5rem auto}
.page-shoulders-of-giants .docs-content #everyone-else-inside-lolly~:is(p,ul){font-size:.9375rem;line-height:1.6}
.page-shoulders-of-giants .docs-content #everyone-else-inside-lolly~ul li+li{margin-top:.45rem}
@media(max-width:640px){
  .page-shoulders-of-giants .docs-content blockquote{transform:none;margin:2.5rem 0}
  .page-shoulders-of-giants .docs-content blockquote:last-of-type p{font-size:1.375rem}
  .page-shoulders-of-giants .docs-content .docs-diagram{overflow-x:auto;overscroll-behavior-x:contain;margin-inline:-16px;padding:0 16px 12px}
  .page-shoulders-of-giants .docs-content .docs-diagram>img{max-width:none}
}
.docs-immersive{padding:0;margin:0}
.doc-audio{margin:0 0 .5rem;padding:0}
.doc-audio audio{width:100%;height:40px;display:block}
/* An audiogram MP4 is square (1080²) and would swamp the column at full width -
   cap it and centre it, letting its own aspect ratio set the height. The dark
   fill matches the audiogram's own background so the poster-load gap isn't black. */
.doc-video{margin:0 auto 1rem;max-width:min(420px,100%)}
.doc-video video{width:100%;height:auto;display:block;border-radius:10px;background:#0d1f17}
[data-theme="dark"] .docs-content pre code{background:none;color:inherit}
/* ── Pilot / prototype disclaimer badge (in the dark hero) ─────────────────── */
.hero-pilot{display:inline-flex;align-items:center;gap:.5rem;margin-bottom:3rem;padding:.34rem .36rem .34rem .55rem;background:rgba(254,124,63,.17);border-radius:999px;text-decoration:none;font-size:.8125rem;color:#ffd9c4;transition:background .15s}
.hero-pilot:hover{background:rgba(254,124,63,.26)}
.hero-pilot-tag{background:var(--orange);color:#2a0f04;font-weight:800;text-transform:uppercase;letter-spacing:.06em;font-size:.66rem;padding:.22em .62em;border-radius:999px}
.hero-pilot-text{padding-right:.35rem}
@media(max-width:600px){.hero-pilot-text{font-size:.74rem}}

/* RTL correctness (Arabic pages get dir="rtl" on <html>): code is Latin and
   always reads LTR - isolate it so surrounding RTL prose doesn't scramble
   leading/trailing punctuation. Mirrors the SPA's parts/rtl.css. */
[dir="rtl"] pre,[dir="rtl"] code,[dir="rtl"] kbd,[dir="rtl"] samp{direction:ltr;text-align:left;unicode-bidi:isolate}
.listen-bar{display:flex;justify-content:flex-end;gap:8px;margin:0 0 -8px}
.listen-bar-float{position:fixed;right:16px;bottom:16px;z-index:89;margin:0}
/* Phones only: docked under the top nav while the landing hero owns the screen, so the
   pill never sits on a hero CTA (plans/168 WP-6; the class comes from NAV_SOLID_JS). */
@media(max-width:600px){.listen-bar-float.over-hero{bottom:auto;top:calc(var(--site-bar-h) + 8px)}}
/* Listen and the print edition beside it are the app's button (buttons.css aliases
   both onto .btn: canvas fill, bevel, control elevation, panel radius, body type),
   finger-sized, with the app's glyph and the minutes in the muted ink. In the band
   they sit in the title row (.mast-title); on the landing Listen floats. */
.docs-listen,.docs-edition{display:inline-flex;align-items:center;gap:7px;min-height:var(--ui-size-target);box-sizing:border-box;font-weight:600;line-height:1.2}
.docs-listen:hover,.docs-edition:hover{background:var(--ui-color-surface-muted);text-decoration:none}
.docs-listen:focus-visible,.docs-edition:focus-visible{outline:2px solid var(--ui-color-focus-ring);outline-offset:2px}
.docs-listen svg,.docs-edition svg{width:16px;height:16px}
.docs-listen .listen-mins,.docs-edition .listen-mins{font-weight:400;color:var(--ui-color-text-muted)}
.docs-listen.is-loading{opacity:.6;pointer-events:none}
/* SPDX-License-Identifier: MPL-2.0 */
/* ── Docs reading components (plan 277 step 3) ─────────────────────────────
   One stylesheet for both readers: docs/build.ts reads it verbatim into the /info
   bundle, and the in-app reader (views/docs.ts, views/document-model.ts) imports it.
   Markup: packages/docs-render/src/components.ts. Behaviour: docs/reader/enhance.ts.

   Built from the app's token roles only (tokens.css), so a component looks the
   same on /info as in the app and follows Light, Dark, Brand and the active design
   system. /info's bridge re-points the two roles its legacy names shadow
   (surface-muted, border-default). The shapes follow the app's own primitives:
   the disclosure card is disclosure.css's section card at reading size, and the
   Copy control restates buttons.css's .btn base under its own class, because /info
   ships an unrelated global .btn from the landing stylesheet.

   Standing rules: meaning is carried by an icon, a label and a tinted fill, never
   by an accent-coloured edge; no negative letter spacing; sizes ride the a11y type
   multiplier, which falls back to 1 where it is not defined. */

.docs-content .doc-visually-hidden {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── Admonition: ::: note | warning | check ─────────────────────────────── */
.docs-content .doc-note {
  display: grid;
  grid-template-columns: calc(20px * var(--a11y-fs, 1)) minmax(0, 1fr);
  gap: 14px;
  margin: 20px 0;
  padding: 14px 18px;
  border-radius: var(--ui-radius-panel);
  background: var(--ui-color-surface-muted);
  font-size: calc(16px * var(--a11y-fs, 1));
  line-height: 1.55;
}
.docs-content .doc-note--check { background: color-mix(in srgb, var(--ui-color-action-primary) 12%, var(--ui-color-surface-muted)); }
/* Tinted into the muted surface rather than the canvas, so the tint still reads on the
   dark grounds (Dark, Brand), where a tint into the canvas all but vanished. */
.docs-content .doc-note--warning { background: color-mix(in srgb, var(--ui-color-status-danger) 14%, var(--ui-color-surface-muted)); }
.docs-content .doc-note-glyph { display: flex; margin-block-start: 2px; color: var(--ui-color-text-muted); }
.docs-content .doc-note--check .doc-note-glyph { color: var(--ui-color-action-primary); }
.docs-content .doc-note--warning .doc-note-glyph { color: color-mix(in oklab, var(--ui-color-status-danger) 60%, var(--ui-color-text-default)); }
.docs-content .doc-note-glyph svg { width: calc(20px * var(--a11y-fs, 1)); height: calc(20px * var(--a11y-fs, 1)); }
.docs-content .doc-note-title { font-weight: 600; line-height: 1.4; color: var(--ui-color-text-default); }
.docs-content .doc-note-body > :first-child { margin-block-start: 4px; }
.docs-content .doc-note-body > :last-child { margin-block-end: 0; }
.docs-content .doc-note-body p { margin: 6px 0 0; }

/* ── Disclosure: ::: details ─────────────────────────────────────────────── */
:is(.docs-content, .docs-compact-nav) .doc-details {
  margin: 12px 0;
  border-radius: var(--ui-radius-panel);
  background: color-mix(in srgb, var(--ui-color-surface-muted) 55%, transparent);
}
:is(.docs-content, .docs-compact-nav) .doc-details + .doc-details { margin-block-start: 8px; }
:is(.docs-content, .docs-compact-nav) .doc-details > summary {
  display: grid;
  grid-template-columns: calc(20px * var(--a11y-fs, 1)) minmax(0, 1fr) calc(20px * var(--a11y-fs, 1));
  gap: 16px;
  align-items: center;
  min-height: var(--ui-size-target, 44px);
  padding: 12px 16px;
  list-style: none;
  cursor: pointer;
  border-radius: var(--ui-radius-panel);
  font-size: calc(16px * var(--a11y-fs, 1));
  font-weight: 600;
  line-height: 1.4;
  color: var(--ui-color-text-default);
}
:is(.docs-content, .docs-compact-nav) .doc-details > summary::-webkit-details-marker { display: none; }
:is(.docs-content, .docs-compact-nav) .doc-details > summary::marker { content: ''; }
:is(.docs-content, .docs-compact-nav) .doc-details-glyph,
:is(.docs-content, .docs-compact-nav) .doc-details-chev { display: flex; align-items: center; justify-content: center; color: var(--ui-color-text-muted); }
:is(.docs-content, .docs-compact-nav) .doc-details-glyph { align-self: start; margin-block-start: 1px; }
:is(.docs-content, .docs-compact-nav) .doc-details-glyph svg,
:is(.docs-content, .docs-compact-nav) .doc-details-chev svg { width: calc(20px * var(--a11y-fs, 1)); height: calc(20px * var(--a11y-fs, 1)); }
:is(.docs-content, .docs-compact-nav) .doc-details-title { min-width: 0; overflow-wrap: anywhere; }
:is(.docs-content, .docs-compact-nav) .doc-details-chev { transition: transform var(--ui-motion-feedback, 150ms); }
:is(.docs-content, .docs-compact-nav) .doc-details[open] > summary .doc-details-chev { transform: rotate(90deg); }
:is(.docs-content, .docs-compact-nav) .doc-details:dir(rtl) > summary .doc-details-chev { transform: rotate(180deg); }
/* The glyph is lines of left-aligned text; right-to-left text aligns right. */
:is(.docs-content, .docs-compact-nav) .doc-details:dir(rtl) > summary .doc-details-glyph svg { transform: scaleX(-1); }
:is(.docs-content, .docs-compact-nav) .doc-details:dir(rtl)[open] > summary .doc-details-chev { transform: rotate(90deg); }
:is(.docs-content, .docs-compact-nav) .doc-details > summary:hover .doc-details-chev { color: var(--ui-color-text-default); }
:is(.docs-content, .docs-compact-nav) .doc-details > summary:focus-visible { outline: 2px solid var(--ui-color-focus-ring); outline-offset: 2px; }
/* The body starts under the title, past the icon column and its gap. */
:is(.docs-content, .docs-compact-nav) .doc-details-body { padding-block: 0 14px; padding-inline: calc(16px + 20px * var(--a11y-fs, 1) + 16px) 16px; }
:is(.docs-content, .docs-compact-nav) .doc-details-body > :first-child { margin-block-start: 0; }
:is(.docs-content, .docs-compact-nav) .doc-details-body > :last-child { margin-block-end: 0; }

/* The formats register in words (docs/build.ts formatsReference): a name and a
   description per format inside the family's disclosure. */
.docs-content .fmt-reference { margin: 1.5rem 0 2rem; }
.docs-content .fmt-ref-list { margin: 0; }
.docs-content .fmt-ref-list dt { margin: .9rem 0 .15rem; color: var(--ui-color-text-default); }
.docs-content .fmt-ref-list dt:first-child { margin-top: 0; }
.docs-content .fmt-ref-list dd { margin: 0; color: var(--ui-color-text-muted); line-height: 1.55; }

/* ── Code block: fenced code ─────────────────────────────────────────────── */
.docs-content .doc-code {
  margin: 16px 0 20px;
  min-width: 0;
  border-radius: var(--ui-radius-panel);
  background: var(--ui-color-surface-muted);
}
.docs-content li > .doc-code,
.docs-content li > pre { margin-block: 10px 4px; }
/* The bar is static markup with no text of its own: the label is the block's
   data-label, shown through generated content so it never enters the page text
   that search, the model index and narration read. The enhancer adds Copy. */
.docs-content .doc-code-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 52px;
  padding: 4px 4px 4px 16px;
  border-block-end: 1px solid var(--ui-color-border-default);
  color: var(--ui-color-text-muted);
  font-size: calc(13px * var(--a11y-fs, 1));
}
.docs-content .doc-code-bar::before { content: attr(data-label); min-width: 0; overflow-wrap: anywhere; }
/* A block without Copy needs only its label. */
.docs-content .doc-code:not([data-copy]) .doc-code-bar { min-height: 36px; }
.docs-content .doc-code pre {
  margin: 0;
  padding: 14px 16px;
  overflow-x: auto;
  max-width: 100%;
  background: none;
  box-shadow: none;
  border: 0;
  border-radius: 0 0 var(--ui-radius-panel) var(--ui-radius-panel);
  white-space: pre;
  overflow-wrap: normal;
  word-break: normal;
  tab-size: 2;
  direction: ltr;
  text-align: left;
  font-family: var(--ui-type-mono-family, var(--font-mono, monospace));
  font-size: calc(14px * var(--a11y-fs, 1));
  line-height: 1.6;
}
/* A short command may wrap between arguments, never inside one: no anywhere-breaks. */
.docs-content .doc-code[data-wrap] pre { white-space: pre-wrap; }
.docs-content .doc-code[data-wrap] .doc-code-token { white-space: nowrap; }
/* A wrapped command reads as one command: its continuation lines hang under the first.
   (Where each-line is unsupported the rule is dropped and the block keeps its padding.) */
.docs-content .doc-code[data-wrap] pre { padding-inline-start: calc(16px + 2ch); text-indent: -2ch each-line; }
.docs-content .doc-code pre code { font: inherit; background: none; padding: 0; color: inherit; white-space: inherit; overflow-wrap: inherit; }
.docs-content .doc-code pre:focus-visible { outline: 2px solid var(--ui-color-focus-ring); outline-offset: -2px; }

/* Copy, the app's button base under its own name. */
.docs-content .doc-copy-slot { position: relative; flex: 0 0 auto; }
.docs-content .doc-copy {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: var(--ui-size-target, 44px);
  padding: 0 14px;
  border: 0;
  border-radius: var(--ui-radius-panel);
  background: var(--ui-color-surface-canvas);
  color: var(--ui-color-text-default);
  box-shadow: var(--ui-effect-bevel), var(--ui-elevation-control);
  font: inherit;
  font-size: var(--ui-type-body, calc(13px * var(--a11y-fs, 1)));
  cursor: pointer;
  transition: background var(--ui-motion-feedback, 150ms);
}
/* The app's button hover (buttons.css, .tool-actions): the accent surface. */
.docs-content .doc-copy:hover { background: hsl(var(--accent)); }
.docs-content .doc-copy:focus-visible { outline: 2px solid var(--ui-color-focus-ring); outline-offset: 2px; }
.docs-content .doc-copy svg { width: calc(18px * var(--a11y-fs, 1)); height: calc(18px * var(--a11y-fs, 1)); flex: none; }
/* Feedback floats: anchored to Copy, outside the flow, so nothing on the page moves. */
.docs-content .doc-copy-toast {
  position: absolute;
  inset-block-start: calc(100% + 8px);
  inset-inline-end: 0;
  z-index: var(--ui-layer-toast, 60);
  translate: var(--doc-toast-shift, 0px) 0;
  padding: 7px 11px;
  border-radius: var(--ui-radius-control, 6px);
  background: var(--ui-color-text-default);
  color: var(--ui-color-surface-canvas);
  box-shadow: var(--ui-elevation-floating);
  font-size: calc(13px * var(--a11y-fs, 1));
  font-weight: 500;
  line-height: 1.35;
  white-space: nowrap;
  pointer-events: none;
}
.docs-content .doc-copy-toast[data-above] { inset-block-start: auto; inset-block-end: calc(100% + 8px); }
.docs-content .doc-copy-help {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  padding: 10px 16px 12px;
  border-block-start: 1px solid var(--ui-color-border-default);
  color: var(--ui-color-text-muted);
  font-size: calc(13px * var(--a11y-fs, 1));
}
.docs-content .doc-copy-help[hidden] { display: none; }

@media (max-width: 520px) {
  :is(.docs-content, .docs-compact-nav) .doc-details > summary { gap: 14px; padding-inline: 14px; }
  :is(.docs-content, .docs-compact-nav) .doc-details-body { padding-inline: calc(14px + 20px * var(--a11y-fs, 1) + 14px) 14px; }
  .docs-content .doc-note { padding: 14px; gap: 12px; }
  .docs-content .doc-code pre { padding: 12px 14px; font-size: calc(13px * var(--a11y-fs, 1)); }
}
@media (prefers-reduced-motion: reduce) {
  :is(.docs-content, .docs-compact-nav) .doc-details-chev { transition: none; }
}
html[data-a11y-motion="reduce"] :is(.docs-content, .docs-compact-nav) .doc-details-chev { transition: none; }
@media print {
  .docs-content .doc-copy-slot, .docs-content .doc-copy-help, .docs-content .doc-details-chev { display: none !important; }
  .docs-content .doc-details > .doc-details-body { display: block !important; }
  .docs-content .doc-details::details-content { content-visibility: visible !important; height: auto !important; }
  /* Paper has no tint, so a plain grey outline marks each box instead. */
  .docs-content .doc-note, .docs-content .doc-details { break-inside: avoid; background: none; box-shadow: none; outline: 1px solid #888; outline-offset: -1px; }
  .docs-content .doc-code { background: none; box-shadow: none; outline: 1px solid #888; outline-offset: -1px; }
  .docs-content .doc-code pre { white-space: pre-wrap; overflow: visible; }
}
