/* THE DEFAULT SCHEME carries `:root:not([data-scheme])` - today verdigris,
   the sixth dot. Move that prefix and set DEFAULT_SCHEME in build.py to
   match; check-static.py asserts the two agree.
   The `:not()` is load-bearing. A bare `:root,` has the SAME specificity as
   `[data-scheme="x"]`, so it beat every block above it in source order: the
   first five dots set the attribute, the attribute matched, verdigris won
   anyway. Five of eight dots did nothing and every check passed. */
[data-scheme="daylight"]{--l-bg:#E4F6FB;--l-surface:#F1FBFE;--l-sunken:#D4EDF3;--l-line:#C5E3EB;--l-text:#1F2F4C;--l-mute:#556B75;--l-accent:#1B6AAE;--l-display:#CD1819;--d-bg:#0C1B28;--d-surface:#16222E;--d-sunken:#0A1E31;--d-line:#0C263E;--d-text:#E0F0F4;--d-mute:#738E9E;--d-accent:#2992D0;--d-display:#F6503C}
[data-scheme="meridian"]{--l-bg:#FDF2DD;--l-surface:#FFF9EE;--l-sunken:#F6E7CC;--l-line:#EEDBBA;--l-text:#0A304F;--l-mute:#546980;--l-accent:#1C6F8B;--l-display:#12727C;--d-bg:#0B1C2A;--d-surface:#162430;--d-sunken:#082033;--d-line:#092840;--d-text:#F5EEDE;--d-mute:#7490A4;--d-accent:#2A99AC;--d-display:#2A9BA0}
[data-scheme="bloom"]{--l-bg:#FEEDEE;--l-surface:#FFF6F6;--l-sunken:#F7E1E2;--l-line:#EFD5D6;--l-text:#412137;--l-mute:#825974;--l-accent:#AF24A9;--l-display:#C7174D;--d-bg:#23141E;--d-surface:#291C25;--d-sunken:#291523;--d-line:#341B2D;--d-text:#F8EAEA;--d-mute:#B17999;--d-accent:#EE33D6;--d-display:#F6495F}
:root:not([data-scheme]),[data-scheme="verdigris"]{--l-bg:#EFF2EB;--l-surface:#F7F8F4;--l-sunken:#E4E8DF;--l-line:#D9DED2;--l-text:#18271B;--l-mute:#546D54;--l-accent:#1C7459;--l-display:#127358;--d-bg:#0C1B13;--d-surface:#16221B;--d-sunken:#0C1F14;--d-line:#0F281B;--d-text:#E6EAE0;--d-mute:#729177;--d-accent:#299B73;--d-display:#299B73}
[data-scheme="aubergine"]{--l-bg:#F4EFF4;--l-surface:#F9F7FA;--l-sunken:#EAE4EB;--l-line:#E0D9E1;--l-text:#2D1B32;--l-mute:#7B5A83;--l-accent:#696A19;--l-display:#C11773;--d-bg:#1E1422;--d-surface:#251C29;--d-sunken:#231529;--d-line:#2D1B34;--d-text:#EEE7EF;--d-mute:#A679AD;--d-accent:#8A8E25;--d-display:#F636A8}
[data-scheme="brand"]{--l-bg:#fdfbf7;--l-surface:#fffdf9;--l-sunken:#f6f1e8;--l-line:#e4ddd1;--l-text:#2b2723;--l-mute:#5f5b54;--l-accent:#a65700;--l-display:#a65700;--d-bg:#1b1917;--d-surface:#232120;--d-sunken:#1f1d1b;--d-line:#2c2822;--d-text:#f2ece3;--d-mute:#bdb4a7;--d-accent:#dfa055;--d-display:#dfa055}
/* Instrument Sans - the designer's first choice, SIL OFL 1.1, self-hosted
   because the site makes zero external requests and the CSP forbids them.
   One variable file per subset, weight axis only (400-700): the full face
   also carries a width and an italic axis, neither of which this design
   uses and both of which cost bytes.

   TWO files, not one merged file. Each declares its own unicode-range, so
   latin-ext is fetched only by a page that renders those glyphs - and no
   page here normally does. A merged file would charge every visitor for
   characters almost none of them see.

   The url() is relative to THIS STYLESHEET, never root-absolute. The legal
   documents link ../site/css/site.css and are rendered to PDF over file://,
   where /assets/... resolves against the filesystem root and fails SILENTLY
   - the prints would come out in a fallback face with no error and no
   warning. Same rule as the brand images, for the same reason. */
@font-face {
  font-family: "Instrument Sans"; font-style: normal; font-weight: 400 700;
  font-display: swap;
  src: url(../assets/fonts/instrument-sans-latin-wght-normal.woff2) format("woff2-variations");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Instrument Sans"; font-style: normal; font-weight: 400 700;
  font-display: swap;
  src: url(../assets/fonts/instrument-sans-latin-ext-wght-normal.woff2) format("woff2-variations");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

@charset "utf-8";
/* Lustig Fairchild — site.css
   One stylesheet, no framework, no external request. Tokens first; every
   colour used as text carries its measured contrast ratio in a comment.
   Budget: 6,144 bytes gzipped (06-build-and-verification.md). */

/* ============================================================ tokens */
:root {
  color-scheme: light dark;
  --css-loaded: 1;                 /* sentinel: check-site.py reads this back */

  /* --------------------------------------------------- colour schemes
     Six schemes, each carrying BOTH halves: --l-* for light, --d-* for
     dark. The mapping below picks a half; a scheme never repeats itself
     per appearance, so adding one is one line and cannot desynchronise.

     Not chosen by eye. Every value is SOLVED in OKLCH: the lightness is
     the answer to a contrast equation and the chroma is the gamut maximum
     at that lightness, so hue is the only free variable and every scheme
     lands on the same ratios. Written up in 11-design-craft.md.
     Ink >= 11.8:1 everywhere; accents, muted and eyebrows >= 4.55:1 on
     the SUNKEN surface, which is the darkest ground any of them sits on -
     solve against the surface that gives the LEAST contrast - which is the
     darkest one in light and the LIGHTEST one in dark, because a card in
     dark mode is lighter than the page. Getting that backwards shipped
     4.38:1 into every card description in all seven new schemes, and only
     a browser measuring all sixteen combinations found it. */
  --bg:var(--l-bg);--surface:var(--l-surface);--sunken:var(--l-sunken);
  --text:var(--l-text);--text-mute:var(--l-mute);--accent:var(--l-accent);
  --display:var(--l-display);--line:var(--l-line);
  --header-bg:color-mix(in srgb,var(--l-bg) 84%,transparent);

  /* type — one modular scale. Arbitrary sizes are the commonest reason a
     site looks amateur while every page looks fine on its own. */
  --f-sys: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --f-body: "Instrument Sans", var(--f-sys);
  --f-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --t-xs:  .8125rem;
  --t-sm:  .9375rem;
  --t-md:  1.0625rem;
  --t-lg:  1.1875rem;
  --t-xl:  clamp(1.4375rem, 1.15rem + 1.1vw, 1.875rem);
  --t-2xl: clamp(1.875rem, 1.35rem + 2.4vw, 2.75rem);
  --t-3xl: clamp(2.375rem, 1.5rem + 4.2vw, 4rem);

  --s-1: .25rem;  --s-2: .5rem;   --s-3: .75rem;  --s-4: 1rem;
  --s-5: 1.5rem;  --s-6: 2rem;    --s-7: 3rem;
  --s-section: clamp(3.5rem, 2rem + 6vw, 6rem);

  --r-sm: 10px;  --r: 16px;  --r-lg: 24px;
  --wrap: 1120px;  --prose: 46rem;
  --pad: clamp(1.25rem, .75rem + 2.5vw, 2rem);
}

@media (prefers-color-scheme: dark){:root:not([data-theme="light"]){--bg:var(--d-bg);--surface:var(--d-surface);--sunken:var(--d-sunken);--text:var(--d-text);--text-mute:var(--d-mute);--accent:var(--d-accent);--display:var(--d-display);--line:var(--d-line);--header-bg:color-mix(in srgb,var(--d-bg) 84%,transparent);--shadow:0 1px 2px rgb(0 0 0/.4),0 10px 30px rgb(0 0 0/.35);--lift:0 2px 4px rgb(0 0 0/.45),0 18px 44px rgb(0 0 0/.45);}}
[data-theme="dark"]{--bg:var(--d-bg);--surface:var(--d-surface);--sunken:var(--d-sunken);--text:var(--d-text);--text-mute:var(--d-mute);--accent:var(--d-accent);--display:var(--d-display);--line:var(--d-line);--header-bg:color-mix(in srgb,var(--d-bg) 84%,transparent);--shadow:0 1px 2px rgb(0 0 0/.4),0 10px 30px rgb(0 0 0/.35);--lift:0 2px 4px rgb(0 0 0/.45),0 18px 44px rgb(0 0 0/.45);}
[data-theme="light"]) {
    --bg: #1b1917; --surface: #221f1c; --sunken: #201d1a;
    --text: #f2ece3;                 /* on #1b1917        13.9:1  AAA  */
    --text-mute: #b3aaa0;            /* on #1b1917         7.0:1  AAA  */
    --accent: #d9954d;               /* on #1b1917         6.2:1  AA   */
    --display: #b9752f;              /* on #1b1917         4.7:1  large */
    --line: #3a352f;
    --shadow: 0 1px 2px rgb(0 0 0 / .4), 0 10px 30px rgb(0 0 0 / .35);
    --lift:   0 2px 4px rgb(0 0 0 / .45), 0 18px 44px rgb(0 0 0 / .45);
    --header-bg: rgb(27 25 23 / .84);
  }
}
[data-theme="dark"] {
  --bg: #1b1917; --surface: #221f1c; --sunken: #201d1a;
  --text: #f2ece3; --text-mute: #b3aaa0; --accent: #d9954d; --display: #b9752f;
  --line: #3a352f;
  --shadow: 0 1px 2px rgb(0 0 0 / .4), 0 10px 30px rgb(0 0 0 / .35);
  --lift:   0 2px 4px rgb(0 0 0 / .45), 0 18px 44px rgb(0 0 0 / .45);
  --header-bg: rgb(27 25 23 / .84);
}

/* ============================================================ base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 400 var(--t-md)/1.65 var(--f-body);
  letter-spacing: -.003em;
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
}
h1, h2, h3, h4 { margin: 0 0 var(--s-3); line-height: 1.14; text-wrap: balance; font-weight: 650; }
h1 { font-size: var(--t-3xl); letter-spacing: -.038em; }
h2 { font-size: var(--t-2xl); letter-spacing: -.028em; }
h3 { font-size: var(--t-lg);  letter-spacing: -.012em; line-height: 1.3; }
p, ul, ol, dl, table { margin: 0 0 var(--s-4); }
a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: .18em; }
a:hover { text-decoration-thickness: 2px; }
img, svg, video { max-width: 100%; height: auto; }
hr { border: 0; border-top: 1px solid var(--line); margin: var(--s-6) 0; }
strong { font-weight: 620; }
small { font-size: var(--t-sm); }
code, kbd { font-family: var(--f-mono); font-size: .9em; }
::selection { background: rgb(185 117 47 / .22); }

:focus-visible {
  outline: 2px solid var(--display); outline-offset: 3px; border-radius: 4px;
}
/* WCAG 2.2 — Focus Not Obscured: the sticky header must not cover the target */
:target, h2, h3 { scroll-margin-block-start: 5.5rem; }

.skip {
  position: absolute; inset-inline-start: -9999px; top: var(--s-2);
  background: var(--surface); color: var(--text); padding: var(--s-2) var(--s-4);
  border: 1px solid var(--line); border-radius: var(--r-sm); z-index: 20;
}
.skip:focus { inset-inline-start: var(--s-4); }

/* ============================================================ layout */
.wrap { max-width: var(--wrap); margin-inline: auto; padding-inline: var(--pad); }
/* A centred prose box inside a centred wrap shifts the content sideways, so
   the left edge stops agreeing with the full-width sections above it. Keep
   the wrap's own width and constrain the CHILDREN instead. */
.prose { max-width: var(--prose); }
.wrap.prose { max-width: var(--wrap); }
.wrap.prose > * { max-width: var(--prose); }
.prose p, .prose li { text-wrap: pretty; }
.section { padding-block: var(--s-section); }
/* Zero the gap only when BOTH sides are plain. A band's padding belongs
   inside its own background, so a section following one needs its own top
   padding back - missing until 19.09.2026, wrong on nine of ten pages. */
.section:not(.section--sunken, .section--ink)
  + .section:not(.section--sunken, .section--ink) { padding-block-start: 0; }
.section--sunken { background: var(--sunken); border-block: 1px solid var(--line); }
/* One band carries the full palette: ink ground, bone text, amber accents.
   Tokens are redeclared rather than colours overridden, so every nested
   component keeps working and the contrast check reads the real values. */
/* The ink band is simply the DARK half of the scheme in force. Six
   schemes, one rule - and it can never disagree with the scheme, which the
   hand-written palette it replaced did the moment a second scheme existed. */
.section--ink{--bg:var(--d-bg);--surface:var(--d-surface);--sunken:var(--d-sunken);
  --text:var(--d-text);--text-mute:var(--d-mute);--accent:var(--d-accent);
  --display:var(--d-display);--line:var(--d-line);
  background:var(--d-bg);color:var(--d-text);}
[data-theme="dark"] .section--ink,:root:not([data-theme="light"]) .section--ink{background:var(--d-sunken)}

/* the rule-over-eyebrow motif, taken from the logo lockup */
.eyebrow {
  display: block; font-size: var(--t-xs); font-weight: 620;
  letter-spacing: .1em; text-transform: uppercase; color: var(--accent);
  margin-block-end: var(--s-3);
}
.eyebrow::before {
  content: ""; display: block; width: 2.25rem; height: 2px;
  background: var(--display); margin-block-end: var(--s-3); border-radius: 1px;
}
.lede { font-size: clamp(1.125rem, 1rem + .4vw, 1.3125rem); line-height: 1.55; color: var(--text-mute); max-width: 42rem; text-wrap: pretty; }
/* the identity sentence: a statement in display type, not a banner */
.identity { font-size: var(--t-xl); letter-spacing: -.018em; line-height: 1.3; max-width: 34rem; margin: 0; }

/* ============================================================ header */
.hdr {
  position: sticky; inset-block-start: 0; z-index: 10;
  background: var(--header-bg); backdrop-filter: saturate(180%) blur(14px);
  border-block-end: 1px solid var(--line);
}
.hdr-in { display: flex; align-items: center; gap: var(--s-4); min-height: 3.75rem; flex-wrap: wrap; }
@media (max-width: 30rem) {
  .hdr-in { min-height: 0; padding-block: .5rem; row-gap: .25rem; column-gap: var(--s-2); }
  .nav { margin-inline-start: 0; width: 100%; justify-content: space-between; }
  .nav a { padding-inline: .375rem; }
}
.brand { display: inline-flex; align-items: center; gap: var(--s-3); color: var(--text); text-decoration: none; font-weight: 650; letter-spacing: -.02em; }
.brand span { white-space: nowrap; }
.nav { margin-inline-start: auto; display: flex; align-items: center; gap: var(--s-1); }
.nav a, .tgl {
  color: var(--text-mute); text-decoration: none; font-size: var(--t-sm); font-weight: 550;
  padding: .5rem .625rem; border-radius: var(--r-sm); min-height: 2.25rem;
  display: inline-flex; align-items: center; transition: background .16s, color .16s;
}
.nav a:hover, .tgl:hover { color: var(--text); background: rgb(185 117 47 / .1); }
.nav a[aria-current="page"] { color: var(--text); }
.tgl { background: none; border: 0; cursor: pointer; font: inherit; min-width: 2.25rem; justify-content: center; }
.tgl svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7; }
[data-theme="dark"] .i-sun, :root:not([data-theme="light"]) .i-sun { display: none; }
[data-theme="dark"] .i-moon, :root:not([data-theme="light"]) .i-moon { display: block; }
.i-moon { display: none; }
[data-theme="light"] .i-sun { display: block; }
[data-theme="light"] .i-moon { display: none; }
@media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) .i-sun { display: block; } :root:not([data-theme="dark"]) .i-moon { display: none; } }

/* ============================================================ hero */
.hero { padding-block: clamp(2.5rem, 1rem + 6vw, 5.5rem) var(--s-section); }
.hero-in { display: flex; flex-direction: column; align-items: center; text-align: center; }
.brand-mark,.hero-mark{background:currentColor;color:var(--text);
  -webkit-mask:var(--m) no-repeat center/contain;mask:var(--m) no-repeat center/contain}
.brand-mark{--m:url("../assets/brand/monogram-mark-192w.webp")}
.hero-mark{--m:url("../assets/brand/monogram-640w.webp")}
.brand-mark { display: block; flex: none; width: 4.6875rem; height: 1.5625rem; }
.hero-mark {
  display: block; width: clamp(11rem, 24vw, 17.5rem); aspect-ratio: 1407 / 470;
  margin-block-end: var(--s-6);
}
/* the mark already anchors the hero; a rule above the eyebrow as well
   makes three stacked ornaments before the first word. */
.hero .eyebrow::before { display: none; }
.hero h1 { max-width: 24ch; }
.hero .lede { margin-block-start: var(--s-4); max-width: 38rem; }
.hero .btn-row { justify-content: center; }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-block-start: var(--s-5); }
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: 2.75rem; padding: .6875rem 1.25rem; border-radius: 999px;
  font-size: var(--t-sm); font-weight: 600; text-decoration: none;
  border: 1.5px solid transparent; cursor: pointer;
  transition: transform .16s, box-shadow .16s, background .16s, border-color .16s;
}
.btn-primary { background: var(--text); color: var(--bg); }
.btn-primary:hover { transform: translateY(-2px); box-shadow: var(--lift); }
/* An amber FILL is not possible: 3.6:1 with bone text, 4.0:1 with ink. So the
   amber call-to-action is outlined — 05-brand.md. */
