/* ==========================================================================
   Aweigh marketing site
   Token names match the existing app.css so the two stay in step.
   Typography stays on the system stacks the current site uses.
   ========================================================================== */

/* ------------------------------------------------------------------- fonts */
/* Self-hosted, not loaded from Google. Same rendering on every machine, which
   is the point — the display face used to resolve to New York on a Mac and
   Georgia on Windows — and it keeps the privacy page's claim that the site
   loads nothing from anywhere else literally true. All three are OFL.
   Latin subset only. Serif and sans are variable fonts, so one file each spans
   400-700; Plex Mono is static and needs a file per weight. 137 KB total.
   font-display:swap renders in the fallback immediately and swaps on arrival,
   so a slow font never blanks the text. */

@font-face{
  font-family:'Source Serif 4'; font-style:normal; font-weight:400 700;
  font-display:swap; src:url('../fonts/source-serif-4-var.woff2') format('woff2');
}
@font-face{
  font-family:'Source Sans 3'; font-style:normal; font-weight:400 700;
  font-display:swap; src:url('../fonts/source-sans-3-var.woff2') format('woff2');
}
@font-face{
  font-family:'Source Sans 3'; font-style:italic; font-weight:400 700;
  font-display:swap; src:url('../fonts/source-sans-3-italic-var.woff2') format('woff2');
}
@font-face{
  font-family:'IBM Plex Mono'; font-style:normal; font-weight:400;
  font-display:swap; src:url('../fonts/ibm-plex-mono-400.woff2') format('woff2');
}
@font-face{
  font-family:'IBM Plex Mono'; font-style:normal; font-weight:600;
  font-display:swap; src:url('../fonts/ibm-plex-mono-600.woff2') format('woff2');
}
@font-face{
  font-family:'IBM Plex Mono'; font-style:normal; font-weight:700;
  font-display:swap; src:url('../fonts/ibm-plex-mono-700.woff2') format('woff2');
}

/* ------------------------------------------------------------------ tokens */
:root{
  /* palette */
  --paper:        #EDE9DD;
  --paper-raised: #F6F3EA;
  --paper-sunk:   #E3DECE;
  --rule:         #D3CCB8;
  --ink:          #233054;
  --ink-soft:     #34426E;
  --muted:        #5C6683;
  --brass:        #7A5C12;

  /* verdicts — the brand's loudest asset */
  --verdict-go:      #1F6B3D;
  --verdict-caution: #8F5400;   /* darkened from the app's #A25F00: at 12.8px the
                                   original only reached 4.18:1 on its own tint */
  --verdict-nogo:    #A32B22;
  --verdict-go-bg:      #E3EEE6;
  --verdict-caution-bg: #F3E9D6;
  --verdict-nogo-bg:    #F4E3E0;

  /* night palette, used by the Red mode band */
  --night:      #14161C;
  --night-2:    #1C1F27;
  --night-rule: #4A2020;
  --night-ink:  #E8A79C;
  --night-mute: #B87F76;

  /* Phone bezel. Not #000: against the cream the pure black edge reads as a
     hole punched in the page, and the shadow under it stops being legible. */
  --device:     #14161C;

  /* type */
  /* The fallback after each self-hosted face is the nearest metric match, so
     the swap on a cold load shifts the layout as little as possible. */
  --font-display: 'Source Serif 4', Georgia, "Iowan Old Style", "Times New Roman", serif;
  --font:         'Source Sans 3', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* space */
  --space-1:.25rem; --space-2:.5rem;  --space-3:.75rem; --space-4:1rem;
  --space-5:1.5rem; --space-6:2rem;   --space-7:3rem;   --space-8:4.5rem;

  --radius:  10px;
  --radius-s: 6px;

  /* Tokens the carried-forward machinery at the end of this file expects.
     Values lifted from the previous stylesheet so the badge, the video
     facade and the back-to-top control keep the proportions they were
     tuned at. */
  --fs-sm:       0.875rem;
  --fs-lg:       1.125rem;
  --radius-lg:   18px;
  --radius-pill: 999px;
  --shadow:      0 1px 2px rgb(35 48 84 / 8%), 0 4px 14px rgb(35 48 84 / 6%);
  --shadow-lg:   0 12px 40px -12px rgb(35 48 84 / 28%);

  --maxw:       72rem;
  --maxw-prose: 38rem;
  /* Set together and overridden together at each breakpoint below. --header-h
     also drives html's scroll-padding-top, so an anchor never lands under the
     sticky bar; --brand-h is the mark inside it. Moving one without the other
     is how a logo ends up overhanging its own header. */
  --header-h:   64px;
  --brand-h:    48px;
}

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

html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; scroll-padding-top:calc(var(--header-h) + 1rem); }
@media (prefers-reduced-motion: reduce){ html{ scroll-behavior:auto; } }

body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--font);
  font-size:1.0625rem;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
}

img{ max-width:100%; height:auto; display:block; }

a{ color:var(--ink); text-underline-offset:.2em; }
a:hover{ color:var(--brass); }
:focus-visible{ outline:2px solid var(--brass); outline-offset:3px; border-radius:2px; }

