/* facetmark site — design system shared with the browser extension.
   Tokens first, components second. One stylesheet for all six pages. */

:root {
  color-scheme: light;
  /* ---- paper ----------------------------------------------------------
     What used to be here was seven overrides that re-pointed the palette's
     paper, ink and rules onto a warm axis: `--cream: #faf9f3`, `--ink:
     #17160f` (hue 52), `--border: #ddd9cc` (hue 46) and four more. Nothing
     in `palettes.css` asked for that -- the palette's own ink is a violet
     near-black -- and the result was a documentation site that read as
     coffee. Six of the seven are gone; the page now takes `--cream`,
     `--card-bg`, `--ink`, `--ink-light` and `--ink-faint` from the palette
     letter, so changing that letter changes the paper too.

     The five below stay site-owned, because the site needs surfaces the
     palette does not carry: two page bands, an inset well, and two weights of
     rule. Each is a fixed fraction of the palette's own `--brand-deep` mixed
     into the palette's own `--cream`, so they follow the letter rather than
     pinning a hue of their own. Measured against paper: hairline 1.12, well
     1.09, band 1.16, feature band 1.63, border 1.33, border-strong 1.51. */
  --hairline: #f3edf3;                  /* orchid-tinted hairline        */
  --surface-2: #f5edf4;                 /* orchid-tinted well            */
  --cream-dark: #f0e8f0;                /* orchid-tinted band            */
  --cream-deep: #dcc4d8;                /* orchid feature band           */
  --border: #e0d4e0;                    /* orchid-tinted border          */
  --border-strong: #d0bcd4;             /* orchid-tinted strong border   */
  /* the display colours are the palette's, and they fill shapes and set
     borders rather than small text -- `--brand` measures 4.28:1 on the
     heaviest card wash, under the body-text bar. `--accent-ink` does text.

     The link ramp is `--brand-deep` darkening to `--ink` on hover. That is
     one hue family, two steps apart in lightness, and it clears AA on every
     surface a link can land on: measured worst case 6.34 for the link and
     10.56 for its hover, across paper, both bands, the well, the card and all
     six card washes. The ramp it replaces was blue and needed a hand-picked
     third step to survive the same sweep. */
  --accent-ink: var(--brand-deep);
  --accent-ink-2: var(--ink);
  /* the filled pill carries a 15px label, so it is held to the body-text bar:
     white on `--brand` measures 6.26:1, on `--brand-deep` 9.69:1 */
  --btn-bg: var(--brand);
  --btn-bg-h: var(--brand-deep);
  --btn-fg: var(--on-brand);
  --info-soft: #f3e8f4;                 /* orchid-tinted info wash */
  /* ---- state ----------------------------------------------------------
     The palette's shared block carries `--success: #2e7955` (hue 151) and
     `--warning: #8a6a00` (hue 46) regardless of letter -- a forest green and
     an olive brown, both of which this site is not allowed to use. They are
     re-pointed here, and neither replacement is the hue a reader would guess
     from the word:

       success  hue 160, a deep sage green
       warning  hue 319, the deep plum

     Which is fine, because none of the three states is signalled by colour
     alone anywhere on this site -- every one of them carries a word, and the
     badges and callouts carry a glyph as well. Colour is the third cue, not
     the first. What the swap buys is that all three stay legible: measured
     worst case 5.12, 6.03 and 7.17 over every surface they can land on.

     `--danger` and `--danger-strong` come from the shared block untouched;
     the old site value for the strong one was #bd3a1a, which is hue 15 -- the
     rust end of the family this pass removed. */
  --success: #7a4d9a;
  --success-soft: #f1e8f4;
  --warning: #7a4860;
  /* ---- window chrome -------------------------------------------------
     What used to live here was `--code-bg: #17160f` and four friends: a
     hand-rolled near-black (luminance 0.0079) that every code block on the
     site sat on. There was no shell around it, no title bar worth the name,
     and it turned four documentation pages into a stack of slabs.

     It is replaced by one component, `.win`, in two skins:
       .win.lite  functional -- a command you are meant to read and copy
       .win.dark  showcase   -- the demo on the home page, and only there
     The dark skin is the palette's own `--dark-panel`, not an invented black.
     `brand-dna.md:167` allows a dark panel on a full HTML page and names
     that token for it; `:144` bans pure black outright, which the old value
     was within a rounding error of.

     The lite skin got a firmer shell in this pass as a side effect of the
     recolour: its title bar and body used to be the band and the well, which
     are 1.06:1 apart -- a bar you cannot see is not a bar. Bar is now the
     border weight and body is the well, measuring 1.22:1, and the frame line
     is the strong rule. */
  --win-bar: #e0d4e0;
  --win-body: #f5edf4;
  --win-line: #d0bcd4;
  --win-dim: var(--ink-light);
  --shadow-1: 0 1px 3px rgba(45, 29, 44, 0.07), 0 2px 10px rgba(45, 29, 44, 0.05);
  --shadow-2: 0 2px 6px rgba(45, 29, 44, 0.08), 0 14px 32px rgba(45, 29, 44, 0.1);
  --radius: 12px;
  --radius-sm: 8px;
  --maxw: 1120px;
  --readw: 760px;
  /* Verbatim from the derived site's `--f-sans` / `--f-display` / `--f-mono`.
     The previous stack led with "Liberation Sans", Arimo, Arial -- Arial is
     on the design system's banned list, and no Han face appeared until after
     three Latin ones. Nothing is downloaded here either: the Google Fonts
     request that used to load Fraunces, Noto Serif SC and Caveat is gone. */
  --sans: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei",
          "Hiragino Sans GB", "Noto Sans SC", sans-serif;
  --display: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
          "Microsoft YaHei", sans-serif;
  --mono: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo,
          monospace;

  /* ---- type scale ----------------------------------------------------
     Nine steps, and the sheet is not allowed to name a tenth: `tests/
     test_landing.py::test_the_type_scale_has_exactly_nine_steps` fails the
     build if any rule outside this block writes an absolute font-size.

     What this replaces: 33 distinct absolute sizes, including the run
     0.74 / 0.75 / 0.76 / 0.77 / 0.78 / 0.79 / 0.80 / 0.81 / 0.83rem. Those
     neighbours are 0.16px apart. Nobody can see 0.16px; what a reader sees
     is that nothing lines up, which is exactly the complaint.

     Ratio is roughly 1.18 at the small end (where a reader needs steps close
     enough to still feel like one family) and opens to 1.33 at the top, so a
     heading is unmistakably a heading -- brand-dna.md:99, "the big ones have
     to be very big and the small ones really small".

     fs-0 is not for prose. It exists because the pipeline diagram is a
     fixed-geometry drawing whose labels have to fit between the arrows. */
  --fs-0: 0.6875rem;                    /* 11px  in-diagram labels only     */
  --fs-1: 0.75rem;                      /* 12px  eyebrow, badge, caption    */
  --fs-2: 0.8125rem;                    /* 13px  meta, terminal, code       */
  --fs-3: 0.9375rem;                    /* 15px  secondary body, nav, btn   */
  --fs-4: 1.0625rem;                    /* 17px  body                       */
  --fs-5: 1.25rem;                      /* 20px  card heading, h4           */
  --fs-6: 1.5rem;                       /* 24px  h3                         */
  --fs-7: clamp(1.5rem, 3.4vw, 2rem);   /* 24-32px  h2                      */
  --fs-8: clamp(2rem, 5.2vw, 3.25rem);  /* 32-52px  h1                      */

  /* ---- leading -------------------------------------------------------
     Five values, down from eight. lh-cjk exists because Han glyphs fill
     their em box edge to edge: the 1.65 that reads as comfortable in Latin
     reads as cramped in Chinese, which is half of "squashed together". */
  --lh-tight: 1.15;                     /* display headings                 */
  --lh-snug: 1.4;                       /* sub-headings, tight card copy    */
  --lh-body: 1.65;                      /* Latin prose                      */
  --lh-cjk: 1.85;                       /* Han prose                        */
  --lh-code: 1.7;                       /* monospace blocks                 */
  /* `line-height: 1` is not a sixth step -- it is what a single-line box
     (a 34px control, a numbered circle) needs to centre its own text, and
     the test below exempts it for that reason. */

  /* ---- tracking ------------------------------------------------------
     Four values, down from sixteen, and the negative one is Latin-only.
     Applying -0.018em to Chinese pushes the glyphs into each other -- there
     is no sidebearing to take it out of, and the zh rule below zeroes it.
     Two caps steps, not one: 0.08em is right for a 12px badge, but a hero
     eyebrow set in the same 12px next to a 52px headline needs the extra
     air or it reads as a typo rather than a label. */
  --ls-display: -0.022em;
  --ls-none: 0;
  --ls-caps: 0.08em;
  --ls-caps-wide: 0.14em;

  /* ---- spacing -------------------------------------------------------
     A 4px grid, eight steps. What it replaces: 24 distinct paddings, 19
     margins and 15 gaps. Two cards 22px and 24px apart do not read as
     "slightly different", they read as broken. */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 72px;

  /* extended palette -- every value verbatim from one of the ten palettes in
     `palettes.css`, which cannot hold them itself: it is pinned byte-for-byte
     against the app's copy, so the extra hues live in both `:root`s instead.

     What this replaces ran nine hues and three of them are now out of bounds:
     `--mint: #4f9a6b` (hue 143), `--aqua: #3e9290` (hue 179) and `--peach:
     #c97845` (hue 26) -- a forest green, a teal and a rust. Removing them
     left the blue-violet-rose sector to carry every meaning on the page, and
     that sector cannot hold nine hues apart: the pink-through-purple run in
     the owner's own palettes is 9 to 12 degrees between neighbours. So this
     is five families at 18 degrees or more, and the sixth lane borrows a
     second density of the first rather than a tenth hue nobody could name.

     Three roles per family, and the roles are not interchangeable:
       --x        display -- fills a shape, draws a border, never sets text
       --x-ink    the text-safe step of the same hue
       --x-soft   the wash, a fixed fraction of the display colour on white

     The washes are not a ramp. They were solved together so that no two land
     within DeltaE 4.8 of each other, and none lands within 3.0 of paper, the
     card, the band, the well or the preview surface -- because six of them
     sit side by side in a result list, where a tint that could be any of two
     things is worse than no tint. Their densities come out uneven for that
     reason (6% to 29%), and evening them up costs real separation: the tidy
     ladder 8/12/16/20/24/28% only reaches DeltaE 3.9.

     Every `-ink` clears 4.5:1 on all six washes as well as on this file's
     surfaces: measured worst cases 7.48, 6.50, 7.06, 7.71 and 5.23. */
  --indigo: #3a6b9c;
  --indigo-ink: #2a5278;
  --indigo-soft: #e2edf6;               /* --indigo     light blue wash */
  --indigo-ink-soft: #d0e0ee;           /* --indigo-ink deeper wash    */
  --iris: #7b5bb6;
  --iris-ink: #5b3b86;
  --iris-soft: #ece4f2;                 /* --iris       pale violet     */
  --orchid: #8b4a8c;
  --orchid-ink: #6b386c;
  --orchid-soft: #f2e6f2;               /* --orchid     pale purple     */
  --plum: #9a4570;
  --plum-ink: #7a2d55;
  --plum-soft: #f4e4ec;                 /* --plum       pale mulberry   */
  --rose: #b24935;
  --rose-ink: #843426;
  --rose-soft: #f4ddd5;                 /* --rose       pale terracotta */
  /* end extended palette */
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --cream: #221428;
  --cream-dark: #241830;
  --cream-deep: #2e2040;
  --surface-2: #382a48;
  --card-bg: #3a2c50;
  --ink: #f0e8f5;
  --ink-light: #c8b8d4;
  --ink-faint: #9888a8;
  --border: #3a2c50;
  --hairline: #2e2040;
  --brand: #d698d4;
  --brand-deep: #c888c8;
  --accent-ink: #d698d4;
  --accent-ink-2: #c888c8;
  --btn-bg: #d698d4;
  --btn-bg-h: #c888c8;
  --btn-fg: #1a0e1e;
  --success: #c8a8e0;
  --warning: #e8c8a0;
  --danger-strong: #ec9098;
  --info-soft: #2a1840;
  --success-soft: #2a1840;
  --warning-soft: #3a1838;
  --highlight-soft: #2a2040;
  --danger-soft: #3a1828;
  --win-bar: #382a48;
  --win-body: #241830;
  --win-line: #3a2c50;
  --win-dim: #c8b8d4;
  --shadow-1: 0 1px 3px rgba(10, 6, 14, 0.4);
  --shadow-2: 0 2px 6px rgba(10, 6, 14, 0.4), 0 16px 36px rgba(10, 6, 14, 0.5);
  --indigo: #98b0d8;
  --indigo-ink: #a0b8e0;
  --iris: #d698d4;
  --iris-ink: #c888c8;
  --orchid: #e898b8;
  --orchid-ink: #e8a0c0;
  --plum: #d8a0b8;
  --plum-ink: #d8a8c0;
  --rose: #e88888;
  --rose-ink: #d87878;
  --indigo-soft: #1a2848;
  --indigo-ink-soft: #162240;
  --iris-soft: #2a1840;
  --orchid-soft: #3a1830;
  --plum-soft: #2a1828;
  --rose-soft: #3a1818;
}

