/* Keelpost marketing site — component stylesheet.
   Every custom property this file reads is declared in t.v2.css, which is
   generated from shared/design-tokens.ts and linked immediately before this
   sheet on every page. Do not re-declare a token here: the app renders the same
   palette through Kumo's token names out of the same source, and a second
   declaration is how the two surfaces drift.

   Versioned filename: bump to s.v6.css (and the <link> in every page) when this
   file changes, so the immutable Cache-Control in public/_headers stays honest. */

*,*::before,*::after{box-sizing:border-box}
[hidden]{display:none!important}

html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--hull);color:var(--ink);
  font-family:var(--font-text);font-size:var(--t-body);line-height:1.62;
  font-synthesis:weight;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
::selection{background:var(--mark);color:var(--hull)}
:focus-visible{outline:2px solid var(--mark);outline-offset:2px;border-radius:3px}
[tabindex="-1"]:focus{outline:none}
svg{max-width:100%}

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.skip{position:absolute;left:var(--s-4);top:-120px;z-index:50;background:var(--deck);color:var(--ink);
  border:1px solid var(--rule);border-radius:3px;padding:10px 14px;text-decoration:none;
  font-family:var(--font-text);font-size:var(--t-small);font-weight:500;line-height:1}
.skip:focus{top:10px}
.shell{max-width:var(--shell);margin-inline:auto;padding-inline:var(--gutter)}

/* --- type ------------------------------------------------------------ */
h1,h2,h3{font-family:var(--font-display);font-weight:500;margin:0;
  text-wrap:balance;overflow-wrap:break-word}
h1{font-size:var(--t-h1);line-height:1.02;letter-spacing:-.03em;max-width:15ch}
h2{font-size:var(--t-h2);line-height:1.15;letter-spacing:-.02em;max-width:24ch}
h3{font-size:var(--t-h3);line-height:1.32;letter-spacing:-.012em}
p{margin:0;text-wrap:pretty}
a{color:var(--mark);text-underline-offset:3px;text-decoration-thickness:1px}
code{font-family:var(--font-mono);font-size:.88em;color:var(--ink);letter-spacing:0}
strong{font-weight:500;color:var(--ink)}
.eyebrow{font-family:var(--font-mono);font-size:var(--t-micro);font-weight:500;line-height:1;
  letter-spacing:.14em;text-transform:uppercase;color:var(--sounding);margin:0}
.lede{font-size:var(--t-lede);line-height:1.5;letter-spacing:-.006em;color:var(--sounding);
  max-width:54ch;margin-top:var(--s-4)}

/* --- header / nav ---------------------------------------------------- */
/* Opaque on purpose: a backdrop-filter across the full width of a sticky bar
   costs a backdrop readback on every scroll frame for 14% of visible blur. */
.site{position:sticky;top:0;z-index:10;border-bottom:1px solid var(--hairline);
  background:var(--hull)}
/* flex-start plus an auto margin, not space-between: on small screens the row is
   brand | call to action | menu, and the middle item must not float to centre. */
.site nav{position:relative;height:var(--nav-h);display:flex;align-items:center;
  justify-content:flex-start;gap:var(--s-4)}
.brand{display:inline-flex;align-items:center;gap:10px;text-decoration:none;color:var(--ink);
  font-family:var(--font-display);font-size:16px;font-weight:500;line-height:1;letter-spacing:-.02em}
.brand svg{flex:none;color:var(--ink)}
.navlinks{display:flex;align-items:center;gap:var(--s-5);min-width:0;margin-left:auto}
/* inline-block, not inline-flex: as a flex item this would blockify to `flex`
   and swallow the space between the two spans in the call to action. */
.navlinks a{display:inline-block;padding-block:16px;
  font-family:var(--font-mono);font-size:var(--t-micro);font-weight:500;line-height:1;
  letter-spacing:.14em;text-transform:uppercase;color:var(--sounding);text-decoration:none;
  white-space:nowrap;transition:color 120ms var(--ease)}