/* iOS holds every tap for about 300ms to see whether a second one follows,
   because a second one would mean double-tap-to-zoom. On a control that gets
   tapped twice in a row that is not a delay, it is a bug: the page zooms
   instead of the control firing. Reported on interact.php, where tapping a
   stepper twice zoomed the page rather than moving the number.

   touch-action:manipulation says this element carries no double-tap gesture,
   so Safari stops waiting. The zoom goes, and the delay goes with it.

   Pinch-zoom is untouched, here and everywhere: this opts individual controls
   out of ONE gesture. It is not user-scalable=no or maximum-scale=1 on the
   viewport meta, which is the usual shortcut and the wrong one — those disable
   pinch-zoom for the whole document, fail WCAG 1.4.4, and Safari has ignored
   them since iOS 10 anyway. The meta in includes/layout.php stays as it is.

   Text and number inputs are deliberately excluded. Nobody double-taps a field
   to zoom, and on iOS a double-tap inside one selects a word, which is worth
   keeping. */
a, button, summary, label, [role="button"],
input[type="checkbox"], input[type="radio"]{ touch-action:manipulation; }

.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}
/* Layout::render() emits .skip-link; the rebuild's stylesheet called it .skip.
   Both are matched rather than renaming one, because the error pages and any
   page not yet ported still emit the other spelling, and an unstyled skip link
   is not invisible — it sits on top of the page reading "Skip to content". */
.skip,
.skip-link{
  position:absolute; left:-9999px; top:0; z-index:100;
  background:var(--ink); color:var(--paper); padding:.75rem 1rem; border-radius:0 0 var(--radius-s) 0;
}
.skip:focus,
.skip-link:focus{ left:0; }

/* -------------------------------------------------------------- typography */
h1,h2,h3,h4{ font-family:var(--font-display); font-weight:700; line-height:1.08; margin:0; text-wrap:balance; }
h1{ font-size:clamp(2.35rem,5.4vw,3.5rem); letter-spacing:-.015em; }
h2{ font-size:clamp(1.75rem,3.6vw,2.6rem); letter-spacing:-.012em; }
h3{ font-size:1.3rem; }
h4{ font-size:1.05rem; }

p{ margin:0 0 var(--space-4); }
p:last-child{ margin-bottom:0; }

/* A heading followed straight by content always gets a gap. Set as a
   margin-top on the sibling so it never doubles with a heading's own margin. */
h1 + p, h2 + p, h2 + ul, h2 + ol, h2 + dl,
h3 + p, h3 + ul, h3 + ol, h3 + dl{ margin-top:var(--space-4); }

.lead{ font-size:1.2rem; color:var(--muted); max-width:34em; }
.muted{ color:var(--muted); }
.small{ font-size:.9rem; }

.eyebrow{
  font-family:var(--font-mono); font-size:.72rem; font-weight:600;
  letter-spacing:.16em; text-transform:uppercase; color:var(--brass);
  margin:0 0 var(--space-3);
}
.label{
  font-family:var(--font-mono); font-size:.72rem; font-weight:600;
  letter-spacing:.14em; text-transform:uppercase; color:var(--muted);
  margin:0 0 var(--space-3);
}
.fineprint{ font-size:.85rem; color:var(--muted); }

/* ------------------------------------------------------------------ layout */
.wrap{ width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:var(--space-5); }

.section{ padding-block:var(--space-8); border-top:1px solid var(--rule); }
.section-first{ border-top:0; }
.section-sunk{ background:var(--paper-sunk); }
.section-tight{ padding-block:var(--space-7); }

.section-head{ max-width:34em; margin-bottom:var(--space-6); }
.section-head .lead{ margin-top:var(--space-4); }

.prose{ max-width:var(--maxw-prose); }
.prose-center{ max-width:var(--maxw-prose); margin-inline:auto; text-align:center; }
.prose-center .eyebrow{ justify-content:center; }
.prose-center .form-row{ text-align:left; }

/* Two-column blocks always carry something on both sides. */
.split{ display:grid; gap:var(--space-6); align-items:center; }
.split-text-first{ grid-template-columns:1fr; }
@media (min-width:56rem){
  .split{ grid-template-columns:1fr 1fr; gap:var(--space-7); }
  .split-narrow-right{ grid-template-columns:1.15fr .85fr; }
  .split-narrow-left{ grid-template-columns:.85fr 1.15fr; }
}

.grid-2,.grid-3{ display:grid; gap:var(--space-5); }
@media (min-width:42rem){ .grid-2{ grid-template-columns:repeat(2,1fr); } }
@media (min-width:56rem){ .grid-3{ grid-template-columns:repeat(3,1fr); } }

/* Screenshots in a three-up are crops of different parts of the app, so they
   are different heights, and left alone they push the heading under each one
   to a different place — three ragged columns that read as unfinished.
   One box per cell, image sitting on its floor: the headings line up and
   nothing has to be cropped to a common shape to get there. The ratio is the
   tallest of the three, so the box scales with the column instead of being a
   fixed pixel height that only works at one width. */
@media (min-width:56rem){
  .grid-3 .shot{
    display:flex; align-items:flex-end; justify-content:center;
    aspect-ratio:346/281; margin-bottom:var(--space-4);
  }
  .grid-3 .shot img{ max-width:100%; max-height:100%; width:auto; height:auto; }
}

.card{
  background:var(--paper-raised);
  border:1px solid var(--rule);
  border-radius:var(--radius);
  padding:var(--space-5);
}
.card h3{ margin-bottom:var(--space-3); }
.card p{ color:var(--muted); }