/* Dark mode selection highlight: the daylight gold-on-ink selection is
   invisible at night. Use a saturated violet wash with white text. */
:root[data-theme="dark"] ::selection {
  background: rgba(214, 152, 212, 0.25);
  color: #f8f0f8;
}

/* The band that breaks the rhythm, and the one the owner pointed at. Ten
   sections of the same paper colour need something that is not paper in the
   middle of them; what used to do it here was a subtree that inverted the
   whole palette -- thirty-one tokens re-pointed onto a near-black, in
   daylight, with the pipeline drawing inside it. Two of those on a
   documentation site is not a rhythm, it is a light switch.

   It is replaced by the third step of the same paper ladder the rest of the
   sheet is built from, so there is nothing to invert and nothing to keep in
   sync: every component below reads the same tokens here as it does anywhere
   else. Measured on it: 1.63 against paper, 1.41 against the alternating band
   it has to differ from, 1.66 under a plain card, ink 8.10 / 5.32 / 3.29, and
   the nearest of the six card washes is DeltaE 3.5 away. */
.band.feature {
  background: var(--cream-deep);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: 84px; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-4);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
}

/* The Chinese pages are not the English pages in another font. Han glyphs are
   full-width and square, so the leading that reads as generous in Latin reads
   as packed, and the negative tracking that tightens a Latin headline has no
   sidebearing to remove and simply collides the characters. Both are switched
   off the only place they can be: on the root, keyed on the lang attribute
   `build.py` already writes. */
:root:lang(zh) body { line-height: var(--lh-cjk); }
/* One selector, and deliberately not a list naming the display headings.
   `:is()` takes the specificity of its heaviest argument, so this lands at
   (0,3,1) and beats the (0,1,1) those three rules carry, without repeating
   their selectors -- they are covered by weight, not by enumeration, and a
   grep for one of them still finds only its own rule. Numerals are left
   tracked, because `-0.022em` on digits
   is a fit, not a collision, and a Chinese page still wants its statistics
   to line up. */
:root:lang(zh) :is(h1, h2, h3, h4, .logo, .seclabel, .kicker) {
  letter-spacing: var(--ls-none);
}
:root:lang(zh) h1, :root:lang(zh) h2 { line-height: var(--lh-snug); }

a { color: var(--accent-ink); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-ink-2); }