.btn-ghost { border-color: var(--display); color: var(--accent); background: transparent; }
.btn-ghost:hover { background: rgb(185 117 47 / .09); transform: translateY(-2px); }

/* ============================================================ grids */
.grid { display: grid; gap: var(--s-4); }
/* Two, always — four cards, two rows. auto-fit cannot say that: the
   minimum that reaches two columns at a 768px tablet also reaches
   three at 1120px, which orphans the fourth card. */
.grid--apps  { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 47rem) { .grid--apps { grid-template-columns: minmax(0, 1fr); } }
.grid--two   { grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr)); }
.grid--three { grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr)); }

.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: var(--s-5); box-shadow: 0 1px 2px rgb(43 39 35 / .05);
  transition: transform .18s, box-shadow .18s, border-color .18s;
}
a.card { display: block; text-decoration: none; color: inherit; }
a.card:hover { transform: translateY(-3px); box-shadow: var(--lift); border-color: var(--display); }
.card h3 { margin-block-end: var(--s-1); }
.card p { color: var(--text-mute); font-size: var(--t-sm); margin: 0; }
.card-top { display: flex; align-items: center; gap: var(--s-4); margin-block-end: var(--s-4); }
.card-top h3, .card-top .meta { margin: 0; }
.card-ico { width: 56px; height: 56px; flex: none; border-radius: 13px; box-shadow: 0 1px 3px rgb(43 39 35 / .18); }
.meta { font-size: var(--t-xs); color: var(--text-mute); margin-block-start: var(--s-3); }
/* By attribute, not by a class somebody must remember: `.out` alone left
   thirteen new-tab links with no arrow (decision 103, enforced in halves
   twice). `.card` is excepted - its arrow is on the h3 inside. */
