/* ==========================================================================
   ECLIPTA — marketing site
   Direction: "Hold". Every image on this site is a capture of the running
   app; everything else is type on true black. Nothing moves unless the
   visitor caused it.

   Colour values are the app's own tokens (design-tokens.json) composited
   over #050505. Every text/ground pair is recorded with its computed WCAG
   ratio beside it. Nothing on this site is below 16px.
   ========================================================================== */

/* ---------- Font ---------------------------------------------------------- */
@font-face {
  font-family: 'General Sans';
  src: url('assets/fonts/GeneralSans-latin.woff2') format('woff2');
  font-weight: 400 500;            /* clamps a stray `bold` to 500, never 700 */
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+2010-2027, U+2030-205E, U+20AC, U+2122, U+2212;
}
/* Metric-matched fallback, so `swap` costs no layout shift.
   From the font's own tables: xHeight 538/1000 ÷ Arial 0.5186 = 1.0374. */
@font-face {
  font-family: 'General Sans Fallback';
  src: local('Arial'), local('Helvetica Neue');
  size-adjust: 104%;
  ascent-override: 97.4%;
  descent-override: 23.1%;
  line-gap-override: 0%;
}

/* ==========================================================================
   TOKENS
   ========================================================================== */
:root {
  /* ---------- Ground ----------
     --s1 is the app's surface1, rgba(255,255,255,.05) over #050505. */
  --bg:    #050505;              /* app `background` token                    */
  --s1:    #121212;              /* app surface1 — one band on the page       */
  --plate: #FFFFFF;              /* the one polarity inversion                */

  /* ---------- Ink ----------
     --ink-2, not pure white, is the default for running text: it emits 15%
     less light exactly where strokes are thinnest, and still clears AA by
     3.9x. Pure white is reserved for >=31px, where there is no bloom to fix
     and it gives exact parity with the app's textPrimary. */
  --ink-1: #FFFFFF;              /* headings >=31px      20.38:1 on --bg      */
  --ink-2: #EDEDED;              /* all running text     17.41:1 on --bg      */
  --ink-3: #B4B4B4;              /* captions, nav, terms  9.83:1 on --bg      */
  --ink-4: #8E8E8E;              /* labels, meta, >=16px  6.22:1 on --bg      */
  /* There is no fifth, fainter ink. Nothing below #8E8E8E carries a
     character anywhere on this site. */

  --plate-ink-1: #050505;        /* the plate sentence   20.38:1 on white     */
  --plate-ink-2: #565656;        /* the plate's foot line 7.34:1 on white     */

  /* ---------- Rules and boundaries ----------
     Split by role: WCAG 1.4.11 governs boundaries that identify a component
     or its state, not decoration. A 1px hairline needs ~4.5x the lightness
     delta of a flat field to read equally, which is why --rule is .14. */
  --rule:        rgba(255,255,255,0.14);   /* decorative hairlines            */
  --rule-strong: rgba(255,255,255,0.20);   /* table rows, plate edges         */
  --boundary:    rgba(255,255,255,0.36);   /* #5F5F5F 3.19:1 — form fields    */
  --underline:   rgba(255,255,255,0.35);   /* #5C5C5C 3.05:1 — link underline */
  --bevel: inset 0 1px 0 rgba(255,255,255,0.07);   /* the lit top facet       */
  /* No box-shadow with a positive blur exists in this file. Fully opaque
     black over #050505 shifts L* by 1.37 — a drop shadow here is physically
     inert, which is why the old design reached for a glow instead. Depth is
     surface lightening + hairline + inset top facet. */

  /* ---------- Spacing — the app's own scale ---------- */
  --sp-xs: 4px;   --sp-sm: 8px;   --sp-md: 12px;  --sp-lg: 16px;
  --sp-xl: 20px;  --sp-xxl: 24px; --sp-3xl: 32px; --sp-4xl: 48px;
  --sp-5xl: 64px; --sp-6xl: 96px; --sp-7xl: 160px;
  /* Section rhythm is asymmetric on purpose: more space below than above,
     so a section pushes away from what follows instead of sitting in a box. */
  --sec-pad-top:    clamp(56px, 6vw, 80px);
  --sec-pad-bottom: clamp(64px, 7vw, 96px);
  --sec-pad-tight:  clamp(40px, 5vw, 64px);

  /* ---------- Containers — exactly two ---------- */
  --gutter:       clamp(20px, 5vw, 64px);
  --shell:        min(100% - (2 * var(--gutter)), 1400px);
  --shell-narrow: min(100% - (2 * var(--gutter)), 720px);

  /* ---------- Radius ---------- */
  --r-sm: 8px;  --r-md: 16px;  --r-xxl: 28px;  --r-full: 999px;

  /* ---------- Motion ---------- */
  --ease: cubic-bezier(.25,.46,.45,.94);
  --t-fast: 140ms;
  --t-slow: 220ms;

  /* ==========================================================================
     TYPE
     Dual ratio: 1.200 at 375px expanding to 1.333 at 1440px. Every fluid band
     is exactly 375 -> 1440, so type moves across the real phone range. Every
     bound is in rem, so browser zoom still moves the whole scale.
     HARD FLOOR: nothing is below 16px.
     ========================================================================== */
  --font: 'General Sans', 'General Sans Fallback', system-ui, sans-serif;
  /* The only permitted second family, scoped to one numeric column. General
     Sans has no `tnum` at all, so `tabular-nums` is a no-op on it. */
  --font-tabular: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  --wt-body: 400;
  --wt-display: 500;
  /* 200, 300, 600 and 700 are banned. At 19px a w300 stem is sub-pixel and
     halation fills the counters on true black; at 80px a w600 stem reads as
     advertising, and irradiation already adds apparent weight on black. */

  --fs-micro:   1rem;                                                /* 16       */
  --fs-body:    clamp(1.1250rem, 1.1030rem + 0.0939vw, 1.1875rem);   /* 18 -> 19 */
  --fs-lede:    clamp(1.3500rem, 1.2679rem + 0.3502vw, 1.5831rem);   /* 21.6->25.3 */
  --fs-h3:      clamp(1.6200rem, 1.4475rem + 0.7362vw, 2.1100rem);   /* 25.9->33.8 */
  --fs-h2:      clamp(1.9438rem, 1.6379rem + 1.3052vw, 2.8125rem);   /* 31.1->45 */
  --fs-h1:      clamp(2.3325rem, 1.8334rem + 2.1296vw, 3.7500rem);   /* 37.3->60 */
  --fs-plate:   clamp(2.7994rem, 1.4963rem + 5.5596vw, 6.5000rem);   /* 44.8->104 */

  /* Body is 1.62, deliberately looser than the ~1.55 this face takes on
     white: bloom makes adjacent lines encroach, so perceived leading on true
     black is tighter than set leading. */
  --lh-micro: 1.50;  --lh-body: 1.62;  --lh-lede: 1.45;  --lh-h3: 1.30;
  --lh-h2: 1.12;     --lh-h1: 1.06;    --lh-plate: 0.96;

  /* Tracking flips sign at ~20px: below it, halation needs the sidebearing
     given back; above it, ordinary optical compensation applies. In rem, so
     the correction does not drift across the fluid range. */
  --ls-micro:  0.0150rem;
  --ls-body:   0.0115rem;
  --ls-lede:   0.0073rem;
  --ls-h3:     clamp(-0.0169rem, -0.0116rem - 0.0004vw, -0.0130rem);
  --ls-h2:     clamp(-0.0450rem, -0.0262rem - 0.0013vw, -0.0311rem);
  --ls-h1:     clamp(-0.0825rem, -0.0403rem - 0.0029vw, -0.0513rem);
  --ls-plate:  clamp(-0.1950rem, -0.0449rem - 0.0104vw, -0.0840rem);

  /* Measure. Every value = target characters-per-line ÷ 1.298, the measured
     mean character width of this face over English prose. Writing a naive
     `66ch` would produce 86 characters per line. */
  --mw-micro:   62ch;   /* 80 CPL */
  --mw-body:    51ch;   /* 66 CPL — the Bringhurst centre */
  --mw-lede:    40ch;   /* 52 CPL */
  --mw-h3:      37ch;   /* 48 CPL */
  --mw-h2:      20ch;   /* 26 CPL */
  --mw-h1:      17ch;   /* 22 CPL */
  --mw-display: 14ch;   /* 18 CPL */
}