h1, h2, h3, h4 {
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
  margin: 0 0 var(--sp-3);
}
h1 { font-size: var(--fs-8); }
h2 { font-size: var(--fs-7); }
/* Display headings are the system sans at 800, the weight and leading the
   reference site uses. The serif they used to run in was Fraunces, which was
   a CDN download and is not a face this project's design system names. */
.hero h1, .wrap > h2, .pagehead h1 {
  font-family: var(--display);
  font-weight: 800;
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
}
h3 { font-size: var(--fs-6); line-height: var(--lh-snug); }
h4 { font-size: var(--fs-5); line-height: var(--lh-snug); }
/* A heading owns the paragraph under it: 12px below the rule above, 32px of
   air above it. The old sheet used a single `0 0 0.5em` on all four levels,
   which meant an h2 and an h4 pushed their body copy away by different
   absolute amounts and no two sections started at the same rhythm. */
h2 + p, h2 + ul, h2 + ol, h3 + p, h3 + ul, h3 + ol, h4 + p { margin-top: 0; }
p { margin: 0 0 var(--sp-4); }
ul, ol { margin: 0 0 var(--sp-4); padding-left: 1.35em; }
li { margin-bottom: var(--sp-1); }
strong { font-weight: 700; }
hr { border: 0; border-top: 1px solid var(--border); margin: var(--sp-7) 0; }

.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--sp-5); }
.read { max-width: var(--readw); }
.muted { color: var(--ink-light); }
.tiny { font-size: var(--fs-2); color: var(--ink-light); }
/* A note that explains the block above it is a caption, not the next
   paragraph. The reset zeroes every paragraph's top margin, which left
   these three pixels under a card grid -- the half-leading, nothing
   else -- so they read as the grid's own last line. */
p.tiny { margin-top: var(--sp-3); }
.center { text-align: center; }
.nowrap { white-space: nowrap; }

/* ---------- header ---------- */

/* the first thing a keyboard user meets, so it takes the highest contrast pair
   we have -- 15.63:1 by day and 11.74:1 at night -- rather than the brand
   tablet's own pair, which is 6.26:1 and 8.98:1 */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 90;
  background: var(--ink); color: var(--cream); padding: var(--sp-2) var(--sp-4);
  border-radius: 0 0 var(--radius-sm) 0; font-weight: 600; text-decoration: none;
}
.skip:focus { left: 0; outline: 2px solid var(--brand); outline-offset: 2px; }

.progress {
  position: fixed; top: 0; left: 0; height: 2px; width: 0;
  background: var(--brand); z-index: 60; transition: width 0.1s linear;
}

/* A floating pill, not a bar welded to the top of the window.

   The design system's own nav demo (component 9) is a rounded rectangle with
   underlined links, but the brief here overrides it: "why isn't the nav a
   pill". So the shell is a pill and every link inside it is a pill too. The
   gold that component 9 puts under the current page as a 2px rule is not
   discarded -- it becomes the hover fill, so the signature colour survives
   the shape change and the current page can take the solid brand tablet. */
header.site {
  position: sticky; top: 0; z-index: 50;
  background: transparent;
  border-bottom: 0;
  padding: var(--sp-3) var(--sp-4) var(--sp-2);
  /* the pill floats over content, so the page needs a strip of paper behind
     it or ascenders show through the gap either side */
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.site-inner {
  max-width: var(--maxw); margin: 0 auto;
  /* The horizontal padding is geometry, not taste. A 999px radius on a 48px
     island puts a 24px arc in each corner, and the arc is at its widest where
     a full-height child's own corner is: 5px down from the top edge it has
     already cut 24 - sqrt(24² - 19²) = 9.3px inward. The right padding used
     to be var(--sp-2) -- 8px -- so the island's border ran straight through
     the theme toggle, which is what a pill inside a pill costs if you pad it
     like a rectangle. var(--sp-4) clears the arc with 6.7px to spare, and
     matching left to right is the other half of the fix: 24 against 8 read as
     a bar whose contents had drifted right. */
  padding: var(--sp-2) var(--sp-4);
  display: flex; align-items: center; gap: var(--sp-4);
  border-radius: 999px;
  /* Literal rgba rather than color-mix: the design system bans color-mix,
     and a sticky bar is the one place a fallback-to-nothing is fatal. */
  background: rgba(253, 251, 249, 0.82);
  -webkit-backdrop-filter: saturate(1.5) blur(14px);
  backdrop-filter: saturate(1.5) blur(14px);
  border: 1px solid var(--hairline);
  box-shadow: var(--shadow-1);
}
/* the literal above is the day paper. Without this line the night page kept a
   cream header, and the logo -- which is var(--ink) -- went white on cream. */
:root[data-theme="dark"] .site-inner { background: rgba(26, 14, 30, 0.82); }
.logo {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-weight: 700; font-size: var(--fs-4); color: var(--ink); text-decoration: none;
  letter-spacing: var(--ls-display);
}
.logo .mark {
  width: 20px; height: 20px; border-radius: 8px; flex: none;
}
nav.top { margin-left: auto; display: flex; align-items: center; gap: 2px; }
nav.top a {
  color: var(--ink-light); text-decoration: none; font-size: var(--fs-3); font-weight: 500;
  padding: var(--sp-2) var(--sp-3); border-radius: 999px;
  transition: background 0.15s ease, color 0.15s ease;
}
nav.top a:hover { color: var(--ink); background: var(--highlight-soft); }
/* the current page is a filled tablet. It is the only nav item that can be,
   which is what makes it findable at a glance */
nav.top a.on {
  color: var(--btn-fg); background: var(--btn-bg); font-weight: 600;
  box-shadow: none;
}
nav.top a.on:hover { color: var(--btn-fg); background: var(--btn-bg-h); }
.ctl {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-1);
  height: 34px; min-width: 34px; padding: 0 var(--sp-3); margin-left: var(--sp-1);
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--card-bg); color: var(--ink-light);
  font-family: var(--sans); font-size: var(--fs-2); font-weight: 600; line-height: 1;
  text-decoration: none; cursor: pointer;
}
.ctl:hover { color: var(--ink); border-color: var(--ink-faint); }
/* below 700px the text nav drops the repo link, so the control cluster carries
   a mark instead: a GitHub project with no way back to GitHub is a dead end */
.ctl.gh { display: none; }
.ctl.gh svg { display: block; width: 17px; height: 17px; fill: currentColor; }

/* ---------- hero ---------- */

.hero { position: relative; overflow: hidden; border-bottom: 1px solid var(--border); }
/* the hero already draws the rule; the band below it must not draw a second */
.hero + .band.alt { border-top: 0; }
.hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: radial-gradient(var(--border) 1px, transparent 1px);
  background-size: 22px 22px;
  mask-image: radial-gradient(ellipse 70% 60% at 50% 0%, var(--ink) 20%, transparent 75%);
  opacity: 0.85;
}
.hero-inner {
  position: relative; max-width: var(--maxw); margin: 0 auto;
  padding: clamp(var(--sp-6), 5.4vw, var(--sp-8)) var(--sp-5);
  display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  /* the text column runs taller than the terminal; top-aligning the two
     parked a ~190px void under the terminal at 1440px */
  gap: clamp(var(--sp-6), 5vw, var(--sp-7)); align-items: center;
}
.kicker {
  display: inline-block; margin: 0 0 var(--sp-3);
  font-size: var(--fs-1); font-weight: 700; letter-spacing: var(--ls-caps-wide); text-transform: uppercase;
  color: var(--accent-ink); background: var(--info-soft);
  padding: var(--sp-1) var(--sp-3); border-radius: 999px;
}
.hero h1 em {
  font-style: normal; color: var(--accent-ink);
  /* a soft highlighter wash behind the keyword, from the design system */
  background: linear-gradient(transparent 62%, rgba(var(--highlight-rgb), 0.4) 62%);
  /* at 0.4 over the night page the wash composites to hue 38 at 18% -- a brown,
     which is the one family this site may not paint -- and it swallows the word
     it is meant to lift, so night takes a third of the alpha */
  padding: 0 0.06em; border-radius: 4px;
  /* Chinese breaks between any two characters, so the marked phrase was being
     split mid-word and the wash was cut with it. The phrase is short in both
     languages; keep it whole. */
  white-space: nowrap;
}
:root[data-theme="dark"] .hero h1 em {
  background: linear-gradient(transparent 62%, rgba(214, 152, 212, 0.22) 62%);
}
.lede { font-size: var(--fs-5); color: var(--ink-light); margin-bottom: 1.4em; }
.lede strong { color: var(--ink); }
/* the reference site's hero sub-heading: the brand hue at 800 with a dashed
   rule under it, so the one sentence that says what this is does not read as
   body */
