/* ============================================================================
   KinetiRO — marketing site styles
   kinetiro.com (apex). Plain CSS, no framework, no build step, no dependency.

   Every asset here is local. No @import, no CDN font, no external image: the
   marketing origin is served under a strict CSP with no external origins, so
   anything off-origin would simply not load.

   ORGANISATION
     1. Brand tokens  — the seam. The only place a literal value may appear.
     2. Reset and base
     3. Layout primitives
     4. Header and navigation
     5. Components
     6. Footer
     7. Editorial / long-form prose
     8. Pre-publication markers
     9. Responsive and preference overrides
   ========================================================================== */


/* ══════════════════════════════════════════════════ 1. brand tokens ═══ */
/*
   THIS BLOCK IS THE SEAM.

   The --kr-* palette has landed. It sits immediately below, copied verbatim
   from the application's styles.css rather than imported: the marketing site
   is a separate deployment on a separate origin and cannot link to the
   application's stylesheet. Keep the two diffable - if you change a value
   here, change it there in the same commit, or the two properties drift and
   stop looking like one company.

   :root beneath it holds nothing but aliases onto that palette. Nothing below
   section 1 contains a literal colour, font or radius, and that is worth
   keeping true: if you find yourself typing a hex code in section 5, add a
   token to the palette instead.
*/
/* ══════════════════════════════════════════ KinetiRO brand palette ═══ */
/*
   Authored by the brand workstream and shared verbatim with the application's
   styles.css, so the two properties resolve to the same values. The seam is
   real: this is a separate deployment on a separate origin and cannot link to
   the application's stylesheet, so the block is copied rather than imported.
   Keep them diffable.

   Ratios in the comments are computed (WCAG relative luminance) against the
   LIGHTEST surface either property uses, #1f2b3c, which is the application's
   --kr-color-surface-elevated-hover. That is a stricter test than this site
   needs, so every figure here is conservative for the marketing pages.
   Colour-vision separation is OKLab dE x100 under Machado protan/deutan.

   DARK STAYS DARK. Ink #101418 is the primary brand colour, so a dark ground
   is the brand rather than a departure from it. The one place that inverts is
   print and PDF export, which render on Bone #f5f3ef - a flowsheet on a dark
   ground is unusable on paper.

   THE ONE RULE THAT HOLDS THIS TOGETHER - a design rule for new work, not a
   description of what either codebase already does.
   Status colours belong to filled badges carrying a glyph and a label. Stream
   colours belong to 2px strokes on the flowsheet. They must not swap channels.
   Eight mutually separable saturated colours do not exist on one canvas, so
   the separation is what makes the set safe rather than the hues themselves.

   Two caveats, kept here so this copy stays diffable with the application's:
   the status glyphs are NOT IMPLEMENTED in either codebase, so a status shown
   by colour with no adjacent text is a WCAG 1.4.1 gap until they are; and one
   status-coloured stroke exists in the application (.ghost-link.invalid), a
   transient drag affordance rather than a persistent stream, which is a
   deliberate exception.
*/
:root {
  /* ── typefaces ────────────────────────────────────────────────────── */
  /* No webfont is loaded here yet. Both faces must arrive as local files
     under site/fonts/ with an @font-face rule - never a CDN link, which the
     CSP would refuse anyway. Until IBM Plex Mono is self-hosted the mono
     stack falls back to faces with DIFFERENT ADVANCE WIDTHS, so unit columns
     will align in the browser and drift in a PDF. That is the reason to
     self-host it, not house style.                                        */
  --kr-font-sans:    "Inter", ui-sans-serif, system-ui, -apple-system,
                     "Segoe UI", Roboto, sans-serif;
  --kr-font-display: "Archivo", var(--kr-font-sans);
  --kr-font-mono:    "IBM Plex Mono", ui-monospace, "Cascadia Mono",
                     Consolas, monospace;
  --kr-numeric: tabular-nums slashed-zero;

  /* ── surfaces, seven depths ───────────────────────────────────────── */
  --kr-color-canvas:                 #080b10;
  --kr-color-stage:                  #0a0e14;
  --kr-color-surface-input:          #080c12;
  --kr-color-surface-sunken:         #0b1119;
  --kr-color-surface:                #0f151e;
  --kr-color-surface-raised:         #131b26;
  --kr-color-surface-elevated:       #182231;
  --kr-color-surface-elevated-hover: #1f2b3c;
  --kr-color-surface-wash:           rgba(255,255,255,.04);
  --kr-color-scrim:                  rgba(4,7,11,.7);

  /* ── borders, four weights ────────────────────────────────────────── */
  --kr-color-border-hairline: rgba(255,255,255,.04);
  --kr-color-border:          #1c2634;
  --kr-color-border-strong:   #27354a;
  --kr-color-border-stronger: #35455c;

  /* ── ink. The blue cast is gone; this is the Bone family, which is what
        the mark is drawn in.                                          ── */
  --kr-color-text:                 #f5f3ef;   /* 12.90:1                  */
  --kr-color-text-muted:           #a8a49c;   /*  5.76:1                  */
  --kr-color-text-subtle:          #8f959d;   /*  4.73:1 - clears AA      */
  --kr-color-text-decorative:      #6d7580;   /*  3.2:1 - ORNAMENT ONLY.
                                                  Never carries meaning.  */
  --kr-color-text-accent:          #ff8a3d;   /*  6.10:1                  */
  --kr-color-text-accent-emphasis: #ffc199;
  --kr-color-text-info:            #a8a49c;
  --kr-color-text-success:         #20c891;   /*  6.62:1                  */
  --kr-color-text-warning:         #fad625;   /* 10.01:1                  */
  --kr-color-text-danger:          #fc5953;   /*  4.56:1 - the TEXT red.
                                                  --kr-color-danger is the
                                                  fill and border red.    */
  --kr-color-text-on-accent:       #101418;   /*  7.89:1. Was #fff, which
                                                  measures 2.35:1 and fails
                                                  harder on orange than it
                                                  did on blue.            */
  --kr-color-text-on-success:      #101418;   /*  8.57:1                  */

  /* ── accent. Sodium. #E2620F is the logo cut; #ff8a3d is the same family
        lifted to clear AA on a dark ground. Do not set UI text in the logo
        value - it measures 3.2:1 here.                                 ── */
  --kr-color-accent:       #ff8a3d;
  --kr-color-accent-hover: #ffa363;
  --kr-color-accent-soft:        color-mix(in srgb, var(--kr-color-accent) 15%, transparent);
  --kr-color-accent-wash:        color-mix(in srgb, var(--kr-color-accent)  7%, transparent);
  --kr-color-accent-wash-border: color-mix(in srgb, var(--kr-color-accent) 20%, transparent);
  --kr-color-accent-ring:        color-mix(in srgb, var(--kr-color-accent) 30%, transparent);
  --kr-color-accent-edit:        color-mix(in srgb, var(--kr-color-accent) 18%, transparent);

  /* ── status. RESERVED: never a stream, never a chart series, never
        chrome. Each SHOULD be rendered with a glyph and a label so it is
        never colour alone - the glyphs named below are the intended second
        channel and are not implemented in either codebase yet.

        The accent could not move - #E2620F is the published mark - so the
        semantics did. warning went yellow (H 96). danger was separated from
        the accent by LIGHTNESS rather than hue, L .641 against the accent's
        .750, because lightness is what survives protanopia and deuteranopia
        when hue does not; moving it by hue instead pushed it into the
        magenta streams. Set minimum is now CVD dE 10.9. It was 6.5, where
        danger and success failed against each other - a red/green collision
        that predates the rebrand.                                      ── */
  --kr-color-success:   #20c891;   /* intended glyph: filled circle 6.62:1 */
  --kr-color-warning:   #fad625;   /* intended glyph: triangle    10.01:1 */
  --kr-color-danger:    #f24341;   /* intended glyph: square       3.85:1
                                      GRAPHICS ONLY - for red text use
                                      --kr-color-text-danger.             */
  --kr-color-predicted: #a8a49c;   /* intended glyph: open circle. The
                                      fourth state: a value not yet
                                      measured.                           */
  --kr-color-success-hover:  #3ad9a4;
  --kr-color-success-soft:   color-mix(in srgb, var(--kr-color-success) 16%, transparent);
  --kr-color-success-border: color-mix(in srgb, var(--kr-color-success) 32%, transparent);
  --kr-color-warning-soft:   color-mix(in srgb, var(--kr-color-warning) 16%, transparent);
  --kr-color-danger-wash:    color-mix(in srgb, var(--kr-color-danger)   7%, transparent);
  --kr-color-danger-border:  color-mix(in srgb, var(--kr-color-danger)  40%, transparent);

  /* ── motion. Decelerating only. No bounce, no overshoot: a number that
        overshoots and settles is lying about the calculation.         ── */
  --kr-duration-fast:     120ms;
  --kr-duration-base:     200ms;
  --kr-duration-emphasis: 320ms;
  --kr-duration-slow:     640ms;
  --kr-stagger:            60ms;
  --kr-ease: cubic-bezier(0.2, 0, 0, 1);
}