/* ==========================================================================
   RESET
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html {
  font-feature-settings: 'ss01' 1;   /* single-storey a — decided once, globally */
  -webkit-text-size-adjust: 100%;
  /* Declared dark to the user agent, not only painted dark. Without this the
     browser treats the page as light and draws its own chrome to match: Safari
     fills an autofilled name/email field with a light wash, and --ink-2 on that
     wash is close to invisible — the one state on this site where text does not
     clear AA. The iOS keyboard, the selection handles and desktop scrollbars all
     follow the same declaration. */
  color-scheme: dark;
  /* No `scroll-behavior: smooth`: a documented vestibular trigger. */
}

body {
  background: var(--bg);
  color: var(--ink-2);
  font-family: var(--font);
  font-weight: var(--wt-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-body);
  -webkit-font-smoothing: antialiased;
  /* No `overflow-x: hidden`. It masked a real overflow from the old corona;
     with that deleted there is no overflow source, and the clip would hide
     every future regression. */
}

img, svg, picture { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
::selection { background: rgba(255,255,255,0.22); }

/* ---------- Focus ----------
   The ring appears instantly, never fades. 20.38:1 against the page. */
:focus-visible {
  outline: 2px solid var(--ink-1);
  outline-offset: 3px;
  border-radius: 2px;
}
.plate-section :focus-visible { outline-color: var(--plate-ink-1); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

.skip {
  position: absolute; left: var(--sp-lg); top: var(--sp-lg); z-index: 100;
  transform: translateY(-200%);
  background: var(--plate); color: var(--plate-ink-1);
  padding: var(--sp-md) var(--sp-xl); border-radius: var(--r-full);
  font-size: var(--fs-micro); font-weight: var(--wt-display);
}
.skip:focus { transform: none; }

/* ==========================================================================
   TYPE ROLES
   ========================================================================== */
h1, h2, h3 { margin: 0; text-wrap: balance; font-weight: var(--wt-display); }
p { margin: 0; text-wrap: pretty; max-width: var(--mw-body); }

/* Optical cap-height trim — aligns a heading's visual top edge to the grid
   instead of its invisible leading. Progressive enhancement. */
@supports (text-box: trim-both cap alphabetic) {
  h1, h2, .t-plate { text-box: trim-both cap alphabetic; }
}

h1, .t-h1 {
  font-size: var(--fs-h1); line-height: var(--lh-h1);
  letter-spacing: var(--ls-h1); max-width: var(--mw-h1); color: var(--ink-1);
}
h2, .t-h2 {
  font-size: var(--fs-h2); line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2); max-width: var(--mw-h2); color: var(--ink-1);
}
h3, .t-h3 {
  font-size: var(--fs-h3); line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3); max-width: var(--mw-h3); color: var(--ink-2);
}
.t-lede {
  font-size: var(--fs-lede); line-height: var(--lh-lede);
  letter-spacing: var(--ls-lede); max-width: var(--mw-lede); color: var(--ink-2);
}
.t-caption {
  font-size: var(--fs-micro); line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro); max-width: var(--mw-micro); color: var(--ink-3);
}
.t-meta {
  font-size: var(--fs-micro); line-height: var(--lh-micro);
  letter-spacing: var(--ls-micro); max-width: var(--mw-micro); color: var(--ink-4);
}
strong, b { font-weight: var(--wt-display); color: var(--ink-1); }

