/* ────────────────────────────────────────────────────────────────────────────
   VENDORED. This file is BUILT in amber-design-system and copied here.
   DO NOT EDIT IT. Edit the system and re-copy:

     cd ~/Code/amber-design-system && npm run build
     cp dist/amber.css ~/Code/git/amber.css && python3 tools/build-partials.py

   source: github.com/arpitmaheshwari/amber-design-system @ main (dist unchanged since v1.0.0)
   consumer: site.css (this repo), layered after this file on the same @layer order.
   ──────────────────────────────────────────────────────────────────────────── */
/* amber-design-system — built distribution. GENERATED by scripts/build-css.mjs.
   Do not edit: edit src/ or tokens/ and rebuild (npm run build:css).

   THE LAYER ORDER IS THE CONTRACT. A later layer beats an earlier one regardless of
   specificity or source order, so a consumer puts its own rules in `overrides` and
   never has to win a specificity argument with this file.

     reset → tokens → ground → type → layout → components → utilities → overrides

   Fonts are NOT bundled: the consumer serves them (see tokens/fonts.css).
*/
@layer reset, tokens, ground, type, layout, components, utilities, overrides;

/* ══════════════════════════ layer: reset ══════════════════════════ */
@layer reset {

/* ── src/00-reset.css ── */
/* layer: reset — the smallest reset that removes surprises and nothing else. */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; }
img, svg, video, canvas { max-width: 100%; height: auto; display: block; }
button, input, select, textarea { font: inherit; color: inherit; }
/* A reveal must never animate opacity from 0: animation-fill-mode:both inside a
   position:sticky ancestor pins the element at 0 forever. Measured on a prototype
   where 37 of 37 elements vanished. Animate transform; leave opacity alone. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

}

/* ══════════════════════════ layer: tokens ══════════════════════════ */
@layer tokens {

/* ── tokens/palette.css ── */
/* Amber · TIER 1 — base palette. GENERATED by scripts/build-palette.mjs.
   Do not hand-edit: re-run the generator. Every value below is a ramp stop, and
   every stop carries its measured contrast against the system's two grounds.

   Provenance: [pilot] hue and the two grounds come from the A1 pilots on
   arpitmaheshwari.com (o2 case study + homepage, 2026-09-12). [gen] everything
   else is computed — steps are even in Oklch L*, so amber-600 and violet-600
   read as the same weight.

   grounds:  paper #F5EEDF   bookend #140C16
   columns:  hex · contrast on paper · contrast on bookend
*/
:root {

  /* amber — [pilot] accent #7D4B00 measures H 67.2 C 0.102; #FFC46B on dark measures H 76.0 C 0.126 */
  --amber-50      : #FFF0C0;  /* paper 1.02  · bookend 16.89 */
  --amber-100     : #FFD49C;  /* paper 1.20  · bookend 13.85 */
  --amber-200     : #F0BA7B;  /* paper 1.51  · bookend 10.98 */
  --amber-300     : #D9A15D;  /* paper 1.97  · bookend 8.42 */
  --amber-400     : #C28942;  /* paper 2.62  · bookend 6.35 */
  --amber-500     : #A97228;  /* paper 3.55  · bookend 4.68 */
  --amber-600     : #905C0C;  /* paper 4.88  · bookend 3.40 */
  --amber-700     : #764700;  /* paper 6.80  · bookend 2.44 */
  --amber-800     : #5C3400;  /* paper 9.34  · bookend 1.78 */
  --amber-900     : #432300;  /* paper 12.29 · bookend 1.35 */

  /* neutral — [pilot] the paper-to-ink axis. #F5EEDF C 0.021, #3F3322 C 0.033, #584E3C C 0.031 — a WARM grey, which is why paper and ink belong to each other */
  --neutral-50    : #FFF7EA;  /* paper 1.09  · bookend 18.05 */
  --neutral-100   : #E7DDCE;  /* paper 1.16  · bookend 14.29 */
  --neutral-200   : #CFC4B4;  /* paper 1.49  · bookend 11.16 */
  --neutral-300   : #B7AC9B;  /* paper 1.94  · bookend 8.58 */
  --neutral-400   : #9F9483;  /* paper 2.58  · bookend 6.43 */
  --neutral-500   : #887D6D;  /* paper 3.49  · bookend 4.75 */
  --neutral-600   : #716757;  /* paper 4.81  · bookend 3.46 */
  --neutral-700   : #5B5244;  /* paper 6.65  · bookend 2.50 */
  --neutral-800   : #453E31;  /* paper 9.15  · bookend 1.82 */
  --neutral-900   : #302A21;  /* paper 12.29 · bookend 1.35 */

  /* copper — ember --ember/--copper #FF8A5C */
  --copper-50     : #FFE1C4;  /* paper 1.08  · bookend 15.38 */
  --copper-100    : #FFC2A0;  /* paper 1.35  · bookend 12.32 */
  --copper-200    : #FFA680;  /* paper 1.65  · bookend 10.07 */
  --copper-300    : #FA8B64;  /* paper 2.03  · bookend 8.17 */
  --copper-400    : #E17149;  /* paper 2.73  · bookend 6.09 */
  --copper-500    : #C65A31;  /* paper 3.70  · bookend 4.49 */
  --copper-600    : #AB441B;  /* paper 5.09  · bookend 3.27 */
  --copper-700    : #8E3004;  /* paper 7.06  · bookend 2.35 */
  --copper-800    : #711E00;  /* paper 9.63  · bookend 1.73 */
  --copper-900    : #521000;  /* paper 12.69 · bookend 1.31 */

  /* violet — ember --violet #E86BFF */
  --violet-50     : #FFDCFF;  /* paper 1.07  · bookend 15.48 */
  --violet-100    : #FFBDFF;  /* paper 1.30  · bookend 12.78 */
  --violet-200    : #F7A0FF;  /* paper 1.59  · bookend 10.45 */
  --violet-300    : #E084EE;  /* paper 2.09  · bookend 7.96 */
  --violet-400    : #C76BD6;  /* paper 2.80  · bookend 5.94 */
  --violet-500    : #AE53BD;  /* paper 3.81  · bookend 4.36 */
  --violet-600    : #953DA3;  /* paper 5.23  · bookend 3.18 */
  --violet-700    : #7B2987;  /* paper 7.24  · bookend 2.29 */
  --violet-800    : #60176B;  /* paper 9.92  · bookend 1.67 */
  --violet-900    : #450A4E;  /* paper 12.92 · bookend 1.29 */

  /* rose — ember --rose #FF7AA8 */
  --rose-50       : #FFD8E9;  /* paper 1.12  · bookend 14.86 */
  --rose-100      : #FFB8CD;  /* paper 1.40  · bookend 11.87 */
  --rose-200      : #FF9AB3;  /* paper 1.73  · bookend 9.62 */
  --rose-300      : #FF7E9A;  /* paper 2.09  · bookend 7.96 */
  --rose-400      : #E76482;  /* paper 2.78  · bookend 5.98 */
  --rose-500      : #CC4B6C;  /* paper 3.79  · bookend 4.38 */
  --rose-600      : #B03557;  /* paper 5.20  · bookend 3.19 */
  --rose-700      : #922043;  /* paper 7.24  · bookend 2.29 */
  --rose-800      : #740E31;  /* paper 9.83  · bookend 1.69 */
  --rose-900      : #550320;  /* paper 12.80 · bookend 1.30 */

  /* forest — positive — the only cool-green in the system */
  --forest-50     : #D8FFDD;  /* paper 1.06  · bookend 17.61 */
  --forest-100    : #B8EFBF;  /* paper 1.13  · bookend 14.75 */
  --forest-200    : #9BD7A3;  /* paper 1.44  · bookend 11.56 */
  --forest-300    : #80BF89;  /* paper 1.87  · bookend 8.90 */
  --forest-400    : #67A871;  /* paper 2.45  · bookend 6.78 */
  --forest-500    : #50905A;  /* paper 3.32  · bookend 5.01 */
  --forest-600    : #3B7846;  /* paper 4.59  · bookend 3.62 */
  --forest-700    : #286133;  /* paper 6.38  · bookend 2.60 */
  --forest-800    : #184B23;  /* paper 8.78  · bookend 1.89 */
  --forest-900    : #0B3515;  /* paper 11.85 · bookend 1.40 */

  /* indigo — info — separated from violet by 58 degrees */
  --indigo-50     : #DCF8FF;  /* paper 1.04  · bookend 17.29 */
  --indigo-100    : #BEDEFF;  /* paper 1.21  · bookend 13.79 */
  --indigo-200    : #A2C5FF;  /* paper 1.52  · bookend 10.94 */
  --indigo-300    : #88ACF7;  /* paper 1.96  · bookend 8.49 */
  --indigo-400    : #7094E0;  /* paper 2.60  · bookend 6.40 */
  --indigo-500    : #5A7DC6;  /* paper 3.51  · bookend 4.74 */
  --indigo-600    : #4666AB;  /* paper 4.85  · bookend 3.43 */
  --indigo-700    : #34508F;  /* paper 6.76  · bookend 2.46 */
  --indigo-800    : #233C72;  /* paper 9.27  · bookend 1.79 */
  --indigo-900    : #162953;  /* paper 12.31 · bookend 1.35 */

  /* the two grounds, named at tier 1 so tier 2 can point at them */
  --paper         : #F5EEDF;  /* [pilot] */
  --bookend       : #140C16;  /* [pilot] */
}


/* ── tokens/colors.css ── */
/* Amber · TIER 2 — semantic roles. Components read tier 3 only; tier 3 reads this.
   ============================================================================
   WHAT CHANGED FROM CREAM, and why the role NAMES did not.
   Every role name below is Cream's, unchanged, because all 60 components and both
   UI kits read them through tier 3 — a rename would be a rewrite of the kit for no
   gain. What changed is what each role POINTS AT: a stop on the generated ramp
   (tokens/palette.css) instead of a hand-picked hex.

   THE RULE THAT REPLACED "MEASURE EVERY PAIR". Cream's colors.css carried a usage
   rule per colour because each colour was solved on its own. The ramp makes one
   rule do the work, and it holds for all seven families:

       stop 500 DECORATES   (3.5:1 on paper — a rule, a bar, a dot, a border)
       stop 600 CARRIES A WORD (4.6-5.2:1 on paper — AA at any size)
       stop 800 IS READING INK (9.1-9.4:1 — inside the 9-12 band)
       stop 50-200 ARE THE BOOKEND SET (11-18:1 on #140C16)

   That is why there is no per-colour usage note here any more. The number IS the
   rule. Provenance: [gen] = a ramp stop, [pilot] = measured on the A1 pilots.

   THE TWO MODES ARE NOT LIGHT AND DARK. This system has a paper ground and a
   BOOKEND ground, and the bookend is not "the same page at night" — it is the
   opening and closing of a document, which is why it keeps the ember identity
   (radial fields, a gradient call to action) that paper deliberately drops.
   [data-ground="bookend"] carries it; see the block at the foot of this file.
   ============================================================================ */
:root {
  /* ── grounds ─────────────────────────────────────────────────────── */
  --surface-page:     var(--paper);         /* [pilot] #F5EEDF */
  --surface-card:     var(--neutral-50);    /* [gen] 1.09:1 above the paper — a raised
                                               surface needs a border as well, because
                                               on paper you cannot raise by adding light */
  --surface-sunken:   var(--neutral-100);
  --surface-inverse:  var(--bookend);       /* [pilot] #140C16 */

  /* ── ink ─────────────────────────────────────────────────────────── */
  --text-primary:     var(--neutral-900);   /* 12.29:1 — headings, the strong voice */
  --text-body:        var(--neutral-800);   /* 9.15:1  — LONG-FORM READING. This is the
                                               whole reason this palette exists: ember
                                               read at 16.74:1 and its cream act at
                                               13.72:1, both glare. 9-12 is the band. */
  --text-muted:       var(--neutral-700);   /* 6.65:1  — secondary, captions */
  --text-faint:       var(--neutral-600);   /* 4.81:1  — quiet labels; still AA */
  --text-disabled:    var(--neutral-500);   /* 3.49:1  — NEVER body text */
  --text-on-accent:   var(--paper);         /* 4.88:1 on --accent-text */
  --text-on-inverse:  var(--neutral-200);   /* 11.16:1 on the bookend */

  /* ── edges. The split Cream drew and this system keeps: a HAIRLINE is decoration
     and may be faint; a STRONG border is the edge of a control and owes WCAG 1.4.11
     its 3:1. On paper that costs more than it does on dark — ink has to reach the
     500 stop before it clears 3:1 at all, which is why the strong border here reads
     as a drawn rule rather than a whisper. Measured on the pilots: at the alpha the
     dark theme used, the same border came out at 2.0:1. */
  --border-hairline:  var(--neutral-300);   /* 1.94:1 — decorative only */
  --border-strong:    var(--neutral-500);   /* 3.49:1 — clears 1.4.11 */
  --border-focus:     var(--amber-600);     /* 4.88:1 */

  /* ── the accent. Three roles, three stops, so nobody has to remember a usage rule. */
  --accent:           var(--amber-500);     /* decoration: rules, dots, bar fills */
  --accent-text:      var(--amber-600);     /* the accent when it carries a word */
  --accent-fill:      var(--amber-700);     /* the accent as a filled control */
  --accent-hover:     var(--amber-700);
  --accent-soft:      var(--amber-100);     /* a tint behind a word, on paper */
  --accent-on-dark:   var(--amber-100);     /* 13.85:1 on the bookend [pilot #FFC46B] */

  /* ── the act accents. ember ran a --heat per page family; this keeps that idea and
     puts every one on the same stop, so no act is louder than another. All six read
     4.59-5.23:1 on paper — the spread is hue, not weight. */
  --acc-amber:   var(--amber-600);
  --acc-copper:  var(--copper-600);
  --acc-violet:  var(--violet-600);
  --acc-rose:    var(--rose-600);
  --acc-forest:  var(--forest-600);
  --acc-indigo:  var(--indigo-600);
  --act:         var(--acc-amber);          /* a page family overrides this, once */

  /* ── status. Same stop rule; 600 carries the word, 100 is the soft fill behind it. */
  --status-positive:      var(--forest-600);
  --status-positive-soft: var(--forest-100);
  --status-caution:       var(--amber-600);
  --status-caution-soft:  var(--amber-100);
  --status-negative:      var(--rose-700);   /* one stop deeper: a warning earns weight */
  --status-negative-soft: var(--rose-100);
  --status-info:          var(--indigo-600);
  --status-info-soft:     var(--indigo-100);

  /* ── overlays and glow. --glow existed in Cream for the dark theme; on paper there
     is nothing to glow against, so it resolves to none here and is re-declared on
     the bookend. The asset audit found this the hard way: 15 radial fields that only
     read as light because the ground was dark. */
  --overlay-scrim: color-mix(in srgb, var(--neutral-900) 55%, transparent);
  --glow: none;

  /* ── tints. Cream carried five named tint pairs for chart series and callouts.
     Kept as a set, re-pointed at the ramp so a series is perceptually even. */
  --tint-amber-a:  var(--amber-100);   --tint-amber-b:  var(--amber-300);
  --tint-copper-a: var(--copper-100);  --tint-copper-b: var(--copper-300);
  --tint-violet-a: var(--violet-100);  --tint-violet-b: var(--violet-300);
  --tint-rose-a:   var(--rose-100);    --tint-rose-b:   var(--rose-300);
  --tint-forest-a: var(--forest-100);  --tint-forest-b: var(--forest-300);
  --tint-indigo-a: var(--indigo-100);  --tint-indigo-b: var(--indigo-300);

  /* ── Cream compatibility aliases. One component reads --cream-tint-blue-b
     directly (a tier-2 leak this system inherits rather than hides), and the UI
     kits reference the brand block. These keep the inherited kit working on day
     one; they are marked deprecated in registry.json and go at the next major,
     per the beta-first lifecycle [LEARNINGS]. */
  --cream-ground: var(--surface-page);   --cream-paper: var(--surface-card);
  --cream-sunken: var(--surface-sunken); --cream-ink: var(--text-primary);
  --cream-ink-2: var(--text-body);       --cream-grey: var(--text-muted);
  --cream-grey-2: var(--text-disabled);  --cream-silver: var(--border-strong);
  --cream-silver-2: var(--border-hairline);
  --cream-gold: var(--accent);           --cream-gold-lt: var(--accent-on-dark);
  --cream-gold-text: var(--accent-text); --cream-gold-deep: var(--accent-fill);
  --cream-positive: var(--status-positive); --cream-caution: var(--status-caution);
  --cream-negative: var(--status-negative); --cream-info: var(--status-info);
  --cream-tint-blue-a: var(--tint-indigo-a);  --cream-tint-blue-b: var(--tint-indigo-b);
  --cream-tint-peach-a: var(--tint-copper-a); --cream-tint-peach-b: var(--tint-copper-b);
  --cream-tint-sage-a: var(--tint-forest-a);  --cream-tint-sage-b: var(--tint-forest-b);
  --cream-tint-lilac-a: var(--tint-violet-a); --cream-tint-lilac-b: var(--tint-violet-b);
  --cream-tint-flax-a: var(--tint-amber-a);   --cream-tint-flax-b: var(--tint-amber-b);
}

/* ============================================================================
   A TINT COSTS EXACTLY ONE STOP. Measured, not asserted.
   ----------------------------------------------------------------------------
   A surface tinted with its own accent (the consumer tints each case card by its
   act, at ~7%) sits darker than the paper, and the 600 stop loses its AA margin on
   it — 3.75 to 4.08:1 across five families, where the paper gives 4.59 to 5.23.
   The 700 stop clears it in every family: 5.19 to 5.65:1.

   That is the whole rule, and it is why this is a ramp rather than a palette: the
   correction is "step down one", not "solve five more colours". The A1 pilots paid
   for this the other way — a 4% card tint took an accent from 5.12 to 4.25 and a
   tinted row took the quiet ink to 4.30, each found by an audit, each fixed by hand.

   Carry it with [data-tint] on the tinted surface, or .a-tinted.
   ============================================================================ */
[data-tint], .a-tinted {
  --text-body:    var(--neutral-800);   /* already deep enough: 9.15 -> 7.6 on a tint */
  --text-muted:   var(--neutral-800);
  --text-faint:   var(--neutral-700);
  --accent-text:  var(--amber-700);
  --accent:       var(--amber-600);
  --acc-amber:    var(--amber-700);
  --acc-copper:   var(--copper-700);
  --acc-violet:   var(--violet-700);
  --acc-rose:     var(--rose-700);
  --acc-forest:   var(--forest-700);
  --acc-indigo:   var(--indigo-700);
  --border-strong: var(--neutral-600);
}


/* ── tokens/colors-dark.css ── */
/* Amber · TIER 2 — THE BOOKEND GROUND.
   ============================================================================
   THIS IS NOT A DARK THEME, and the distinction is the system's central idea.
   A dark theme is the same page at night: every surface inverts and the reader
   stays in it. A BOOKEND is the opening and the closing of a document — the hero
   and the close — with paper in between. The reader passes through it twice and
   reads in it never, which is what licenses things paper cannot afford: radial
   fields, a gradient call to action, an accent at 13:1.

   ember's own words for it, which this system takes as doctrine: "fields are
   bookends, not wallpaper". The mid-page fields it ran are the reason its long-form
   read at 16.74:1 — the glare came from making a bookend the whole page.

   THE FILENAME IS INHERITED. Cream's styles.css imports colors-dark.css and both UI
   kits switch on [data-theme="dark"], so the name stays and BOTH selectors are
   honoured: nothing in the inherited kit breaks, and new work can say what it means.
   [data-ground="bookend"] is the one to write.

   MEASURED on #140C16 [pilot]:
     text-on-inverse  neutral-200  #CFC4B4  11.16:1
     accent-on-dark   amber-100    #FFD49C  13.85:1
     the quiet ink    neutral-300  #B7AC9B   8.58:1
   Note the inversion Cream also recorded: on the bookend the LIGHT accent passes
   for text, so --accent-text points up the ramp rather than down it. Same rule
   ("the stop decides"), opposite direction.
   ============================================================================ */
[data-theme="dark"],
[data-ground="bookend"] {
  /* ── grounds. bg1 is the only raised surface: on dark you raise by adding light,
     which is exactly what paper cannot do and why --surface-card differs in kind
     between the two modes rather than just in value. */
  --surface-page:     var(--bookend);
  --surface-card:     #1E1420;               /* [pilot] ember --bg1 family, warmed */
  --surface-sunken:   #0E080F;
  --surface-inverse:  var(--paper);

  /* ── ink. The ramp read upward. 200 is the reading ink here for the same reason
     800 is on paper: it lands in the 9-12 band (11.16:1). */
  --text-primary:     var(--neutral-100);    /* 14.29:1 — headings */
  --text-body:        var(--neutral-200);    /* 11.16:1 — in band */
  --text-muted:       var(--neutral-300);    /*  8.58:1 */
  --text-faint:       var(--neutral-400);    /*  6.43:1 */
  --text-disabled:    var(--neutral-500);    /*  4.75:1 — still AA, unlike on paper */
  --text-on-accent:   var(--bookend);        /* dark ink on a light accent fill */
  --text-on-inverse:  var(--text-body);      /* i.e. the paper mode's ink */

  /* ── edges. Cream's note applies verbatim: a control edge owes 1.4.11 its 3:1, and
     on the bookend a cream at 37% alpha composites to 3.12:1 — which is where this
     site's 3:1 standard came from in the first place. */
  --border-hairline:  color-mix(in srgb, var(--neutral-100) 14%, transparent);
  --border-strong:    color-mix(in srgb, var(--neutral-100) 37%, transparent);
  --border-focus:     var(--amber-100);

  /* ── the accent, read upward */
  --accent:           var(--amber-200);      /* 10.98:1 — decoration */
  --accent-text:      var(--amber-100);      /* 13.85:1 — carries a word */
  --accent-fill:      var(--amber-200);
  --accent-hover:     var(--amber-50);
  --accent-soft:      color-mix(in srgb, var(--amber-100) 12%, transparent);
  --accent-on-dark:   var(--amber-100);

  /* ── the act accents, read upward. Same stop for all six, same principle. */
  --acc-amber:   var(--amber-100);
  --acc-copper:  var(--copper-100);
  --acc-violet:  var(--violet-100);
  --acc-rose:    var(--rose-100);
  --acc-forest:  var(--forest-100);
  --acc-indigo:  var(--indigo-100);

  /* ── status, read upward */
  --status-positive: var(--forest-100); --status-positive-soft: color-mix(in srgb, var(--forest-100) 14%, transparent);
  --status-caution:  var(--amber-100);  --status-caution-soft:  color-mix(in srgb, var(--amber-100) 14%, transparent);
  --status-negative: var(--rose-100);   --status-negative-soft: color-mix(in srgb, var(--rose-100) 14%, transparent);
  --status-info:     var(--indigo-100); --status-info-soft:     color-mix(in srgb, var(--indigo-100) 14%, transparent);

  /* ── AND THE THING PAPER CANNOT HAVE. A radial field is additive light; it only
     reads because there is dark underneath. This is the token that makes the
     bookend worth having, and the reason --glow resolves to none on paper. */
  --glow: radial-gradient(900px 520px at 8% -10%,
            color-mix(in srgb, var(--acc-violet) 26%, transparent), transparent 62%),
          radial-gradient(800px 520px at 92% 0%,
            color-mix(in srgb, var(--acc-copper) 22%, transparent), transparent 60%);
  --overlay-scrim: color-mix(in srgb, #000 62%, transparent);
}


/* ── tokens/typography.css ── */
/* Amber · TIER 1/2 — type.
   ============================================================================
   THE FACES ARE THE CONSUMER'S. Cream v1.4 runs Source Serif 4 + Inter + Space
   Mono. This system exists to drive arpitmaheshwari.com, where five faces are
   already self-hosted, latin-subset, preloaded and cache-versioned — so it carries
   those instead of asking a live site to serve two more webfonts for no gain.
   Source Serif 4 is shared with Cream, so only the sans and the mono move.

     display   Source Serif 4      headings, claims, the figures a section exists for
     body/ui   Source Sans 3       reading and interface — one face, two jobs
     mono      JetBrains Mono      MACHINE OUTPUT ONLY: code, counts, data tables
     hand      Caveat              the margin note. One per page, never structural.
     a11y      Atkinson Hyperlegible  the dyslexia toggle the consumer already ships

   Two faces Cream does not have, and they are not decoration: the hand is a real
   register in this identity (the portfolio writes in the margin), and the a11y face
   is a user-facing toggle. A system that omitted them would be overridden on day one.

   THE DISCIPLINE IS CREAM'S, UNCHANGED [Cream v1.4]: FIVE steps at a 1.25 ratio and
   nothing else. v1.3 declared twelve registers, which is twelve ways for two pages to
   disagree. A component that needs a size off this list is a component to rethink.

   THE READING SPINE IS THE PILOT'S. --type-body is 18px/1.65 — which is what Cream
   already had, and what the four-palette reading comparison settled on independently.
   Nothing a visitor must read sits below 16px; argument-carrying prose sits at 18.
   ============================================================================ */
:root {
  --font-display: 'Source Serif 4', Georgia, serif;
  --font-body: 'Source Sans 3', system-ui, -apple-system, sans-serif;
  --font-ui: 'Source Sans 3', system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'Courier New', monospace;
  --font-hand: 'Caveat', cursive;
  --font-a11y: 'Atkinson Hyperlegible', var(--font-body);

  /* the five steps — 1.25 ratio from an 18px base */
  /* floor 40px, not 38: at 38 the claim falls in the 24-40px band whose leading
     floor is 1.15, making 1.12 illegal. One ratio, legal at every size. */
  --type-claim:   600 clamp(40px, 5vw, 55px)/1.12 var(--font-display);
  /* RESPONSIVE as of 2026-09-06. This was a fixed 35px while every other
     display step here is a clamp, so a section heading stayed 35px from a
     390px phone to a 1680px monitor. A site-wide census of every section
     heading found nine losing to their own content — one tied at 35 against
     35, one at 35 against a 48px figure. Floor is the previous 35px, so no
     layout shrinks; it only grows where there is room. */
  --type-section: 600 clamp(35px, 2.9vw, 46px)/1.2 var(--font-display);
  --type-title:   600 22px/1.3 var(--font-display);
  --type-body:    400 18px/1.65 var(--font-body);
  --type-label:   500 14px/1.5 var(--font-ui);

  /* aliases kept so the 60 existing components need no edits [token-snap, not
     restyle]. Each points at one of the five steps — no sixth size hides here. */
  --type-display-xl: var(--type-claim);
  --type-display-l:  var(--type-claim);
  --type-display-m:  var(--type-section);
  --type-heading:    var(--type-section);
  --type-body-l:     var(--type-body);
  --type-body-s:     var(--type-label);
  --type-label-s:    var(--type-label);
  --type-metric:     var(--type-title);
  --type-code:       400 14px/1.7 var(--font-mono);

  --tracking-label: 0.06em;      /* [B] */
  --tracking-label-wide: 0.1em;
}

/* ---------------------------------------------------------------------------
   THE ROLES BELOW THE FIVE STEPS  (added 2026-09-06)

   A census of one portfolio page found 199 text elements carrying THIRTY-FOUR
   distinct type signatures against the five steps declared above. The five were
   real and dominant, and everything else was drift: sizes 10, 11, 12, 13, 16,
   21, 24, 26 and 43; weight 300 on ledes and pull quotes; leadings 1.08, 1.45,
   1.6, 1.75 and 1.9.

   The lesson was not that five steps had been violated. It is that five steps
   never covered the roles a real page has — a lede, a caption, a mono status
   line, a data figure — and a system that does not name a role gets it invented
   per instance. So the roles are named, each fixed to the leading floor for its
   band (>=40px 1.1 / 24-40 1.2 / 18-24 1.5 / <18 1.6).

   Weight 300 is not in this system. On a paper ground a 300 at 16px loses its
   stroke, and nothing here is set below 12px.
   --------------------------------------------------------------------------- */
:root {
  --t-figure:  600 40px/1.1  var(--font-display); /* the number a section exists to show */
  --t-lede:    400 21px/1.5  var(--font-body);
  --t-small:   400 15px/1.6  var(--font-body);
  --t-caption: 400 13px/1.6  var(--font-body);
  --t-hand:    400 21px/1.35 var(--font-hand);  /* the margin note */
  --t-micro:   500 12px/1.5  var(--font-mono);    /* machine output, tags, status */
}


/* ── tokens/spacing.css ── */
/* Cream · spacing — 4px base [LEARNINGS]. Airy (gallery) default; [data-density="compact"] for workbench surfaces. */
:root {
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
  --space-5: 20px; --space-6: 24px; --space-7: 32px; --space-8: 40px;
  --space-9: 56px; --space-10: 80px; --space-11: 120px;
  --pad-card: var(--space-6);
  --pad-section: var(--space-10);
  --gap-stack: var(--space-4);
  --gap-inline: var(--space-2);
  --control-h: 44px;           /* HIG mobile minimum */
  --control-h-desktop: 40px;
  /* RADIUS. Cream's gallery was square by decision (--radius-0). Amber is not: the
     pilots settled on soft rectangles, and a scale stops each component guessing.
     Every value is a multiple of 2 on the 4px base. */
  --radius-0: 0px;             /* kept: a rule, a bar track, anything that is a line */
  --radius-1: 4px;             /* a bar, a chip, a small inset */
  --radius-2: 10px;            /* a card, a plate, a code inset [pilot] */
  --radius-3: 16px;            /* a full-bleed figure */
  --radius-pill: 999px;        /* the single exception: pills for tags/badges */
  --measure: 62ch;
  --container: 1240px;
}
[data-density="compact"] {
  --pad-card: var(--space-4);
  --pad-section: var(--space-7);
  --gap-stack: var(--space-3);
  --control-h: 36px;
  --control-h-desktop: 32px;
}

/* ---------------------------------------------------------------------------
   THE ACT RHYTHM AND THE MEASURE SCALE  (added 2026-09-06)

   Synced from the portfolio, where all of this was measured into existence.
   NOTE ON BASES: the scale above is 4px and these are 8px, which is a subset
   rather than a contradiction — 8/16/24/32/40/80 are --space-2/4/6/7/8/10. Only
   48, 64 and 96 are new, and they are named here rather than added above so the
   existing --space-N numbering keeps meaning what components already expect.

   Why they exist: the portfolio had NO spacing system. Section padding-top
   carried six values (0, 92, 96, 104, 120, 140) and padding-bottom five; two
   sections had zero top padding and leaned on a neighbour's margin, so the
   rhythm collapsed wherever that neighbour changed. Evenly spaced means the
   SAME number — 92 against 96 reads as a mistake at a glance without ever being
   nameable, and that is what "the sections don't look evenly spaced" meant.

   And it had no measure scale: eight different single-column widths, two of
   them fractional accidents (749.461px, 387.615px), and THREE different
   two-column splits for one pattern (612/500, 630/473, 575/521). Top-level
   blocks ended at fourteen different x positions — all the raggedness on the
   right, which is why it read as wrong without being locatable.

   Enforced by tools/spacing-scale-check.py in the portfolio repo, which measures
   DECLARED margins and paddings, never rendered box gaps: a box-to-box gap
   includes each line box's half-leading and is almost never a clean multiple
   even when the spacing is correct.
   --------------------------------------------------------------------------- */
:root {
  --space-48: 48px;
  --space-64: 64px;
  --space-96: 96px;

  /* every section in a sequence shares this; a hero is exempt, being an
     opening rather than an act in the sequence */
  --act-rhythm: var(--space-10);   /* 80px */

  --m-full:    none;               /* the container's own width */
  --m-wide:    960px;              /* lists, grids, indexes */
  --m-prose:   720px;              /* a reading measure, ~68 characters at 18px */
  --split:     1.15fr .85fr;       /* the ONE two-column split */
  --split-gap: var(--space-64);
}


/* ── tokens/grid.css ── */
/* Amber · TIER 1/2 — the grid. NEW in this system; Cream had a Grid component and a
   --container, and no grid tokens at all, so every layout decided its own gutter.

   WHY THESE BREAKPOINTS AND NOT THE USUAL FIVE. They are the four widths the
   consumer is actually tested at — the portfolio's QA order is 390 → 768 → 1024 →
   1440, mobile first, and the repo's own execution lesson 14 says that order is the
   rule. A breakpoint nobody renders at is a breakpoint nobody maintains. `max` is
   the fifth only because a 12-column fluid grid needs a stop, or a 2560px monitor
   gets 200px columns.

   WHY 12 COLUMNS [Carbon]. It divides by 2, 3, 4 and 6, which is every split this
   system actually uses. The one asymmetric split the portfolio measured into
   existence (--split 1.15fr .85fr) is kept as a named exception rather than
   pretended away.

   EVERYTHING IS A MULTIPLE OF 4 [LEARNINGS: "we used a 4px base and it composed
   with all of them"]. Gutters 16/24/32, margins 20/32/64/80. No value below is
   chosen; each is --space-N.
*/
:root {
  /* ── breakpoints. Declared as tokens AND used in the media queries below, so a
     change here is a change everywhere. Custom properties cannot be used inside a
     media query, so the numbers are repeated there — the QA harness asserts the two
     agree, because a silently-diverged breakpoint is the whole reason to name it. */
  --bp-sm: 390px;   /* the phone the site is walked on */
  --bp-md: 768px;   /* tablet portrait */
  --bp-lg: 1024px;  /* the narrowest laptop, and the width layouts fail at */
  --bp-xl: 1440px;  /* the design width */
  --bp-max: 1600px; /* the stop */

  /* ── the grid itself */
  --grid-cols: 12;
  --grid-gutter: var(--space-4);   /* 16px — phone */
  --grid-margin: var(--space-5);   /* 20px — phone */
  --container: 1240px;             /* [portfolio] measured */
  --container-max: var(--bp-max);

  /* ── the measure scale [portfolio, measured]. A column is not a measure: the grid
     says how wide a box may be, the measure says how wide READING may be. Keeping
     them separate is what stopped eight different single-column widths. */
  --m-prose: 720px;                /* ~68 characters at 18px — the reading measure */
  --m-narrow: 560px;               /* a pull-quote, a form */
  --m-wide: 960px;                 /* a table, a diagram that is not full-bleed */
  --m-full: none;                  /* the container's own width */
  --split: 1.15fr .85fr;           /* the ONE asymmetric two-column split */
}

@media (min-width: 768px) {
  :root { --grid-gutter: var(--space-6); --grid-margin: var(--space-7); }  /* 24 / 32 */
}
@media (min-width: 1024px) {
  :root { --grid-gutter: var(--space-7); --grid-margin: var(--space-9); }  /* 32 / 56 */
}
@media (min-width: 1440px) {
  :root { --grid-margin: var(--space-10); }                                /* 80 */
}

/* ── the grid as a class, for consumers that are not React.
   Cream's Grid is a JSX component with inline styles, which a static HTML site
   cannot use. These three classes are the same grid, available to anything. */
.a-container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--grid-margin);
}
.a-container--wide { max-width: var(--container-max); }
.a-container--prose { max-width: var(--m-prose); }

