/* =========================================================================
   DALOREUM DESIGN SYSTEM
   Generated by ds/build.sh — DO NOT EDIT. Edit ds/src/*.css and rebuild.

   The layer order below is the whole cascade contract: later layers win
   regardless of selector specificity, so a utility always beats a component
   and a component always beats an element selector in base.

   `page` is reserved for a consuming site's own composition — put page-only
   rules in @layer page and they will never fight the system's specificity.
   ========================================================================= */
@layer reset, tokens, base, components, utilities, page;


/* ---- src/01-tokens.css ---- */
/* =========================================================================
   DALOREUM DESIGN SYSTEM — TOKENS
   Every value in the system originates here. Components never hard-code a
   colour, size, duration or easing; they consume these. Rebrand a property by
   overriding tokens alone.
   ========================================================================= */

@layer tokens {

  :root {
    color-scheme: light dark;

    /* ---- raw palette -----------------------------------------------------
       Sampled from the approved logo artwork
       (brand/00_SOURCE_EXACT_ORIGINAL/daloreum_original_user_approved_2048x1008.png),
       not chosen by eye. Do not "tidy" these values — they are the brand.
         ground  #010000   the artwork's field
         ivory   #f0eae1   the DALOREUM lettering
         sun     #f5431c   the rising sun, and the dot inside the A
       Anything else is derived with color-mix() so a palette change
       propagates instead of needing twelve hand-picked variants. */
    --ral-ink:        #050505;  /* just off the artwork's black, so transparent
                                   logo PNGs sit on it without a visible edge */
    --ral-ink-raised: #101011;
    --ral-ink-sunk:   #000000;
    --ral-bone:       #f0eae1;  /* brand ivory */
    --ral-bone-raised: #f7f3ec;
    --ral-bone-sunk:  #e3dcd1;

    --ral-signal:     #f5431c;  /* brand sun — primary action, live state */
    --ral-ultra:      #1b1fd6;  /* ultramarine — secondary block */
    --ral-acid:       #d8ff47;  /* highlight, used sparingly */

    --ral-positive:   #0f9d58;
    --ral-warning:    #e8a33d;
    --ral-danger:     #e02d17;

    /* ---- semantic colour -------------------------------------------------
       light-dark() keeps both themes in one declaration. The plain value on
       the line above is the fallback for engines without it. */
    --surface:        var(--ral-bone);
    --surface:        light-dark(var(--ral-bone), var(--ral-ink));
    --surface-raised: var(--ral-bone-raised);
    --surface-raised: light-dark(var(--ral-bone-raised), var(--ral-ink-raised));
    --surface-sunk:   var(--ral-bone-sunk);
    --surface-sunk:   light-dark(var(--ral-bone-sunk), var(--ral-ink-sunk));

    --text:           var(--ral-ink);
    --text:           light-dark(var(--ral-ink), var(--ral-bone));
    /* Measured against the darkest surface, not chosen for looks. At 62/40 the
       faint step landed at rgb(85,83,80) on #050505 — 2.66:1, below AA for the
       small uppercase labels that use it (eyebrows, index numbers, domains,
       field hints). 74/58 keeps three distinct steps and clears 4.5:1 on both
       themes. Lowering these re-breaks every label in the system. */
    --text-muted:     color-mix(in oklab, var(--text) 74%, var(--surface));
    --text-faint:     color-mix(in oklab, var(--text) 58%, var(--surface));

    /* Inverted pair, for blocks that flip the page's polarity. */
    --text-invert:    var(--ral-bone);
    --text-invert:    light-dark(var(--ral-bone), var(--ral-ink));
    --surface-invert: var(--ral-ink);
    --surface-invert: light-dark(var(--ral-ink), var(--ral-bone));

    --line:           color-mix(in oklab, var(--text) 22%, transparent);
    --line-strong:    color-mix(in oklab, var(--text) 78%, transparent);
    --line-faint:     color-mix(in oklab, var(--text) 10%, transparent);

    --accent:          var(--ral-signal);
    --accent-text:     #fff;               /* readable ON --accent */
    --accent-hover:    color-mix(in oklab, var(--accent) 86%, var(--text));
    --accent-active:   color-mix(in oklab, var(--accent) 72%, var(--text));
    --accent-wash:     color-mix(in oklab, var(--accent) 12%, var(--surface));

    --block:           var(--ral-ultra);
    --block-text:      #fff;

    --focus:           var(--ral-ultra);
    --focus:           light-dark(var(--ral-ultra), var(--ral-acid));
    --focus-ring:      3px;
    --focus-offset:    2px;

    --danger:          var(--ral-danger);
    --danger-wash:     color-mix(in oklab, var(--danger) 12%, var(--surface));
    --positive:        var(--ral-positive);
    --warning:         var(--ral-warning);

    /* ---- type ------------------------------------------------------------
       One superfamily. Archivo carries a width axis, so display type gets its
       drama from `font-stretch` rather than a second face — fewer bytes, more
       cohesion. */
    --font-display: "Archivo", "Helvetica Neue", Arial, sans-serif;
    --font-body:    "Archivo", "Helvetica Neue", Arial, sans-serif;
    --font-mono:    "Martian Mono", ui-monospace, "SF Mono", Menlo, monospace;

    --wdth-tight:   87;
    --wdth-normal: 100;
    --wdth-wide:   112;
    --wdth-widest: 125;

    /* Fluid modular scale, 1.25 at small / 1.333 at large.
       Every step interpolates between a 360px and a 1600px viewport. */
    --step--2: clamp(0.69rem, 0.67rem + 0.09vw, 0.75rem);
    --step--1: clamp(0.83rem, 0.79rem + 0.16vw, 0.94rem);
    --step-0:  clamp(1rem,    0.95rem + 0.24vw, 1.17rem);
    --step-1:  clamp(1.2rem,  1.12rem + 0.37vw, 1.46rem);
    --step-2:  clamp(1.44rem, 1.31rem + 0.56vw, 1.83rem);
    --step-3:  clamp(1.73rem, 1.54rem + 0.83vw, 2.29rem);
    --step-4:  clamp(2.07rem, 1.79rem + 1.22vw, 2.86rem);
    --step-5:  clamp(2.49rem, 2.08rem + 1.78vw, 3.58rem);
    --step-6:  clamp(2.99rem, 2.4rem + 2.55vw,  4.47rem);
    --step-7:  clamp(3.58rem, 2.76rem + 3.6vw,  5.59rem);
    /* Display steps intentionally break the scale — they are meant to bleed.
       Tuned so the longest word the site sets at each step ("COMPANIES." at
       --step-9, "hello@daloreum.com" at --step-8) stays on one line from
       360px up. Raising these without re-checking those two strings will wrap
       them, which reads as a bug rather than as scale. */
    --step-8:  clamp(1.7rem,  0.35rem + 5vw,   3.95rem);
    --step-9:  clamp(1.95rem, 0.22rem + 6.5vw, 5.65rem);

    --leading-flat:  0.86;
    --leading-tight: 1.05;
    --leading-snug:  1.25;
    --leading-body:  1.55;
    --leading-loose: 1.75;

    --tracking-display: -0.03em;
    --tracking-tight:   -0.015em;
    --tracking-normal:  0;
    --tracking-label:   0.16em;

    /* ---- space -----------------------------------------------------------
       Fluid so vertical rhythm compresses on small screens without a media
       query in every component. */
    --space-3xs: clamp(0.25rem, 0.24rem + 0.05vw, 0.31rem);
    --space-2xs: clamp(0.5rem,  0.48rem + 0.1vw,  0.58rem);
    --space-xs:  clamp(0.75rem, 0.71rem + 0.17vw, 0.88rem);
    --space-s:   clamp(1rem,    0.95rem + 0.24vw, 1.17rem);
    --space-m:   clamp(1.5rem,  1.43rem + 0.36vw, 1.75rem);
    --space-l:   clamp(2rem,    1.9rem + 0.49vw,  2.33rem);
    --space-xl:  clamp(3rem,    2.85rem + 0.73vw, 3.5rem);
    --space-2xl: clamp(4rem,    3.8rem + 0.97vw,  4.67rem);
    --space-3xl: clamp(6rem,    5.71rem + 1.46vw, 7rem);
    --space-4xl: clamp(8rem,    7.61rem + 1.94vw, 9.33rem);

    /* ---- layout ----------------------------------------------------------
       --gutter is the page's side margin; --shell the max text column. Both
       are read by .shell and by any component that needs to bleed past it. */
    --gutter: clamp(1.25rem, 0.9rem + 1.7vw, 3rem);
    --shell: 78rem;
    --measure: 62ch;
    --measure-tight: 44ch;

    /* ---- form ------------------------------------------------------------ */
    --control-height: 3rem;
    --control-height-sm: 2.25rem;
    --control-height-lg: 3.75rem;
    --control-padding: var(--space-s);

    /* ---- shape ----------------------------------------------------------- */
    --radius-0: 0;
    --radius-1: 2px;
    --radius-2: 4px;
    --radius-pill: 999px;
    --border: 1px;
    --border-heavy: 2px;

    /* ---- motion ---------------------------------------------------------- */
    --dur-1: 90ms;
    --dur-2: 180ms;
    --dur-3: 320ms;
    --dur-4: 560ms;
    --dur-5: 900ms;
    --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);
    --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
    --ease-snap:   cubic-bezier(0.2, 0.9, 0.1, 1);

    /* ---- layering --------------------------------------------------------
       Named so nothing invents a z-index. */
    --z-base: 0;
    --z-raised: 10;
    --z-sticky: 100;
    --z-overlay: 200;
    --z-modal: 300;
    --z-toast: 400;
  }

  /* Explicit theme overrides. Honour an author's choice over the OS in both
     directions — a page that only defines dark inside a media query cannot be
     forced light. */
  :root[data-theme="light"] { color-scheme: light; }
  :root[data-theme="dark"]  { color-scheme: dark; }
}

