/* Self-hosted, latin subset, pulled from the Google CSS so unicode-range and the
   variable weight ranges are preserved exactly. Section 3.A bans linking Google
   Fonts in production, and this project already paid for that: order 0067 was
   "every page waited on Google Fonts". Three variable files cover every weight. */
@font-face{font-family:'Fraunces';font-style:normal;font-weight:500 600;font-display:swap;src:url('fonts/fraunces-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/inter-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/inter-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url('fonts/inter-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/jetbrains-mono-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/jetbrains-mono-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}

/* Flotilla site — public product page and internal reference page.
   Design language is the dashboard's: docs/designs/dashboard.md.
   Tokens are copied verbatim from client/src/tokens.css. Do not invent new colours here;
   any divergence from the board is a bug, same rule the dashboard follows. */

:root{
  --paper:#FAF9F7; --card:#FFFFFF; --ink:#1A1917; --ink2:#4A4741;
  --muted:#8A857C; --line:#E8E4DD; --line2:#D9D4CA;
  --teal:#0F766E; --teal-soft:#E6F2F0;
  --red:#B91C1C; --red-soft:#FDEDED;
  --amber:#B45309; --amber-soft:#FDF4E7;
  --sans:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --serif:'Fraunces',Georgia,serif;
  --mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  --r-card:12px; --r-ctl:8px; --r-tag:5px;
  --shadow:0 1px 2px rgba(26,25,23,.04),0 1px 1px rgba(26,25,23,.02);
  --page:1080px;
}

*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;scroll-padding-top:84px}
body{background:var(--paper);color:var(--ink);font-family:var(--sans);font-size:15.5px;
     line-height:1.62;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
a{color:var(--teal);text-decoration:none}
a:hover{text-decoration:underline;text-underline-offset:2px}
img,svg{display:block;max-width:100%}
code{font-family:var(--mono);font-size:.875em}
:focus-visible{outline:2px solid var(--teal);outline-offset:3px;border-radius:3px}

/* ---- layout ---- */
.wrap{max-width:var(--page);margin:0 auto;padding:0 28px}
section{padding:74px 0}
section + section{border-top:1px solid var(--line)}
.narrow{max-width:720px}

/* ---- top nav: mirrors the dashboard nav, one row, hairline rule ---- */
.nav{position:sticky;top:0;z-index:40;background:rgba(255,255,255,.97);
     backdrop-filter:saturate(140%) blur(8px);border-bottom:1px solid var(--line)}
.nav .wrap{height:62px;display:flex;align-items:center;gap:22px}
.nav .lockup{height:26px;width:auto;flex:none}
.nav .links{margin-left:auto;display:flex;align-items:center;gap:22px}
.nav .links a{color:var(--ink2);font-size:13.5px;font-weight:500;white-space:nowrap}
.nav .links a:hover{color:var(--ink);text-decoration:none}
.nav .tag{font-family:var(--mono);font-size:11px;color:var(--teal);background:var(--teal-soft);
     border-radius:var(--r-tag);padding:3px 8px;flex:none}
.navtoggle{display:none}

/* ---- buttons ---- */
.btn{display:inline-flex;align-items:center;gap:8px;border-radius:var(--r-ctl);padding:10px 17px;
     font:500 14px var(--sans);cursor:pointer;border:1px solid transparent;white-space:nowrap}
.btn:hover{text-decoration:none}
.btn-p{background:var(--teal);color:#fff}
.btn-p:hover{background:#0C5F59}
.btn-s{background:var(--card);color:var(--ink);border-color:var(--line2)}
.btn-s:hover{border-color:var(--muted)}
.btn-row{display:flex;gap:12px;flex-wrap:wrap;align-items:center}

/* ---- type ---- */
.eyebrow{font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.11em;
     color:var(--muted);margin-bottom:14px}
/* Fraunces is already a compact face, so the negative tracking that suits a
   grotesque made it cramped -- "agents." was crowding "One" at 51px. Relaxed to
   roughly a quarter of what it was.

   WONK 0 switches off Fraunces' quirky angled j/y/g terminals, which is what
   made the headings read as fussy old-magazine rather than quiet editorial.
   This axis only exists because the font URL now requests SOFT and WONK; with
   the previous opsz,wght-only request this declaration was a silent no-op. */
h1{font-family:var(--serif);font-weight:600;font-size:clamp(40px,7vw,86px);line-height:1.02;
   letter-spacing:-.014em;font-variation-settings:'WONK' 0;text-wrap:balance}
h2{font-family:var(--serif);font-weight:600;font-size:clamp(26px,3.2vw,34px);line-height:1.18;
   letter-spacing:-.010em;font-variation-settings:'WONK' 0}
h3{font-family:var(--serif);font-weight:600;font-size:18.5px;line-height:1.3;
   letter-spacing:-.008em;font-variation-settings:'WONK' 0}
h4{font-family:var(--sans);font-weight:600;font-size:14.5px;letter-spacing:-.005em}
.lead{font-size:18.5px;line-height:1.58;color:var(--ink2);max-width:62ch}
.sub{color:var(--ink2);max-width:66ch}
.sub + .sub{margin-top:14px}
.muted{color:var(--muted)}
.s-head{margin-bottom:34px}
.s-head h2 + .sub{margin-top:14px}
strong{font-weight:600;color:var(--ink)}

/* ---- hero: centred, screenshot-led ----
   Restructured after looking at devin.ai. The lesson worth taking was not its
   typeface or its nav, it was this: the hero shows the REAL product, large,
   bleeding off the bottom of the viewport, with almost no copy around it. An
   abstract illustration cannot buy the credibility a real screenshot does.

   Deliberately NOT copied: their geometric sans (we have a serif wordmark to
   match), their dropdown nav, and "Pricing" / "Customers" / "Contact sales" --
   there is no pricing, no customer list and no sales team here, and inventing
   that chrome is exactly what makes a page read as fake. */
.hero{padding:86px 0 0;overflow:hidden}
.hero-c{text-align:center;max-width:920px}
.hero-c h1{margin:0 auto;max-width:22ch}
.hero-def{font-size:19px;line-height:1.55;color:var(--ink2);margin:24px auto 0;max-width:60ch}
.hero .btn-row{margin-top:32px;justify-content:center}
.hero .fine{margin-top:18px;font-size:13px;color:var(--muted)}

/* The screenshot. Fixed-height window with object-position:top, so the demo
   board's empty lower half is never shown and the frame stays dense at every
   width without re-cropping the asset. */
.hero-shot{margin-top:60px;padding:0 28px}
/* Clip the BOTTOM only, never the sides. object-fit:cover cropped ~99px off the
   right and sliced the detail panel mid-word, because the frame's aspect was
   narrower than the image's. Full-width image inside a max-height window cuts
   only where the board is sparse anyway, and that cut is the bleed. */
.shot-frame{max-width:1240px;margin:0 auto;max-height:min(50vh,470px);
  background:var(--card);border:1px solid var(--line2);
  border-radius:14px 14px 0 0;border-bottom:none;overflow:hidden;
  box-shadow:0 24px 60px -28px rgba(26,25,23,.28)}
.shot-frame img{width:100%;height:auto;display:block}

/* ---- cards ---- */
.grid{display:grid;gap:16px}
.g2{grid-template-columns:repeat(2,1fr)}
.g3{grid-template-columns:repeat(3,1fr)}
.g4{grid-template-columns:repeat(4,1fr)}
.tile{background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);
      padding:22px 22px 24px;box-shadow:var(--shadow)}
.tile h3{margin-bottom:9px}
.tile p{font-size:14px;color:var(--ink2);line-height:1.6}
.tile .n{font-family:var(--mono);font-size:11px;color:var(--muted);margin-bottom:13px;display:block}
.tile ul{margin-top:10px}

/* ---- numbered steps ---- */
.steps{counter-reset:s;display:grid;gap:2px}
.step{display:grid;grid-template-columns:34px 1fr;gap:16px;padding:18px 0;
      border-bottom:1px solid var(--line)}
.step:last-child{border-bottom:none}
.step::before{counter-increment:s;content:counter(s);font-family:var(--mono);font-size:12px;
      color:var(--teal);background:var(--teal-soft);border-radius:50%;width:26px;height:26px;
      display:grid;place-items:center;margin-top:1px}
.step h4{margin-bottom:5px}
.step p{font-size:14px;color:var(--ink2)}
.step code{background:var(--card);border:1px solid var(--line);border-radius:5px;padding:1px 6px}

/* ---- lists ---- */
ul.plain{list-style:none;display:grid;gap:9px}
ul.plain li{position:relative;padding-left:17px;font-size:14px;color:var(--ink2)}
ul.plain li::before{content:'';position:absolute;left:0;top:.62em;width:5px;height:5px;
      border-radius:50%;background:var(--line2)}
ul.plain li.yes::before{background:var(--teal)}
ul.plain li.no::before{background:var(--line2)}

/* ---- code ---- */
pre{background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);
    padding:17px 19px;overflow-x:auto;font-family:var(--mono);font-size:12.5px;line-height:1.72;
    color:var(--ink2);box-shadow:var(--shadow)}
pre b{color:var(--ink);font-weight:500}
pre .c{color:var(--muted)}
pre .t{color:var(--teal)}
.pre-label{font-family:var(--mono);font-size:11px;color:var(--muted);margin-bottom:8px}
figure{margin:0}
figcaption{font-size:12.5px;color:var(--muted);margin-top:10px}

/* ---- tables ---- */
.tbl{width:100%;border-collapse:collapse;background:var(--card);border:1px solid var(--line);
     border-radius:var(--r-card);overflow:hidden;box-shadow:var(--shadow)}
.tbl th,.tbl td{text-align:left;padding:12px 16px;border-bottom:1px solid var(--line);
     font-size:13.5px;vertical-align:top}
.tbl th{font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.09em;
     color:var(--muted);background:var(--paper);white-space:nowrap}
.tbl tr:last-child td{border-bottom:none}
.tbl td code{font-size:12px;color:var(--ink2)}
.tbl td.k{white-space:nowrap;font-weight:500}
.scroll-x{overflow-x:auto;-webkit-overflow-scrolling:touch}
/* narrow screens scroll the table rather than crushing five columns into 320px */
.scroll-x .tbl{min-width:640px}

/* ---- tags, badges, pills (dashboard idioms, reused verbatim) ---- */
.kind{font-size:10.5px;font-weight:600;letter-spacing:.03em;text-transform:uppercase;
      border-radius:var(--r-tag);padding:2px 7px;display:inline-block}
.kind[data-k="backend"]{background:var(--teal-soft);color:var(--teal)}
.kind[data-k="frontend"]{background:#EFEAF6;color:#5B4A7D}
.kind[data-k="qa"]{background:#FBF0E8;color:#9A5B2E}
.kind[data-k="docs"],.kind[data-k="devops"]{background:#EEEDEA;color:var(--ink2)}
.badge{font-size:10.5px;font-weight:600;border-radius:var(--r-tag);padding:2px 7px;white-space:nowrap;
      display:inline-block}
.badge[data-t="ci-failed"],.badge[data-t="blocked"]{background:var(--red-soft);color:var(--red)}
.badge[data-t="review"]{background:var(--amber-soft);color:var(--amber)}
.badge[data-t="ok"]{background:var(--teal-soft);color:var(--teal)}
.verpill{font-family:var(--mono);font-size:10.5px;background:var(--teal-soft);color:var(--teal);
      border-radius:var(--r-tag);padding:2px 7px;font-weight:500;display:inline-block}

/* The hand-built miniature board was removed: the page now shows real captures
   of the product instead, in the hero and in the board section. Its .bf-* and
   shared are kept where other sections still use them. */
.row{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.count{font-family:var(--mono);font-size:10.5px;color:var(--muted);background:var(--card);
      border:1px solid var(--line);border-radius:20px;padding:1px 7px}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.32}}

/* ---- callout ---- */
.note{background:var(--card);border:1px solid var(--line);border-left:3px solid var(--teal);
      border-radius:var(--r-ctl);padding:16px 19px;font-size:14px;color:var(--ink2)}
.note.warn{border-left-color:var(--amber)}
.note.stop{border-left-color:var(--red)}
.note h4{margin-bottom:6px;color:var(--ink)}

/* ---- dark band (the one inversion; uses the white lockup per brand rules) ---- */
.band{background:var(--ink);color:#F5F3F0;border-top:none}
.band h2{color:#fff}
.band .sub,.band .lead{color:#C9C4BC}
.band .eyebrow{color:#8A857C}
.band pre{background:#242320;border-color:#35332F;color:#D8D3CB}
.band pre b{color:#fff}
.band pre .t{color:#5EC4B8}
.band pre .c{color:#7E7972}
.band a{color:#5EC4B8}
.band .btn-s{background:transparent;color:#fff;border-color:#45423D}
.band .btn-s:hover{border-color:#6E6A63}

/* ---- ASCII architecture diagram ---- */
.arch{background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);
      padding:24px;overflow-x:auto;box-shadow:var(--shadow)}
.arch pre{background:none;border:none;box-shadow:none;padding:0;font-size:12px;line-height:1.85;
      color:var(--ink2)}

/* ---- two-column prose + aside ---- */
.split{display:grid;grid-template-columns:1.35fr 1fr;gap:42px;align-items:start}
/* Grid items default to min-width:auto, so a white-space:pre block sets the track floor from
   its longest line and the whole PAGE gains a horizontal scrollbar on narrow screens. The pre
   already scrolls itself; the track just has to be allowed to shrink. */
.split > *,.hero-grid > *{min-width:0}

/* ---- reference page: sticky table of contents ---- */
.doc{display:grid;grid-template-columns:216px 1fr;gap:52px;align-items:start}
.toc{position:sticky;top:86px;display:grid;gap:2px}
.toc .eyebrow{margin-bottom:8px}
.toc a{display:block;font-size:13px;color:var(--ink2);padding:5px 0;line-height:1.4}
.toc a:hover{color:var(--teal);text-decoration:none}
.doc-body{min-width:0;display:grid;gap:58px}
.doc-body > article > h2{padding-bottom:12px;border-bottom:1px solid var(--line);margin-bottom:22px}
.doc-body > article > * + *{margin-top:18px}
.doc-body > article > h3{margin-top:36px}
.doc-body > article > h2 + h3{margin-top:2px}

/* ---- internal banner ---- */
.internal{background:var(--amber-soft);border-bottom:1px solid #F0E2CB}
.internal .wrap{padding:11px 28px;display:flex;gap:12px;align-items:baseline;flex-wrap:wrap}
.internal .k{font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.09em;
      color:var(--amber);flex:none}
.internal p{font-size:13px;color:#7A4A12}

/* ---- footer ---- */
footer{border-top:1px solid var(--line);padding:44px 0 56px;background:var(--card)}
footer .wrap{display:flex;gap:32px;flex-wrap:wrap;align-items:flex-start}
footer .lockup{height:24px;width:auto}
footer .cols{margin-left:auto;display:flex;gap:56px;flex-wrap:wrap}
footer .col{display:grid;gap:8px}
footer .col .eyebrow{margin-bottom:2px}
footer .col a{font-size:13.5px;color:var(--ink2)}
footer .col a:hover{color:var(--teal);text-decoration:none}
footer .fine{width:100%;margin-top:30px;padding-top:22px;border-top:1px solid var(--line);
      font-size:12.5px;color:var(--muted)}

/* ---- responsive ---- */
@media (max-width:920px){
  .g4{grid-template-columns:repeat(2,1fr)}
  .g3{grid-template-columns:1fr 1fr}
  .split{grid-template-columns:1fr;gap:28px}
      .doc{grid-template-columns:1fr;gap:26px}
  .toc{position:static;border:1px solid var(--line);background:var(--card);
       border-radius:var(--r-card);padding:16px 18px}
  .toc{grid-template-columns:repeat(2,1fr)}
  .toc .eyebrow{grid-column:1/-1}
}
@media (max-width:640px){
  .shot-frame{max-height:min(40vh,260px);border-radius:10px 10px 0 0}
  .hero-shot{margin-top:40px;padding:0 16px}

  body{font-size:15px}
  section{padding:56px 0}
  .hero{padding:60px 0 56px}
      .g2,.g3,.g4{grid-template-columns:1fr}
  .wrap{padding:0 20px}
  .nav .links{gap:15px}
  .nav .links a.hide-sm,.nav .tag{display:none}
  footer .cols{margin-left:0;gap:32px}
}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .bf-nav .fresh .dot,.tf-live{animation:none}
}

/* ---- print ---- */
@media print{
  .nav,footer,.toc{display:none}
  body{background:#fff}
  section{padding:24px 0;break-inside:avoid}
}


/* ============================================================ brand splash
   Ported from the HyperFrames logo sting. The boats fly in along the
   formation's own -7deg axis (they sit inside the rotated group, so local
   translateX IS that axis), squash as they land, and the name is uncovered by
   a paper-coloured pane sliding off the same axis.

   Budget: 1.5s total. The sting itself is 4.3s, which is fine for a video and
   far too long to sit in front of a page on every visit.

   The overlay's DEFAULT state is hidden; the animation is what reveals it.
   That way a browser that never runs the keyframes shows no splash at all
   rather than a permanent white cover. */
.splash{
  position:fixed;inset:0;z-index:200;
  background:var(--paper);
  display:grid;place-items:center;
  overflow:hidden;                      /* the overlay is the frame: nothing paints outside it */
  opacity:0;visibility:hidden;          /* fail-safe resting state */
  animation:sp-life 2s linear forwards;
}
.splash-art{width:min(560px,62vw);height:auto;overflow:visible}

/* visible for the first ~77%, then fades out and stays gone */
@keyframes sp-life{
  0%,84%{opacity:1;visibility:visible}
  100%{opacity:0;visibility:hidden}
}

.sp-boat{
  fill:var(--teal);
  transform-box:fill-box;               /* origin resolves against the boat itself */
  transform-origin:100% 50%;            /* nose holds, body catches up */
  animation:sp-sail 1.15s cubic-bezier(.33,.06,.28,1) backwards;
}
/* Sailing, then docking. The brand forbids waves and wakes outright, so the
   water is in the MOVEMENT rather than the artwork: each boat rises and falls as
   it travels, and the bob decays to nothing as it moors. Buoyancy implies the
   water; nothing is drawn.

   translateY here is in the rotated group's local space, so the bob is
   perpendicular to the direction of travel, which is what a hull actually does.
   The vertical bob is REMOVED: at a visible amplitude it read as wiggling
   rather than as swell. Travel plus the dock settle only. A light swish behind
   each hull is being designed in the HyperFrames composition and will be ported
   here once it is agreed. */
@keyframes sp-sail{
  0%,10% {transform:translateX(-1520px) scale(1,1);opacity:0}
  28%    {transform:translateX(-940px) scale(1,1);opacity:.5}
  44%    {transform:translateX(-520px) scale(1,1);opacity:.88}
  58%    {transform:translateX(-235px) scale(1,1);opacity:1}
  70%    {transform:translateX(-70px) scale(1,1);opacity:1}
  81%    {transform:translateX(16px) scale(.93,1.06);opacity:1}
  90%    {transform:translateX(4px) scale(1.025,.99);opacity:1}
  100%   {transform:translateX(0) scale(1,1);opacity:1}
}

/* The name simply appears. The wipe that used to uncover it read as a
   mechanical device sliding across the word; a slow fade lets the name resolve
   instead. No movement either: the boats already carry the motion, and a
   drifting wordmark on top of them fights for the same attention.

   Long and gentle on purpose. ease-in-out starts imperceptibly, so it reads as
   "appearing" rather than as an animation starting. */
.sp-word{fill:var(--ink);opacity:0;animation:sp-appear .62s cubic-bezier(.4,0,.2,1) 1.06s forwards}
@keyframes sp-appear{to{opacity:1}}

/* Reduced motion: no splash at all. Not a faster splash -- none. */
@media (prefers-reduced-motion:reduce){
  .splash{display:none}
}


/* ============================================ illustration system
   One vocabulary for every diagram on the page, so they read as a family
   rather than six unrelated pictures:

     .il-rail    structure and flow      ink at 18%, 2px
     .il-live    the active/committed path  teal, 2.6px
     .il-card    a machine, file or repo    paper card + hairline
     .il-node    a landed event            ink at 20%
     .il-hot     the thing happening now   teal
     .il-lbl     mono micro-label          replaces a sentence
     .il-warn    a conflict                red

   Strokes are declared once here. An illustration that needs a new weight or
   colour is a sign the vocabulary is wrong, not that it needs an exception. */
.il{width:100%;height:auto;display:block}
.il-rail{fill:none;stroke:var(--ink);stroke-opacity:.18;stroke-width:2;stroke-linecap:round}
.il-rail-d{fill:none;stroke:var(--ink);stroke-opacity:.2;stroke-width:2;stroke-linecap:round;
      stroke-dasharray:5 6}
.il-live{fill:none;stroke:var(--teal);stroke-width:2.6;stroke-linecap:round}
.il-card{fill:var(--card);stroke:var(--line2);stroke-width:1.6}
.il-card-q{fill:var(--paper);stroke:var(--line2);stroke-width:1.6}
.il-glyph{fill:none;stroke:var(--ink);stroke-opacity:.26;stroke-width:2;stroke-linecap:round}
.il-node{fill:var(--ink);fill-opacity:.2}
.il-hot{fill:var(--teal)}
.il-ring{fill:none;stroke:var(--teal);stroke-opacity:.3;stroke-width:2}
.il-warn{fill:var(--red)}
.il-warn-s{fill:none;stroke:var(--red);stroke-width:2.4;stroke-linecap:round}
.il-lbl{font-family:var(--mono);font-size:16px;fill:var(--muted)}
.il-lbl-t{font-family:var(--mono);font-size:16px;fill:var(--teal)}
.il-ttl{font-family:var(--mono);font-size:16px;font-weight:500;fill:var(--ink2)}

/* figure wrapper: an illustration is content, so it gets the card treatment
   only where it needs a ground of its own */
.il-frame{background:var(--card);border:1px solid var(--line);border-radius:var(--r-card);
      padding:26px 24px;box-shadow:var(--shadow);overflow-x:auto;
      -webkit-overflow-scrolling:touch}
/* A 1000-unit viewBox squeezed into a 335px phone renders its 16px labels at
   4.6px, which is not a diagram, it is a smudge. Hold a legible floor and let
   the figure scroll instead -- the same trade the wide tables already make. */
.il-frame svg.il{min-width:720px}
/* A real capture inside a figure frame. No min-width: a screenshot degrades
   gracefully by scaling, unlike an SVG whose labels would shrink to a smudge. */
.il-frame img.shot{width:100%;height:auto;display:block;border-radius:8px;
      border:1px solid var(--line)}
/* A UI detail rather than a page shot: the real board holds three tasks, so it
   cannot evidence "six columns". It CAN evidence a locked file scope, so the
   crop is that, at detail scale. */
.il-frame img.shot-sm{max-width:560px;margin:0 auto}
.il-cap{font-size:13px;color:var(--muted);margin-top:12px;max-width:62ch}

/* One-shot draw-in. Illustrations are below the fold except the hero, so this
   is deliberately cheap: opacity and a short offset, no path-length tricks. */
@keyframes il-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.il-frame{animation:il-in .5s ease both}
@media (prefers-reduced-motion:reduce){
  .il-frame{animation:none}
}

/* The dark band inverts the ground, so the illustration vocabulary needs the
   same inversion rather than a white box dropped onto ink. */
.band .il-frame{background:#242320;border-color:#35332F}
.band .il-rail{stroke:#F5F3F0;stroke-opacity:.22}
.band .il-rail-d{stroke:#F5F3F0;stroke-opacity:.26}
.band .il-live{stroke:#5EC4B8}
.band .il-card{fill:#2C2B27;stroke:#45423D}
.band .il-card-q{fill:#242320;stroke:#45423D}
.band .il-ttl{fill:#E8E4DD}
.band .il-lbl{fill:#8A857C}
.band .il-lbl-t{fill:#5EC4B8}
.band .il-cap{color:#8A857C}


/* ============================================ layout families
   Section 4.7's repetition ban: one layout family may appear ONCE. The page was
   using "row of equal bordered cards" five times (problem, how, board, cost,
   scope). Section 4.4 also says cards are for when elevation communicates real
   hierarchy, and it did not. So four of the five lose their boxes and become
   genuinely different families, and the dark cost band keeps the only card grid
   -- there, separation from the inverted ground earns it. */

/* family: numbered vertical stack (the problem) */
.fam-stack{display:grid;gap:0;margin-top:26px;border-top:1px solid var(--line)}
.fam-stack > div{display:grid;grid-template-columns:52px 1fr 1.35fr;gap:20px;
      align-items:baseline;padding:20px 0;border-bottom:1px solid var(--line)}
.fam-stack .n{font-family:var(--mono);font-size:11.5px;color:var(--muted)}
.fam-stack h3{font-size:16px}
.fam-stack p{font-size:14px;color:var(--ink2)}

/* family: horizontal hairline strip (how it works) */
.fam-strip{display:grid;grid-template-columns:repeat(4,1fr);margin-top:32px;
      border-top:1px solid var(--line)}
.fam-strip > div{padding:18px 22px 0 0}
.fam-strip > div + div{border-left:1px solid var(--line);padding-left:22px}
.fam-strip h4{margin-bottom:6px}
.fam-strip p{font-size:13.5px;color:var(--ink2);line-height:1.55}

/* family: definition pairs (the board) */
.fam-defs{display:grid;grid-template-columns:repeat(2,1fr);gap:0 40px;margin-top:32px}
.fam-defs > div{display:grid;grid-template-columns:auto;gap:4px;padding:16px 0;
      border-bottom:1px solid var(--line)}
.fam-defs dt,.fam-defs h4{font-weight:600;font-size:14.5px}
.fam-defs p{font-size:13.5px;color:var(--ink2);line-height:1.55}

/* family: negation list (scope) */
.fam-nots{display:grid;grid-template-columns:repeat(2,1fr);gap:2px 44px;margin-top:26px}
.fam-nots > div{display:grid;grid-template-columns:18px 1fr;gap:12px;align-items:baseline;
      padding:15px 0;border-bottom:1px solid var(--line)}
.fam-nots .x{color:var(--muted);font-family:var(--mono);font-size:13px;line-height:1.5}
.fam-nots b{display:block;font-weight:600;font-size:14.5px;margin-bottom:3px}
.fam-nots p{font-size:13.5px;color:var(--ink2);line-height:1.55}

@media (max-width:920px){
  .fam-strip{grid-template-columns:repeat(2,1fr)}
  .fam-strip > div + div{border-left:none;padding-left:0}
  .fam-strip > div:nth-child(2n){border-left:1px solid var(--line);padding-left:22px}
  .fam-defs,.fam-nots{grid-template-columns:1fr}
}
@media (max-width:640px){
  .fam-stack > div{grid-template-columns:40px 1fr;gap:8px 14px}
  .fam-stack p{grid-column:2}
  .fam-strip{grid-template-columns:1fr}
  .fam-strip > div:nth-child(2n){border-left:none;padding-left:0}
  .fam-strip > div + div{border-top:1px solid var(--line);padding-top:18px}
}