.scroll-x{ overflow-x:auto; -webkit-overflow-scrolling:touch; }

/* ------------------------------------------------------------------ header */
.site-header{
  position:sticky; top:0; z-index:50;
  background:color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter:saturate(1.2) blur(8px);
  border-bottom:1px solid var(--rule);
}
.header-inner{
  min-height:var(--header-h);
  display:flex; align-items:center; gap:var(--space-4);
}
.brand{ display:flex; align-items:center; flex:0 0 auto; }
.brand img{ height:var(--brand-h); width:auto; transition:height .18s ease; }

/* The mark is a script wordmark with the anchor stacked into it at 420x331 —
   nearly square, where the placeholder this was drafted against was a wide
   rectangle. Height is what makes it legible: below about 40px the lettering
   closes up into a smudge. Four resting sizes, growing with the viewport. */
@media (min-width:48rem){          /* tablet portrait */
  :root{ --header-h:76px; --brand-h:56px; }
}
@media (min-width:64rem){          /* laptop */
  :root{ --header-h:84px; --brand-h:62px; }
}
@media (min-width:90rem){          /* desktop */
  :root{ --header-h:92px; --brand-h:68px; }
}

/* Touch devices give the height back once the reader has scrolled; pointer
   devices keep it.
   The condition is `pointer:coarse` first and width second, because width
   alone gets iPad wrong: an iPad Pro in landscape reports 1366px and would
   read as a desktop, which is exactly the device with the least screen to
   spare for a sticky bar. The width clause is what catches a narrowed laptop
   window, where the same argument applies for the same reason. */
@media (pointer:coarse), (max-width:63.99rem){
  .site-header.is-scrolled{ --header-h:50px; --brand-h:32px; }
}

.header-inner{ transition:min-height .18s ease; }

@media (prefers-reduced-motion:reduce){
  .brand img, .header-inner{ transition:none; }
}

.site-nav{ margin-inline:auto; }
.site-nav ul{ display:flex; gap:var(--space-5); list-style:none; margin:0; padding:0; }
.site-nav a{
  text-decoration:none; font-size:.95rem; color:var(--ink-soft);
  padding-block:.35rem; border-bottom:2px solid transparent; display:block;
}
.site-nav a:hover{ color:var(--brass); }
.site-nav a[aria-current="page"]{ color:var(--brass); border-bottom-color:var(--brass); }

.header-cta{ display:flex; align-items:center; gap:var(--space-3); flex:0 0 auto; }

/* On the landing variant there is no .site-nav, and .site-nav's margin-inline:auto
   was the only thing pushing the brand and the buttons to opposite ends of the
   bar. Without this they sit together on the left with the rest of the header
   empty. */
.layout--landing .header-cta{ margin-left:auto; }

.nav-toggle{
  display:none; margin-left:auto;
  width:44px; height:44px; border:1px solid var(--rule); border-radius:var(--radius-s);
  background:var(--paper-raised); cursor:pointer;
}
.nav-toggle-bars{ position:relative; display:block; width:18px; height:2px; background:var(--ink); margin-inline:auto; }
.nav-toggle-bars::before,
.nav-toggle-bars::after{
  content:""; position:absolute; left:0; width:18px; height:2px; background:var(--ink);
}
.nav-toggle-bars::before{ top:-6px; }
.nav-toggle-bars::after{ top:6px; }

@media (max-width:62rem){
  /* Both the toggle and the collapse are gated on .has-js, which the inline
     script in <head> sets. A visitor whose script never arrives gets a stacked
     but fully usable nav instead of a dead hamburger next to a hidden menu.
     Carried over from the previous stylesheet — it was a deliberate call there
     and the rebuild would otherwise have quietly dropped it. */
  .has-js .nav-toggle{ display:block; }
  .has-js .site-nav{
    display:none; position:absolute; left:0; right:0; top:100%;
    background:var(--paper-raised); border-bottom:1px solid var(--rule);
    padding:var(--space-4) var(--space-5);
  }
  .has-js .site-nav.is-open{ display:block; }
  .site-nav ul{ flex-direction:column; gap:var(--space-2); }
  .site-nav a{ padding-block:.6rem; border-bottom:0; }
  .header-cta .btn-quiet{ display:none; }
}
@media (max-width:34rem){
  .header-cta .btn-primary{ font-size:.85rem; padding:.5rem .8rem; }
}

/* ----------------------------------------------------------------- buttons */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.4rem;
  font:inherit; font-size:.98rem; font-weight:600; line-height:1;
  padding:.72rem 1.2rem; border-radius:999px; border:1px solid transparent;
  text-decoration:none; cursor:pointer; white-space:nowrap;
  transition:background-color .15s ease, border-color .15s ease, color .15s ease;
}
@media (prefers-reduced-motion: reduce){ .btn{ transition:none; } }