.navlinks a:hover{color:var(--ink)}
.navlinks a[aria-current=page]{color:var(--ink);text-decoration:underline;
  text-underline-offset:5px;text-decoration-thickness:1px}
.navdiv{width:1px;height:14px;background:var(--hairline);flex:none}
.navlinks a.navcta{color:var(--mark);text-decoration:underline;
  text-underline-offset:4px;text-decoration-thickness:1px}
.navlinks a.navcta:hover{color:var(--ink)}

/* Mobile disclosure. Hidden above 900px, where the full row is shown instead;
   no script involved, so it works before and without JavaScript. */
.navmenu{display:none}
.navmenu>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:9px;
  padding-block:16px;padding-inline:2px;
  font-family:var(--font-mono);font-size:var(--t-micro);font-weight:500;line-height:1;
  letter-spacing:.14em;text-transform:uppercase;color:var(--sounding)}
.navmenu>summary::-webkit-details-marker{display:none}
.navmenu>summary::after{content:"";width:8px;height:8px;flex:none;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:translateY(-2px) rotate(45deg);transition:transform 140ms var(--ease)}
.navmenu[open]>summary,.navmenu>summary:hover{color:var(--ink)}
.navmenu[open]>summary::after{transform:translateY(1px) rotate(225deg)}
.navmenu>summary:focus-visible{outline:2px solid var(--mark);outline-offset:2px;border-radius:3px}
.navpanel{position:absolute;top:100%;right:0;z-index:11;display:grid;min-width:190px;
  margin-top:1px;padding-block:var(--s-2);background:var(--deck);
  border:1px solid var(--hairline);border-top:0;border-radius:0 0 3px 3px}
.navpanel a{display:block;padding:13px var(--s-4);
  font-family:var(--font-mono);font-size:var(--t-micro);font-weight:500;line-height:1;
  letter-spacing:.14em;text-transform:uppercase;color:var(--sounding);text-decoration:none}
.navpanel a:hover{color:var(--ink)}
.navpanel a[aria-current=page]{color:var(--ink);text-decoration:underline;
  text-underline-offset:5px;text-decoration-thickness:1px}
/* The row is `white-space:nowrap` links in a `min-width:0` flex container, so it
   cannot shrink: past its natural width it pushes the call to action off the
   right edge and the whole document scrolls sideways. Measured in a real layout
   engine, five links reached 750px on a 560px viewport and six reach 817px on a
   768px one — i.e. the row was already overflowing at tablet widths before the
   Docs link was added, on every page, and adding one made it worse. 900px is
   where it demonstrably fits, and it is the breakpoint the draught rail and the
   soundings already switch at, so the header now changes shape with the rest of
   the page instead of at a number of its own. */
@media (max-width:899.98px){
  .navlinks a:not(.navcta),.navdiv{display:none}
  .navlinks{gap:0}
  .navmenu{display:block}
}
/* Only where "Join the waitlist" genuinely does not fit beside the menu. */
@media (max-width:559.98px){
  .navcta-long{display:none}
}

/* --- main, draught scale, soundings ---------------------------------- */
main{position:relative;display:block;scroll-margin-top:calc(var(--nav-h) + var(--s-3))}
@media (min-width:900px){main{padding-left:var(--rail)}}
.scale{position:absolute;inset-block:0;left:0;width:16px;pointer-events:none;
  border-block:1px solid var(--rule);
  background:
    linear-gradient(var(--rule),var(--rule)) right 0 top 0/1px 100% no-repeat,
    repeating-linear-gradient(to bottom,var(--tickmark) 0 1px,transparent 1px 48px) right/16px 100% no-repeat,
    repeating-linear-gradient(to bottom,var(--hairline) 0 1px,transparent 1px 8px) right/7px 100% no-repeat}
@media (max-width:899.98px){.scale{display:none}}

section{position:relative;padding-block:clamp(56px,8vw,104px);
  scroll-margin-top:calc(var(--nav-h) + var(--s-5))}