.hero .lede strong {
  color: var(--accent-ink); font-weight: 800;
  text-decoration: underline dashed rgba(var(--brand-rgb), 0.45);
  text-underline-offset: 5px; text-decoration-thickness: 1.5px;
}
.cta { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.btn {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4); border-radius: 999px; font-weight: 600; font-size: var(--fs-3);
  text-decoration: none; border: 1px solid var(--border); color: var(--ink);
  background: var(--card-bg); box-shadow: var(--shadow-1);
  /* the hover lifts the pill 1px; without a transition the lift snaps, and an
     active state that holds the lift reads as "stuck" rather than "pressed" */
  transition: border-color 150ms ease, color 150ms ease, background 150ms ease, transform 120ms ease;
}
.btn:hover { border-color: var(--ink-faint); color: var(--ink); transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn.primary { background: var(--btn-bg); border-color: var(--btn-bg); color: var(--btn-fg); }
.btn.primary:hover { background: var(--btn-bg-h); border-color: var(--btn-bg-h); color: var(--btn-fg); }
/* Five facts about the project, as component 10C/10D: a dashed frame on a
   visible wash, a different hue each, numeral set large. They were five
   identical grey pills, which is the uniform row the design system bans. */
/* 3 + 2 on a six-column track, the same solve `.g5` uses further down: five
   equal cards in an auto-fit grid leave the fifth alone on its own row. */
.chips {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--sp-2); margin-top: var(--sp-1); padding-top: var(--sp-4);
}
.chip { grid-column: span 2; }
.chip:nth-child(4), .chip:nth-child(5) { grid-column: span 3; }
.chip[hidden] { display: none; }
.chip {
  display: block; padding: var(--sp-2) var(--sp-3) var(--sp-3);
  border: 1.6px dashed var(--indigo); border-radius: var(--radius);
  background: var(--indigo-soft); color: var(--ink-light);
  font-size: var(--fs-1); font-weight: 700; letter-spacing: var(--ls-caps); text-transform: uppercase;
}
.chip b {
  display: block; margin-top: 2px; color: var(--ink); text-transform: none;
  font-family: var(--display); font-size: var(--fs-5); font-weight: 800;
  letter-spacing: var(--ls-display); font-variant-numeric: tabular-nums;
}
.chip:nth-child(2) { border-color: var(--orchid); background: var(--orchid-soft); }
.chip:nth-child(3) { border-color: var(--rose); background: var(--rose-soft); }
.chip:nth-child(4) { border-color: var(--plum); background: var(--plum-soft); }
.chip:nth-child(5) { border-color: var(--iris); background: var(--iris-soft); }

/* ---------- terminal ---------- */

/* The hero demo.  Its shell is `.win.dark` above; what is left here is the
   text inside it.

   History, because this is the second reversal and the reasoning should not
   be lost: it started as a hand-made near-black slab, was rewritten in the
   previous pass as a dashed frame on a blue wash on the grounds that the
   design system bans dark panels in functional areas, and is now a real dark
   window again. The middle step was wrong on a technicality -- `brand-dna.md`
   bans the dark panel in *functional* areas and on 3:4 cards, and explicitly
   allows it on a full HTML page (`:167`), which the hero is. It is a picture
   of a terminal, not a control. What it must not be is an undesigned black
   rectangle, which is what the first version was. */
.term {
  font-family: var(--mono);
  font-size: var(--fs-2);
  line-height: var(--lh-code);
}
.term-body { padding: var(--sp-4); }
.term .pr { color: var(--iris); }
.term .q { color: var(--highlight); font-weight: 700; }
.term .dim { color: var(--on-dark-dim); }
.term .hit { display: flex; gap: var(--sp-2); padding: 1px 0; }
.term .hit .n { color: var(--on-dark-dim); width: 1.2em; flex: none; text-align: right; }
.term .hit .t { flex: 1; min-width: 0; }
/* the one line the whole demo is about, so it takes the accent the rest of
   the page uses for a hit. The daylight rose is 3.31:1 on this panel and the
   daylight brand 2.82:1 -- neither can carry text here, so the panel lifts the
   two hues it needs to their night steps below and this reads 9.92:1. */
.term .hit.tgt .t { color: var(--rose); font-weight: 700; }
.term .hit .sc { color: var(--on-dark-dim); flex: none; }
.term .caret {
  display: inline-block; width: 7px; height: 1.05em; margin-left: 1px;
  background: var(--on-dark); vertical-align: text-bottom;
  animation: blink 1.1s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }
.win-note {
  padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--win-line);
  font-family: var(--sans); font-size: var(--fs-2); color: var(--win-dim);
}
.win-note code {
  background: rgba(255, 255, 255, 0.09); color: var(--on-dark);
  border: 1px solid var(--win-line); border-radius: var(--radius-sm);
  font-size: 1em; padding: 1px var(--sp-1);
}

/* ---------- sections ---------- */

section.band { padding: clamp(var(--sp-7), 7vw, var(--sp-8)) 0; border-bottom: 1px solid var(--border); }
section.band.alt { background: var(--cream-dark); border-top: 1px solid var(--hairline); }
.seclabel {
  font-size: var(--fs-1); font-weight: 700; letter-spacing: var(--ls-caps-wide); text-transform: uppercase;
  color: var(--ink-light); margin: 0 0 var(--sp-2);
}
/* a 32px rule under the eyebrow: the only thing that gave ten identical
   left-aligned section headers any shape of their own */
.seclabel::after {
  content: ""; display: block; width: 32px; height: 2px; border-radius: 2px;
  margin: var(--sp-2) 0 0; background: var(--brand);
}
/* the two feature bands and the closing call to action centre their header */
.wrap.hcenter > .seclabel, .wrap.hcenter > h2, .wrap.hcenter > .lede { text-align: center; }
.wrap.hcenter > .seclabel::after { margin-left: auto; margin-right: auto; }
.wrap.hcenter > .lede { margin-left: auto; margin-right: auto; }
.reveal { opacity: 0; transform: translateY(18px); transition: opacity 0.6s ease, transform 0.6s ease; }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
}

/* ---------- grids and cards ---------- */

.grid { display: grid; gap: var(--sp-3); }
.g2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.g3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.g4 { grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); }
/* five items without an orphan: 3 + 2 on one six-column track. auto-fit fitted
   only four columns in a 1120px container and left the fifth card alone. */
.g5 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.g5 > * { grid-column: span 2; }
.g5 > :nth-child(4), .g5 > :nth-child(5) { grid-column: span 3; }
/* six interface cards: 3 x 2. `.g5` hand-splits five as 3 + 2, which strands a
   sixth card alone on a third row; an even split is the only one of the two
   that stays even when a seventh is added. */
.g6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* the extension band: one tall popup frame beside a stacked frame + legend */
/* 0.72/1.28 is solved, not tuned by eye: the popup mock is portrait (840x1054)
   and the options mock is landscape (1120x864), and this is the split at which
   both frames plus their captions end on the same line. */