:root {
  /* -- surfaces -------------------------------------------------------- */
  --bg:        var(--kr-color-canvas);
  --stage:     var(--kr-color-stage);
  --panel:     var(--kr-color-surface);
  --panel-2:   var(--kr-color-surface-raised);
  --raised:    var(--kr-color-surface-elevated);
  --line:      var(--kr-color-border);
  --line-2:    var(--kr-color-border-strong);

  /* -- ink ------------------------------------------------------------- */
  /*
     CONTRAST, RE-MEASURED NOW THE PALETTE HAS LANDED.

     Against the four surfaces this site uses (--bg, --stage, --panel,
     --panel-2), worst figure of the four:

       --txt     12.9   --acc      6.1
       --txt-2    5.8   --ok       6.6
       --txt-3    4.7   --warn    10.0

     The note this replaces recorded --txt-3 at 3.5:1 and barred it from all
     text. Its replacement measures 4.7:1 on --panel-2, so it clears AA for
     normal text and the quiet-text role is usable again. --edge stays aliased
     to it: 4.7:1 is comfortably over the 3:1 that applies to a control
     boundary, and more headroom than the 3.7:1 it had.

     One correction to the note this replaces: --panel-2 is the lightest
     surface THIS SITE uses, but not the lightest in the palette. The
     application also defines --kr-color-surface-elevated-hover #1f2b3c, and
     every figure in the --kr-* block is measured against that, so the numbers
     there are conservative relative to the ones above.

     --err is 3.9:1 here. It is a fill and border colour, where 3:1 applies;
     for red TEXT use --kr-color-text-danger, which measures 4.6:1.
  */
  --txt:       var(--kr-color-text);
  --txt-2:     var(--kr-color-text-muted);
  --txt-3:     var(--kr-color-text-subtle);

  /* -- accent and state ------------------------------------------------ */
  --acc:       var(--kr-color-accent);
  --acc-soft:  var(--kr-color-accent-soft);
  --ok:        var(--kr-color-success);
  --warn:      var(--kr-color-warning);
  --err:       var(--kr-color-danger);

  /* -- radii ----------------------------------------------------------- */
  --r-sm: 5px;
  --r-md: 7px;
  --r-lg: 11px;

  /* -- families -------------------------------------------------------- */
  /* No webfont is loaded. --sans names "Inter" first because the application
     does; with no @font-face and no external stylesheet permitted, it resolves
     to the system UI stack. If the brand workstream ships a face it must
     arrive as local files under site/fonts/ with an @font-face rule added
     here — never as a CDN link. */
  --mono: var(--kr-font-mono);
  --sans: var(--kr-font-sans);
  --display: var(--kr-font-display);

  /* -- marketing additions --------------------------------------------- */
  /* Not present in the application's token block: the application is a dense
     tool at one viewport, this is a document read at any width. Named on the
     same pattern so the brand block can absorb them. */

  /* type scale */
  --t-hero:  clamp(2.25rem, 1.30rem + 4.2vw, 4rem);
  --t-h1:    clamp(1.95rem, 1.35rem + 2.6vw, 3rem);
  --t-h2:    clamp(1.45rem, 1.15rem + 1.4vw, 2.05rem);
  --t-h3:    clamp(1.12rem, 1.02rem + 0.5vw, 1.35rem);
  --t-lede:  clamp(1.06rem, 0.98rem + 0.4vw, 1.28rem);
  --t-body:  1rem;
  --t-sm:    0.9rem;
  --t-xs:    0.8rem;

  /* spacing */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;
  --s-8: 4.5rem;
  --s-9: 6.5rem;

  /* measure and rhythm */
  --measure:    68ch;   /* long-form prose */
  --measure-sm: 46ch;   /* card and column copy */
  --wrap:       1140px;
  --wrap-tight: 780px;

  --lh-tight: 1.15;
  --lh-head:  1.25;
  --lh-body:  1.65;

  --border:   1px solid var(--line);
  --border-2: 1px solid var(--line-2);

  /*
     CONTROL BOUNDARIES — WCAG 2.1 SC 1.4.11 Non-text Contrast, 3:1.

     --line-2 is 1.6:1 against every surface here. That is fine for a card
     edge or a section rule, which are decoration. It is NOT fine for the
     boundary of a control, and this site has two kinds where the border is
     the ONLY thing marking the control: form fields (whose fill is the page
     colour, so 1.0:1 from the surface) and secondary buttons (whose --raised
     fill is 1.2:1 from the page). Neither is distinguishable without its
     border, so the border has to carry the contrast on its own.

     --edge is --txt-3. RE-MEASURED against the KinetiRO palette on the
     surfaces this site actually uses: 6.5:1 on --bg, 6.4:1 on --stage,
     6.1:1 on --panel and 5.7:1 on --panel-2 — comfortably over the 3:1 bar,
     and better than the 3.7-3.9:1 it managed under the interim palette.

     Note --txt-3 now aliases --kr-color-text-subtle (4.7:1 at the palette's
     own strictest reference surface), NOT --kr-color-text-decorative, which
     the palette marks 3.2:1 and ORNAMENT ONLY. If anyone re-points --txt-3
     at the decorative value, every control boundary on the site goes with
     it and this rule stops clearing 3:1.

     --btn-primary and the focus ring do not need this: the accent fill is
     8.4:1 against the page on its own under the KinetiRO palette.

     When the --kr-* palette lands, re-measure this against --panel-2, the
     lightest surface and therefore the worst case.
  */
  --edge:      var(--txt-3);
  --border-ui: 1px solid var(--edge);

  --ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--acc);
}