.out::after, a[target="_blank"]:not(.card)::after { content: " ↗"; color: var(--display); }

/* Available to a screen reader, absent from the page. Used for the
   "(opens in a new tab)" note on outbound links, where the ↗ carries the
   same fact for anyone who can see it. */
.vh { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
      overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }

/* Cross-document view transitions. One rule: Chromium fades between pages,
   every other browser ignores it, and nothing is loaded to make it work. The
   reduced-motion block below turns it off with the rest of the motion. */
@view-transition { navigation: auto; }

/* Interior page opener: heading and standfirst side by side, so the page
   starts at the full measure instead of a narrow left column with an empty
   right half. The homepage hero stays centred — this is what distinguishes an
   interior page from the front. */
.intro { display: grid; gap: var(--s-4) clamp(2rem, 5vw, 4.5rem); align-items: start;
         grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
.intro > div { min-width: 0; }
.intro .lede { margin: 0; }
.wrap.prose > .intro { max-width: none; }
@media (max-width: 52rem) { .intro { grid-template-columns: minmax(0, 1fr); } }

/* a statement and its particulars, side by side */
.split { display: grid; gap: var(--s-5) clamp(2rem, 4vw, 4rem); align-items: start;
         grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); margin-block-end: var(--s-7); }
@media (max-width: 52rem) { .split { grid-template-columns: minmax(0, 1fr); } }
.facts { display: grid; grid-template-columns: auto 1fr; margin: 0; font-size: var(--t-sm); }
.facts dt { color: var(--text-mute); }
.facts dd { margin: 0; text-align: end; font-weight: 620; }
.facts dt, .facts dd { padding-block: var(--s-3); border-block-start: 1px solid var(--line); }
/* two columns put 'Apple Watch' alone on a second line on a phone; stack instead */
@media (max-width: 34rem) {
  .facts { grid-template-columns: minmax(0, 1fr); }
  .facts dt { padding-block-end: 0; }
  .facts dd { text-align: start; border-block-start: 0; padding-block-start: var(--s-1); }
}
/* principles: one word, then the fact that earns it */
.prin { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--s-4); grid-template-columns: repeat(auto-fit, minmax(min(10.5rem, 100%), 1fr)); }
.prin dt { font-size: var(--t-lg); font-weight: 640; letter-spacing: -.018em; color: var(--text); margin-block-end: var(--s-2); }
.prin dt::before { content: ""; display: block; width: 1.25rem; height: 2px; background: var(--display); margin-block-end: var(--s-3); border-radius: 1px; }
.prin dd { margin: 0; font-size: var(--t-sm); color: var(--text-mute); }