/* ---- src/02-reset.css ---- */
/* =========================================================================
   RESET
   Modern baseline only — no opinions that belong in base or components.
   ========================================================================= */

@layer reset {

  *, *::before, *::after { box-sizing: border-box; }

  /* Margin is a layout decision; components and utilities own it. */
  :where(body, h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ul, ol, pre) {
    margin: 0;
  }

  :where(ul[role="list"], ol[role="list"]) { list-style: none; padding: 0; }

  html {
    -webkit-text-size-adjust: none;
    text-size-adjust: none;
    /* Offset anchor targets so a sticky header never covers the heading. */
    scroll-padding-block-start: calc(var(--header-height, 4rem) + var(--space-m));
    /* Must be on the ROOT, not only on body. When one axis is clip and the
       other visible, the visible axis computes to auto, body stops propagating
       its overflow to the viewport, and wide descendants still scroll the page
       sideways — even inside an ancestor that is itself overflow:clip. This
       page scrolled 108px sideways at 390px wide with body alone. */
    overflow-x: clip;
  }

  @media (prefers-reduced-motion: no-preference) {
    html:focus-within { scroll-behavior: smooth; }
  }

  body { min-block-size: 100svb; }

  :where(img, picture, svg, video, canvas) {
    max-inline-size: 100%;
    block-size: auto;
    display: block;
  }

  :where(svg) { fill: currentColor; }
  :where(svg:not([fill="none"]) [stroke]) { stroke: currentColor; }

  /* Inherit type into form controls — the single most common source of a
     stray system font appearing mid-page. */
  :where(input, button, textarea, select, optgroup) {
    font: inherit;
    color: inherit;
    letter-spacing: inherit;
  }

  :where(textarea:not([rows])) { min-block-size: 8rem; }
  :where(textarea) { resize: vertical; }

  :where(button) { background: none; border: none; }
  :where(button, label[for], select, summary, [type="radio"], [type="checkbox"]) {
    cursor: pointer;
  }

  :where(table) { border-collapse: collapse; border-spacing: 0; }

  :where(p, li, h1, h2, h3, h4, h5, h6, dd, dt, figcaption) {
    overflow-wrap: break-word;
  }

  :where(hr) {
    border: none;
    border-block-start: var(--border) solid var(--line);
    margin-block: var(--space-l);
  }

  /* Every focusable thing gets the same visible ring, once, here. */
  :where(:focus-visible) {
    outline: var(--focus-ring) solid var(--focus);
    outline-offset: var(--focus-offset);
    border-radius: var(--radius-1);
  }
  :where(:focus:not(:focus-visible)) { outline: none; }

  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
      scroll-behavior: auto !important;
    }
  }

  /* Windows high-contrast: never let a colour-only affordance vanish. */
  @media (forced-colors: active) {
    :where(.btn, .input, .card, .badge) { border: 1px solid currentColor; }
  }
}