.gext { grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.28fr); gap: var(--sp-4); align-items: start; }
.ecol { display: grid; gap: var(--sp-4); align-content: start; }

.card {
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--sp-4) var(--sp-5); box-shadow: var(--shadow-1);
}
.card h3 { margin-bottom: var(--sp-1); }
.card p:last-child { margin-bottom: 0; }
.card .eyebrow {
  font-family: var(--mono); font-size: var(--fs-1); color: var(--accent-ink);
  text-transform: uppercase; letter-spacing: var(--ls-caps); font-weight: 700;
}
.card .ex {
  margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px dashed var(--border);
  color: var(--accent-ink); font-size: var(--fs-3);
}
.card.off { background: var(--surface-2); }
.card.off h3 { color: var(--ink-light); }

/* Component 10D. A grid of six identical white boxes is the pattern the design
   system names outright as the thing not to ship, and this site had ten of
   them. The cards keep their copy and their order; what changes is that each
   one arrives in its own hue behind a hand-drawn frame, so a reader can point
   at "the rose one" instead of "the third one". Six hues, dealt by position. */
/* column + `margin-top:auto` on the footer stat: the three cards hold copy of
   different lengths, and the numerals used to land at three different heights */
.grid > .card {
  border-width: 1.6px; border-style: dashed; box-shadow: none;
  display: flex; flex-direction: column;
}
.grid > .card > .stat { margin-top: auto; }
/* dealt so that no two neighbours in a three-column grid share a family:
   the two densities of indigo land diagonally opposite, never side by side */
.grid > .card:nth-child(6n + 1) { background: var(--indigo-soft); border-color: var(--indigo); }
.grid > .card:nth-child(6n + 2) { background: var(--orchid-soft); border-color: var(--orchid); }
.grid > .card:nth-child(6n + 3) { background: var(--rose-soft); border-color: var(--rose); }
.grid > .card:nth-child(6n + 4) { background: var(--plum-soft); border-color: var(--plum); }
.grid > .card:nth-child(6n + 5) { background: var(--indigo-ink-soft); border-color: var(--indigo-ink); }
.grid > .card:nth-child(6n + 6) { background: var(--iris-soft); border-color: var(--iris); }
/* a disabled card keeps the well: the hue would read as a state it is not in */
.grid > .card.off { background: var(--surface-2); border-color: var(--border); }
/* the faintest ink does not clear 4.5:1 on a wash -- measured 4.17 at worst */
.grid > .card .tiny, .grid > .card .muted { color: var(--ink-light); }

.stat {
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--sp-4) var(--sp-4); box-shadow: var(--shadow-1);
}
/* a stat inside a card is a footer of that card, not a second box: one border,
   one shadow, one background per object */
.card .stat {
  background: none; border: 0; border-radius: 0; box-shadow: none;
  margin-top: var(--sp-3); padding: var(--sp-3) 0 0; border-top: 1px dashed var(--border);
}
.stat .v { font-size: var(--fs-7); font-weight: 800; letter-spacing: var(--ls-display); font-variant-numeric: tabular-nums; }
.stat .v.good { color: var(--success); }
.stat .v.bad { color: var(--danger-strong); }
.stat .k { font-size: var(--fs-2); color: var(--ink-light); }

/* ---------- tables ---------- */

.tw {
  overflow-x: auto; margin: 0 0 1.2em;
  border: 1px solid var(--border); border-radius: var(--radius);
  /* scroll shadows: the two `local` layers ride with the content and cover the
     two `scroll` layers whenever that edge is already reached, so the shadow
     only shows on the side that still has hidden columns */
  background:
    linear-gradient(to right, var(--card-bg) 40%, transparent) left / 26px 100% no-repeat local,
    linear-gradient(to left, var(--card-bg) 40%, transparent) right / 26px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, rgba(36, 30, 46, 0.13), transparent) left / 11px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(36, 30, 46, 0.13), transparent) right / 11px 100% no-repeat scroll,
    var(--card-bg);
}
.tw::-webkit-scrollbar, .diagram .dscroll::-webkit-scrollbar { height: 7px; }
.tw::-webkit-scrollbar-thumb, .diagram .dscroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.tw::-webkit-scrollbar-track, .diagram .dscroll::-webkit-scrollbar-track { background: transparent; }
table { border-collapse: collapse; width: 100%; font-size: var(--fs-3); }
th, td { text-align: left; padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--hairline); vertical-align: middle; }
th { text-align: center; background: var(--surface-2); font-size: var(--fs-1); text-transform: uppercase; letter-spacing: var(--ls-caps); color: var(--ink-light); font-weight: 700; white-space: nowrap; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover td { background: var(--surface-2); }
td code, th code { white-space: nowrap; }
td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
tr.win td { background: var(--info-soft); }
tr.win:hover td { background: var(--info-soft); }

code {
  font-family: var(--mono); font-size: 0.88em;
  background: var(--surface-2); border: 1px solid var(--hairline);
  padding: 1px var(--sp-1); border-radius: 7px;
  /* long paths in prose must be allowed to break, or they widen the page */
  overflow-wrap: anywhere;
}
kbd {
  font-family: var(--mono); font-size: 0.82em; padding: 2px var(--sp-1);
  border: 1px solid var(--border); border-bottom-width: 2px; border-radius: 8px;
  background: var(--card-bg);
}

/* ---------- code blocks ---------- */

/* One window, two skins.  The chrome is the design system's "code panel /
   macOS window": rounded shell, a title bar with three lights and the file
   name centred in it, body below.  The lights are the palette's own rose, iris
   and indigo rather than Apple's #ff5f56 / #ffbd2e / #27c93f, so the figure
   still belongs to this page's colour scheme while reading instantly as a
   window.

   .lite  is the functional skin and the default for documentation. A command
          you are meant to read and copy does not belong on a dark slab.
   .dark  is the showcase skin, used once, for the demo in the hero. */
.win {
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--win-line);
  background: var(--win-body);
  box-shadow: var(--shadow-2);
  margin: 0 0 var(--sp-5);
}
.win-bar {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-3);
  background: var(--win-bar); border-bottom: 1px solid var(--win-line);
}
.win-bar i { width: 11px; height: 11px; border-radius: 50%; flex: none; }
/* Three 11px dots, held to 3:1 against the bar they sit on because that is
   the bar for a non-text graphic. The middle one used to be the palette's gold
   and on the recoloured daylight bar it measured 1.02:1 -- present in the
   markup, invisible on the page. These three measure 3.89 / 4.56 / 5.51 there,
   5.40 or better on the night bar, and 7.67 or better on the dark panel. */
.win-bar i:nth-child(1) { background: var(--rose); }
.win-bar i:nth-child(2) { background: var(--iris); }
.win-bar i:nth-child(3) { background: var(--indigo); }
/* the name is centred by taking the free space, which also pushes the copy
   button to the right edge without a second `margin-left: auto` */
.win-name {
  flex: 1; text-align: center; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--mono); font-size: var(--fs-1); color: var(--win-dim);
  letter-spacing: var(--ls-none);
}
/* three lights on the left, so the same width has to be reserved on the right
   or the name is centred on the wrong axis */
.win-bar .pad { width: 57px; flex: none; }
.win-bar button {
  flex: none; background: none; border: 1px solid var(--win-line);
  color: var(--win-dim); border-radius: 999px;
  padding: var(--sp-1) var(--sp-3);
  font-family: var(--sans); font-size: var(--fs-1); font-weight: 600;
  line-height: var(--lh-snug); cursor: pointer;
}
.win-bar button:hover { color: var(--ink); border-color: var(--ink-faint); }
.win pre {
  margin: 0; padding: var(--sp-4); overflow-x: auto;
  font-family: var(--mono); font-size: var(--fs-2); line-height: var(--lh-code);
}
/* a horizontally scrolling region has to be reachable without a mouse --
   axe `scrollable-region-focusable`, and it was failing on every page */