.a-grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-cols), minmax(0, 1fr));
  gap: var(--grid-gutter);
}
/* span-N, generated for 1..12. minmax(0,·) on the track and min-width:0 here are
   both load-bearing: without them a long unbreakable token widens its own column
   and drags the whole grid past the viewport — measured on the portfolio, where a
   <pre> did exactly that at 390px. */
.a-grid > [class*="a-col-"] { min-width: 0; }
.a-col-1  { grid-column: span 1  }
.a-col-2  { grid-column: span 2  }
.a-col-3  { grid-column: span 3  }
.a-col-4  { grid-column: span 4  }
.a-col-5  { grid-column: span 5  }
.a-col-6  { grid-column: span 6  }
.a-col-7  { grid-column: span 7  }
.a-col-8  { grid-column: span 8  }
.a-col-9  { grid-column: span 9  }
.a-col-10 { grid-column: span 10 }
.a-col-11 { grid-column: span 11 }
.a-col-12 { grid-column: span 12 }

/* Below md every column is full width. Stated once here rather than per component,
   which is what stopped the portfolio's per-page .xi- overrides multiplying. */
@media (max-width: 767px) {
  .a-grid > [class*="a-col-"] { grid-column: 1 / -1; }
}

/* the one asymmetric split, as a class so it cannot be re-invented per page */
.a-split { display: grid; gap: var(--grid-gutter); grid-template-columns: 1fr; }
@media (min-width: 1024px) {
  .a-split { grid-template-columns: var(--split); }
}