/* ---- src/03-base.css ---- */
/* =========================================================================
   BASE
   How unclassed HTML looks. Anything here should be true of every page.
   ========================================================================= */

@layer base {

  body {
    background: var(--surface);
    color: var(--text);
    font-family: var(--font-body);
    font-size: var(--step-0);
    font-weight: 400;
    line-height: var(--leading-body);
    font-variation-settings: "wdth" var(--wdth-normal);
    font-synthesis-weight: none;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overflow-x: clip;
  }

  /* ---- headings ---------------------------------------------------------
     Display weight and negative tracking scale together — large type needs
     tighter letterfit than the same face at reading size. */
  h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
    font-family: var(--font-display);
    font-weight: 700;
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tight);
    text-wrap: balance;
  }

  h1, .h1 { font-size: var(--step-7); font-weight: 800; letter-spacing: var(--tracking-display); line-height: var(--leading-flat); }
  h2, .h2 { font-size: var(--step-5); font-weight: 800; letter-spacing: var(--tracking-display); }
  h3, .h3 { font-size: var(--step-3); }
  h4, .h4 { font-size: var(--step-2); }
  h5, .h5 { font-size: var(--step-1); }
  h6, .h6 { font-size: var(--step-0); }

  p { text-wrap: pretty; }

  strong, b { font-weight: 700; }
  small    { font-size: var(--step--1); }

  code, kbd, samp, pre {
    font-family: var(--font-mono);
    font-size: 0.86em;
    font-variant-ligatures: none;
  }

  :not(pre) > code {
    background: var(--surface-sunk);
    padding: 0.15em 0.4em;
    border-radius: var(--radius-1);
  }

  pre {
    background: var(--surface-sunk);
    padding: var(--space-s);
    overflow-x: auto;
    border-inline-start: var(--border-heavy) solid var(--accent);
  }

  /* ---- links ------------------------------------------------------------
     The underline is drawn as a background so it can animate from 0 to full
     width; text-decoration cannot. */
  a {
    color: inherit;
    text-decoration: none;
  }

  .link,
  .prose a {
    background-image: linear-gradient(currentColor, currentColor);
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 100% 1px;
    padding-block-end: 0.08em;
    transition: background-size var(--dur-3) var(--ease-out),
                color var(--dur-2) var(--ease-out);
  }
  .link:hover,
  .prose a:hover {
    color: var(--accent);
    background-size: 0 1px;
    background-position: 100% 100%;
  }

  ::selection { background: var(--accent); color: var(--accent-text); }

  /* ---- prose ------------------------------------------------------------
     One class for any run of authored copy. Spacing uses the lobotomised owl
     so it never doubles up on the first or last child. */
  .prose {
    max-inline-size: var(--measure);
    line-height: var(--leading-loose);
    color: var(--text-muted);
  }
  .prose > * + *      { margin-block-start: var(--space-s); }
  .prose > * + :is(h2, h3, h4) { margin-block-start: var(--space-l); }
  .prose :is(h2, h3, h4) { color: var(--text); }
  .prose > ul, .prose > ol { padding-inline-start: 1.25em; }
  .prose li + li { margin-block-start: var(--space-2xs); }
  .prose blockquote {
    border-inline-start: var(--border-heavy) solid var(--accent);
    padding-inline-start: var(--space-s);
    font-size: var(--step-1);
    color: var(--text);
  }
}