.win pre:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.win code {
  background: none; border: 0; padding: 0; color: var(--ink);
  font-family: var(--mono); font-size: inherit; white-space: pre;
}
.win .c { color: var(--ink-light); }
/* The one dark surface left on the daylight site, and the only one the tests
   exempt from the surface floor. Its body is the palette's own `--dark-panel`
   rather than an invented black -- the shell above it is that value lightened
   1.29 for the title bar and 1.88 for the frame line, the same step the
   reference component this figure is modelled on uses.

   It also lifts the three hues it needs to their night steps, because a panel
   this dark is a night surface wherever it appears: the daylight rose measures
   3.31:1 on it and the daylight brand 2.82:1, and the dots and the prompt both
   have to clear their bars. */
.win.dark {
  --win-bar: #2a1838;
  --win-body: var(--dark-panel);
  --win-line: #3a2848;
  --win-dim: var(--on-dark-dim);
  --ink: var(--on-dark);
  --ink-light: var(--on-dark-dim);
  --rose: #e88888;
  --iris: #d698d4;
  --indigo: #98b0d8;
  color: var(--on-dark);
}
:root[data-theme="dark"] .win.dark { box-shadow: var(--shadow-1); }

/* ---------- diagram ---------- */

.diagram { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--sp-5) var(--sp-4) var(--sp-4); box-shadow: var(--shadow-1); position: relative; }
/* a yellow accent bar above the diagram, the same gesture as the col-line on
   the workflow columns: a 3px slash of --highlight that says "this is a
   process" without adding a heading weight the section already has */
.diagram::before {
  content: ""; position: absolute; top: 0; left: var(--sp-4);
  width: 40px; height: 3px; background: var(--highlight); border-radius: 0 0 2px 2px;
}
.diagram .dscroll { overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; }
.diagram svg { width: 100%; min-width: 860px; height: auto; display: block; }
/* narrow-screen rewrite of the same pipeline: same nodes, stacked */
.dstack { display: none; }
.dstack .dn {
  border: 1.5px solid var(--border); background: var(--card-bg);
  border-radius: 9px; padding: var(--sp-2) var(--sp-3); text-align: center;
}
.dstack .dn b { display: block; font-size: var(--fs-3); color: var(--ink); }
.dstack .dn i { display: block; font-style: normal; font-size: var(--fs-2); color: var(--ink-light); margin-top: 1px; }
.dstack .dn s { display: block; text-decoration: none; font-style: italic; font-size: var(--fs-1); color: var(--ink-light); margin-top: 1px; }
.dstack .dn.on { background: var(--info-soft); border-color: var(--brand); }
.dstack .dn.key { background: var(--highlight-soft); border-color: var(--highlight); }
/* the four facets fan out in parallel. Stacked in one column with no group
   boundary they read as a five-step sequence, which is the wrong architecture:
   they are wrapped in a labelled bracket and laid out two-up wherever there is
   room for two. */
.dpar { position: relative; margin: 0; padding: var(--sp-2) 0 var(--sp-2) var(--sp-3); border-left: 2px solid var(--brand); border-radius: 6px 0 0 6px; }
.dpar::before, .dpar::after {
  content: ""; position: absolute; left: -2px; width: 11px; height: 2px; background: var(--brand);
}
.dpar::before { top: 0; }
.dpar::after { bottom: 0; }
.dpar-h { margin: 0 0 var(--sp-2); font-size: var(--fs-1); line-height: var(--lh-snug); }
.dpar-h b { color: var(--ink); font-weight: 700; letter-spacing: var(--ls-none); }
.dpar-h i { font-style: normal; color: var(--ink-light); }
/* The separator was --ink-faint, which is 3.59:1 on the page in daylight.
   axe never saw it -- the rule grades text nodes and this is generated
   content -- so it survived every scan. --ink-faint is a hairline colour in
   this stylesheet and nothing else; see the contrast tests. */
.dpar-h i::before { content: " \00b7\00a0"; color: var(--ink-light); }
.dstack .dgrid { display: grid; gap: var(--sp-2); grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 419px) { .dstack .dgrid { grid-template-columns: minmax(0, 1fr); } }
.dstack .darr { position: relative; height: 22px; }
.dstack .darr::before {
  content: ""; position: absolute; left: 50%; top: 0; bottom: 6px; width: 2px;
  transform: translateX(-50%); background: var(--brand);
}
.dstack .darr::after {
  content: ""; position: absolute; left: 50%; bottom: 0; transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: var(--brand); border-bottom: 0;
}
.dstack .darr.mut::before { background: var(--ink-faint); width: 1.5px; }
.dstack .darr.mut::after { border-top-color: var(--ink-faint); }
.dstack .dbr {
  margin: var(--sp-3) 0 var(--sp-2); padding-top: var(--sp-3); border-top: 1px dashed var(--border);
  font-size: var(--fs-2); color: var(--ink-light); text-align: center;
}
.dstack .dlegend { margin: var(--sp-3) 0 0; font-size: var(--fs-1); color: var(--ink-light); line-height: var(--lh-cjk); }
.dstack .dlegend .k { display: inline-block; width: 22px; height: 2px; margin: 0 var(--sp-2) 0 0; vertical-align: middle; }
.dstack .dlegend .k.on { background: var(--brand); height: 3px; }
.dstack .dlegend .k.off { background: var(--ink-faint); margin-left: var(--sp-3); }

@media (max-width: 880px) {
  .diagram .dscroll { display: none; }
  .dstack { display: block; }
  .diagram { padding: var(--sp-4) var(--sp-3); }
}
.diagram svg text { font-family: var(--sans); fill: var(--ink); }
/* the off boxes read as white cards with a hairline edge; the on box carries
   the brand wash and a brand edge; the key boxes (query, hits) carry the
   highlight wash so the endpoints of the pipeline read as the same gesture
   as the yellow bar above the diagram */
.d-box { fill: var(--card-bg); stroke: var(--border); }
.d-box-on { fill: var(--info-soft); stroke: var(--brand); }
.d-box-key { fill: var(--highlight-soft); stroke: var(--highlight); }
.d-arrow { stroke: var(--ink-faint); fill: none; stroke-dasharray: 5 3; }
.d-arrow-on { stroke: var(--brand); fill: none; }
/* titles in brand-deep so the node reads as a label, not as prose; the key
   nodes get ink so the yellow wash does not fight a blue title */
.d-t { font-size: var(--fs-2); font-weight: 700; fill: var(--brand-deep); }
.d-box-key + text.d-t, text.d-t:first-of-type { fill: var(--ink); }
.d-s { font-size: var(--fs-0); fill: var(--ink-light); }
.d-s-off { font-size: var(--fs-0); fill: var(--ink-faint); font-style: italic; }
.d-head { fill: var(--ink-faint); }
.d-head-on { fill: var(--brand); }

/* ---------- bars ---------- */

.bars { display: grid; gap: var(--sp-2); margin: var(--sp-1) 0 var(--sp-3); }
.bar-row { display: grid; grid-template-columns: minmax(150px, 210px) 1fr 58px; gap: var(--sp-3); align-items: center; font-size: var(--fs-3); }
.bar-row .lb { color: var(--ink-light); }
.bar-row .lb b { color: var(--ink); }
.bar-track { height: 20px; border-radius: 8px; background: var(--surface-2); border: 1px solid var(--hairline); overflow: hidden; }
.bar-fill { height: 100%; width: 0; background: var(--ink-faint); transition: width 1.05s cubic-bezier(0.22, 1, 0.36, 1); }
.bars.go .bar-fill { width: var(--w); }
.bar-fill.win { background: var(--brand); }
.bar-row .vv { font-variant-numeric: tabular-nums; font-weight: 700; text-align: right; }