/* ── tokens/elevation.css ── */
/* Cream · elevation 0-4 [M3-modeled]. Warm umbra, long throw — museum light, not SaaS blur. */
:root {
  --elev-0: none;
  --elev-1: 0 10px 24px -16px rgba(32, 29, 24, 0.28);
  --elev-2: 0 30px 60px -30px rgba(32, 29, 24, 0.35);
  --elev-3: 0 44px 80px -30px rgba(32, 29, 24, 0.45);
  --elev-4: 0 60px 120px -32px rgba(32, 29, 24, 0.55);
  --frame-inset: inset 0 0 0 12px var(--surface-card), inset 0 0 0 13px var(--border-hairline);
}
[data-theme="dark"] {
  --elev-1: 0 10px 24px -14px rgba(0, 0, 0, 0.55);
  --elev-2: 0 30px 60px -26px rgba(0, 0, 0, 0.65);
  --elev-3: 0 44px 80px -26px rgba(0, 0, 0, 0.75);
  --elev-4: 0 60px 120px -28px rgba(0, 0, 0, 0.85);
}


/* ── tokens/motion.css ── */
/* Cream · motion [M3-modeled durations, Concept 9 easings — full motion per spec].
   Signature: gallery-ease reveals rising 26-40px; 3D frame tilt; cursor-following glow. */