/* ---- src/04-components.css ---- */
/* =========================================================================
   COMPONENTS
   Every interactive element in the system. Nothing outside this file should
   style a button, a field, or a search box.
   ========================================================================= */

@layer components {

  /* =======================================================================
     BUTTON  —  .btn
     .btn--primary | --secondary | --ghost | --danger
     .btn--sm | --lg   .btn--block   .btn--sharp   .btn--icon
     Works on <button>, <a>, and <input type=submit> identically.
     ===================================================================== */
  .btn {
    --_bg: transparent;
    --_fg: var(--text);
    --_border: var(--line-strong);
    --_lift: 0px;

    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2xs);
    min-block-size: var(--control-height);
    padding-inline: var(--space-m);
    padding-block: 0;

    font-family: var(--font-body);
    font-size: var(--step--1);
    font-weight: 600;
    font-variation-settings: "wdth" var(--wdth-normal);
    line-height: 1;
    letter-spacing: 0.02em;
    text-align: center;
    white-space: nowrap;

    background: var(--_bg);
    color: var(--_fg);
    border: var(--border-heavy) solid var(--_border);
    border-radius: var(--radius-pill);

    translate: 0 var(--_lift);
    transition: background-color var(--dur-2) var(--ease-out),
                color var(--dur-2) var(--ease-out),
                border-color var(--dur-2) var(--ease-out),
                translate var(--dur-2) var(--ease-snap);
    user-select: none;
  }

  /* Arrows and icons drift on hover — the whole affordance, not just colour. */
  .btn > .btn__icon {
    inline-size: 1em;
    block-size: 1em;
    flex: none;
    transition: translate var(--dur-3) var(--ease-snap);
  }
  .btn:hover > .btn__icon { translate: 0.25em 0; }

  .btn:hover  { --_lift: -2px; }
  .btn:active { --_lift: 0px; transition-duration: var(--dur-1); }

  .btn[disabled], .btn[aria-disabled="true"] {
    opacity: 0.4;
    pointer-events: none;
  }

  .btn--primary {
    --_bg: var(--accent);
    --_fg: var(--accent-text);
    --_border: var(--accent);
  }
  .btn--primary:hover  { --_bg: var(--accent-hover);  --_border: var(--accent-hover); }
  .btn--primary:active { --_bg: var(--accent-active); --_border: var(--accent-active); }

  .btn--secondary {
    --_bg: transparent;
    --_fg: var(--text);
    --_border: var(--line-strong);
  }
  .btn--secondary:hover {
    --_bg: var(--text);
    --_fg: var(--surface);
    --_border: var(--text);
  }

  .btn--ghost {
    --_border: transparent;
    padding-inline: var(--space-s);
  }
  .btn--ghost:hover { --_bg: var(--surface-sunk); }

  .btn--danger {
    --_bg: var(--danger);
    --_fg: #fff;
    --_border: var(--danger);
  }

  .btn--sm { min-block-size: var(--control-height-sm); padding-inline: var(--space-s); font-size: var(--step--2); }
  .btn--lg { min-block-size: var(--control-height-lg); padding-inline: var(--space-l); font-size: var(--step-0); }
  .btn--block { display: flex; inline-size: 100%; }
  .btn--sharp { border-radius: var(--radius-0); }
  .btn--icon  { padding-inline: 0; aspect-ratio: 1; }

  /* =======================================================================
     FIELD  —  .field wraps label + control + hint/error
     ===================================================================== */
  .field {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
  }

  .field__label {
    font-family: var(--font-mono);
    font-size: var(--step--2);
    font-weight: 500;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--text-muted);
  }
  .field__label[data-required]::after {
    content: "*";
    color: var(--accent);
    margin-inline-start: 0.25em;
  }

  .field__hint {
    font-size: var(--step--1);
    color: var(--text-faint);
  }
  .field__error {
    font-size: var(--step--1);
    font-weight: 600;
    color: var(--danger);
  }

  /* The label turns red when the field it contains is invalid — the state
     lives on the control, so :has() is what carries it up to the wrapper. */
  .field:has(.input[aria-invalid="true"]) .field__label { color: var(--danger); }

  /* ---- the control itself ---------------------------------------------- */
  .input {
    inline-size: 100%;
    min-block-size: var(--control-height);
    padding-inline: var(--control-padding);
    padding-block: 0.6em;

    font-size: var(--step-0);
    color: var(--text);
    background: var(--surface-raised);
    border: var(--border-heavy) solid var(--line);
    border-radius: var(--radius-0);

    transition: border-color var(--dur-2) var(--ease-out),
                background-color var(--dur-2) var(--ease-out);
  }
  .input::placeholder { color: var(--text-faint); opacity: 1; }
  .input:hover { border-color: color-mix(in oklab, var(--text) 45%, transparent); }
  .input:focus-visible {
    border-color: var(--text);
    background: var(--surface);
  }
  .input[aria-invalid="true"] {
    border-color: var(--danger);
    background: var(--danger-wash);
  }
  .input[disabled], .input[readonly] {
    background: var(--surface-sunk);
    color: var(--text-faint);
    cursor: not-allowed;
  }

  /* Grows with its content instead of scrolling. */
  textarea.input { field-sizing: content; min-block-size: 6rem; line-height: var(--leading-body); }

  /* Native select keeps the OS dropdown but takes our chrome. */
  select.input {
    appearance: none;
    padding-inline-end: calc(var(--control-padding) * 2.5);
    background-image:
      linear-gradient(45deg, transparent 50%, currentColor 50%),
      linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position:
      right calc(var(--control-padding) + 6px) center,
      right var(--control-padding) center;
    background-size: 6px 6px, 6px 6px;
    background-repeat: no-repeat;
  }

  /* =======================================================================
     SEARCH  —  .search
     A labelled input with a leading glyph and a clear button that only
     appears once there is something to clear.
     ===================================================================== */
  .search {
    --_pad: var(--control-padding);
    position: relative;
    display: flex;
    align-items: center;
    inline-size: 100%;
    max-inline-size: 32rem;
  }

  .search__icon {
    position: absolute;
    inset-inline-start: var(--_pad);
    inline-size: 1.05em;
    block-size: 1.05em;
    color: var(--text-faint);
    pointer-events: none;
    transition: color var(--dur-2) var(--ease-out);
  }

  .search .input {
    padding-inline-start: calc(var(--_pad) * 2 + 1.05em);
    padding-inline-end: calc(var(--_pad) * 2 + 1em);
    border-radius: var(--radius-pill);
  }

  .search:focus-within .search__icon { color: var(--accent); }

  .search__clear {
    position: absolute;
    inset-inline-end: calc(var(--_pad) / 1.5);
    display: grid;
    place-items: center;
    inline-size: 1.75em;
    block-size: 1.75em;
    border-radius: var(--radius-pill);
    color: var(--text-faint);
    opacity: 0;
    scale: 0.8;
    pointer-events: none;
    transition: opacity var(--dur-2) var(--ease-out),
                scale var(--dur-2) var(--ease-snap),
                color var(--dur-2) var(--ease-out),
                background-color var(--dur-2) var(--ease-out);
  }
  /* Reveal only when the input is non-empty. No JS needed for the state. */
  .search:has(.input:not(:placeholder-shown)) .search__clear {
    opacity: 1;
    scale: 1;
    pointer-events: auto;
  }
  .search__clear:hover { color: var(--text); background: var(--surface-sunk); }

  .search--sm .input { min-block-size: var(--control-height-sm); font-size: var(--step--1); }
  .search--lg .input { min-block-size: var(--control-height-lg); font-size: var(--step-1); }

  /* =======================================================================
     CHOICE  —  checkbox, radio, switch
     Custom-drawn but driven by the real input, so keyboard and AT behaviour
     are the platform's, not ours.
     ===================================================================== */
  .choice {
    display: inline-flex;
    align-items: flex-start;
    gap: var(--space-xs);
    line-height: var(--leading-snug);
  }

  .choice__control {
    appearance: none;
    flex: none;
    inline-size: 1.35em;
    block-size: 1.35em;
    margin: 0;
    margin-block-start: 0.1em;
    background: var(--surface-raised);
    border: var(--border-heavy) solid var(--line-strong);
    border-radius: var(--radius-0);
    display: grid;
    place-content: center;
    transition: background-color var(--dur-2) var(--ease-out),
                border-color var(--dur-2) var(--ease-out);
  }
  .choice__control[type="radio"] { border-radius: var(--radius-pill); }

  .choice__control::before {
    content: "";
    inline-size: 0.65em;
    block-size: 0.65em;
    scale: 0;
    transition: scale var(--dur-2) var(--ease-snap);
    background: var(--accent-text);
    clip-path: polygon(14% 44%, 0 60%, 40% 100%, 100% 18%, 84% 4%, 38% 68%);
  }
  .choice__control[type="radio"]::before {
    clip-path: none;
    border-radius: var(--radius-pill);
    inline-size: 0.5em;
    block-size: 0.5em;
  }
  .choice__control:checked {
    background: var(--accent);
    border-color: var(--accent);
  }
  .choice__control:checked::before { scale: 1; }
  .choice__control:indeterminate {
    background: var(--accent);
    border-color: var(--accent);
  }
  .choice__control:indeterminate::before {
    scale: 1;
    clip-path: polygon(0 38%, 100% 38%, 100% 62%, 0 62%);
  }
  .choice:has(.choice__control[disabled]) { opacity: 0.45; pointer-events: none; }

  /* switch */
  .switch { display: inline-flex; align-items: center; gap: var(--space-xs); }
  .switch__control {
    appearance: none;
    flex: none;
    inline-size: 3rem;
    block-size: 1.6rem;
    margin: 0;
    padding: 2px;
    background: var(--surface-sunk);
    border: var(--border-heavy) solid var(--line-strong);
    border-radius: var(--radius-pill);
    display: flex;
    align-items: center;
    transition: background-color var(--dur-2) var(--ease-out),
                border-color var(--dur-2) var(--ease-out);
  }
  .switch__control::before {
    content: "";
    inline-size: 1.05rem;
    block-size: 1.05rem;
    border-radius: var(--radius-pill);
    background: var(--text);
    translate: 0;
    transition: translate var(--dur-3) var(--ease-snap),
                background-color var(--dur-2) var(--ease-out);
  }
  .switch__control:checked {
    background: var(--accent);
    border-color: var(--accent);
  }
  .switch__control:checked::before {
    translate: 1.35rem 0;
    background: var(--accent-text);
  }

  /* =======================================================================
     BADGE  —  .badge  (.badge--live / --wip / --danger)
     ===================================================================== */
  .badge {
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    padding: 0.35em 0.7em;
    font-family: var(--font-mono);
    font-size: var(--step--2);
    font-weight: 500;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    line-height: 1;
    color: var(--text-muted);
    border: var(--border) solid var(--line);
    border-radius: var(--radius-0);
    white-space: nowrap;
  }
  .badge::before {
    content: "";
    inline-size: 0.45em;
    block-size: 0.45em;
    border-radius: var(--radius-pill);
    background: currentColor;
  }
  .badge--live   { color: var(--accent); border-color: color-mix(in oklab, var(--accent) 45%, transparent); }
  .badge--wip    { color: var(--warning); border-color: color-mix(in oklab, var(--warning) 45%, transparent); }
  .badge--danger { color: var(--danger); border-color: color-mix(in oklab, var(--danger) 45%, transparent); }
  .badge--solid  { color: var(--accent-text); background: var(--accent); border-color: var(--accent); }

  /* =======================================================================
     CARD  —  .card
     Container queries: the card restyles on its own width, so the same markup
     works in a sidebar and a full-bleed grid without variant classes.
     ===================================================================== */
  .card {
    container-type: inline-size;
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-m);
    background: var(--surface-raised);
    border: var(--border-heavy) solid var(--line);
    border-radius: var(--radius-0);
    transition: border-color var(--dur-2) var(--ease-out),
                background-color var(--dur-2) var(--ease-out);
  }
  a.card:hover, .card--interactive:hover {
    border-color: var(--text);
    background: var(--surface);
  }
  .card__title { font-size: var(--step-2); }
  .card__body  { color: var(--text-muted); }
  .card__foot  { margin-block-start: auto; padding-block-start: var(--space-s); }

  @container (min-width: 30rem) {
    .card { padding: var(--space-l); }
    .card__title { font-size: var(--step-3); }
  }

  /* =======================================================================
     TABLE  —  .table
     ===================================================================== */
  .table-scroll { overflow-x: auto; }
  .table {
    inline-size: 100%;
    font-size: var(--step--1);
  }
  .table :is(th, td) {
    padding: var(--space-xs) var(--space-s);
    text-align: start;
    border-block-end: var(--border) solid var(--line-faint);
  }
  .table th {
    font-family: var(--font-mono);
    font-size: var(--step--2);
    font-weight: 500;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--text-faint);
    border-block-end-color: var(--line-strong);
  }
  .table tbody tr { transition: background-color var(--dur-2) var(--ease-out); }
  .table tbody tr:hover { background: var(--surface-sunk); }
  .table td:last-child, .table th:last-child { text-align: end; }

  /* =======================================================================
     NAV  —  .nav
     ===================================================================== */
  .nav { display: flex; align-items: center; gap: var(--space-m); }
  .nav__link {
    position: relative;
    font-family: var(--font-mono);
    font-size: var(--step--2);
    font-weight: 500;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--text-muted);
    padding-block: 0.35em;
    transition: color var(--dur-2) var(--ease-out);
  }
  .nav__link::after {
    content: "";
    position: absolute;
    inset-block-end: 0;
    inset-inline-start: 0;
    inline-size: 100%;
    block-size: var(--border-heavy);
    background: var(--accent);
    scale: 0 1;
    transform-origin: left;
    transition: scale var(--dur-3) var(--ease-out);
  }
  .nav__link:hover, .nav__link[aria-current] { color: var(--text); }
  .nav__link:hover::after, .nav__link[aria-current]::after { scale: 1 1; }

  /* =======================================================================
     EYEBROW / SECTION RULE
     ===================================================================== */
  .eyebrow {
    display: flex;
    align-items: center;
    gap: var(--space-s);
    font-family: var(--font-mono);
    font-size: var(--step--2);
    font-weight: 500;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--text-faint);
  }
  .eyebrow--ruled::after {
    content: "";
    flex: 1;
    block-size: var(--border);
    background: var(--line);
  }

  .rule-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-s);
    padding-block-end: var(--space-2xs);
    border-block-end: var(--border-heavy) solid var(--text);
    font-family: var(--font-mono);
    font-size: var(--step--2);
    font-weight: 500;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
  }

  /* =======================================================================
     MARQUEE  —  .marquee
     The band of company names. Duplicated track so the loop is seamless; the
     copy is aria-hidden so screen readers hear the list once.
     ===================================================================== */
  .marquee {
    --_speed: 38s;
    display: flex;
    overflow: hidden;
    user-select: none;
    mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  }
  .marquee__track {
    display: flex;
    flex: none;
    align-items: center;
    gap: var(--space-l);
    padding-inline-end: var(--space-l);
    min-inline-size: max-content;
    animation: marquee-scroll var(--_speed) linear infinite;
  }
  .marquee:hover .marquee__track { animation-play-state: paused; }
  .marquee--reverse .marquee__track { animation-direction: reverse; }

  @keyframes marquee-scroll {
    to { translate: -100% 0; }
  }

  .marquee__item {
    font-family: var(--font-display);
    font-size: var(--step-6);
    font-weight: 800;
    font-variation-settings: "wdth" var(--wdth-widest);
    letter-spacing: var(--tracking-display);
    line-height: 1;
    text-transform: uppercase;
    white-space: nowrap;
  }
  .marquee__item--outline {
    color: transparent;
    -webkit-text-stroke: 1.5px var(--text);
  }
  .marquee__sep {
    flex: none;
    inline-size: 0.5em;
    block-size: 0.5em;
    background: var(--accent);
  }

  /* =======================================================================
     BLOCK  —  hard colour panels, the spine of the kinetic direction
     ===================================================================== */
  .block {
    background: var(--surface-invert);
    color: var(--text-invert);
    --line: color-mix(in oklab, var(--text-invert) 22%, transparent);
    --line-strong: color-mix(in oklab, var(--text-invert) 78%, transparent);
    --line-faint: color-mix(in oklab, var(--text-invert) 10%, transparent);
    --text: var(--text-invert);
    --text-muted: color-mix(in oklab, var(--text-invert) 66%, var(--surface-invert));
    --text-faint: color-mix(in oklab, var(--text-invert) 44%, var(--surface-invert));
    --surface: var(--surface-invert);
    --surface-raised: color-mix(in oklab, var(--surface-invert) 92%, var(--text-invert));
    --surface-sunk: color-mix(in oklab, var(--surface-invert) 96%, var(--text-invert));
  }
  .block--accent { --surface-invert: var(--accent); --text-invert: var(--accent-text); }
  .block--ultra  { --surface-invert: var(--block); --text-invert: var(--block-text); }
}