/* ═════════════════════════════════════════════════ 2. reset and base ═══ */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--txt);
  font-family: var(--sans);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* The application sets overflow:hidden here. A document must scroll. */
  min-height: 100%;
}

h1, h2, h3, h4 {
  line-height: var(--lh-head);
  font-weight: 650;
  letter-spacing: -0.011em;
  margin: 0 0 var(--s-4);
  text-wrap: balance;
}

h1 { font-size: var(--t-h1); }
h2 { font-size: var(--t-h2); }
h3 { font-size: var(--t-h3); }
h4 { font-size: var(--t-body); }

p, ul, ol, dl, table, figure, blockquote { margin: 0 0 var(--s-4); }
p { text-wrap: pretty; }

a { color: var(--acc); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { color: var(--txt); }

strong { font-weight: 650; color: var(--txt); }
em { font-style: italic; }
small { font-size: var(--t-sm); }

hr { border: 0; border-top: var(--border); margin: var(--s-7) 0; }

code, kbd, samp, pre { font-family: var(--mono); font-size: 0.92em; }
code {
  background: var(--panel-2);
  border: var(--border);
  border-radius: var(--r-sm);
  padding: 0.1em 0.35em;
}
pre {
  background: var(--panel);
  border: var(--border);
  border-radius: var(--r-md);
  padding: var(--s-4);
  overflow-x: auto;
}
pre code { background: none; border: 0; padding: 0; }

img, svg, video { max-width: 100%; height: auto; }

svg { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

[hidden] { display: none !important; }

::selection { background: var(--acc-soft); }

/* One focus treatment everywhere, visible against every surface used here. */
:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-radius: var(--r-sm);
}

/* Skip link: first thing in the tab order on every page. */
.skip-link {
  position: absolute;
  left: var(--s-4);
  top: var(--s-4);
  z-index: 100;
  padding: var(--s-2) var(--s-4);
  background: var(--raised);
  color: var(--txt);
  border: var(--border-2);
  border-radius: var(--r-md);
  text-decoration: none;
  transform: translateY(-200%);
}
.skip-link:focus { transform: none; }


/* ══════════════════════════════════════════════ 3. layout primitives ═══ */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--s-5);
}
.wrap-tight { max-width: var(--wrap-tight); }