:root {
  --dur-instant: 90ms;
  --dur-quick: 240ms;
  --dur-standard: 400ms;
  --dur-slow: 700ms;
  --dur-reveal: 1000ms;
  --dur-drift: 1200ms;
  --ease-gallery: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-exit: cubic-bezier(0.4, 0, 1, 1);
  --reveal-rise: 26px;
  --tilt-max-x: 7deg;
  --tilt-max-y: 9deg;
  --glow-radius: 560px;
}
@keyframes cream-fade-up { from { opacity: 0; transform: translateY(var(--reveal-rise)); } to { opacity: 1; transform: none; } }
@keyframes cream-fade-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  :root { --dur-quick: 1ms; --dur-standard: 1ms; --dur-slow: 1ms; --dur-reveal: 1ms; --dur-drift: 1ms; --reveal-rise: 0px; --tilt-max-x: 0deg; --tilt-max-y: 0deg; }
}


/* ── tokens/tokens-component.css ── */
/* Amber · TIER 3 — component tokens [Carbon-modeled]. Components read ONLY these.

   THE SELECTOR IS THREE-PART ON PURPOSE, and it is the subtlest rule in the system.
   A custom property is resolved where it is DECLARED, not where it is used. Declare
   tier 3 only at :root and every var(--accent-text) inside it freezes the paper
   value, which then inherits into a bookend and cannot be corrected from below —
   measured on the consumer: a nav link painted #905C0C (the paper accent) on a dark
   bar at 2.15:1 while getComputedStyle reported --accent-text as #FFD49C on that
   exact element. Both readings were true. Matching the mode carriers here makes
   tier 3 re-derive wherever tier 2 changes, which is the only way a two-mode system
   with a component tier can work.
*/
:root,
[data-theme="dark"],
[data-ground="bookend"] {
  --btn-bg: var(--surface-inverse);
  --btn-ink: var(--text-on-inverse);
  --btn-bg-hover: var(--accent);
  --btn-ink-hover: var(--text-on-accent);
  --btn-secondary-border: var(--text-primary);
  --btn-ghost-ink: var(--text-primary);
  --btn-h: var(--control-h-desktop);
  --btn-pad-x: var(--space-6);
  --btn-font: var(--type-label);
  --input-bg: transparent;
  --input-border: var(--border-strong);
  --input-border-focus: var(--border-focus);
  --input-ink: var(--text-primary);
  --input-placeholder: var(--text-faint);
  --input-h: var(--control-h-desktop);
  --card-bg: var(--surface-card);
  --card-border: var(--border-strong);
  --card-shadow: var(--elev-1);
  --card-pad: var(--pad-card);
  --dialog-shadow: var(--elev-3);
  --tooltip-bg: var(--surface-inverse);
  --tooltip-ink: var(--text-on-inverse);
  --table-row-border: var(--border-hairline);
  --table-head-ink: var(--text-faint);
  --tab-ink: var(--text-muted);
  --tab-ink-active: var(--text-primary);
  --tab-underline: var(--accent);
  --badge-font: var(--type-label-s);
  --progress-track: var(--border-hairline);
  --progress-fill: var(--accent-fill);
  --control-fill: var(--accent-fill);   /* checked/on/done states */
  --control-fill-ink: #FFFFFF;
  --skeleton-a: var(--surface-sunken);
  --skeleton-b: var(--border-hairline);
  --focus-ring: 0 0 0 2px var(--surface-page), 0 0 0 4px var(--border-focus);
  /* ── chart primitives. THE ONE REAL EDIT the asset audit named: on a dark field an
     unfilled bar reads as absence, and on paper there is nothing behind it, so the
     groove has to be drawn. The track is ink at 11% because that is what measured
     1.21:1 against a raised surface — visible as a channel, quiet enough not to read
     as a filled bar. */
  --bar-track: color-mix(in srgb, var(--text-primary) 11%, transparent);
  --bar-fill:  var(--act);
  --bar-h: 10px;
  /* ── tier 3 for the CSS component layer (src/05-components.css). The JSX kit had
     these for its own components; the CSS half needs its own set or it reaches into
     tier 2, which is the thing tier 3 exists to prevent. */
  --card-bg: var(--surface-card);
  --card-ink: var(--text-body);
  --card-border: var(--border-hairline);
  --card-pad: var(--pad-card);
  --plate-bg: var(--surface-card);
  --plate-border: var(--border-hairline);
  --plate-chrome-bg: var(--surface-sunken);
  --plate-chrome-ink: var(--text-muted);
  --screen-bg: var(--surface-inverse);
  --screen-chrome-bg: #22252B;          /* [audit] a quoted product keeps its own chrome */
  --screen-chrome-line: #2E323A;
  --screen-chrome-ink: var(--neutral-400);
  --code-bg: var(--surface-inverse);
  --code-ink: var(--text-on-inverse);
  --code-accent: var(--accent-on-dark);
  --table-line: var(--border-hairline);
  --table-head-ink: var(--text-muted);
  --table-lead-ink: var(--text-primary);
  --link-ink: var(--accent-text);
  --link-ink-hover: var(--accent-hover);
  --label-ink: var(--text-muted);
  --lede-ink: var(--text-muted);
  --caption-ink: var(--text-muted);
  --btn-fill-ink: var(--text-on-accent);
  --btn-fill-bg: var(--accent-fill);
  --btn-fill-bg-hover: var(--accent-hover);
  --btn-line: var(--border-strong);
  --btn-line-ink: var(--text-primary);
  --btn-soft-bg: var(--accent-soft);
  --status-pos-bg: var(--status-positive-soft); --status-pos-ink: var(--status-positive);
  --status-cau-bg: var(--status-caution-soft);  --status-cau-ink: var(--status-caution);
  --status-neg-bg: var(--status-negative-soft); --status-neg-ink: var(--status-negative);
  --status-inf-bg: var(--status-info-soft);     --status-inf-ink: var(--status-info);
}

}