/* Numerals: proportional in prose (tabular figures make rivers in a
   sentence). `case` lifts figures to cap height beside capitals. */

/* ---------- Inline links ---------- */
.link {
  color: var(--ink-1);
  text-decoration: underline;
  text-decoration-color: var(--underline);
  text-underline-offset: 0.22em;
  text-decoration-thickness: 1px;
}
@media (hover: hover) and (pointer: fine) {
  .link { transition: text-decoration-color var(--t-fast) var(--ease); }
  .link:hover { text-decoration-color: var(--ink-1); }
}

/* ==========================================================================
   LAYOUT PRIMITIVES
   ========================================================================== */
.shell  { width: var(--shell);        margin-inline: auto; }
.narrow { width: var(--shell-narrow); margin-inline: auto; }
/* Shell-wide block whose contents are capped at the narrow measure, so a
   720px column still starts at the page's one left edge instead of being
   centred. The left rag stays constant down the whole page; the only
   deliberately centred moments are section 03, the demonstration and the
   plate. */
.narrow-left { width: var(--shell); margin-inline: auto; }
.narrow-left > * { max-width: var(--shell-narrow); }
/* The tile grid is the section's visual, not its prose — it spans the shell
   while the reading measure stays capped. */
.narrow-left > .tiles { max-width: none; }

.section { padding-block: var(--sec-pad-top) var(--sec-pad-bottom); }
.section--tight { padding-block: var(--sec-pad-top) var(--sec-pad-tight); }

/* Full-bleed. The note below was right and the rule under it was wrong: it
   used `50vw`, and `100vw` includes the scrollbar. Every .bleed element is a
   direct child of <main>, and <main> is unstyled inside an unpadded <body> —
   so it already spans the full content width and needs no negative margin at
   all. `calc(50% - 50vw)` pulled it half a scrollbar past each edge, which is
   0 where scrollbars overlay (macOS, iOS) and ~7px each side where they take
   layout space (Windows, Linux, and macOS set to "always show") — a real
   horizontal scrollbar, and a violation of this site's own no-overflow rule.
   Never reintroduce a viewport unit here. */