.section { padding-block: var(--s-8); }
.section-tight { padding-block: var(--s-7); }
.section + .section { border-top: var(--border); }

/* A section that needs to read as a distinct band rather than a rule. */
.band { background: var(--stage); }
.band-panel { background: var(--panel); }

.section-head { margin-bottom: var(--s-6); max-width: var(--measure); }
.section-head p { color: var(--txt-2); margin-bottom: 0; }

.eyebrow {
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--txt-2);
  margin: 0 0 var(--s-3);
}

.grid { display: grid; gap: var(--s-5); }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.stack > * + * { margin-top: var(--s-4); }
.measure { max-width: var(--measure); }
.muted { color: var(--txt-2); }
.dim { color: var(--txt-2); }


/* ═══════════════════════════════════════ 4. header and navigation ═══ */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--bg);
  border-bottom: var(--border);
}

.site-header > .wrap {
  display: flex;
  align-items: center;
  gap: var(--s-5);
  min-height: 64px;
  padding-block: var(--s-3);
}

/* -- wordmark ---------------------------------------------------------- */
.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  color: var(--txt);
  text-decoration: none;
  font-weight: 650;
  letter-spacing: -0.01em;
  flex: none;
}
.brand:hover { color: var(--txt); }

/* The mark is not designed yet and arrives as one file, /logo.svg. Height is
   constrained and width is free, so a replacement of any aspect ratio drops in
   without touching this rule. Do not add a fixed width here. */
.brand-mark {
  height: 26px;
  width: auto;
  max-width: 180px;
  flex: none;
}

.brand-name { font-size: 1.06rem; }

/* -- the menu ---------------------------------------------------------- */
/*
   No JavaScript anywhere on this site, so the two submenus are <details>
   elements rather than scripted dropdowns. That buys keyboard operation and
   screen-reader semantics for nothing, and costs one behaviour: a menu left
   open does not close when you click elsewhere on the page. That is the right
   trade against a script the CSP would have to make room for.
*/
.nav { flex: 1; }

.nav-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

.nav-link,
.nav-menu > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm);
  color: var(--txt-2);
  font-size: var(--t-sm);
  font-weight: 550;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.nav-link:hover,
.nav-menu > summary:hover { background: var(--raised); color: var(--txt); }

/* The page you are on. aria-current carries it for assistive tech. */
.nav-link[aria-current="page"],
.nav-menu[data-section-current] > summary { color: var(--txt); background: var(--panel-2); }

.nav-menu { position: relative; }
.nav-menu > summary { list-style: none; }
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu > summary::after {
  content: "";
  width: 0.42em;
  height: 0.42em;
  margin-left: var(--s-1);
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-0.15em) rotate(45deg);
}
.nav-menu[open] > summary::after { transform: translateY(0.1em) rotate(225deg); }

.nav-menu-panel {
  position: absolute;
  top: calc(100% + var(--s-2));
  left: 0;
  min-width: 254px;
  padding: var(--s-2);
  background: var(--panel);
  border: var(--border-2);
  border-radius: var(--r-lg);
  list-style: none;
  margin: 0;
}
.nav-menu-panel a {
  display: block;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm);
  color: var(--txt-2);
  font-size: var(--t-sm);
  text-decoration: none;
}
.nav-menu-panel a:hover { background: var(--raised); color: var(--txt); }
.nav-menu-panel a[aria-current="page"] { color: var(--txt); background: var(--panel-2); }
.nav-status { color: var(--txt-2); font-size: var(--t-xs); }