/* ---- src/05-layout.css ---- */
/* =========================================================================
   LAYOUT + UTILITIES
   Composable primitives. Prefer these over one-off margins in a page.
   ========================================================================= */

@layer utilities {

  /* ---- shell ------------------------------------------------------------
     The page's measure. Named grid columns let a child opt into bleeding
     past the gutter without leaving the flow — no negative margins. */
  .shell {
    display: grid;
    grid-template-columns:
      [full-start] var(--gutter)
      [content-start] minmax(0, var(--shell))
      [content-end] var(--gutter)
      [full-end];
  }
  .shell > *          { grid-column: content; }
  .shell > .bleed     { grid-column: full; }
  .shell > .bleed-end { grid-column: content-start / full-end; }
  .shell > .bleed-start { grid-column: full-start / content-end; }

  /* ---- stack / cluster / grid ------------------------------------------- */
  .stack { display: flex; flex-direction: column; }
  .stack > * + * { margin-block-start: var(--gap, var(--space-s)); }

  .cluster {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--gap, var(--space-s));
  }
  .cluster--between { justify-content: space-between; }
  .cluster--end     { justify-content: flex-end; }

  /* Auto-fitting grid — no breakpoints, columns fall out of the min width. */
  .grid-auto {
    display: grid;
    gap: var(--gap, var(--space-m));
    grid-template-columns: repeat(auto-fit, minmax(min(var(--min, 18rem), 100%), 1fr));
  }

  .section { padding-block: var(--space-3xl); }
  .section--tight { padding-block: var(--space-xl); }

  /* ---- type utilities ---------------------------------------------------- */
  .display {
    font-family: var(--font-display);
    font-weight: 800;
    font-variation-settings: "wdth" var(--wdth-widest);
    font-size: var(--step-8);
    line-height: var(--leading-flat);
    letter-spacing: var(--tracking-display);
    text-transform: uppercase;
    text-wrap: balance;
  }
  .display--xl { font-size: var(--step-9); }
  .display--outline {
    color: transparent;
    -webkit-text-stroke: 2px var(--text);
  }

  .mono {
    font-family: var(--font-mono);
    font-size: var(--step--2);
    font-weight: 500;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
  }

  .measure       { max-inline-size: var(--measure); }
  .measure-tight { max-inline-size: var(--measure-tight); }

  .text-muted { color: var(--text-muted); }
  .text-faint { color: var(--text-faint); }
  .text-accent { color: var(--accent); }
  .text-end   { text-align: end; }

  /* ---- a11y -------------------------------------------------------------- */
  .visually-hidden:not(:focus):not(:active) {
    clip-path: inset(50%);
    block-size: 1px;
    inline-size: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
  }

  .skip-link {
    position: absolute;
    inset-block-start: var(--space-xs);
    inset-inline-start: var(--space-xs);
    z-index: var(--z-toast);
    padding: var(--space-2xs) var(--space-s);
    background: var(--accent);
    color: var(--accent-text);
    font-weight: 600;
    translate: 0 -200%;
    transition: translate var(--dur-2) var(--ease-out);
  }
  .skip-link:focus { translate: 0; }
}