section[data-sounding]::before{content:attr(data-sounding);
  font-family:var(--font-mono);font-size:var(--t-micro);font-weight:500;line-height:1;
  letter-spacing:.14em;color:var(--sounding);font-variant-numeric:tabular-nums}
@media (min-width:900px){
  section[data-sounding]::before{position:absolute;right:calc(100% + var(--rail) - 22px);
    top:calc(clamp(56px,8vw,104px) + 4px);background:var(--hull);
    padding-block:7px;padding-right:6px}
}
@media (max-width:899.98px){
  section[data-sounding]::before{display:block;margin-bottom:var(--s-3)}
}

/* --- waterline + load line ------------------------------------------- */
.waterline{position:relative;height:1px;background:var(--hairline);color:var(--mark)}
.waterline svg{position:absolute;top:-12px;left:0}
@media (min-width:900px){
  .waterline{margin-left:calc(var(--rail) * -1);width:calc(100% + var(--rail))}
  .waterline svg{left:calc(var(--rail) - 20px)}
}

/* --- hero ------------------------------------------------------------ */
.hero{padding-block:clamp(72px,10vw,128px) clamp(56px,8vw,96px)}
@media (min-width:960px){
  .hero{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);
        gap:var(--s-8);align-items:start}
}
.hero-copy{min-width:0}
.hero h1{margin-top:var(--s-5)}
.hero .lede{margin-top:var(--s-5)}
.hero .wl-wrap{margin-top:var(--s-7)}
.hero-fig{min-width:0;margin-top:var(--s-8)}
@media (min-width:960px){.hero-fig{margin-top:0}}
.pagehead{padding-block:clamp(64px,9vw,112px) clamp(48px,6vw,72px)}
.pagehead h1{margin-top:var(--s-5)}

/* --- feature grid ----------------------------------------------------- */
.features{display:grid;grid-template-columns:repeat(auto-fit,minmax(248px,1fr));
  gap:var(--s-7) var(--s-6);margin-top:var(--s-7)}
.feature{min-width:0}
.tick{display:block;width:24px;height:2px;background:var(--rule);margin-bottom:14px}
.feature h3{margin-bottom:var(--s-2)}
.feature p{font-size:var(--t-meta);line-height:1.58;color:var(--sounding);max-width:40ch}

/* --- prose ------------------------------------------------------------ */
.prose{margin-top:var(--s-6);display:grid;gap:var(--s-4);max-width:66ch}
.prose p{font-size:var(--t-body);line-height:1.62;color:var(--ink)}
.prose h3{margin-top:var(--s-5)}
ul.ledger{list-style:none;margin:var(--s-5) 0 0;padding:0;display:grid;gap:var(--s-3)}
ul.ledger li{position:relative;padding-left:var(--s-5);max-width:56ch;
  font-size:var(--t-meta);line-height:1.58;color:var(--sounding)}
ul.ledger li::before{content:"";position:absolute;left:0;top:.68em;width:10px;height:1px;background:var(--rule)}

/* --- steps ------------------------------------------------------------ */
.steps{list-style:none;margin:var(--s-7) 0 0;padding:0;display:grid;gap:var(--s-6);counter-reset:step}
.steps li{counter-increment:step;display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:var(--s-4);align-items:start;min-width:0}
.steps li::before{content:counter(step,decimal-leading-zero);
  font-family:var(--font-mono);font-size:var(--t-micro);font-weight:500;line-height:1;
  letter-spacing:.14em;color:var(--sounding);padding-top:6px;font-variant-numeric:tabular-nums}
.steps h3{margin-bottom:var(--s-1)}
.steps p{font-size:var(--t-meta);line-height:1.58;color:var(--sounding);max-width:60ch}

/* --- two-column ledger ------------------------------------------------ */
.cols{display:grid;gap:var(--s-7);margin-top:var(--s-7)}
@media (min-width:720px){.cols{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-6)}}
.col{min-width:0}