/* -- the header call to action ----------------------------------------
   Two lines: "Open KinetiRO Sim" over "An account is required". The qualifier
   is not decoration — an account is required to design and calculate, and a
   visitor must never learn that by hitting the wall. Where the header is too
   narrow to carry both lines, the whole label is replaced by "Create an
   account", which says the same thing in the space available. Both labels ship
   in the markup and the swap is a media query, so nothing here needs script.
   Do not "simplify" this to a single "Open KinetiRO Sim". */
.nav-cta { flex: none; text-align: center; }
.nav-cta-full { display: flex; flex-direction: column; line-height: 1.25; }
.nav-cta-sub { font-size: var(--t-xs); font-weight: 500; opacity: .85; }
.nav-cta-short { display: none; }

/* The mobile disclosure. Hidden above the breakpoint; see section 9. */
.nav-toggle { display: none; }
.nav-toggle > summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  border: var(--border-ui);
  border-radius: var(--r-md);
  color: var(--txt-2);
  font-size: var(--t-sm);
  font-weight: 600;
  cursor: pointer;
}
.nav-toggle > summary::-webkit-details-marker { display: none; }


/* ══════════════════════════════════════════════════════ 5. components ═══ */

/* -- buttons ----------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-5);
  border: var(--border-ui);
  border-radius: var(--r-md);
  background: var(--raised);
  color: var(--txt);
  font: inherit;
  font-size: var(--t-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
.btn:hover { background: var(--panel-2); border-color: var(--acc); color: var(--txt); }

.btn-primary { background: var(--acc); border-color: var(--acc); color: var(--bg); }
.btn-primary:hover { background: var(--txt); border-color: var(--txt); color: var(--bg); }

.btn-ghost { background: transparent; }
.btn-sm { padding: var(--s-2) var(--s-4); font-size: var(--t-xs); }

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
  margin-block: var(--s-5);
}

/* Sits directly under a call to action that opens the application. An account
   is required to design and calculate — there is no anonymous use — so a
   button reading "Open KinetiRO Sim" on its own would promise a first run that
   does not exist. This is the line that keeps it honest; do not delete it
   without checking that the account requirement has actually changed. */
.cta-note {
  margin-top: calc(var(--s-4) * -1);
  margin-bottom: var(--s-5);
  font-size: var(--t-sm);
  color: var(--txt-2);
}

/* -- the arrow link, used at the foot of every card and block ---------- */
.arrow {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-2);
  font-size: var(--t-sm);
  font-weight: 600;
  text-decoration: none;
}
.arrow::after { content: "\2192"; transition: transform .12s; }
.arrow:hover::after { transform: translateX(2px); }
.arrow-block { display: flex; margin-top: var(--s-4); }

/* -- hero -------------------------------------------------------------- */
.hero { padding-block: var(--s-9) var(--s-8); }
.hero h1 {
  font-size: var(--t-hero);
  line-height: var(--lh-tight);
  letter-spacing: -0.024em;
  max-width: 18ch;
  margin-bottom: var(--s-5);
}
.hero-category {
  font-size: var(--t-lede);
  font-weight: 550;
  line-height: 1.45;
  color: var(--txt);
  max-width: var(--measure);
  margin-bottom: var(--s-5);
}
.hero-body { color: var(--txt-2); max-width: var(--measure); font-size: var(--t-lede); }

/* Interior pages: title plus a lede. */
.page-head { padding-block: var(--s-8) var(--s-6); }
.page-head h1 { max-width: 22ch; }
.page-head .lede {
  font-size: var(--t-lede);
  color: var(--txt-2);
  max-width: var(--measure);
  margin-bottom: 0;
}

.breadcrumb { font-size: var(--t-xs); color: var(--txt-2); margin-bottom: var(--s-4); }
.breadcrumb ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--s-2); }
.breadcrumb li + li::before { content: "/"; margin-right: var(--s-2); color: var(--line-2); }
.breadcrumb a { color: var(--txt-2); text-decoration: none; }
.breadcrumb a:hover { color: var(--txt-2); text-decoration: underline; }

/* -- cards ------------------------------------------------------------- */
.card {
  display: flex;
  flex-direction: column;
  padding: var(--s-5);
  background: var(--panel);
  border: var(--border);
  border-radius: var(--r-lg);
}
.card h3 { margin-bottom: var(--s-3); }
.card p { color: var(--txt-2); margin-bottom: var(--s-3); }
.card > :last-child { margin-bottom: 0; }
.card .arrow { margin-top: auto; padding-top: var(--s-3); }

.card-raised { background: var(--panel-2); border-color: var(--line-2); }

/* -- the router band --------------------------------------------------- */
.router-item {
  padding: var(--s-5);
  background: var(--panel);
  border: var(--border);
  border-left: 3px solid var(--acc);
  border-radius: var(--r-md);
}
.router-item h3 { font-size: var(--t-body); font-weight: 650; color: var(--txt); margin-bottom: var(--s-3); }
.router-item p { color: var(--txt-2); margin-bottom: var(--s-3); }
.router-item > :last-child { margin-bottom: 0; }