.bleed { width: auto; margin-inline: 0; }

/* ==========================================================================
   MASTHEAD — static, in normal flow. Not fixed, not sticky, no backdrop
   filter, no scroll listener anywhere on this site.
   ========================================================================== */
.masthead { border-bottom: 1px solid var(--rule); }
.masthead__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-lg); min-height: 56px;
}
.brand {
  display: inline-flex; align-items: center; gap: var(--sp-sm);
  min-height: 44px;                /* WCAG 2.2 SC 2.5.8 — it is a real link */
  font-size: var(--fs-micro); font-weight: var(--wt-display);
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-1); text-decoration: none;
}
.brand img { width: 24px; height: 24px; }
.masthead nav { display: flex; align-items: center; }
.masthead nav a {
  color: var(--ink-3); font-size: var(--fs-micro); text-decoration: none;
  padding: var(--sp-md) var(--sp-lg); min-height: 44px;
  display: inline-flex; align-items: center;
}
@media (hover: hover) and (pointer: fine) {
  .masthead nav a { transition: color var(--t-fast) var(--ease); }
  .masthead nav a:hover { color: var(--ink-1); }
}

/* ==========================================================================
   HERO
   A live port of the app's breathing dot-field (see hero.js).

   Phone: the field is a band across the top and the copy sits below it on
   clean ground. Overlaying full-height text on the field reads as noise at
   this width — the rings are wider than the viewport, so only fragments of
   arc cross the type.

   Desktop: the field fills the section and the copy sits in a scrimmed left
   column, with the rings blooming away to the right.
   ========================================================================== */
.hero { position: relative; overflow: hidden; padding-bottom: var(--sec-pad-bottom); }

.hero__canvas { display: block; width: 100%; height: 56svh; }

/* Fades the band into the page so it has no hard bottom edge. */
.hero::after {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 56svh;
  z-index: 1; pointer-events: none;
  background: linear-gradient(to bottom,
    transparent 0%, transparent 46%, rgba(5,5,5,0.72) 82%, var(--bg) 100%);
}

.hero__inner { position: relative; z-index: 2; margin-top: var(--sp-5xl); }

@media (min-width: 900px) {
  .hero {
    min-height: 100svh;
    display: grid; align-content: end;
    padding-block: var(--sp-6xl) var(--sec-pad-bottom);
  }
  .hero__canvas { position: absolute; inset: 0; height: 100%; }
  .hero::after {
    inset: 0; height: auto;
    background:
      linear-gradient(to right,
        rgba(5,5,5,0.94) 0%, rgba(5,5,5,0.86) 26%,
        rgba(5,5,5,0.42) 46%, transparent 64%),
      linear-gradient(to bottom,
        transparent 0%, rgba(5,5,5,0.10) 34%, rgba(5,5,5,0.42) 62%,
        rgba(5,5,5,0.86) 82%, var(--bg) 100%);
  }
  .hero__inner { margin-top: 0; }
}

/* A large iPhone in landscape (932x430, 926x428) matches the rule above, so it
   takes 100svh plus --sp-6xl of top padding on a viewport barely 430px tall.
   `.statement` and `.plate-section` already take this escape; the hero was the
   one full-height section that did not. */
@media (min-width: 900px) and (max-height: 480px) {
  .hero { min-height: auto; padding-block: var(--sp-xxl) var(--sec-pad-bottom); }
}

.hero h1 { margin-top: 0; }
.hero .t-lede { margin-top: var(--sp-xxl); }
.hero .cta { margin-top: var(--sp-4xl); }
.hero .t-lede { margin-top: var(--sp-xxl); }

.hero__foot {
  margin-top: var(--sp-4xl);
  display: grid; gap: var(--sp-4xl);
  align-items: start;
}
@media (min-width: 1024px) {
  .hero__foot { grid-template-columns: minmax(0,1fr) minmax(0,26rem); }
}

/* ---------- The download CTA ----------
   One rule: BADGE IN CONTENT, PILL IN CHROME, never both in one view. Two
   controls pointing at the same URL side by side split attention and read as
   an affiliate page.

   The badge is Apple's official WHITE lockup, unmodified. The black variant
   that shipped before is a black body with a #a6a6a6 hairline — on #050505 it
   read as a faint outline rather than an object, which is why the call to
   action had no presence. Source art is 119.66x40 (2.9915:1); set width and
   let height follow.
   ---------------------------------------------------------------------- */
.cta { display: grid; gap: var(--sp-xl); justify-items: start; }