/* --- status chips ----------------------------------------------------- */
.chips{display:flex;flex-wrap:wrap;gap:var(--s-2);margin-top:var(--s-4)}
.chip{display:inline-flex;align-items:center;gap:8px;padding:5px 9px;border-radius:2px;
  font-family:var(--font-mono);font-size:var(--t-micro);font-weight:500;line-height:1;
  letter-spacing:.12em;text-transform:uppercase;border:1px solid;background:transparent}
.chip .glyph{width:6px;height:6px;flex:none}
.chip .sep{opacity:.5}
.chip[data-state=live]{border-style:solid;border-color:var(--verdigris);color:var(--verdigris)}
.chip[data-state=live] .glyph{background:currentColor}
.chip[data-state=planned]{border-style:dashed;border-color:var(--rule);color:var(--sounding)}
.chip[data-state=planned] .glyph{box-shadow:inset 0 0 0 1px currentColor}
/* A third state between the two, and it is a stronger claim than `planned`: it
   says somebody is working on this right now, which obliges the roadmap to be
   accurate about what is actually in progress rather than what is intended.
   Dashed like `planned`, because it is still not standing; `shoal` rather than
   grey, because it is the one row a reader is entitled to ask about; the glyph
   half-filled, between the hollow ring of `planned` and the solid of `live`. */
.chip[data-state=next]{border-style:dashed;border-color:var(--shoal);color:var(--shoal)}
.chip[data-state=next] .glyph{box-shadow:inset 0 0 0 1px currentColor;
  background:linear-gradient(to right,currentColor 0 50%,transparent 50%)}

/* --- approval card ---------------------------------------------------- */
figure{margin:0;min-width:0}
figcaption{margin-top:var(--s-3);font-size:var(--t-small);line-height:1.5;
  color:var(--sounding);max-width:54ch}
.acard{background:var(--deck);border:1px solid var(--rule);border-radius:3px;padding:14px;min-width:0}
@media (prefers-color-scheme:dark){
  .acard{box-shadow:inset 0 1px 0 color-mix(in oklab,var(--rule) 40%,transparent)}
}
.acard-head{display:flex;align-items:center;gap:var(--s-2);margin-bottom:var(--s-4);flex-wrap:wrap}
.acard-head svg{flex:none;color:var(--mark)}
.acard-title{font-size:var(--t-meta);font-weight:500;line-height:1.3;color:var(--ink);margin-right:auto}
.acard-tag{font-family:var(--font-mono);font-size:10.5px;line-height:1;letter-spacing:.08em;
  text-transform:uppercase;color:var(--sounding)}
.block-server{background:var(--hull);border:1px solid var(--rule);border-radius:2px;padding:12px}
.block-cap{font-family:var(--font-mono);font-size:10.5px;font-weight:500;line-height:1;
  letter-spacing:.14em;text-transform:uppercase;margin:0 0 10px}
.block-server .block-cap{color:var(--verdigris)}
.block-model .block-cap{color:var(--mark)}
.fields{display:grid;grid-template-columns:104px minmax(0,1fr);gap:6px var(--s-3);margin:0}
.fields dt{font-family:var(--font-mono);font-size:10.5px;line-height:1.5;letter-spacing:.08em;
  color:var(--sounding)}