/* -- a labelled list of things (services strip, "what is included") ---- */
.deflist { margin: 0; }
.deflist > div { padding-block: var(--s-5); border-top: var(--border); }
.deflist > div:first-child { border-top: 0; padding-top: 0; }
.deflist dt { font-weight: 650; color: var(--txt); margin-bottom: var(--s-2); }
.deflist dd { margin: 0 0 var(--s-3); color: var(--txt-2); max-width: var(--measure); }
.deflist dd:last-child { margin-bottom: 0; }

/* -- stacked blocks, each with its own heading -------------------------
   The same rhythm as .deflist, for the places where each entry needs a real
   heading. A <dt> may not contain heading content, so those sections use
   <article><h3> rather than a definition list. */
.blocks > article { padding-block: var(--s-5); border-top: var(--border); }
.blocks > article:first-child { border-top: 0; padding-top: 0; }
.blocks h3 { margin-bottom: var(--s-3); }
.blocks p { color: var(--txt-2); max-width: var(--measure); margin-bottom: var(--s-3); }
.blocks > article > :last-child { margin-bottom: 0; }

/* -- ticked and crossed lists ----------------------------------------- */
.list-plain { list-style: none; padding: 0; }
.list-plain li {
  position: relative;
  padding-left: var(--s-5);
  margin-bottom: var(--s-3);
  color: var(--txt-2);
  max-width: var(--measure);
}
.list-plain li::before { position: absolute; left: 0; top: 0; font-weight: 700; }
.list-yes  li::before { content: "\2713"; color: var(--ok); }
.list-no   li::before { content: "\2715"; color: var(--err); }
.list-dash li::before { content: "\2014"; color: var(--txt-2); }

/* -- callouts and status blocks --------------------------------------- */
.callout {
  padding: var(--s-5);
  background: var(--panel-2);
  border: var(--border);
  border-radius: var(--r-lg);
  margin-block: var(--s-5);
}
.callout > :last-child { margin-bottom: 0; }
.callout-title { font-weight: 650; color: var(--txt); margin-bottom: var(--s-3); }

.callout-accent { border-left: 3px solid var(--acc); }
.callout-warn   { border-left: 3px solid var(--warn); }
.callout-ok     { border-left: 3px solid var(--ok); }

/* The "planned" / "empty by design" state block. */
.status-block {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-5);
  background: var(--stage);
  border: var(--border-2);
  border-radius: var(--r-lg);
}

.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  align-self: flex-start;
  padding: var(--s-1) var(--s-3);
  border-radius: 999px;
  border: var(--border-2);
  background: var(--panel);
  color: var(--txt-2);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.tag-planned { color: var(--warn); border-color: var(--warn); }
.tag-empty   { color: var(--txt-2); }
.tag-live    { color: var(--ok); border-color: var(--ok); }

/* -- the one-line claim ------------------------------------------------ */
.claim {
  margin: var(--s-6) 0;
  padding-left: var(--s-5);
  border-left: 3px solid var(--line-2);
  font-size: var(--t-lede);
  color: var(--txt);
  max-width: var(--measure);
}
.claim p:last-child { margin-bottom: 0; }

/* -- counters (the Registry) ------------------------------------------ */
.counter-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-4);
  margin-block: var(--s-5);
}
.counter {
  padding: var(--s-5);
  background: var(--panel);
  border: var(--border);
  border-radius: var(--r-lg);
  text-align: center;
}
.counter-value {
  display: block;
  font-family: var(--mono);
  font-size: clamp(2rem, 1.4rem + 2.4vw, 3rem);
  line-height: 1;
  color: var(--txt);
  margin-bottom: var(--s-2);
}
.counter-label {
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--txt-2);
}

/* -- tables ------------------------------------------------------------ */
.table-scroll { overflow-x: auto; margin-bottom: var(--s-5); }
table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); }
caption { text-align: left; color: var(--txt-2); font-size: var(--t-xs); padding-bottom: var(--s-3); }
th, td { text-align: left; vertical-align: top; padding: var(--s-3); border-bottom: var(--border); }
thead th {
  color: var(--txt-2);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-bottom: var(--border-2);
  white-space: nowrap;
}
tbody th { font-weight: 600; color: var(--txt); }
td { color: var(--txt-2); }
.num { font-family: var(--mono); text-align: right; white-space: nowrap; }

.table-empty {
  padding: var(--s-7) var(--s-5);
  text-align: center;
  color: var(--txt-2);
  border: 1px dashed var(--line-2);
  border-radius: var(--r-lg);
}

/* -- plans -------------------------------------------------------------
   Flex rather than a fixed grid: there are two paid plans today and there may
   be three later. A `repeat(3, 1fr)` grid left an empty third column when
   given two children, and a card that stretches the full half-width reads as
   a banner rather than a price. This wraps at any count and caps the card. */