/* numbered feature list */
.features { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--s-5); grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr)); }
.features .num { display: block; font: 600 var(--t-xs)/1 var(--f-mono); color: var(--accent); letter-spacing: .08em; margin-block-end: var(--s-2); }
.features h3 { font-size: var(--t-md); }
.features p { color: var(--text-mute); font-size: var(--t-sm); margin: 0; }

/* spec table */
table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); font-variant-numeric: tabular-nums; }
th, td { text-align: start; padding: .6875rem 0; border-block-end: 1px solid var(--line); vertical-align: top; }
/* Only a ROW header is a label in a two-column spec table. Giving column
   headers the same 40% made the three-column register claim 120% and squeezed
   its link column into the text beside it. */
th { font-weight: 600; color: var(--text-mute); }
tbody th { width: 34%; }
/* A gutter BETWEEN columns; outer edges stay flush. Cells had no inline
   padding, so the register's two link columns read as one run. */
th + th, td + td { padding-inline-start: var(--s-5); }
/* Both link columns, or "Apple ↗" breaks and orphans the arrow. */
.reg td:nth-last-child(-n+2) { white-space: nowrap; }
.reg td:last-child { width: 1%; text-align: end; }
/* `position: relative` is load-bearing. A .vh span inside a table cell is
   absolutely positioned; with no positioned ancestor it resolves against the
   initial containing block, so its static position sits wherever the WIDE
   table put it — outside a 320px viewport, pushing the whole page sideways.
   Naming the scroll container as the containing block keeps it inside.
   Found by check-site.py's 320px overflow pass on /legal/, 20.09.2026, the
   moment the register's links gained accessible names. */