.fields dd{margin:0;font-family:var(--font-mono);font-size:var(--t-mono);line-height:1.5;
  color:var(--ink);overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
@media (max-width:420px){
  .fields{grid-template-columns:minmax(0,1fr);gap:2px}
  .fields dd{margin-bottom:8px}
}
.fence{position:relative;height:1px;background:var(--hairline);color:var(--mark);
  margin-block:var(--s-5);display:flex;justify-content:center}
.fence svg{position:absolute;top:-10px;background:var(--deck)}
.fence-label{margin-top:calc(var(--s-5) * -1 + 14px);margin-bottom:var(--s-5);text-align:center;
  font-family:var(--font-mono);font-weight:400;font-size:10.5px;line-height:1;
  letter-spacing:.08em;color:var(--sounding)}
.move{display:flex;align-items:center;gap:10px;margin-top:10px;flex-wrap:wrap;
  font-family:var(--font-mono);font-size:var(--t-mono);line-height:1.5;color:var(--ink)}
.move svg{flex:none;color:var(--mark)}
.acard-actions{display:flex;gap:var(--s-2);margin-top:var(--s-5);flex-wrap:wrap}
/* Drawn, not interactive: the whole card is exposed as a single role="img". */
.acard-actions span{display:inline-flex;align-items:center;justify-content:center;height:34px;
  padding-inline:16px;border-radius:3px;font-family:var(--font-text);font-size:var(--t-small);
  font-weight:500;line-height:1;cursor:default}
.btn-approve{background:var(--ink);color:var(--hull);border:1px solid var(--ink)}
.btn-deny{background:transparent;color:var(--ink);border:1px solid var(--rule)}
.acard-foot{margin-top:var(--s-3);font-size:var(--t-small);line-height:1.5;color:var(--sounding)}

/* --- the briefing, drawn ------------------------------------------------ */
/* The briefing is the product and it is not built, so every one of these is a
   drawing with a figcaption that says so. What they are drawn in is the
   approval card's own vocabulary one level deeper: a `deck` card whose objects
   sit on `hull`, exactly as `.block-server` sits inside `.acard`, with the same
   fence between what the server holds and what the model wants. The point of
   reusing it rather than inventing a marketing illustration is that the day the
   surface ships, the site will have been depicting it accurately all along. */
.brief{background:var(--deck);border:1px solid var(--rule);border-radius:3px;padding:14px;
  min-width:0;display:grid;gap:var(--s-3)}
@media (prefers-color-scheme:dark){
  .brief{box-shadow:inset 0 1px 0 color-mix(in oklab,var(--rule) 40%,transparent)}
}
.brief-head{display:flex;flex-wrap:wrap;align-items:center;gap:0 8px;
  padding-bottom:var(--s-3);border-bottom:1px solid var(--hairline);
  font-family:var(--font-mono);font-size:10.5px;font-weight:500;line-height:1.8;
  letter-spacing:.14em;text-transform:uppercase;color:var(--sounding)}
.brief-head .sep,.brief-foot .sep{opacity:.5}
.brief-foot{font-family:var(--font-mono);font-size:10.5px;font-weight:500;line-height:1.8;
  letter-spacing:.14em;text-transform:uppercase;color:var(--sounding);
  padding-top:var(--s-3);border-top:1px solid var(--hairline)}

/* One decision. */
.dcard{background:var(--hull);border:1px solid var(--rule);border-radius:2px;padding:12px;
  min-width:0}
/* A standing rule is an offer rather than an act, and dashed is already this
   site's word for not-yet-standing — it is what `.chip[data-state=planned]`
   means. Borrowing it costs the reader no new concept. */
.dcard[data-kind=rule]{border-style:dashed;background:transparent}
.dcard-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px;
  font-family:var(--font-mono);font-size:10.5px;font-weight:500;line-height:1.5;
  letter-spacing:.12em;text-transform:uppercase;color:var(--sounding)}
.dcard-kind{margin-right:auto}
/* Written out, never shortened to a display name and never allowed to truncate:
   which account a reply leaves from is the hardest promise in the product, so it
   belongs on the face of the card rather than behind a hover. */
.dcard-from{color:var(--ink);text-transform:none;letter-spacing:.02em;overflow-wrap:anywhere}
/* The consequence class, named. `shoal` is the site's warning; there is no
   filled accent button or filled accent chip anywhere here, because dread should
   not be louder than the thing it is about. */
.consequence{display:inline-flex;align-items:center;padding:3px 6px;border-radius:2px;
  border:1px solid currentColor;color:var(--shoal);letter-spacing:.12em}
.dcard-msg{margin:0;font-size:var(--t-meta);line-height:1.5;color:var(--ink)}
.dcard-meta{margin:4px 0 0;font-family:var(--font-mono);font-size:10.5px;line-height:1.6;
  letter-spacing:.08em;color:var(--sounding)}