/* ══════════════════════════ layer: ground ══════════════════════════ */
@layer ground {

/* ── src/02-ground.css ── */
/* layer: ground — the two grounds, and the rule that keeps them apart.
   A bookend is the opening and the closing of a document. Anything that reads as
   additive light (--glow) belongs to it and resolves to none on paper. */
body {
  background: var(--surface-page);
  color: var(--text-body);
  font: var(--type-body);
  -webkit-font-smoothing: antialiased;
}
/* A MODE MUST PAINT, NOT ONLY DECLARE. [data-ground] switches tier 2, but a switched
   token paints nothing on its own — so an element in bookend mode sitting inside a
   paper container showed light ink on paper at 1.00:1. Measured on the consumer,
   where the footer is a child of <main>: the mode was right, the ground was not.
   Any carrier of [data-ground] therefore paints its own ground and ink. */
[data-ground] { background: var(--surface-page); color: var(--text-body); }

.a-bookend { position: relative; overflow: hidden; }
.a-bookend::before {
  content: ""; position: absolute; inset: 0; background: var(--glow); pointer-events: none;
}
.a-bookend > * { position: relative; }

}

/* ══════════════════════════ layer: type ══════════════════════════ */
@layer type {

/* ── src/03-type.css ── */
/* layer: type — element defaults read off the five steps. Nothing here invents a size.
   LEADING FLOORS, by rendered size, because a unitless ratio follows a clamp() and a
   floor does not: >=40px 1.05 · 24-40 1.15 · 18-24 1.25 · <18 1.40. Only WRAPPED text
   can be too tight, so a one-line label is never a defect. */
h1 { font: var(--type-claim);   letter-spacing: -.02em; margin: 0 0 var(--space-5); }
h2 { font: var(--type-section); letter-spacing: -.015em; margin: var(--space-9) 0 var(--space-4); }
h3 { font: var(--type-title);   margin: var(--space-7) 0 var(--space-3); }
p, li, dd, dt, blockquote { font: var(--type-body); margin: 0 0 var(--space-4); max-width: var(--m-prose); }
small, .a-caption { font: var(--t-caption); color: var(--caption-ink); }
code, pre, .a-mono { font: var(--type-code); }
.a-label { font: var(--type-label); letter-spacing: var(--tracking-label); color: var(--caption-ink); }
.a-lede  { font: var(--t-lede); color: var(--caption-ink); max-width: var(--m-prose); }
.a-figure-number { font: var(--t-figure); color: var(--act); }
.a-hand  { font: var(--t-hand); color: var(--act); }
a { color: var(--link-ink); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--link-ink-hover); }
:focus-visible { outline: 3px solid var(--border-focus); outline-offset: 2px; }
/* Prose keeps a measure; a CARD does not — a card is a container and its CONTENTS
   take the measure. Getting this wrong left 900px voids beside 431px paragraphs. */