.btn-primary{ background:var(--ink); color:var(--paper-raised); }
.btn-primary:hover{ background:var(--verdict-go); color:#fff; }

.btn-quiet{ background:transparent; color:var(--ink); border-color:var(--rule); }
.btn-quiet:hover{ border-color:var(--ink); color:var(--ink); }

.btn-invert{ background:var(--paper); color:var(--ink); }
.btn-invert:hover{ background:#fff; color:var(--ink); }

.btn-row{ display:flex; flex-wrap:wrap; gap:var(--space-3); align-items:center; }

.textlink{ font-weight:600; text-decoration:none; border-bottom:1px solid var(--rule); }
.textlink:hover{ border-bottom-color:var(--brass); }

/* ------------------------------------------------------------------ stamps */
.stamp{
  font-family:var(--font-mono); font-size:.8rem; font-weight:700;
  letter-spacing:.1em; padding:.35rem .6rem; border-radius:var(--radius-s);
  border:2px solid currentColor; display:inline-block; line-height:1;
}
.stamp-go{      color:var(--verdict-go);      background:var(--verdict-go-bg); }
.stamp-caution{ color:var(--verdict-caution); background:var(--verdict-caution-bg); }
.stamp-nogo{    color:var(--verdict-nogo);    background:var(--verdict-nogo-bg); }
.stamp-lg{ font-size:1.15rem; padding:.55rem .95rem; }

/* -------------------------------------------------------------------- hero */
.hero{ padding-block:var(--space-8) var(--space-7); }

/* Five siblings, not a text column beside an image column: wordmark, headline,
   sentence, screenshot, buttons. On a phone that DOM order is the layout, which
   is the whole point — the screenshot sits between the sentence and the calls
   to action instead of below them.

   Spacing is row-gap rather than margins on each child, so the rhythm is set in
   one place and the screenshot can be lifted or dropped without four margins
   needing to agree. */
.hero-grid{ display:grid; row-gap:var(--space-4); }

/* Above the breakpoint the screenshot takes a second column and spans the four
   text rows beside it.

   grid-template-rows is REQUIRED here, not decoration. `grid-row:1/-1` resolves
   -1 against the EXPLICIT grid, so with only implicit rows it means "row 1 to
   row 1" and the image collapses into the first row next to the wordmark.
   Four rows = the four non-shot children; adding a fifth means adding a row. */
@media (min-width:56rem){
  .hero-grid{
    grid-template-columns:1.05fr .95fr;
    grid-template-rows:repeat(4, auto);
    column-gap:var(--space-7);
    align-content:center;
  }
  .hero-grid > :not(.hero-shot){ grid-column:1; }
  .hero-shot{ grid-column:2; grid-row:1 / -1; align-self:center; }
}

/* The mark at full size, which is the one place on the site it gets to be the
   brand rather than a nav item. Same min(260px, 62vw) the current site uses, so
   it does not outgrow a narrow phone. */
.hero-wordmark{ display:block; width:min(260px,62vw); height:auto; margin-bottom:var(--space-2); }
@media (min-width:56rem){ .hero-wordmark{ width:300px; } }

.hero h1{ margin-bottom:0; }
.hero .lead{ font-size:1.28rem; color:var(--ink-soft); margin-bottom:0; }
.hero-note{ font-family:var(--font-mono); font-size:.78rem; letter-spacing:.06em; color:var(--muted); margin-top:var(--space-4); }

/* ------------------------------------------------------------------- strip */
.strip{ background:var(--ink); color:var(--paper-raised); padding-block:var(--space-5); }
.strip a{ color:inherit; }
.strip-live{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-4) var(--space-6); }
.strip-port{ font-family:var(--font-mono); font-size:.8rem; letter-spacing:.1em; text-transform:uppercase; margin:0; display:flex; align-items:center; gap:.5rem; }
.strip-port .dot{ width:.5rem; height:.5rem; border-radius:50%; background:var(--verdict-go); display:inline-block; }
.strip-verdict{ display:flex; align-items:center; gap:var(--space-3); margin:0; font-size:1.05rem; }
.strip-facts{ display:flex; flex-wrap:wrap; gap:var(--space-2) var(--space-5); margin:0; }
.strip-facts div{ display:flex; flex-direction:column; }
.strip-facts dt{ font-family:var(--font-mono); font-size:.66rem; letter-spacing:.12em; text-transform:uppercase; opacity:.7; }
.strip-facts dd{ margin:0; font-size:.95rem; }
.strip-cta{ margin:0 0 0 auto; }
.strip .btn-primary{ background:var(--paper-raised); color:var(--ink); }
.strip .btn-primary:hover{ background:#fff; }

.strip-invite{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-3) var(--space-6); }
.strip-invite-lead{ margin:0; font-family:var(--font-display); font-size:1.3rem; }
.strip-invite-sub{ margin:0; font-size:.95rem; opacity:.82; max-width:36em; }

/* ------------------------------------------------------------------- shots */
.shot{ margin:0; }
.shot img{ max-width:100%; height:auto; border-radius:var(--radius); border:1px solid var(--rule); background:var(--paper-raised); }
/* Phone shots get a device frame. The bezel is the img's own border, so the
   screenshot is clipped by the border-radius' inner curve automatically and no
   wrapper element is needed — outer radius minus border width is the screen
   radius, which is how a real handset is shaped. Shadow is three layers: a
   tight contact shadow, a mid lift, and a wide soft one. A single large shadow
   reads as a sticker; the stack reads as an object above the page. */
.shot-phone img{
  max-width:340px; margin-inline:auto; display:block;
  border:13px solid var(--device);
  border-radius:42px;
  background:var(--device);
  box-shadow:
    0 1px 2px  rgba(20,22,28,.16),
    0 10px 22px rgba(20,22,28,.20),
    0 30px 60px rgba(20,22,28,.18);
}
.shot figcaption{ font-size:.88rem; color:var(--muted); margin-top:var(--space-3); }

/* Placeholder shown until a real capture is dropped in. */
.shot-todo{
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:.4rem;
  border:2px dashed var(--rule); border-radius:var(--radius);
  background:
    repeating-linear-gradient(135deg, transparent 0 10px, rgba(35,48,84,.03) 10px 20px),
    var(--paper-raised);
  color:var(--muted); text-align:center; padding:var(--space-5);
}
.shot-phone .shot-todo{ max-width:340px; margin-inline:auto; }
.shot-todo-slug{ font-family:var(--font-mono); font-size:.8rem; color:var(--brass); letter-spacing:.06em; }
.shot-todo-alt{ font-size:.9rem; max-width:26em; }
.shot-todo-dim{ font-family:var(--font-mono); font-size:.7rem; opacity:.6; }

/* --------------------------------------------------------------- week grid */
.week{ border-collapse:collapse; width:100%; min-width:44rem; font-size:.92rem; }
.week th,.week td{ border:1px solid var(--rule); padding:.6rem .5rem; text-align:center; }
.week thead th{
  font-family:var(--font-mono); font-size:.7rem; letter-spacing:.1em; text-transform:uppercase;
  color:var(--muted); font-weight:600; background:var(--paper-sunk);
}
.week tbody th{
  text-align:left; font-family:var(--font-display); font-weight:700; font-size:1rem;
  background:var(--paper-raised); white-space:nowrap; min-width:11rem;
}
.week tbody th small{ display:block; font-family:var(--font-mono); font-size:.66rem; font-weight:400; letter-spacing:.06em; color:var(--muted); text-transform:uppercase; }
.week .v-go{      background:var(--verdict-go-bg);      color:var(--verdict-go); }
.week .v-caution{ background:var(--verdict-caution-bg); color:var(--verdict-caution); }
.week .v-nogo{    background:var(--verdict-nogo-bg);    color:var(--verdict-nogo); }
.week td b{ font-family:var(--font-mono); font-size:.72rem; letter-spacing:.08em; }

/* ----------------------------------------------------------------- vessels */
.vessel-card{ display:flex; flex-direction:column; gap:var(--space-3); }
.vessel-card .stamp{ align-self:flex-start; }
/* A plain prose list. .limits is monospace because it renders numbers; this is
   for the places a paragraph reads better broken into points. */
ul.plain{ margin:0 0 var(--space-4); padding-left:1.15rem; color:var(--ink-soft); }
ul.plain li{ margin-block:.3rem; }

.limits{ list-style:none; margin:0; padding:0; font-family:var(--font-mono); font-size:.82rem; color:var(--ink-soft); }
.limits li{ padding-block:.15rem; }

.conditions{ display:flex; flex-wrap:wrap; gap:var(--space-4) var(--space-6); margin-bottom:var(--space-5); }
.conditions div{ display:flex; flex-direction:column; }
.conditions dt{ font-family:var(--font-mono); font-size:.66rem; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); }
.conditions dd{ margin:0; font-family:var(--font-mono); font-size:1rem; }