.tbl-wrap { overflow-x: auto; position: relative; }
/* A table is not prose: three columns inside the 46rem measure is cramped,
   and the full 1120px wrap is too loose for two. */
.wrap.prose > .tbl-wrap { max-width: 60rem; }

/* callout + notes */
.callout { background: var(--sunken); border: 1px solid var(--line); border-radius: var(--r-lg); padding: clamp(1.5rem, 1rem + 2.5vw, 2.5rem); }
.note { border-inline-start: 3px solid var(--display); padding-inline-start: var(--s-4); color: var(--text-mute); font-size: var(--t-sm); }

/* FAQ */
details { border-block-end: 1px solid var(--line); padding-block: var(--s-4); }
summary { cursor: pointer; font-weight: 600; list-style: none; display: flex; gap: var(--s-3); align-items: baseline; min-height: 1.75rem; }
summary::-webkit-details-marker { display: none; }
summary::before { content: "+"; color: var(--display); font: 600 1.125rem/1 var(--f-mono); flex: 0 0 .75rem; }
details[open] summary::before { content: "−"; }
details > *:not(summary) { margin-block: var(--s-3) 0; color: var(--text-mute); max-width: var(--prose); }

/* ============================================================ footer */
.ftr { border-block-start: 1px solid var(--line); background: var(--sunken); padding-block: var(--s-7) var(--s-5); font-size: var(--t-sm); }
.ftr-grid { display: grid; gap: var(--s-6); grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr)); }
.ftr h2 { font-size: var(--t-xs); letter-spacing: .1em; text-transform: uppercase; color: var(--text-mute); margin-block-end: var(--s-3); font-weight: 620; }
.ftr ul { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--s-2); }
.ftr a { color: var(--text-mute); text-decoration: none; }
.ftr a:hover { color: var(--accent); text-decoration: underline; }
.ftr-btm { display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-5); align-items: baseline; justify-content: space-between; margin-block-start: var(--s-6); padding-block-start: var(--s-4); border-block-start: 1px solid var(--line); color: var(--text-mute); font-size: var(--t-xs); }