.cta__badge { display: inline-block; }
.cta__badge img { width: 168px; height: auto; }
.cta__badge--lg img { width: 180px; }
@media (min-width: 600px) {
  .cta__badge img { width: 180px; }
  .cta__badge--lg img { width: 200px; }
}
@media (hover: hover) and (pointer: fine) {
  .cta__badge { transition: opacity var(--t-fast) var(--ease); }
  .cta__badge:hover { opacity: 0.86; }
}
.cta__badge:active { transform: scale(0.985); transition: transform var(--t-fast) var(--ease); }

/* Two 16px lines under the hero badge, in place of the old data plate. */
.cta__note {
  display: flex; flex-wrap: wrap; gap: var(--sp-md) var(--sp-xl);
  font-size: var(--fs-micro); color: var(--ink-4); max-width: none;
}
.cta__note .link { color: var(--ink-3); }

/* Body size, not micro: this is the commercial disclosure, not fine print. */
.cta__terms {
  font-size: var(--fs-body); line-height: var(--lh-body);
  color: var(--ink-3); max-width: var(--mw-body);
}

/* ---------- The pill, for chrome only ---------- */
.btn-download {
  display: inline-flex; align-items: center; gap: var(--sp-sm);
  background: var(--plate); color: var(--plate-ink-1);
  border-radius: var(--r-full);
  /* 44px, not the 40/32 an earlier pass used: this is a real tap target and
     the site holds itself to Apple's 44pt figure, well above WCAG's 24px. */
  min-height: 44px; padding-inline: var(--sp-xl);
  font-size: var(--fs-micro); font-weight: var(--wt-display);
  text-decoration: none; white-space: nowrap;
}
.btn-download svg { width: 1.05em; height: 1.05em; flex: none; }
.btn-download--sm { min-height: 44px; padding-inline: var(--sp-lg); }
.btn-download:active { transform: scale(0.985); transition: transform var(--t-fast) var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .btn-download { transition: filter var(--t-fast) var(--ease); }
  .btn-download:hover { filter: brightness(0.88); }
}

/* ---------- Sticky bar — a 48px top bar, every viewport ----------
   It replaces the masthead as that scrolls away, which is Apple's own
   product-page pattern. Not a full-width bottom bar: none of the reference
   sites ship one, it reads as a DTC upsell rail, and it would cover the
   bottom of a page whose whole argument is restraint.
   ---------------------------------------------------------------------- */
.sticky-cta {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  min-height: 56px; display: flex; align-items: center;
  background: var(--bg); border-bottom: 1px solid var(--rule);
  transform: translateY(-110%);
  /* `visibility`, not just `transform`. A transform only moves the bar off
     screen — its download link stays in the tab order, so a keyboard user
     tabs into an invisible control and the focus ring lands on nothing
     (WCAG 2.4.7 Focus Visible, 2.4.11 Focus Not Obscured). visibility:hidden
     takes it out of the tab order and the accessibility tree, and unlike
     display:none it still allows the slide. The 0s visibility transition is
     DELAYED by the slide duration when retracting, so the bar stays visible
     while it animates away, and is applied with no delay when revealing. */
  visibility: hidden;
  transition: transform var(--t-slow) var(--ease),
              visibility 0s linear var(--t-slow);
}
.sticky-cta[data-show] {
  transform: none;
  visibility: visible;
  transition: transform var(--t-slow) var(--ease),
              visibility 0s linear 0s;
}
.sticky-cta__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-lg); width: var(--shell); margin-inline: auto;
  padding-block: var(--sp-sm);
}
.sticky-cta__name {
  font-size: var(--fs-micro); font-weight: var(--wt-display);
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-2);
}
@media (prefers-reduced-motion: reduce) { .sticky-cta { transition: none; } }

/* ==========================================================================
   NUMBERED ENTRIES — the chain of evidence
   ========================================================================== */
.entry { padding-block: var(--sec-pad-top) var(--sec-pad-bottom); }
.entry h2 + p { margin-top: var(--sp-xxl); }

/* ---------- Block-type list ---------- */
.types { margin-top: var(--sp-3xl); }
/* No rules between entries. The gap does the separating; a horizontal line
   every three lines of prose turned the page into a table. */
.types div {
  display: grid; gap: var(--sp-xs);
  padding-block: var(--sp-md);
}
.types dt { color: var(--ink-1); font-weight: var(--wt-display); }
.types dd { color: var(--ink-3); max-width: var(--mw-body); }

/* ==========================================================================
   STATEMENT — the page's one confrontational line, and what replaces the
   statistics that were cut. Type alone, no asset, nothing else in the view.
   ========================================================================== */