/* The same pairing the approval card makes and for the same reason: verdigris is
   what the server holds, mark is what the model wants, and the two never share a
   block. Compressing the card for the front page is allowed to lose detail; it
   is not allowed to lose that. */
.dcard-cap{margin:0 0 8px;font-family:var(--font-mono);font-size:10.5px;font-weight:500;
  line-height:1;letter-spacing:.14em;text-transform:uppercase;color:var(--mark)}
.dcard-cap[data-source=server]{color:var(--verdigris)}
.dcard-prop{margin:0;font-size:var(--t-meta);line-height:1.5;color:var(--ink)}
.dcard-prop + .dcard-prop{margin-top:8px}
/* The ring on the fence is masked by whatever surface is behind it, and inside a
   decision card that is `hull` rather than the briefing's own `deck`. */
.dcard .fence{margin-block:var(--s-4)}
.dcard .fence-label{margin-top:calc(var(--s-4) * -1 + 14px);margin-bottom:var(--s-4)}
.dcard .fence svg{background:var(--hull)}
.dcard[data-kind=rule] .fence svg{background:var(--deck)}
.dcard .acard-actions{margin-top:var(--s-4)}
/* The rule exactly as it would be written in the list the user later edits. A
   paraphrase here would mean the list did not contain what was approved. */
.rulebody{margin:0;font-family:var(--font-mono);font-size:var(--t-mono);line-height:1.7;
  color:var(--ink);overflow-wrap:anywhere}
.brief ul.ledger{margin-top:0}
/* Receipts are past tense and healthy, so the tick is `verdigris` — the same
   colour that means "this is what the server holds" on the approval card. */
ul.ledger[data-tone=done] li::before{background:var(--verdigris)}

/* --- tiers ------------------------------------------------------------- */
/* A definition list rather than a price table, because there are no prices: a
   table with an empty price column reads as one that failed to load, and the
   shape of the meter is the argument anyway. */
.tiers{margin:var(--s-6) 0 0;padding:0;max-width:64ch;display:grid;
  grid-template-columns:minmax(0,1fr);border-bottom:1px solid var(--hairline)}
@media (min-width:560px){.tiers{grid-template-columns:136px minmax(0,1fr);gap:0 var(--s-5)}}
.tiers dt{padding-top:var(--s-4);border-top:1px solid var(--hairline);
  font-family:var(--font-mono);font-size:var(--t-micro);font-weight:500;line-height:1.5;
  letter-spacing:.14em;text-transform:uppercase;color:var(--sounding)}
.tiers dd{margin:0;padding-bottom:var(--s-4);font-size:var(--t-meta);line-height:1.58;
  color:var(--sounding)}
@media (min-width:560px){
  .tiers dd{padding-top:var(--s-4);border-top:1px solid var(--hairline)}
}
@media (max-width:559.98px){.tiers dd{padding-top:var(--s-2)}}

/* --- FAQ -------------------------------------------------------------- */
.faq{margin-top:var(--s-6)}
.faq details{border-top:1px solid var(--rule)}
.faq details:last-of-type{border-bottom:1px solid var(--rule)}
.faq summary{list-style:none;cursor:pointer;display:grid;grid-template-columns:minmax(0,1fr) 14px;
  align-items:center;gap:var(--s-4);padding-block:var(--s-5)}
.faq summary::-webkit-details-marker{display:none}
.faq summary h3{margin:0;font-family:var(--font-display);font-size:var(--t-h3);font-weight:500;
  line-height:1.32;letter-spacing:-.012em;color:var(--ink);text-wrap:pretty}
.faq summary::after{content:"";width:14px;height:14px;
  background:
    linear-gradient(var(--sounding),var(--sounding)) center/14px 1px no-repeat,
    linear-gradient(var(--sounding),var(--sounding)) center/1px 14px no-repeat;
  transition:background-size 140ms var(--ease)}