.plan-grid { display: flex; flex-wrap: wrap; gap: var(--s-4); }
.plan {
  flex: 1 1 280px;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  padding: var(--s-5);
  background: var(--panel);
  border: var(--border);
  border-radius: var(--r-lg);
}
.plan-name { font-weight: 650; margin-bottom: var(--s-2); }
.plan-price { font-family: var(--mono); color: var(--txt); margin-bottom: var(--s-4); }
.plan ul { margin-bottom: 0; }

/* -- step list (the method) ------------------------------------------- */
.steps { list-style: none; counter-reset: step; margin: 0; padding: 0; }
.steps > li {
  counter-increment: step;
  position: relative;
  padding-left: var(--s-7);
  padding-bottom: var(--s-6);
  border-left: var(--border);
  margin-left: var(--s-4);
}
.steps > li:last-child { border-left-color: transparent; padding-bottom: 0; }
.steps > li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 0;
  transform: translateX(-50%);
  width: 2rem;
  height: 2rem;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--panel-2);
  border: var(--border-2);
  color: var(--txt-2);
  font-family: var(--mono);
  font-size: var(--t-xs);
}
.steps h3 { margin-bottom: var(--s-2); }
.steps p { color: var(--txt-2); max-width: var(--measure); }
.steps > li > :last-child { margin-bottom: 0; }

/* -- FAQ / disclosure -------------------------------------------------- */
.faq { border-top: var(--border); }
.faq > details { border-bottom: var(--border); }
.faq > details > summary {
  padding: var(--s-4) 0;
  cursor: pointer;
  font-weight: 600;
  color: var(--txt);
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: var(--s-4);
}
.faq > details > summary::-webkit-details-marker { display: none; }
.faq > details > summary::after { content: "+"; color: var(--txt-2); font-family: var(--mono); }
.faq > details[open] > summary::after { content: "\2212"; }
.faq > details > :not(summary) { padding-bottom: var(--s-4); color: var(--txt-2); max-width: var(--measure); }

/* -- forms -------------------------------------------------------------
   One form on the site, on /contact. No JavaScript: validation is the
   browser's own (required, type=email), and the error presentation is
   whatever the browser does natively — which is keyboard-accessible and
   translated for the user already, and a scripted replacement would not be. */
.form { max-width: var(--measure); }

.field { margin-bottom: var(--s-5); border: 0; padding: 0; }

.field > label,
.field > legend {
  display: block;
  margin-bottom: var(--s-2);
  font-weight: 600;
  color: var(--txt);
  padding: 0;
}

.req { color: var(--acc); margin-left: var(--s-1); }
.opt { color: var(--txt-2); font-weight: 400; font-size: var(--t-xs); margin-left: var(--s-2); }

input[type="text"],
input[type="email"],
input[type="tel"],
textarea,
select {
  display: block;
  width: 100%;
  padding: var(--s-3);
  background: var(--bg);
  color: var(--txt);
  border: var(--border-ui);
  border-radius: var(--r-md);
  font: inherit;
  font-size: var(--t-sm);
}
textarea { resize: vertical; min-height: 8rem; }

input[type="text"]:hover,
input[type="email"]:hover,
input[type="tel"]:hover,
textarea:hover,
select:hover { border-color: var(--txt-2); }

/* A radio or checkbox and its label on one line, the label clickable. */
.choice {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  margin-bottom: var(--s-3);
}
.choice input { flex: none; accent-color: var(--acc); margin: 0; }
.choice label { color: var(--txt-2); font-weight: 400; }
.choice:hover label { color: var(--txt); }

/* -- article index ----------------------------------------------------- */
.note-list { list-style: none; margin: 0; padding: 0; }
.note-list > li { border-top: var(--border); }
.note-list > li:last-child { border-bottom: var(--border); }
.note-list a { display: block; padding-block: var(--s-5); text-decoration: none; color: inherit; }
.note-list a:hover { background: var(--panel); }
.note-list h3 { color: var(--acc); margin-bottom: var(--s-2); }
.note-list a:hover h3 { color: var(--txt); }
.note-list p { color: var(--txt-2); margin-bottom: 0; max-width: var(--measure); }
.note-meta { font-size: var(--t-xs); color: var(--txt-2); font-family: var(--mono); margin-bottom: var(--s-2); }


/* ═════════════════════════════════════════════════════════ 6. footer ═══ */

.site-footer {
  border-top: var(--border);
  background: var(--stage);
  padding-block: var(--s-8) var(--s-6);
  font-size: var(--t-sm);
}

/* auto-FILL, not auto-fit: two columns are live and two more are frozen
   pending a founder decision. auto-fit collapses the empty tracks, which
   stretched the two live columns across the full width and read as a layout
   mistake. auto-fill keeps the track, so two columns sit at their natural
   width and four drop straight back in. Restoring them is a list entry in the
   markup, not a change here. */
.footer-cols {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--s-6);
  padding-bottom: var(--s-7);
}
.footer-cols h2 {
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--txt-2);
  margin-bottom: var(--s-4);
}
.footer-cols ul { list-style: none; margin: 0; padding: 0; }
.footer-cols li { margin-bottom: var(--s-3); }
.footer-cols a { color: var(--txt-2); text-decoration: none; }
.footer-cols a:hover { color: var(--txt); text-decoration: underline; }