.bigstat { font-size: var(--fs-8); font-weight: 800; letter-spacing: var(--ls-display); line-height: 1; font-variant-numeric: tabular-nums; }
.bigstat.bad { color: var(--danger-strong); }
.bigstat small { display: block; font-size: 0.26em; font-weight: 600; letter-spacing: var(--ls-none); color: var(--ink-light); margin-top: var(--sp-1); }

/* ---------- badges ---------- */

.badge {
  display: inline-block; font-size: var(--fs-1); font-weight: 700; letter-spacing: var(--ls-caps);
  padding: 2px var(--sp-2); border-radius: 999px; text-transform: uppercase; white-space: nowrap;
  max-width: 100%; overflow-wrap: anywhere;
}
@media (max-width: 700px) { .badge { white-space: normal; } }
.badge.pass { background: var(--success-soft); color: var(--success); }
.badge.fail { background: var(--danger-soft); color: var(--danger-strong); }
.badge.info { background: var(--info-soft); color: var(--accent-ink); }
/* this used to carry the only two hand-mixed colours left in the badges --
   a hue 38 cream and a hue 36 brown text on it -- with a separate night rule
   underneath to undo them. Both are the state tokens now, which are already
   night-aware, so the second rule is gone: measured 10.65:1 by day and 5.88:1
   at night. */
.badge.warn { background: var(--warning-soft); color: var(--warning); }

/* A whole dashed frame, not a bar down the left edge. The design system's
   taboo list names the `border-left` quote rule specifically, and the site
   already speaks in dashed frames -- the hero chips and the pipeline diagram
   are drawn the same way, so a notice now belongs to the same family instead
   of importing a convention from a Markdown renderer. */
.callout {
  border: 1.6px dashed var(--brand); background: var(--info-soft);
  padding: var(--sp-4); border-radius: var(--radius); margin: 0 0 var(--sp-5);
}
.callout.warn { border-color: var(--warning); background: var(--warning-soft); }
.callout.bad { border-color: var(--danger-strong); background: var(--danger-soft); }
.callout p:last-child { margin-bottom: 0; }
.callout .t { font-weight: 700; }

/* ---------- shots ---------- */

.shot { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-1); overflow: hidden; }
.shot .cap { padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--border); font-size: var(--fs-2); color: var(--ink-light); }
.shot .cap b { color: var(--ink); }
.shot img { display: block; width: 100%; height: auto; background: var(--surface-2); }
/* the dark-mode popup is a fact about the extension, not a second screenshot:
   the frame swaps its image with the site theme instead of taking a column */
.only-dark { display: none; }
:root[data-theme="dark"] .only-light { display: none; }
:root[data-theme="dark"] .only-dark { display: block; }

/* what each marker in a result row means - the part readers actually ask about */
.mlegend { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--sp-4) var(--sp-4); box-shadow: var(--shadow-1); }
/* full-width variant: the legend reads across the band under both frames, so
   the popup column no longer ends a third of the band above the options one */
.mlegend.wide { margin-top: var(--sp-4); }
.mlegend.wide .mlist { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3) var(--sp-6); }
.mlegend h3 { margin-bottom: var(--sp-3); }
.mlist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.mlist > li { margin: 0; display: grid; grid-template-columns: minmax(0, auto) minmax(0, 1fr); gap: var(--sp-2); align-items: baseline; font-size: var(--fs-3); color: var(--ink-light); }
.mlist .mk { justify-self: start; }
.mlist b { color: var(--ink); font-weight: 600; }
.gmk { font-size: var(--fs-1); font-weight: 700; letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--ink-light); background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; padding: 2px var(--sp-2); white-space: nowrap; }

/* ---------- questions and boundaries ---------- */

/* answers are always visible. Six collapsed rows with a blank right half was
   the emptiest screen on the site, and hiding the answers is the opposite of
   what this page is for. */
.qa { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-1) var(--sp-6); }
.qa-i { padding: var(--sp-4) 0 3px; border-top: 1px solid var(--border); }
.qa-i h3 { font-size: var(--fs-5); margin-bottom: var(--sp-2); }
.qa-i .a { color: var(--ink-light); font-size: var(--fs-3); }
.qa-i .a p:last-child { margin-bottom: 0; }

/* the five boundaries: a marked list, not five cards that wrap 4 + 1 */
.plist { list-style: none; padding: 0; margin: 0; gap: var(--sp-1) var(--sp-6); }
.plist > li { margin: 0; padding: var(--sp-4) 0 3px; border-top: 1px solid var(--border); display: grid; grid-template-columns: 21px minmax(0, 1fr); gap: var(--sp-3); align-items: start; }
.plist h3 { font-size: var(--fs-5); margin: 0 0 var(--sp-1); }
.plist p { margin: 0; color: var(--ink-light); font-size: var(--fs-3); }
.pmk { width: 21px; height: 21px; margin-top: 3px; fill: none; stroke: var(--brand); stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- doc layout (guide / measured) ---------- */

.pagehead { padding: clamp(var(--sp-6), 5vw, var(--sp-7)) 0 var(--sp-6); border-bottom: 1px solid var(--border); background: var(--cream-dark); }
.pagehead h1 { font-size: var(--fs-8); }
.pagehead p { color: var(--ink-light); max-width: var(--readw); margin-bottom: 0; }

.doc { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: var(--sp-7); align-items: start; padding: var(--sp-6) 0 var(--sp-8); }
/* grid items default to min-width:auto, which lets a wide table or code block
   stretch the whole column past the viewport. Pin them to 0. */
.doc > * { min-width: 0; }
.toc { position: sticky; top: 84px; font-size: var(--fs-3); }
.toc .h { font-size: var(--fs-1); text-transform: uppercase; letter-spacing: var(--ls-caps-wide); color: var(--ink-light); font-weight: 700; margin-bottom: var(--sp-2); }
.toc ol { list-style: none; margin: 0; padding: 0; counter-reset: t; }
.toc li { margin: 0; counter-increment: t; }
.toc a {
  display: block; padding: var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-6); color: var(--ink-light); text-decoration: none;
  border-left: 2px solid var(--hairline); position: relative; border-radius: 0 6px 6px 0;
}
.toc a::before {
  content: counter(t, decimal-leading-zero); position: absolute; left: 8px; top: 50%; width: 22px;
  transform: translateY(-50%); text-align: right; color: var(--ink-light); font-variant-numeric: tabular-nums;
}
.toc a:hover { color: var(--ink); background: var(--surface-2); }
.toc a.on { color: var(--accent-ink); border-left-color: var(--brand); background: var(--info-soft); font-weight: 600; }

.doc article > section { padding-bottom: var(--sp-6); }
.doc article > section + section { border-top: 1px solid var(--border); padding-top: var(--sp-6); }
.doc article h2 { display: flex; align-items: baseline; gap: var(--sp-3); }
.doc article h2 .n { font-size: 0.8em; color: var(--ink-light); font-variant-numeric: tabular-nums; font-weight: 700; }
.doc article h3 { margin-top: 1.7em; }
.doc article > section > p, .doc article > section > ul, .doc article > section > ol { max-width: var(--readw); }
.steps { counter-reset: s; list-style: none; padding: 0; }
.steps > li { counter-increment: s; position: relative; padding-left: var(--sp-6); margin-bottom: var(--sp-3); }
.steps > li::before {
  content: counter(s); position: absolute; left: 0; top: 1px;
  width: var(--sp-5); height: var(--sp-5); border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--info-soft); color: var(--accent-ink);
  font-family: var(--sans); font-weight: 700; font-size: var(--fs-2);
  line-height: 1;
}

/* ---------- footer ---------- */