/* --------------------------------------------------------------- data chips */
.chips{ display:flex; flex-wrap:wrap; gap:var(--space-2); list-style:none; margin:0 0 var(--space-4); padding:0; }
.chips li{
  font-family:var(--font-mono); font-size:.78rem; letter-spacing:.04em;
  background:var(--paper-raised); border:1px solid var(--rule);
  border-radius:999px; padding:.35rem .75rem; color:var(--ink-soft);
}

/* --------------------------------------------------------------- red mode */
.redmode{ background:var(--night); color:var(--night-ink); border-top:1px solid var(--night-rule); border-bottom:1px solid var(--night-rule); }
.redmode .eyebrow{ color:#C4564A; }
.redmode h2{ color:var(--night-ink); }
.redmode p{ color:var(--night-mute); }
.redmode .shot-todo{
  border-color:var(--night-rule); color:var(--night-mute);
  background:repeating-linear-gradient(135deg, transparent 0 10px, rgba(232,167,156,.05) 10px 20px), var(--night-2);
}
.redmode .shot-todo-slug{ color:#C4564A; }
.redmode .shot img{ border-color:var(--night-rule); background:var(--night-2); }
.redmode .btn-quiet{ color:var(--night-ink); border-color:var(--night-rule); }
.redmode .btn-quiet:hover{ border-color:var(--night-ink); }

/* ------------------------------------------------------------------ aboard */
.aboard-desktop{ display:none; }
@media (min-width:56rem){
  .aboard-desktop{ display:block; }
  .aboard-mobile{ display:none; }
}

/* Copy, QR, photo. The QR track is fixed rather than auto: auto sizes to the
   caption's one-line width and pushes the photo column narrow. 11rem holds the
   150px code plus its padding and lets the caption wrap under it. */
.aboard-grid{ display:grid; gap:var(--space-6); align-items:center; }
.aboard-photo img{ display:block; width:100%; max-width:22rem; margin-inline:auto; }
@media (min-width:56rem){
  .aboard-grid{ grid-template-columns:1.3fr 11rem 1fr; gap:var(--space-7); }
  .aboard-grid .aboard-desktop{ text-align:center; }
  /* The reset makes img display:block, which text-align does not reach. */
  .aboard-grid .qr{ margin-inline:auto; }
}
.aboard-desktop .qr,
.footer-aboard .qr{ width:150px; height:150px; background:#fff; padding:.5rem; border-radius:var(--radius-s); }

.steps{ counter-reset:step; list-style:none; margin:0; padding:0; }
.steps li{ counter-increment:step; display:grid; grid-template-columns:2rem 1fr; gap:var(--space-3); padding-block:var(--space-2); }
.steps li::before{
  content:counter(step,decimal-leading-zero);
  font-family:var(--font-mono); font-size:.78rem; font-weight:600; color:var(--brass); padding-top:.2rem;
}

/* ------------------------------------------------------------------- forms */
.form{ display:grid; gap:var(--space-4); max-width:34rem; }
.form-row{ display:grid; gap:var(--space-2); }
.form label{ font-family:var(--font-mono); font-size:.74rem; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); font-weight:600; }
.form input,.form select,.form textarea{
  font:inherit; font-size:1rem; color:var(--ink);
  background:var(--paper-raised); border:1px solid var(--rule); border-radius:var(--radius-s);
  padding:.7rem .85rem; width:100%;
}
.form textarea{ min-height:9rem; resize:vertical; }
.form .hint{ font-size:.85rem; color:var(--muted); }
.hp{ position:absolute; left:-9999px; }

.inline-form{ display:flex; flex-wrap:wrap; gap:var(--space-3); align-items:flex-end; max-width:40rem; }
.inline-form .form-row{ flex:1 1 16rem; }

/* ------------------------------------------------------------------ guides */
/* Collapsed guides. <details> rather than a scripted accordion: keyboard
   operable for free, present in the accessibility tree, and find-in-page opens
   a closed one by itself. The h2 lives in the summary so the shut page is still
   navigable by heading. */
.guide-list{ display:grid; gap:var(--space-3); }
.guide-item{ background:var(--paper-raised); border:1px solid var(--rule); border-radius:var(--radius); }
.guide-item > summary{
  display:flex; align-items:center; justify-content:space-between; gap:var(--space-4);
  padding:var(--space-4) var(--space-5); cursor:pointer; list-style:none;
}
/* display:flex drops the marker in Chrome and Firefox; Safari needs this too. */
.guide-item > summary::-webkit-details-marker{ display:none; }
.guide-item > summary:hover{ color:var(--brass); }
.guide-item > summary:focus-visible{ outline:2px solid var(--brass); outline-offset:-2px; }
.guide-item summary h2{ font-size:1.15rem; margin:0; }
.guide-item__mark{ flex:0 0 auto; position:relative; width:1rem; height:1rem; }
.guide-item__mark::before,
.guide-item__mark::after{ content:""; position:absolute; background:var(--brass); }
.guide-item__mark::before{ left:0; right:0; top:calc(50% - 1px); height:2px; }
.guide-item__mark::after{ top:0; bottom:0; left:calc(50% - 1px); width:2px; transition:transform .15s ease; }
.guide-item[open] .guide-item__mark::after{ transform:scaleY(0); }
@media (prefers-reduced-motion: reduce){ .guide-item__mark::after{ transition:none; } }
.guide-item__body{ padding:0 var(--space-5) var(--space-5); }

.guide-index{ display:grid; gap:var(--space-2); }
@media (min-width:42rem){ .guide-index{ grid-template-columns:repeat(2,1fr); } }
.guide-index a{
  display:flex; gap:var(--space-3); align-items:baseline;
  background:var(--paper-raised); border:1px solid var(--rule); border-radius:var(--radius-s);
  padding:.7rem .9rem; text-decoration:none;
}
.guide-index a:hover{ border-color:var(--brass); }
.guide-index .n{ font-family:var(--font-mono); font-size:.75rem; color:var(--brass); font-weight:600; }

.guide{ padding-block:var(--space-7); border-top:1px solid var(--rule); }
.guide-meta{ font-family:var(--font-mono); font-size:.72rem; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); margin-bottom:var(--space-2); }
.guide ol{ padding-left:1.3rem; }
.guide ol li{ margin-block:.5rem; max-width:44em; }

/* ------------------------------------------------------------------- about */
.collage{ display:grid; grid-template-columns:repeat(2,1fr); gap:var(--space-3); }
@media (min-width:42rem){ .collage{ grid-template-columns:repeat(3,1fr); } }
.collage .shot{ margin:0; }
.collage .shot-todo{ aspect-ratio:4/5 !important; padding:var(--space-3); }
.collage .shot-tall{ grid-row:span 2; }
.collage .shot-tall .shot-todo{ aspect-ratio:4/9 !important; }

.person{ display:grid; gap:var(--space-4); }
@media (min-width:48rem){ .person{ grid-template-columns:14rem 1fr; gap:var(--space-6); align-items:start; } }
.person h3{ margin-bottom:var(--space-2); }
.person .role{ font-family:var(--font-mono); font-size:.72rem; letter-spacing:.12em; text-transform:uppercase; color:var(--brass); margin-bottom:var(--space-3); }

/* ------------------------------------------------------------------ footer */
.site-footer{ background:var(--ink); color:var(--paper-sunk); padding-block:var(--space-7) var(--space-6); margin-top:var(--space-8); }
.site-footer a{ color:var(--paper-sunk); }
.site-footer a:hover{ color:#fff; }
/* .site-footer a is (0,1,1) and would otherwise win over .btn-invert (0,1,0). */
.site-footer a.btn-invert{ color:var(--ink); }
.site-footer a.btn-invert:hover{ color:var(--ink); }
.footer-grid{ display:grid; gap:var(--space-6); }
@media (min-width:56rem){ .footer-grid{ grid-template-columns:1.4fr .8fr .8fr; gap:var(--space-7); } }

/* The landing variant drops the "This site" column. Without its own template
   the two survivors keep the first two tracks of a three-track grid and leave a
   column of empty footer on the right. */
@media (min-width:56rem){ .footer-grid--lean{ grid-template-columns:1.4fr .8fr; } }
.footer-legal-links{
  display:flex; flex-wrap:wrap; gap:var(--space-3) var(--space-5);
  margin-bottom:var(--space-5);
}
.footer-legal-links a{ text-decoration:none; }
.footer-legal-links a:hover{ text-decoration:underline; }
.footer-mark{ height:64px; width:auto; margin-bottom:var(--space-4); }
.footer-brand p{ max-width:32em; color:var(--paper-sunk); opacity:.85; }
.footer-actions{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-4); margin-top:var(--space-5); }
.footer-link{ text-decoration:underline; font-size:.95rem; }
.footer-nav ul{ list-style:none; margin:0; padding:0; display:grid; gap:.45rem; }
.footer-nav a{ text-decoration:none; font-size:.95rem; }
.footer-nav a:hover{ text-decoration:underline; }
.site-footer .label{ color:var(--paper-sunk); opacity:.65; }
.footer-aboard p{ font-size:.88rem; opacity:.8; margin-top:var(--space-3); max-width:22em; }
.footer-legal{ border-top:1px solid rgba(255,255,255,.16); margin-top:var(--space-6); padding-top:var(--space-5); font-size:.85rem; opacity:.8; }
.footer-legal img{ width:150px; height:auto; background:#fff; padding:.35rem .5rem; border-radius:var(--radius-s); margin-bottom:var(--space-4); }
.footer-legal p{ margin-bottom:var(--space-2); max-width:52em; }
.footer-legal .disclaimer{ opacity:.8; }

/* ------------------------------------------------------------------- print */
@media print{
  .site-header,.site-footer,.strip,.nav-toggle{ display:none !important; }
  body{ background:#fff; color:#000; }
}

/* ===========================================================================
   Carried forward from the previous stylesheet.

   These are not part of the redesign. They style machinery that outlives any
   visual pass: the environment badge, the honeypot, the video facade, the
   form field wrapper and the back-to-top control. They were extracted
   verbatim rather than rewritten, because the honeypot rule in particular is
   a security control and "tidying" it is how a hidden field becomes visible.
   ========================================================================== */

  /* -------------------------------------------------------- video "facade" */

  /* No YouTube iframe until a click. The poster and play control are ours, so
     a visitor who never plays a video never touches a Google server and never
     receives a Google cookie. That keeps the consent question about analytics
     only, instead of about analytics plus five embeds. */
  .videocard { display: grid; gap: var(--space-3); }

  .videocard__facade {
    position: relative;
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    border: 1px solid var(--rule);
    border-radius: var(--radius-lg);
    background: var(--ink);
    overflow: hidden;
    cursor: pointer;
  }
  .videocard__facade img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0.72;
    transition: opacity 0.2s ease, transform 0.35s ease;
  }
  .videocard__facade:hover img { opacity: 0.85; transform: scale(1.02); }

  .videocard__play {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    pointer-events: none;
  }
  .videocard__play::before {
    content: "";
    width: 68px;
    height: 68px;
    border-radius: 50%;
    background: var(--paper);
    box-shadow: var(--shadow-lg);
  }
  .videocard__play::after {
    content: "";
    position: absolute;
    width: 0;
    height: 0;
    border-inline-start: 20px solid var(--ink);
    border-block-start: 12px solid transparent;
    border-block-end: 12px solid transparent;
    transform: translateX(4px);
  }

  .videocard__frame { width: 100%; height: 100%; border: 0; display: block; }


  .conditions .conditions__value { font-size: var(--fs-lg); color: var(--ink); }

  /* ----------------------------------------------------------------- forms */

  .field { margin-block-end: var(--space-4); }

  label {
    display: block;
    margin-block-end: var(--space-1);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--ink);
  }
  .field__hint {
    display: block;
    font-size: var(--fs-sm);
    font-weight: 400;
    color: var(--muted);
    margin-block-end: var(--space-2);
  }

  input[type="text"],
  input[type="email"],
  input[type="url"],
  select,
  textarea {
    width: 100%;
    min-height: 44px;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: #fff;
    color: var(--ink);
  }
  textarea { min-height: 9rem; resize: vertical; }
  input:focus-visible, select:focus-visible, textarea:focus-visible {
    border-color: var(--brass);
  }

  /* The honeypot. Off-canvas rather than display:none — some bots skip fields
     that are display:none specifically because it is the obvious tell. It is
     also aria-hidden and tabindex=-1 in the markup so no real user can reach
     it by keyboard and fill it by accident. */
  .hp-field {
    position: absolute !important;
    inset-inline-start: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
  }

  .alert {
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius);
    border: 1px solid var(--rule);
    background: var(--paper-raised);
    margin-block-end: var(--space-6);
  }
  .alert--error   { background: #FBEBE9; border-color: #E3B7B1; color: var(--verdict-nogo); }
  .alert--success { background: #E7F2EA; border-color: #B4D3BE; color: var(--verdict-go); }

  /* Inline, per-field validation message. Deliberately NOT .alert: that is a
     full-width banner and this sits next to one input. */
  .form-error {
    display: block;
    color: var(--verdict-nogo);
    font-size: var(--fs-sm);
    margin-block-start: var(--space-1);
  }
  input[aria-invalid="true"], textarea[aria-invalid="true"] {
    border-color: var(--verdict-nogo);
  }

  /* ----------------------------------------------------------- back to top */

  .backtotop {
    position: fixed;
    inset-block-end: 1rem;
    inset-inline-end: 1rem;
    z-index: 1900;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 44px is the smallest comfortable touch target, and this control is
       aimed at a thumb on a phone at the bottom of a long page. */
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: 1px solid var(--rule);
    background: var(--paper-raised);
    color: var(--ink);
    box-shadow: var(--shadow);
    /* visibility, not display: display is not transitionable, so the fade
       below would not happen at all.
       visibility is deliberately NOT in the transition list. It is a discrete
       property, so a transition on it does not interpolate — it flips at the
       halfway mark, which leaves the control unfocusable for 90ms after it has
       visibly appeared, and pins it at `hidden` outright wherever transitions
       are stalled (a background tab throttles them). Flipping it instantly and
       fading only opacity and transform gives the same look with none of that:
       the moment it is on screen it is in the tab order. */
    opacity: 0;
    visibility: hidden;
    transform: translateY(6px);
    transition: opacity 0.18s ease, transform 0.18s ease;
  }
  .backtotop:hover { background: var(--paper); }
  .backtotop.is-visible {
    opacity: 1;
    visibility: visible;
    transform: none;
  }
  @media (prefers-reduced-motion: reduce) {
    .backtotop { transition: none; }
  }
  @media print { .backtotop { display: none; } }

  /* ------------------------------------------------------------- env badge */

  /* Rendered in local and staging only, never in production, so a tab or a
     screenshot in a bug report identifies itself. Non-interactive and
     aria-hidden, so it cannot get in the way of the page. */
  /* Bottom-LEFT, because the back-to-top control owns the bottom-right corner
     and is a real control where this is decoration. Keeping the badge on the
     right and nudging the button up instead would mean local and staging laid
     out differently from production, where no badge renders — so the corner
     you test would not be the corner that ships. */
  .env-badge {
    position: fixed;
    inset-block-end: 1rem;
    inset-inline-start: 1rem;
    z-index: 2000;
    pointer-events: none;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.5rem 0.75rem;
    border-radius: var(--radius-pill);
    background: var(--env-badge-color, var(--ink));
    color: #fff;
    font: 700 0.72rem/1 var(--font-mono);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    box-shadow: 0 8px 20px -6px rgb(0 0 0 / 55%);
  }
  .env-badge__dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #fff;
    opacity: 0.85;
  }
  @media print { .env-badge { display: none; } }

  .icon { display: inline-block; vertical-align: -0.15em; }

/* Two holdovers with no equivalent in the rebuild's vocabulary.
   .formwrap wraps the feedback form and its flash region; .error-code is the
   numeral on the branded 403 and 404 pages. Both are one rule each, which is
   cheaper than renaming them across files that are not otherwise changing. */
.formwrap{ max-width:34rem; }
.error-code{
  font-family:var(--font-mono); font-size:.8rem; font-weight:700;
  letter-spacing:.14em; text-transform:uppercase; color:var(--brass);
  margin:0 0 var(--space-3);
}

/* .visually-hidden is what the back-to-top partial and blocks.php emit; the
   rebuild's stylesheet calls the same thing .sr-only. Aliased rather than
   renamed across files that are not otherwise changing. */
.visually-hidden{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* The hero screenshot. `order:2` used to push it below the buttons on a phone;
   it now sits between the sentence and the buttons by DOM order, so the
   override is gone rather than fighting the new one. */
.hero-shot{ display:flex; justify-content:center; }
@media (max-width:56rem){ .hero-shot{ margin-block:var(--space-2); } }

/* Below the breakpoint the hero's own buttons were landing around 1180px on an
   812px screen, so nobody saw them without scrolling one and a half screens.
   The order stays as it is (wordmark, headline, sentence, screenshot, buttons).
   The mark is already in the sticky header at this width, so it does not need
   to be 183px tall a second time.

   The screenshot is NOT capped. f9d5162 also held it to 40svh, and on a phone
   that shrank the 390x780 capture to roughly 162px wide inside a bezel that is
   a fixed 13px border — the frame read as thick and the screen as small.
   Roland reverted it on 2026-09-04: the phone is the product shot and gets its
   full 340px. That puts the buttons back below the fold on a phone, which is
   the trade he chose. If the fold matters again, shrink the bezel with the
   image rather than the image alone. */
@media (max-width:56rem){
  .hero{ padding-block:var(--space-4) var(--space-6); }
  .hero-wordmark{ width:min(140px,38vw); }
}

/* The written steps under each guide video. Carried over with the facade. */
.videocard__steps{
  margin:var(--space-3) 0 0; padding-left:1.2rem;
  display:grid; gap:var(--space-2); color:var(--muted); font-size:var(--fs-sm);
}