/* ============================================================ a11y + print */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  @view-transition { navigation: none; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
@media print {
  .hdr, .nav, .tgl, .skip, .btn-row, .ftr-grid { display: none !important; }
  :root { --bg: #fff; --text: #000; --text-mute: #333; --line: #bbb; }
  body { font-size: 11pt; }
  .section { padding-block: 0 1.5rem; }
  a { color: #000; text-decoration: underline; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; }
  .card, .callout { box-shadow: none; border: 1px solid #bbb; break-inside: avoid; }
}

/* ============================================================ small parts */
.crumbs { padding-block-start: var(--s-5); }
.crumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: var(--s-2); padding: 0; margin: 0; font-size: var(--t-xs); color: var(--text-mute); }
.crumbs li + li::before { content: "/"; color: var(--line); margin-inline-end: var(--s-2); }
.crumbs a { color: var(--text-mute); text-decoration: none; }
.crumbs a:hover { color: var(--accent); text-decoration: underline; }
.app-ico { width: 80px; height: 80px; border-radius: 18px; margin-block-end: var(--s-4); box-shadow: 0 2px 10px rgb(43 39 35 / .22); }
.app-hero { display: grid; gap: clamp(2rem, 1rem + 4vw, 4rem); align-items: center;
            grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); }
.app-hero--noshot { grid-template-columns: minmax(0, 1fr); }
@media (max-width: 52rem) { .app-hero { grid-template-columns: minmax(0, 1fr); } }
/* These are the App Store screenshots, and each one already has a device
   frame and a headline rendered into it. Drawing a second bezel around them
   nests one phone inside another, so the site adds only a corner radius and
   the lift that separates the panel from the page. */
.shot { justify-self: center; width: min(100%, 20rem); }
.shot img {
  display: block; width: 100%; height: auto; border-radius: var(--r-lg);
  box-shadow: 0 2px 6px rgb(43 39 35 / .13), 0 20px 50px rgb(43 39 35 / .17);
}
/* Three or one. auto-fit gave two from 414px to 600px — an orphaned
   third panel, and two panels too narrow to read. A screenshot needs
   width before it is worth showing at all. */
.shots { display: grid; gap: var(--s-6) clamp(1rem, 3vw, 2.5rem);
         grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 48rem) { .shots { grid-template-columns: minmax(0, 1fr); } }
.shots .shot { width: 100%; max-width: 19rem; }
a.shot { text-decoration: none; color: inherit; }
a.shot img { transition: transform .18s; }
a.shot:hover img { transform: translateY(-5px); }
.shot-cap { display: block; margin-block-start: var(--s-4); text-align: center;
            font-size: var(--t-sm); font-weight: 620; }
.addr { margin-block-start: var(--s-4); }
.back { margin-block-start: var(--s-6); }
/* legal documents: the dateline carries the version and effective date, and
   make-legal-pdfs.py reads it — so it is a class, not an ad-hoc <small>. */
.dateline { font-size: var(--t-sm); color: var(--text-mute); margin-block-end: var(--s-2); }
/* the summary at the top of a policy: the same words a reader would get if
   they only read one screen, so it is set apart rather than styled down */
.glance p { font-size: var(--t-lg); line-height: 1.55; max-width: var(--prose); }
.glance p:last-child { margin-block-end: 0; }
/* A legal instrument is not site furniture: it keeps the face it was
   drafted and printed in, so a typeface decision never quietly restates a
   document. Also keeps the web font out of make-legal-pdfs.py entirely. */
.doc { --f-body: var(--f-sys); font-family: var(--f-body); }
/* Instrument Sans has NO Cyrillic - 0 codepoints in U+0400-04FF, measured
   in both files. Without this the registered Bulgarian name renders
   character by character in whatever the system supplies, mixed with the
   brand face around it. Deliberate, not accidental. */
.cyr { font-family: var(--f-sys); }
.doc h2 + p, .doc h3 + p { margin-block-start: 0; }
/* Several h2 sections sharing one prose column: a rule above each one gives */
   the page its structure, which lets the heading come down a size. Used by the
   two website-level legal pages and by the security policy. */
.doc h2 { font-size: var(--t-xl); margin-block-start: var(--s-6); padding-block-start: var(--s-4); border-block-start: 1px solid var(--line); }
.doc h2:first-child { margin-block-start: 0; border: 0; padding: 0; }
.doc p, .doc li { text-wrap: pretty; }

/* The scheme chooser: six middle dots under the attribution, the quietest
   control on the site - a preference, not a feature. Quiet is how it LOOKS,
   not how big it is: the dots were 10x19 and too tight for the spacing
   exception, so each sits in a 1.5rem box for WCAG 2.2 AA 2.5.8. The glyph
   is unchanged; only the part you can hit grew, and check-site.py measures
   it. The chosen one is darker AND larger - weight alone on a middle dot is
   a difference you have to go looking for. */
.schemes{display:flex;align-items:center;justify-content:flex-end;
  margin-block-start:var(--s-1)}
.schemes button{background:0;border:0;padding:0;cursor:pointer;font:inherit;
  display:inline-flex;align-items:center;justify-content:center;
  inline-size:1.5rem;block-size:1.5rem;line-height:1;
  color:var(--text-mute);border-radius:var(--r-sm)}
.schemes button:hover{color:var(--accent)}
.schemes button[aria-checked="true"]{color:var(--text);font-weight:800;
  transform:scale(1.5)}

/* Each app page takes its accent from ITS OWN ICON. The hue is the
   chroma-weighted mean of the icon's chromatic pixels in OKLCH; the
   lightness is then solved so the colour clears 4.55:1 on the darkest
   sunken surface any of the six schemes produces, and the lightest dark
   one - so one value per app works in all sixteen combinations.

   Magic Ball's icon is monochrome and has no hue to honour, so it was
   given the widest free gap on the wheel. Age App and Quotes sit 35 apart
   in their own artwork, which is too close to tell apart, and were pushed
   to 44. The apps never agreed a palette; this is what agreeing one
   afterwards looks like without overruling any of them.

   The display colour is set to the same value, so an app page is ONE hue
   throughout - otherwise the rule above the eyebrow stays the scheme's
   colour and the eyebrow under it is the app's, which reads as a mistake.

   Regenerate with tools/make-brand.py when an icon changes. */
[data-app="MagicBall"]{--l-accent:#5A6C0E;--d-accent:#7E9518;--l-display:#5A6C0E;--d-display:#7E9518}
[data-app="Quotes"]{--l-accent:#116E7A;--d-accent:#1C9AA9;--l-display:#116E7A;--d-display:#1C9AA9}
[data-app="AgeApp"]{--l-accent:#1065B4;--d-accent:#1A8DF7;--l-display:#1065B4;--d-display:#1A8DF7}
[data-app="RoutineRandomizer"]{--l-accent:#C71715;--d-accent:#FB4E40;--l-display:#C71715;--d-display:#FB4E40}