/* ---- src/06-motion.css ---- */
/* =========================================================================
   MOTION

   ONE RULE, and it is not negotiable: a scroll-driven animation may never be
   the thing that makes content visible. An element below the viewport sits at
   0% progress, so `from { opacity: 0 }` on a scroll timeline means the content
   is genuinely absent — to a full-page screenshot, to print, to find-in-page,
   and to anyone who lands on an anchor deep in the document. Scroll animations
   here therefore move things; they never reveal them.

   Fades belong on .rise, which runs on a time timeline and always completes.
   ========================================================================= */

@layer utilities {

  /* Animatable custom property, so a rule or underline can be tweened. */
  @property --reveal {
    syntax: "<percentage>";
    inherits: false;
    initial-value: 0%;
  }

  /* ---- entrance (time-based, safe to fade) ------------------------------
     Runs once on load. Stagger with --d. Because it is time-driven it always
     reaches its end state, so opacity is fine here. */
  @media (prefers-reduced-motion: no-preference) {
    .rise {
      animation: rise var(--dur-5) var(--ease-out) both;
      animation-delay: var(--d, 0ms);
    }
  }
  @keyframes rise {
    from { opacity: 0; translate: 0 2rem; }
    to   { opacity: 1; translate: 0; }
  }

  /* ---- scroll-driven (motion only, never opacity) ----------------------- */
  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      /* Content slides up as it enters. Fully legible at every point. */
      .reveal {
        animation: reveal-shift linear both;
        animation-timeline: view();
        animation-range: entry 0% entry 90%;
      }

      /* The core kinetic move: letterforms widen on the width axis as the
         line scrolls through. Type is readable the entire time — only its
         proportions change. */
      .kinetic {
        animation: kinetic-width linear both;
        animation-timeline: view();
        animation-range: entry 10% cover 40%;
      }

      /* Horizontal drift for full-bleed bands, driven by page scroll. */
      .drift {
        animation: drift linear both;
        animation-timeline: scroll(root block);
      }
      .drift--reverse { animation-direction: reverse; }

      /* Rule that fills as the page is read. Decorative, so scale is safe. */
      .scroll-rule {
        animation: scroll-rule linear both;
        animation-timeline: scroll(root block);
        transform-origin: left;
      }
    }
  }

  @keyframes reveal-shift {
    from { translate: 0 2.5rem; }
    to   { translate: 0 0; }
  }

  @keyframes kinetic-width {
    from { font-variation-settings: "wdth" 74;  letter-spacing: 0.02em; }
    to   { font-variation-settings: "wdth" 125; letter-spacing: var(--tracking-display); }
  }

  @keyframes drift {
    from { translate: 5% 0; }
    to   { translate: -5% 0; }
  }

  @keyframes scroll-rule {
    from { scale: 0 1; }
    to   { scale: 1 1; }
  }

  /* ---- view transitions -------------------------------------------------
     Cross-document, so moving between pages cuts instead of flashing white. */
  @view-transition { navigation: auto; }

  @media (prefers-reduced-motion: no-preference) {
    ::view-transition-old(root) { animation: vt-out var(--dur-3) var(--ease-in-out) both; }
    ::view-transition-new(root) { animation: vt-in  var(--dur-4) var(--ease-out) both; }
  }
  @keyframes vt-out { to   { opacity: 0; translate: 0 -1rem; } }
  @keyframes vt-in  { from { opacity: 0; translate: 0 1.5rem; } }

  /* ---- print -------------------------------------------------------------
     Belt and braces: nothing animated may carry a transform or a faded state
     onto paper. */
  @media print {
    .rise, .reveal, .kinetic, .drift, .scroll-rule {
      animation: none !important;
      opacity: 1 !important;
      translate: none !important;
      scale: none !important;
    }
    .marquee__track { animation: none !important; }
  }
}