.faq details[open] summary::after{background-size:14px 1px,1px 0}
.faq summary:focus-visible{outline:2px solid var(--mark);outline-offset:-2px}
.answer{padding-bottom:var(--s-5);max-width:62ch;display:grid;gap:var(--s-3)}
.answer p{font-size:var(--t-body);line-height:1.62;color:var(--sounding)}
@supports (interpolate-size:allow-keywords){
  :root{interpolate-size:allow-keywords}
  .faq details::details-content{block-size:0;overflow:clip;content-visibility:hidden;
    transition:block-size 180ms var(--ease),content-visibility 180ms allow-discrete}
  .faq details[open]::details-content{block-size:auto;content-visibility:visible}
}

/* --- waitlist form ---------------------------------------------------- */
.wl-wrap{max-width:460px;min-width:0}
.waitlist{display:flex;gap:var(--s-2);flex-wrap:wrap;min-height:46px}
.waitlist .field{position:relative;flex:1 1 240px;min-width:0}
.waitlist input{width:100%;height:46px;padding:0 14px;border:1px solid var(--rule);border-radius:3px;
  background:var(--deck);color:var(--ink);font-family:var(--font-text);font-size:16px;line-height:1}
.waitlist input::placeholder{color:var(--sounding);opacity:1}
.waitlist button{flex:0 0 auto;min-width:152px;height:46px;padding-inline:20px;border-radius:3px;
  background:var(--ink);color:var(--hull);border:1px solid var(--ink);cursor:pointer;
  font-family:var(--font-text);font-size:15px;font-weight:500;line-height:1;
  transition:background-color 120ms var(--ease),border-color 120ms var(--ease)}
.waitlist button:hover{background:color-mix(in oklab,var(--ink) 88%,var(--mark));
  border-color:color-mix(in oklab,var(--ink) 88%,var(--mark))}
/* In-flight state keeps the button focusable — disabling it drops keyboard focus
   to <body> mid-submission, so the submit handler guards on data-state instead. */
.waitlist button.is-busy,.waitlist button[aria-disabled=true]{cursor:default;opacity:.72}
.waitlist button.is-busy:hover,.waitlist button[aria-disabled=true]:hover{
  background:var(--ink);border-color:var(--ink)}
.field::after{content:"";position:absolute;left:0;bottom:-1px;height:2px;width:30%;
  background:var(--mark);opacity:0}
form[data-state=loading] .field::after{opacity:1;animation:sweep 1100ms cubic-bezier(.4,0,.6,1) infinite}
@keyframes sweep{from{transform:translateX(-100%)}to{transform:translateX(333%)}}
form[data-state=error] input{border-color:var(--shoal)}
.wl-done{display:flex;align-items:center;gap:10px;min-height:46px;padding:8px 14px;
  border:1px solid var(--verdigris);border-radius:3px;color:var(--verdigris);
  font-family:var(--font-text);font-size:var(--t-small);line-height:1.45}
.wl-done:focus{outline:2px solid var(--mark);outline-offset:2px;border-radius:3px}
.wl-done .glyph{width:8px;height:8px;background:currentColor;flex:none}
.wl-msg{min-height:1.5em;margin-top:var(--s-3)}
.wl-status,.wl-alert{margin:0;font-size:var(--t-small);line-height:1.5;color:var(--sounding)}
.wl-status.ok{color:var(--verdigris)}
.wl-alert{color:var(--shoal)}
.wl-alert:not(:empty)::before{content:"";display:inline-block;width:1px;height:11px;
  background:currentColor;margin-right:8px;vertical-align:-1px}
/* Success is shown in the .wl-done box; the polite region keeps the same
   sentence for assistive technology without printing it on screen twice. */
.wl-wrap.is-done .wl-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.wl-note{margin-top:var(--s-3);font-size:var(--t-small);line-height:1.5;color:var(--sounding);max-width:54ch}

/* --- documentation ----------------------------------------------------- */
/* The docs are more pages in this Worker, on this origin, reading this file.
   Nothing below is a docs-only palette or a docs-only type scale: a second
   visual language is exactly what a separate docs host would have produced. */