footer.site { padding: var(--sp-6) 0 var(--sp-7); background: var(--cream-dark); border-top: 1px solid var(--border); }
.foot { display: flex; flex-wrap: wrap; gap: var(--sp-5) var(--sp-7); justify-content: space-between; }
.foot h3 { font-size: var(--fs-1); text-transform: uppercase; letter-spacing: var(--ls-caps-wide); color: var(--ink-light); margin-bottom: var(--sp-2); }
.foot ul { list-style: none; padding: 0; margin: 0; font-size: var(--fs-3); }
.foot li { margin-bottom: var(--sp-1); }
.foot a { color: var(--ink-light); text-decoration: none; }
.foot a:hover { color: var(--accent-ink); }
.foot-bar { margin-top: var(--sp-6); padding-top: var(--sp-4); border-top: 1px solid var(--border); font-size: var(--fs-2); color: var(--ink-light); display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); }

/* ---------- responsive ---------- */

@media (max-width: 900px) {
  .gext { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 820px) {
  .g6 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .g5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .g5 > *, .g5 > :nth-child(4) { grid-column: span 1; }
  .g5 > :nth-child(5) { grid-column: 1 / -1; }
}
@media (max-width: 780px) {
  .qa, .plist { grid-template-columns: minmax(0, 1fr); }
  .mlegend.wide .mlist { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 560px) {
  .g6 { grid-template-columns: minmax(0, 1fr); }
  .g5 { grid-template-columns: minmax(0, 1fr); }
  .g5 > *, .g5 > :nth-child(4), .g5 > :nth-child(5) { grid-column: 1 / -1; }
}
@media (max-width: 980px) {
  .hero-inner { grid-template-columns: 1fr; }
  .doc { grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); }
  .toc { position: static; border: 1px solid var(--border); border-radius: var(--radius); padding: var(--sp-3) var(--sp-4); background: var(--card-bg); }
  .toc ol { columns: 2; column-gap: var(--sp-4); }
}
@media (max-width: 700px) {
  body { font-size: var(--fs-3); }
  
  nav.top a.hide-sm { display: none; }
  .ctl.gh { display: inline-flex; }
  .site-inner { gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); }
  .logo { font-size: var(--fs-3); gap: var(--sp-2); }
  nav.top { gap: 0; min-width: 0; }
  nav.top a { font-size: var(--fs-2); padding: var(--sp-1) var(--sp-2); }
  .ctl { height: 30px; min-width: 30px; padding: 0 var(--sp-2); margin-left: 3px; font-size: var(--fs-2); }
  .wrap { padding: 0 var(--sp-4); }
  .hero-inner { padding: var(--sp-6) var(--sp-4) var(--sp-6); }
  .bar-row { grid-template-columns: 1fr auto; grid-template-areas: "lb vv" "tr tr"; gap: var(--sp-1) var(--sp-2); }
  .bar-row .lb { grid-area: lb; }
  .bar-row .vv { grid-area: vv; }
  .bar-row .bar-track { grid-area: tr; }
  .toc ol { columns: 1; }
  .foot { gap: var(--sp-4) var(--sp-5); }
  table { font-size: var(--fs-2); }
  th, td { padding: var(--sp-2) var(--sp-2); }
}
@media (max-width: 430px) {
  /* the mark alone still reads as the home link; the nav needs the room */
  .logo .word { display: none; }
  nav.top a { padding: var(--sp-1) var(--sp-1); }
}
@media (max-width: 380px) {
  /* three nav links plus three controls: at 320px every pixel of chrome
     has to come out of the header or the whole page scrolls sideways */
  .site-inner { padding: var(--sp-2) var(--sp-2); gap: var(--sp-1); }
  nav.top a { font-size: var(--fs-2); padding: var(--sp-1) var(--sp-1); }
  .ctl { height: 28px; min-width: 28px; padding: 0 var(--sp-1); margin-left: 2px; font-size: var(--fs-1); }
  .ctl.gh svg { width: 16px; height: 16px; }
  .wrap { padding: 0 var(--sp-3); }
  .hero-inner { padding: var(--sp-6) var(--sp-3) var(--sp-6); }
}

@media print {
  header.site, footer.site, .toc, .progress { display: none; }
  body { background: #fff; }
}

/* ==========================================================================
   hand-drawn frames and tinted base cards
   --------------------------------------------------------------------------
   The two shapes this site borrows from the design system, and the two the
   app uses as well, so a reader who has seen one recognises the other.

   The frame is a dashed rule in one of four hues with a Caveat label sitting
   on the top edge. Colour is never the only signal: the label always names
   the thing. The tinted card is a low-alpha wash of the same hue, written as
   a single `background` gradient -- a `background-color` plus a
   `background-image` composite to 1-(1-a)^2, which is how a "0.08 wash"
   silently becomes 0.15 and stops matching the number in the comment.
   ========================================================================== */

.sketch {
  position: relative;
  margin: var(--sp-6) 0;
  padding: var(--sp-5) var(--sp-5) var(--sp-5);
  border: 2px dashed var(--brand);
  border-radius: 16px;
  background: var(--card-bg);
}

.sketch > .label {
  position: absolute;
  top: -13px;
  left: 20px;
  padding: 0 var(--sp-2);
  background: var(--cream);
  color: var(--accent-ink);
  font-family: var(--sans);
  font-size: var(--fs-1);
  font-weight: 800;
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

/* one lane, one family: the frame takes the display step and the label takes
   the text-safe step of the same hue. The lexical frame used to be the gold,
   which is 1.31:1 on paper -- a frame nobody could see round a card that was
   supposed to be identifiable by it. */
.sketch.lex { border-color: var(--indigo); }
.sketch.lex > .label { color: var(--indigo-ink); }
.sketch.intent { border-color: var(--plum); }
.sketch.intent > .label { color: var(--plum-ink); }
.sketch.context { border-color: var(--rose); }
.sketch.context > .label { color: var(--rose-ink); }

.sketch > :first-child + * { margin-top: 0; }
.sketch > :last-child { margin-bottom: 0; }

/* Inside a band that already alternates to paper-2, the label's own paper has
   to follow, or it reads as a white sticker pasted over the frame. */
.band.alt .sketch > .label,
.alt .sketch > .label { background: var(--cream-dark); }

/* Four tinted cards in the prose, one per lane. What this replaces was
   twelve hand-mixed rgba literals -- two blues, a gold, a red and a forest
   green, each written twice as a 145-degree gradient and then written a third
   time in a night override underneath. The gradients were invisible at 3%
   alpha and the night overrides existed only because the literals could not
   follow the theme. These are the solved lane washes instead: separated from
   each other and from every surface they can sit on, in both themes, without a
   single override. */
.tintcard {
  margin: var(--sp-6) 0;
  padding: var(--sp-5);
  /* the border is the hue's second chance: at wash density alone a card in the
     middle of prose reads as the one white card in a coloured set */
  border: 1px solid var(--iris);
  border-radius: 20px;
  background: var(--iris-soft);
}

.tintcard.lex { border-color: var(--indigo); background: var(--indigo-soft); }

.tintcard.intent { border-color: var(--plum); background: var(--plum-soft); }

.tintcard.context { border-color: var(--rose); background: var(--rose-soft); }

.tintcard > .t {
  margin-bottom: var(--sp-2);
  font-weight: 700;
}

.tintcard > .t::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: var(--sp-2);
  border-radius: 50%;
  vertical-align: 1px;
  background: var(--iris);
}

.tintcard.lex > .t::before { background: var(--indigo); }
.tintcard.intent > .t::before { background: var(--plum); }
.tintcard.context > .t::before { background: var(--rose); }

.tintcard > :last-child { margin-bottom: 0; }

/* Three-up grid of small tinted cards, for the "four facets" and "which
   provider" rows that are four short things rather than one long one. */
.tintrow {
  display: grid;
  gap: var(--sp-4);
  margin: var(--sp-6) 0;
}

/* Two columns, not auto-fit. Auto-fit fitted three at the reading width and
   left the fourth card alone on its own row beside a hole; four things that
   belong together have to look like four things that belong together. */
@media (min-width: 700px) {
  .tintrow { grid-template-columns: 1fr 1fr; }
}

.tintrow > .tintcard { margin: 0; }