.footer-base {
  border-top: var(--border);
  padding-top: var(--s-5);
  color: var(--txt-2);
  font-size: var(--t-xs);
  line-height: 1.7;
}
.footer-base p { max-width: var(--measure); margin-bottom: var(--s-3); }
.footer-base .footer-category { color: var(--txt-2); font-size: var(--t-sm); }
.footer-base a { color: var(--txt-2); }


/* ══════════════════════════════════════════ 7. editorial / long-form ═══ */
/*
   The Notes articles and the legal pages, where the markup is a stream of
   headings and paragraphs rather than components.
*/
.prose { max-width: var(--measure); }
.prose > * + * { margin-top: var(--s-4); }
.prose h2 { margin-top: var(--s-7); }
.prose h3 { margin-top: var(--s-6); }
.prose h2 + p, .prose h3 + p { margin-top: var(--s-3); }
.prose ul, .prose ol { padding-left: var(--s-5); }
.prose li { margin-bottom: var(--s-2); color: var(--txt-2); }
.prose p { color: var(--txt-2); }
.prose blockquote {
  margin-left: 0;
  padding-left: var(--s-5);
  border-left: 3px solid var(--line-2);
  color: var(--txt);
}
.prose figure { margin-inline: 0; }
.prose figcaption { font-size: var(--t-xs); color: var(--txt-2); margin-top: var(--s-2); }
.prose table { margin-block: var(--s-5); }

.toc {
  padding: var(--s-4) var(--s-5);
  background: var(--panel);
  border: var(--border);
  border-radius: var(--r-lg);
}
.toc h2 {
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--txt-2);
  margin: 0 0 var(--s-3);
}
.toc ol { margin: 0; padding-left: var(--s-5); }
.toc li { margin-bottom: var(--s-2); }


/* ══════════════════════════════════════ 8. pre-publication markers ═══ */
/*
   content.md §9.14: no page is publishable while it still carries a bracket.
   Two kinds are marked here, and both are deliberately loud — a placeholder
   that looks like finished copy is how one gets published.

     .tbd    a value only the founder can supply     [LIKE THIS]
     .unver  a claim not yet verified against a source

   Each also carries a data- attribute, so the check is mechanical rather than
   visual:

       grep -rn "data-tbd\|data-unverified" site/

   That grep returning nothing is the gate for going live. It belongs in
   ci/audit.sh, which is not this workstream's file — see site/README.md.
*/
/* These wrap. An earlier version set `white-space: nowrap` to keep a short
   marker like [N] on one line, and a long one — a placeholder carrying its own
   instructions — then pushed the document to nearly twice the viewport width.
   A marker that breaks the page it is warning you about is worse than a marker
   that wraps, and `overflow-wrap: anywhere` means no length can overflow. */
.tbd {
  display: inline;
  padding: 0 var(--s-2);
  border-radius: var(--r-sm);
  background: var(--warn);
  color: var(--bg);
  font-family: var(--mono);
  font-size: 0.9em;
  font-weight: 700;
  white-space: normal;
  overflow-wrap: anywhere;
}
.tbd-block {
  display: block;
  padding: var(--s-4);
  margin-block: var(--s-5);
  border-radius: var(--r-md);
}

.unver { border-bottom: 2px dotted var(--warn); cursor: help; }


/* ═══════════════════════════════════ 9. responsive and preferences ═══ */

@media (max-width: 1000px) {
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* .footer-cols needs no breakpoint: auto-fit already reflows it. */
}

@media (max-width: 860px) {
  /*
     The nav collapses into a single disclosure. Same markup, same links, same
     order — only the presentation changes, so nothing is hidden from a
     keyboard or a crawler at any width.
  */
  .nav-toggle { display: block; order: 2; }
  .site-header > .wrap { flex-wrap: wrap; row-gap: var(--s-3); gap: var(--s-3); }
  .brand { margin-right: auto; }

  .nav { flex-basis: 100%; order: 4; display: none; }
  .nav-toggle[open] ~ .nav { display: block; }

  /* Not enough width for the two-line label; swap it for the short one rather
     than dropping the qualifier. See .nav-cta in section 4. */
  .nav-cta-full { display: none; }
  .nav-cta-short { display: inline; }

  .nav-list { flex-direction: column; align-items: stretch; gap: 0; }
  .nav-list > li { border-top: var(--border); }
  .nav-link, .nav-menu > summary { padding: var(--s-4) 0; }
  .nav-menu-panel {
    position: static;
    min-width: 0;
    border: 0;
    border-left: var(--border-2);
    border-radius: 0;
    margin-left: var(--s-3);
    background: none;
  }
  .nav-cta { order: 3; }
}

@media (max-width: 720px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: minmax(0, 1fr); }
  .plan-grid { grid-template-columns: minmax(0, 1fr); }
  .counter-row { grid-template-columns: minmax(0, 1fr); }
  .section { padding-block: var(--s-7); }
  .hero { padding-block: var(--s-7) var(--s-6); }
  .footer-cols { gap: var(--s-5); }
}

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

@media print {
  .site-header, .site-footer, .skip-link, .cta-row { display: none; }
}