.a-card p, .a-card li, .a-grid p, .a-grid li { max-width: none; }

}

@layer layout { /* reserved */ }

/* ══════════════════════════ layer: components ══════════════════════════ */
@layer components {

/* ── src/05-components.css ── */
/* layer: components — the CSS half of the kit.
   The 60 JSX components read tier 3 through inline styles, which a static HTML site
   cannot use. These classes are the same tokens as real CSS, for consumers that are
   not React. Every one declares its own ink on its own ground: a component that
   inherits colour renders differently per page, which is the single most expensive
   lesson in the consumer's history (a nav that computed two line-heights, a pill that
   declared line-height on one page and inherited it on 42). */

/* ── button / call to action ─────────────────────────────────────────── */
.a-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: var(--control-h); padding: 0 var(--btn-pad-x);
  font: var(--type-label); line-height: 1;           /* DECLARED, never inherited */
  border-radius: var(--radius-pill); border: 1px solid transparent;
  background: var(--btn-fill-bg); color: var(--btn-fill-ink);
  cursor: pointer; text-decoration: none;
  transition: background var(--dur-quick) var(--ease-gallery);
}
.a-btn:hover { background: var(--btn-fill-bg-hover); }
.a-btn--secondary { background: transparent; color: var(--table-lead-ink); border-color: var(--btn-line); }
.a-btn--secondary:hover { background: var(--btn-soft-bg); border-color: var(--link-ink); color: var(--link-ink); }
.a-btn--ghost { background: transparent; color: var(--link-ink); border-color: transparent; text-decoration: underline; }
@media (min-width: 1024px) { .a-btn { min-height: var(--control-h-desktop); } }