.statement {
  min-height: 70svh; display: grid; align-content: center;
  padding-block: var(--sp-6xl);
}
.t-statement {
  font-size: var(--fs-plate); line-height: var(--lh-plate);
  letter-spacing: var(--ls-plate); max-width: var(--mw-display);
  font-weight: var(--wt-display); color: var(--ink-1);
}
@media (max-height: 480px) { .statement { min-height: auto; } }

/* ---------- Closing line of a numbered entry ---------- */
.entry__coda { margin-top: var(--sp-3xl); color: var(--ink-2); }

/* ---------- The escape-hatch list ----------
   Struck through: these are the controls Eclipta does not have. The rule is
   drawn by the text decoration, so it needs no icon column and no table. */
.ways__label { margin-top: var(--sp-4xl); margin-bottom: var(--sp-lg); }
.ways { list-style: none; display: grid; gap: var(--sp-md); }
.ways li {
  color: var(--ink-3); font-size: var(--fs-lede);
  text-decoration: line-through;
  text-decoration-color: rgba(255,255,255,0.42);
  text-decoration-thickness: 1px;
  text-underline-offset: 0;
}

/* ==========================================================================
   MID-PAGE CTA — its own black band immediately after the white plate, so it
   catches the reader at the peak without touching the plate itself.
   ========================================================================== */
.ctamid { padding-block: var(--sp-5xl); }
.ctamid h2 { margin-bottom: var(--sp-4xl); }

/* ==========================================================================
   THE PLATE — the only inversion on the site.
   ========================================================================== */
.plate-section {
  background: var(--plate); color: var(--plate-ink-1);
  min-height: 88svh;
  display: grid; align-content: center;
  padding-block: var(--sp-6xl);
  position: relative;
}
/* Optically centred: 46% from the top, not 50%. */
.plate-section__inner { padding-bottom: 8%; }
.t-plate {
  font-size: var(--fs-plate); line-height: var(--lh-plate);
  letter-spacing: var(--ls-plate); max-width: var(--mw-display);
  font-weight: var(--wt-display); color: var(--plate-ink-1);
}
@media (max-height: 480px) {
  .plate-section { min-height: auto; padding-block: var(--sp-6xl); }
  }

/* ==========================================================================
   FOUNDER — the quietest block, placed immediately after the loudest.
   No card, no border, no rule, no avatar.
   ========================================================================== */
.founder { padding-block: var(--sp-5xl) var(--sec-pad-bottom); }
.founder .t-h3 { margin-bottom: var(--sp-3xl); }
.founder p + p { margin-top: var(--sp-xxl); }
.founder__sign { margin-top: var(--sp-3xl); color: var(--ink-3); }

/* ==========================================================================
   QUESTIONS
   ========================================================================== */
.faq details { border-bottom: 1px solid var(--rule-strong); }
.faq summary {
  list-style: none; cursor: pointer;
  min-height: 56px; padding-block: var(--sp-lg);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-xl); color: var(--ink-1); font-weight: var(--wt-display);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+"; color: var(--ink-3); font-weight: var(--wt-body);
  flex: none;
}
.faq details[open] summary::after { content: "\2212"; }   /* − U+2212 */
@media (hover: hover) and (pointer: fine) {
  .faq summary { transition: filter var(--t-fast) var(--ease); }
  .faq summary:hover { filter: brightness(1.35); }
}
.faq__body { display: grid; grid-template-rows: 0fr; }
.faq details[open] .faq__body { grid-template-rows: 1fr; }
.faq__body > div { overflow: hidden; }
.faq details[open] .faq__body > div { padding-bottom: var(--sp-xxl); }
@media (prefers-reduced-motion: no-preference) {
  .faq__body { transition: grid-template-rows var(--t-slow) var(--ease); }
}
.faq__note { margin-top: var(--sp-3xl); }

/* ==========================================================================
   CLOSE
   ========================================================================== */
.close h2 { margin-bottom: var(--sp-4xl); }

/* ==========================================================================
   FOOTER
   ========================================================================== */
.footer { border-top: 1px solid var(--rule); padding-block: var(--sp-6xl) var(--sp-4xl); }
.footer__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--sp-4xl); padding-bottom: var(--sp-5xl);
}
.footer-heading {
  font-size: var(--fs-micro); color: var(--ink-4);
  letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: var(--sp-sm);
}
.footer nav a {
  display: flex; align-items: center; min-height: 44px;
  color: var(--ink-3); font-size: var(--fs-micro); text-decoration: none;
}
@media (hover: hover) and (pointer: fine) {
  .footer nav a { transition: color var(--t-fast) var(--ease); }
  .footer nav a:hover { color: var(--ink-1); }
}
.footer__meta {
  border-top: 1px solid var(--rule);
  padding-top: var(--sp-3xl);
  max-width: none;                 /* the rule spans the shell, the text does not */
}