/* Section links across the top of a long page. The draught rail already
   numbers the sections on wide screens; this is the same list, tappable, and
   the only navigation a documentation page here needs. */
.toc{display:flex;flex-wrap:wrap;gap:0 var(--s-4);margin-top:var(--s-5);
  padding-block:var(--s-2);border-block:1px solid var(--hairline)}
.toc a{display:inline-block;padding-block:8px;
  font-family:var(--font-mono);font-size:var(--t-micro);font-weight:500;line-height:1;
  letter-spacing:.14em;text-transform:uppercase;color:var(--sounding);text-decoration:none;
  transition:color 120ms var(--ease)}
.toc a:hover{color:var(--ink)}

/* Commands and configuration. Long lines scroll inside the block rather than
   widening the page, which is what a runbook full of wrangler invocations does
   to a phone otherwise. */
pre{margin:var(--s-4) 0 0;padding:var(--s-4);overflow-x:auto;background:var(--deck);
  border:1px solid var(--rule);border-radius:3px;
  font-family:var(--font-mono);font-size:var(--t-mono);line-height:1.7;color:var(--ink);
  tab-size:2}
pre code{font-size:inherit;color:inherit}
/* Prompts, comments and elisions inside a command block. */
pre .cm{color:var(--sounding)}

/* A card in the feature grid whose heading is the link. `a` is `mark`
   site-wide, and a grid of six magenta headings reads as a warning. */
.feature h3 a{color:var(--ink);text-decoration:none}
.feature h3 a:hover{color:var(--mark);text-decoration:underline;text-underline-offset:4px;
  text-decoration-thickness:1px}

/* --- misc ------------------------------------------------------------- */
.more{margin-top:var(--s-6);font-size:var(--t-meta);line-height:1.58;color:var(--sounding)}
.callout{margin-top:var(--s-6);padding:var(--s-4) var(--s-5);border-left:2px solid var(--mark);
  max-width:62ch;font-size:var(--t-meta);line-height:1.58;color:var(--sounding)}

/* --- footer ----------------------------------------------------------- */
footer{border-top:1px solid var(--hairline);padding-block:var(--s-7) var(--s-9);
  display:grid;gap:var(--s-5);font-family:var(--font-mono);font-size:var(--t-micro);
  line-height:1.8;letter-spacing:.08em;color:var(--sounding)}
@media (min-width:720px){footer{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-6)}}
footer a{color:var(--sounding);text-decoration:underline;text-decoration-thickness:1px;
  text-underline-offset:3px;
  text-decoration-color:color-mix(in oklab,var(--sounding) 45%,transparent)}
@supports not (color:color-mix(in oklab,red,blue)){footer a{text-decoration-color:currentColor}}
footer a:hover{color:var(--ink);text-decoration-color:currentColor}
.fbrand{display:flex;align-items:center;gap:10px;color:var(--sounding)}
.fbrand svg{flex:none}
.flinks{display:flex;flex-wrap:wrap;gap:var(--s-4)}
.flinks a{display:inline-block;padding-block:6px}
.ftm{margin-top:var(--s-3);letter-spacing:.04em;line-height:1.7}

/* --- motion ------------------------------------------------------------ */
@media (prefers-reduced-motion:no-preference){
  html{scroll-behavior:smooth}
  /* Transform only: an opacity:0 start would take the h1 and the figure out of
     LCP candidacy for the length of the delay plus the fade. */
  @keyframes rise{from{transform:translateY(8px)}to{transform:none}}
  .hero .eyebrow,.hero h1,.hero .lede,.hero .wl-wrap,.hero-fig{
    animation:rise 260ms var(--ease) both}
  .hero h1{animation-delay:60ms}
  .hero .lede{animation-delay:120ms}
  .hero .wl-wrap{animation-delay:180ms}
  .hero-fig{animation-delay:240ms}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
  /* ::details-content is not matched by the universal selector above. */
  .faq details::details-content{transition:none!important}
  form[data-state=loading] .field::after{animation:none;width:100%;opacity:.5}
}