/* ── surfaces ────────────────────────────────────────────────────────── */
.a-card {
  background: var(--card-bg); color: var(--card-ink);
  border: 1px solid var(--card-border); border-radius: var(--radius-2);
  padding: var(--card-pad);
}
/* On paper a card cannot be raised by adding light, so it is raised by an EDGE.
   A drop shadow on paper darkens the page under its own caption — measured: a
   64px shadow took a figure caption from 5.24:1 to 2.55:1. */
.a-card--raised { box-shadow: var(--elev-1); }
.a-plate {
  background: var(--card-bg); border: 1px solid var(--card-border);
  border-radius: var(--radius-2); padding: var(--card-pad); overflow: hidden;
}
.a-plate__chrome {
  display: flex; align-items: center; gap: var(--space-2);
  margin: calc(var(--card-pad) * -1) calc(var(--card-pad) * -1) var(--space-5);
  padding: var(--space-3) var(--space-4);
  background: var(--plate-chrome-bg); border-bottom: 1px solid var(--card-border);
  font: var(--t-micro); color: var(--table-head-ink);
}
/* a screen QUOTING someone else's product keeps their chrome and their interior */
.a-screen { background: var(--code-bg); border-radius: var(--radius-2); overflow: hidden; }
.a-screen .a-plate__chrome { background: #22252B; border-bottom-color: #2E323A; color: var(--screen-chrome-ink); }

/* ── the chart primitives. THE ONE REAL EDIT the asset audit found: on a dark field
   an unfilled bar reads as absence; on paper there is nothing behind it, so the
   groove has to be drawn. Every bar in this system has a track. ─────────── */
.a-bar { position: relative; height: 10px; border-radius: var(--radius-1); background: var(--bar-track); overflow: hidden; }
.a-bar > i { display: block; height: 100%; background: var(--bar-fill); }
.a-bar--none { background: repeating-linear-gradient(90deg, var(--bar-track) 0 3px, transparent 3px 7px); }
.a-bars { display: flex; align-items: flex-end; gap: var(--space-1); }
.a-bars > li { flex: 1; background: var(--bar-track); border-radius: var(--radius-1) var(--radius-1) 0 0; position: relative; list-style: none; }
.a-bars > li > i { position: absolute; inset: auto 0 0 0; background: var(--bar-fill); border-radius: inherit; }
.a-meter { display: grid; gap: var(--space-3); }
.a-meter > div { display: grid; gap: var(--space-2) var(--space-4); align-items: center; grid-template-columns: 1fr; }
@media (min-width: 620px) { .a-meter > div { grid-template-columns: 190px 1fr max-content; } }

/* ── table. Below the flip width a comparison table becomes cards, because a column
   behind a sideways scroll is a column a reader cannot know about. The roles are in
   the markup because Safari has historically dropped table semantics through the
   display:block flip. ────────────────────────────────────────────────── */
.a-table { width: 100%; border-collapse: collapse; font: var(--type-body); }
.a-table :is(th, td) { text-align: left; padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--card-border); vertical-align: top; }
.a-table th { font: var(--type-label); letter-spacing: var(--tracking-label); color: var(--table-head-ink); }
@media (max-width: 860px) {
  .a-table { display: block; min-width: 0; }
  .a-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .a-table :is(tbody, tbody tr, td) { display: block; }
  .a-table tbody tr { background: var(--card-bg); border: 1px solid var(--card-border); border-radius: var(--radius-2); padding: var(--card-pad); margin-bottom: var(--space-4); }
  .a-table td { padding: 0; border-bottom: 0; }
  .a-table td:first-child { font-weight: 600; color: var(--table-lead-ink); padding-bottom: var(--space-3); margin-bottom: var(--space-3); border-bottom: 1px solid var(--card-border); }
  .a-table td[data-label] { padding-left: var(--space-3); border-left: 2px solid var(--card-border); margin-top: var(--space-3); }
  .a-table td[data-label]::before { content: attr(data-label); display: block; font: var(--type-label); letter-spacing: var(--tracking-label); color: var(--table-head-ink); margin-bottom: 3px; }
}