/* ==========================================================================
   SUBPAGES — legal and contact
   ========================================================================== */
.page-head { padding-block: var(--sec-pad-top) var(--sp-4xl); }
.page-head h1 { max-width: var(--mw-h1); }
.page-head .t-lede { margin-top: var(--sp-xxl); }
.updated { margin-top: var(--sp-lg); color: var(--ink-3); font-size: var(--fs-micro); }

/* ---------- Legal prose ---------- */
.legal { padding-bottom: var(--sec-pad-bottom); }
.legal h2 {
  font-size: var(--fs-h3); line-height: var(--lh-h3); letter-spacing: var(--ls-h3);
  color: var(--ink-1); max-width: var(--mw-h3);
  margin-top: var(--sp-6xl); margin-bottom: var(--sp-lg);
  scroll-margin-top: var(--sp-4xl);
}
.legal h2 .n { color: var(--ink-3); font-weight: var(--wt-body); }
.legal h3 { font-size: var(--fs-body); margin-top: var(--sp-3xl); margin-bottom: var(--sp-sm); color: var(--ink-1); }
.legal p { margin-bottom: var(--sp-lg); }
.legal ul { list-style: none; margin-bottom: var(--sp-xl); }
.legal li {
  position: relative; padding-left: var(--sp-xxl);
  margin-bottom: var(--sp-md); max-width: var(--mw-body); color: var(--ink-2);
}
.legal li::before {
  content: ""; position: absolute; left: var(--sp-xs); top: 0.72em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--ink-4);
}
.toc { margin-top: var(--sp-4xl); border-top: 1px solid var(--rule); }
.toc ul { list-style: none; margin-bottom: 0; }
/* The TOC sits inside .legal, so it would otherwise inherit the prose list's
   bullet and its 51ch measure — which put a dot beside every entry and left
   the row rules ending at ragged widths. */
.toc li { padding-left: 0; margin-bottom: 0; max-width: none; }
.toc li::before { content: none; }
.toc a {
  display: flex; align-items: center; min-height: 44px;
  color: var(--ink-3); font-size: var(--fs-micro); text-decoration: none;
  border-bottom: 1px solid var(--rule);
}
@media (hover: hover) and (pointer: fine) {
  .toc a { transition: color var(--t-fast) var(--ease); }
  .toc a:hover { color: var(--ink-1); }
}

/* ---------- Contact form ---------- */
.contact-grid { display: grid; gap: var(--sp-6xl); align-items: start; }
@media (min-width: 900px) { .contact-grid { grid-template-columns: 1.2fr 0.8fr; } }
.form { display: grid; gap: var(--sp-xxl); }
.field { display: grid; gap: var(--sp-sm); }
.field label { font-size: var(--fs-micro); color: var(--ink-3); }
.field input, .field textarea {
  font-family: var(--font); font-size: var(--fs-body); color: var(--ink-2);
  background: transparent;                 /* --boundary is 3.19:1 on --bg */
  border: 1px solid var(--boundary); border-radius: var(--r-md);
  padding: var(--sp-md) var(--sp-lg); min-height: 48px;
}
.field textarea { resize: vertical; min-height: 160px; }
.field input::placeholder, .field textarea::placeholder { color: var(--ink-4); }
.field input:focus-visible, .field textarea:focus-visible { outline-offset: 2px; }
.btn {
  justify-self: start;
  background: var(--plate); color: var(--plate-ink-1);
  border: 0; border-radius: var(--r-full);
  min-height: 56px; padding-inline: var(--sp-4xl);
  font-family: var(--font); font-size: var(--fs-body);
  font-weight: var(--wt-display); cursor: pointer;
}
.btn:active { transform: scale(0.985); transition: transform var(--t-fast) var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .btn { transition: filter var(--t-fast) var(--ease); }
  .btn:hover { filter: brightness(0.88); }
}
.form-status { min-height: 1.5em; }
.form-status[data-state="err"] { color: var(--ink-1); }
.contact-aside h2 { margin-bottom: var(--sp-sm); }
.contact-aside > * + h2 { margin-top: var(--sp-4xl); }

/* ==========================================================================
   REDUCED MOTION
   `.01ms` rather than `none`, so any transitionend listener still fires.
   Transforms are explicitly killed — the old file reset keyframes but left
   eight transform hovers running, which is the exact motion the preference
   exists to stop.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  *:active, *:hover { transform: none !important; }
}

/* Founder prose is measure-capped but flush to the shell's text edge, not
   centred — it is a letter, not a pull-quote. */
.founder__body { max-width: var(--shell-narrow); }

/* The wordmark used to be hidden below 345px, because the masthead once held
   the mark, the wordmark AND two nav links, which overflowed a 280px content
   box. Those nav links are gone — `.masthead nav a` now matches nothing — and
   measured at 320px the mark, wordmark and download button need 264px of that
   280px box, with 16px to spare and no overflow. The rule was costing the home
   link its tap target (24x44 instead of 114x44) to solve a problem the markup
   no longer has. */

/* ==========================================================================
   CHANGELOG — a version rail beside a continuous body.
   The rail is navigation, not a tab strip: every version stays in one scroll,
   so a reader can jump to a version OR keep scrolling into the one below it.
   ========================================================================== */
.log { padding-bottom: var(--sec-pad-bottom); }
.log__grid { display: grid; gap: var(--sp-4xl); }

/* Phones: the rail is a horizontal row above the body. It scrolls sideways on
   its own rather than wrapping, so adding versions never pushes the first
   entry off the first screen. */
.log__versions {
  list-style: none; display: flex; gap: var(--sp-sm);
  overflow-x: auto; padding-bottom: var(--sp-xs);
  scrollbar-width: none;
}
.log__versions::-webkit-scrollbar { display: none; }
.log__versions a {
  display: inline-flex; align-items: center; min-height: 44px;
  padding-inline: var(--sp-lg);
  border: 1px solid var(--rule); border-radius: var(--r-full);
  color: var(--ink-3); text-decoration: none; white-space: nowrap;
  font-size: var(--fs-micro); font-weight: var(--wt-display);
  letter-spacing: 0.08em;
}
.log__versions a[aria-current="true"] { color: var(--ink-1); border-color: var(--ink-4); }

/* Each version keeps clear of the top edge when jumped to. */
.log__entry { scroll-margin-top: var(--sp-4xl); }
.log__entry + .log__entry { margin-top: var(--sp-6xl); }
/* .legal gives h2 a 6xl top margin, which would double up on the rule above. */
.log__entry + .log__entry h2 { margin-top: var(--sp-4xl); }
.log__entry h2:first-child { margin-top: 0; }

@media (min-width: 900px) {
  .log__grid { grid-template-columns: 150px 1fr; gap: var(--sp-6xl); align-items: start; }
  .log__rail { position: sticky; top: var(--sp-4xl); }
  .log__versions {
    display: grid; gap: var(--sp-xs); overflow: visible;
    margin-top: var(--sp-lg);
  }
  .log__versions a {
    justify-content: flex-start; border: 0; border-left: 1px solid var(--rule);
    border-radius: 0; padding-inline: var(--sp-lg);
  }
  .log__versions a[aria-current="true"] { border-left-color: var(--ink-1); }
}

/* ==========================================================================
   TILES — the block types and the meditation modes
   A 2-up grid whose 1px gutters ARE the rules: the grid's own background
   shows through the gaps, so no cell needs a border. Each cell carries a
   line mark that depicts its mechanic rather than decorating it.
   ========================================================================== */
.tiles {
  list-style: none;
  display: grid; grid-template-columns: 1fr;
  gap: 1px; background: var(--rule);
  margin-top: var(--sp-4xl);
  border-block: 1px solid var(--rule);
}
.tile {
  background: var(--bg);
  padding: var(--sp-3xl) var(--sp-xxl) var(--sp-4xl);
  display: grid; align-content: start; gap: var(--sp-md);
}
.tile__mark {
  width: 34px; height: 34px; color: var(--ink-1);
  stroke: currentColor; fill: none;
  stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round;
  margin-bottom: var(--sp-sm);
}
.tile__mark .solid { fill: currentColor; stroke: none; }
.tile__name {
  font-size: var(--fs-body); line-height: 1.3; letter-spacing: var(--ls-body);
  font-weight: var(--wt-display); color: var(--ink-1); max-width: none;
}
.tile__desc { font-size: var(--fs-micro); line-height: var(--lh-micro); color: var(--ink-3); }

/* One column is the base; the grid widens once there is room. Authored this way
   round so the phone case is the default rather than a correction to it. */
@media (min-width: 721px) {
  .tiles { grid-template-columns: repeat(2, 1fr); }
  /* Three-up for the meditation modes, which are three not four. */
  .tiles--3 { grid-template-columns: repeat(3, 1fr); }
}