/* ── code. A dark inset on paper is what every editor and every doc site does, and
   it gives the page a second material without inventing one. It WRAPS: the longest
   line used to hide behind a sideways scroll. ─────────────────────────── */
.a-code {
  background: var(--code-bg); color: var(--code-ink);
  border-radius: var(--radius-2); padding: var(--space-5) var(--space-5);
  font: var(--type-code); white-space: pre-wrap; overflow-wrap: break-word; overflow-x: visible;
}
.a-code b { color: var(--code-accent); font-weight: 400; }

/* ── status ──────────────────────────────────────────────────────────── */
.a-status { display: inline-flex; align-items: center; gap: var(--space-2); padding: 3px var(--space-3); border-radius: var(--radius-pill); font: var(--type-label); }
.a-status--positive { background: var(--status-pos-bg); color: var(--status-pos-ink); }
.a-status--caution  { background: var(--status-cau-bg);  color: var(--status-cau-ink); }
.a-status--negative { background: var(--status-neg-bg);  color: var(--status-neg-ink); }
.a-status--info     { background: var(--status-inf-bg);      color: var(--status-inf-ink); }

}

/* ══════════════════════════ layer: utilities ══════════════════════════ */
@layer utilities {

/* ── src/06-utilities.css ── */
/* layer: utilities — deliberately short. A utility that duplicates a component is a
   second answer to the same question. */
.a-measure   { max-width: var(--m-prose); }
.a-measure-n { max-width: var(--m-narrow); }
.a-measure-w { max-width: var(--m-wide); }
.a-full      { max-width: none; }
.a-stack > * + * { margin-top: var(--gap-stack); }
.a-row { display: flex; align-items: center; gap: var(--gap-inline); flex-wrap: wrap; }
.a-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.a-act-amber  { --act: var(--acc-amber);  }
.a-act-copper { --act: var(--acc-copper); }
.a-act-violet { --act: var(--acc-violet); }
.a-act-rose   { --act: var(--acc-rose);   }
.a-act-forest { --act: var(--acc-forest); }
.a-act-indigo { --act: var(--acc-indigo); }

}

@layer overrides { /* reserved */ }
