/* Shared by every page: tokens, type, nav, footer, dialogs, and the page-specific blocks.
   Moved out of index.html when the site grew an about and a feedback page. */
:root{
  color-scheme:dark;

  --ground:#000; --surface:#0E0D0B; --surface-2:#15140F;
  --rule:#2B2A23; --rule-soft:#1F1E19;
  --ink:#EFEDE6; --dim:#9C998C; --faint:#6A6759;
  --accent:#FFF2B6; --accent-text:#FFF2B6; --accent-deep:#C9B96F; --accent-ink:#14130A;
  --flag:#F0A98C;

  /* the stage is a screen, and was already its own palette when there were two themes */
  --stage:#090907; --stage-ink:#EFEDE6; --stage-dim:#8E8B7E;
  --stage-faint:#5F5C51; --stage-rule:#25241D; --stage-accent:#FFF2B6;

  --panel:#1C1B16; --panel-edge:#35322A; --panel-shadow:0 16px 44px rgba(0,0,0,.38);
  /* One tint for every container on the dark field: a hairline over almost nothing. Defined
     here because every page that loads mb-sections.css loads this first. --panel above is
     still a solid surface and stays one - .navmenu needs to be opaque over the page. */
  --glass:rgba(233,215,158,.022); --glass-raised:rgba(233,215,158,.045);
  /* The engine grid's headings, and the only green in the palette. */
  --capability:#4FB88B;
  --measure:64ch;
  /* mb-sections.css takes --state-partial from this. */
  --amber:#E8B04A;
}

/* mb-sections.css aliases --text-* to the theme tokens, and the hero carries its own, darker
   palette. Remapping the aliases for everything inside .field keeps the two from crossing:
   anything using --text-primary in the hero reads the hero's own palette, not the page's. */
.field{--text-primary:var(--f-ink); --text-secondary:var(--f-dim); --text-muted:var(--f-faint)}

/* the hero field is a screen: its own palette, a shade below the page's */
:root{--f-ground:#000; --f-ink:#EFEDE6; --f-dim:#9C998C; --f-faint:#6A6759;
  --f-rule:#2B2A23; --f-line:rgba(255,242,182,.055)}

*{box-sizing:border-box}
img{max-width:100%}
body{
  margin:0; background:var(--ground); color:var(--ink);
  font-family:"Archivo","Helvetica Neue",Arial,sans-serif;
  font-size:16.5px; line-height:1.55; -webkit-font-smoothing:antialiased;
}
.wrap{max-width:1080px; margin:0 auto; padding:0 28px}
.mono{font-family:"JetBrains Mono",ui-monospace,SFMono-Regular,monospace}

h1,h2,h3{margin:0; text-wrap:balance}
.h1{font-size:clamp(33px,5.4vw,58px); line-height:1.08; font-weight:600;
  font-stretch:112%; letter-spacing:-.012em; max-width:15ch}
.h2{font-size:clamp(25px,3.3vw,36px); line-height:1.14; font-weight:600;
  font-stretch:110%; letter-spacing:-.008em; max-width:20ch}
.h3{font-size:17px; font-weight:600; letter-spacing:-.002em}
.lead{font-size:clamp(16.5px,1.5vw,18.5px); line-height:1.55; color:var(--dim); max-width:var(--measure)}
.body{font-size:16.5px; line-height:1.62; color:var(--dim); max-width:var(--measure)}
.small{font-size:13.5px; line-height:1.55; color:var(--faint); max-width:var(--measure)}
/* Color guide rule 04: the muted tone is for labels. A paragraph that carries information
   a reader needs takes the secondary tone, at the same size. */
.small.info{color:var(--dim)}
.eyebrow{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10.5px;
  letter-spacing:.15em; text-transform:uppercase; color:var(--accent-text); font-weight:500}

/* ---------- dark field: nav + hero + stage ---------- */
.field{position:relative; background:var(--f-ground); color:var(--f-ink);
  overflow:hidden; padding-bottom:42px; border-bottom:1px solid #1D1C16}
/* The flat 100px grid that used to sit here is gone: the stage's perspective floor is the
   field's ground now, and two grids in one section fought each other. The floor reaches up
   past the nav, so the nav and the hero copy are lifted over it. */
.field > *{position:relative}
.field .hero{position:relative; z-index:1}
.field .nav{position:relative; z-index:5}
.field .navlinks a,.field .navlinks button{color:var(--f-dim)}
.field .navlinks a:hover,.field .navlinks button:hover{color:var(--f-ink)}
.field .pill{border-color:var(--f-rule); color:var(--f-dim)}
.field .h1{color:var(--f-ink)}
.field .lead{color:var(--f-dim)}
.field .btn.ghost{color:var(--f-ink); border-color:#3A392F}
.field .btn.ghost:hover{border-color:var(--f-ink)}
.field .hero{border-top:0}
.field .stagecap{color:var(--f-faint)}
.field + .wrap > .band:first-child{border-top:0; margin-top:60px}

/* ---------- nav ---------- */
.nav{display:flex; align-items:center; gap:14px; padding:22px 0 12px}
.brand{display:block; text-decoration:none; color:inherit}
.brand .lockup{width:clamp(232px,27vw,344px); height:auto; display:block}
.navlinks{margin-left:auto; display:flex; gap:24px; align-items:center}
.navlinks a,.navlinks button{font:inherit; font-size:14px; color:var(--dim); text-decoration:none;
  background:none; border:0; border-bottom:1px solid transparent; padding:0 0 1px; cursor:pointer}
.navlinks a:hover,.navlinks button:hover{color:var(--ink); border-bottom-color:var(--accent)}
.navlinks a:focus-visible,.navlinks button:focus-visible{outline:2px solid var(--accent);
  outline-offset:3px; border-radius:2px}

/* ---------- hero ---------- */
/* The eyebrow sat ~20px under the rule and read as part of the nav rather than as the
   start of the page. It scales so a phone does not inherit a desktop-sized dead gap. */
.hero{padding:clamp(44px,5.5vw,80px) 0 0; border-top:1px solid var(--rule-soft)}
/* align-self, because .herotext is a column flex container and a flex item stretches by
   default: inline-flex sized the pill to its content and the parent then pulled the box
   the full width, so it read as an empty input bar beside the headline. */
.pill{display:inline-flex; align-self:start; align-items:center; gap:9px;
  border:1px solid var(--rule); border-radius:999px; padding:5px 13px 5px 6px;
  font-size:12.5px; color:var(--dim); margin-bottom:26px}
.pill:has(i[hidden]){padding-left:13px; gap:0}
.pill i{font-style:normal; background:var(--accent); color:var(--accent-ink); border-radius:999px;
  padding:2px 8px; font-family:"JetBrains Mono",ui-monospace,monospace; font-size:9.5px;
  letter-spacing:.12em; font-weight:700}
.herotext{display:flex; flex-direction:column; gap:20px; max-width:none}
.btns{display:flex; gap:11px; flex-wrap:wrap; align-items:center; margin-top:2px}
.btn{font-size:14.5px; font-weight:600; padding:11px 20px; border-radius:7px; cursor:pointer;
  background:var(--accent); color:var(--accent-ink); border:1px solid var(--accent);
  font-family:inherit; text-decoration:none; display:inline-block}
.btn:hover{background:var(--accent-deep); border-color:var(--accent-deep)}
.btn.ghost{background:transparent; color:var(--ink); border-color:var(--rule)}
.btn.ghost:hover{border-color:var(--ink); background:transparent}
.btn:focus-visible{outline:2px solid var(--accent-deep); outline-offset:3px}
/* The build line and the two side links sit under the buttons, not beside them: beside
   them they competed with the download for the same horizontal glance, and on a narrow
   window they wrapped into the button row at arbitrary points. */
.linkbtn{font:inherit; font-size:13px; color:var(--faint); background:none; border:0;
  padding:0; cursor:pointer; text-decoration:underline; text-underline-offset:3px}
.linkbtn:hover{color:var(--ink)}

/* ---------- homebrew ---------- */
/* One line somebody copies. It sits under the download button rather than beside it: the
   button is the answer for most people, and a tap command in the same row reads as a choice
   they have to make before they can start. */
.brew{margin-top:18px; border:1px solid var(--rule); border-radius:10px;
  background:var(--glass); padding:14px 16px; max-width:700px}
.brew h3{margin:0 0 9px; font-size:13.5px; font-weight:650; color:var(--ink);
  display:flex; align-items:center; gap:8px}
.brew h3 svg{width:14px; height:14px; fill:none; stroke:var(--faint); stroke-width:1.6}
.brewcmd{display:flex; align-items:flex-start; gap:10px; background:var(--glass-raised);
  border:1px solid var(--rule-soft); border-radius:7px; padding:10px 12px}
/* Wraps rather than scrolls. A command you have to drag sideways to read is one you cannot
   check before you run it, and this one is a few characters too wide at the card's width. */
.brewcmd code{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:12.5px;
  color:var(--ink); white-space:pre-wrap; overflow-wrap:anywhere; line-height:1.6; flex:1}
.brewcopy{font:inherit; font-size:11.5px; font-weight:600; color:var(--faint);
  background:none; border:1px solid var(--rule); border-radius:5px; padding:4px 9px;
  cursor:pointer; flex:none}
.brewcopy:hover{color:var(--ink); border-color:var(--ink)}
.brew p{margin:9px 0 0; font-size:12.5px; color:var(--faint); line-height:1.5}
/* The paragraph straight after the heading sits under the heading's own bottom margin;
   without this the two stack and the card opens with a gap it did not ask for. */
.brew h3 + p{margin-top:0}
.brew .brewcmd{margin-top:12px}
.brew .act{margin:12px 0 0}
.brew h3 svg.solid{fill:currentColor; stroke:none}
.brew code{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11.5px;
  color:var(--dim); overflow-wrap:anywhere}
@media (max-width:560px){ .brewcmd code{font-size:11.5px} }

/* ---------- hero: governance stage ----------
   Ported from the brief's reference mockup. Its Geist / Geist Mono are stand-ins and map to
   the site's Archivo and JetBrains Mono; its hex values map to the fixed-dark field tokens,
   which is why this reads correctly without a light variant — .field is dark in both themes.
   The one color the mockup names outright is its coral; the site already has a refused
   color, used on the Threat Library chips and in the blog figures, so that is what is used
   here and --f-refuse carries it. */
:root{--f-refuse:#EF6F5E; --f-refuse-bg:#2A1712}

/* The reference centres the hero column; the old one was left-aligned against the stage that
   used to sit beside it. The stage is below it now, so centred is what the composition wants
   and what the brief asked for. */
.hero .herotext{align-items:center; text-align:center; gap:20px}
.hero .h1{max-width:920px; font-size:clamp(38px,5.2vw,64px); line-height:1.04; letter-spacing:-.02em}
.hero .hsub{margin-left:auto; margin-right:auto}
.hero .btns{justify-content:center; margin-top:8px}

.heyebrow{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:13px;
  letter-spacing:.12em; color:var(--stage-accent); margin:0}
.hsub{margin:0; font-size:19px; line-height:1.55; color:#B3AC9C; max-width:680px}

/* Narrower rails than the cards strictly want: the stage's middle column is the graphic,
   and 38px off each side is the cheapest way to make it bigger. */
.gstage{display:grid; grid-template-columns:232px minmax(0,1fr) 232px; gap:20px;
  align-items:center; margin-top:60px}
.gcol{display:flex; flex-direction:column; gap:120px; position:relative; z-index:1}
.gscene{display:flex; justify-content:center}
/* Three layers in one box: the device, the shell that turns around it, and the words. The
   stack is what gives the canvas and the front layer a box to match - .gscene is wider than
   the scene whenever the column is, and the shell has to sit on the device, not on the
   column. Only the back layer is in flow; it is what sets the height. */
.gstack{position:relative; width:100%; max-width:640px}
.gstack > svg{display:block}
.gshell,.gfront{position:absolute; left:0; top:0; width:100%; height:100%; pointer-events:none}
/* The floor is drawn outside the viewBox so it can cover the whole dark field while the
   device keeps the 640-unit scale the column gives it. .field clips the overspill; the
   card columns are lifted above it so the floor passes behind them. */
.gscene svg{width:100%; max-width:640px; height:auto; overflow:visible}

.gcard{background:rgba(233,215,158,.022); border:1px solid var(--rule-soft);
  border-radius:12px; padding:18px 20px; display:flex; flex-direction:column; gap:6px}
.gcard__lab{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11px;
  letter-spacing:.1em; color:var(--f-faint)}
.gcard__lab--refuse{color:var(--f-refuse)}
.gcard__n{font-size:30px; font-weight:600; color:var(--f-ink)}
.gcard__n span{font-size:15px; font-weight:400; color:var(--f-faint)}
.gcard__h{font-size:20px; font-weight:600; line-height:1.3; color:var(--f-ink)}
.gcard__d{font-size:13px; color:#A8A192}

/* The refusal reads at a glance or it is decoration, so the card turns with the scene rather
   than after it: same 5.4s period, same 1.35s delay, same beats. */
.g-dot{offset-rotate:0deg; opacity:0; fill:var(--stage-accent)}
.g-a{offset-path:path('M96 98 L231.7 187.9'); animation:g-pass-a 3.6s linear infinite 0s}
.g-c{offset-path:path('M558 98 L411.1 189.6'); animation:g-pass-c 3.6s linear infinite 1.2s}
.g-d{offset-path:path('M570 388 L414.8 300.1'); animation:g-pass-d 3.6s linear infinite 2.4s}
.g-b{offset-path:path('M70 388 L148.2 343.7'); animation:g-refuse 5.4s linear infinite 1.35s}

/* Each hold sits at the fraction of its own line that the boundary falls on, so every dot
   stops at the field and not a few pixels short of it or inside it. */
@keyframes g-pass-a{0%{offset-distance:0%;opacity:0}8%{opacity:1}40%,55%{offset-distance:43.7%}
  80%{opacity:1}86%,100%{offset-distance:100%;opacity:0}}
@keyframes g-pass-c{0%{offset-distance:0%;opacity:0}8%{opacity:1}40%,55%{offset-distance:47.9%}
  80%{opacity:1}86%,100%{offset-distance:100%;opacity:0}}
@keyframes g-pass-d{0%{offset-distance:0%;opacity:0}8%{opacity:1}40%,55%{offset-distance:50.3%}
  80%{opacity:1}86%,100%{offset-distance:100%;opacity:0}}
@keyframes g-refuse{0%{offset-distance:0%;opacity:0;fill:var(--stage-accent)}6%{opacity:1}
  36%{offset-distance:100%;fill:var(--stage-accent)}37%{fill:var(--f-refuse)}
  46%{offset-distance:68%}70%{opacity:1;offset-distance:68%;fill:var(--f-refuse)}
  78%,100%{opacity:0;offset-distance:68%}}

/* The shell itself is drawn on a canvas - see assets/hero.js. It left here because it has to
   tessellate and it has to turn, and neither is something static polygons can do. */

.g-flash{opacity:0; animation:g-flash 3.6s linear infinite}
@keyframes g-flash{0%,40%{opacity:0}46%{opacity:1}56%,100%{opacity:0}}

.g-tag,.g-red{opacity:0; animation:g-show 5.4s linear infinite 1.35s}
@keyframes g-show{0%,35%{opacity:0}37%,70%{opacity:1}78%,100%{opacity:0}}
.g-red{stroke:var(--f-refuse)}
.g-tag rect{stroke:var(--f-refuse); stroke-width:1}
.g-tag text{fill:#FF9A82}

.g-burst{opacity:0; transform-box:fill-box; transform-origin:center; stroke:var(--f-refuse);
  animation:g-burst 5.4s ease-out infinite 1.35s}
@keyframes g-burst{0%,35%{opacity:0;transform:scale(1)}37%{opacity:1;transform:scale(1)}
  58%,100%{opacity:0;transform:scale(5)}}

.g-cursor{animation:g-cursor 5.4s linear infinite 1.35s}
@keyframes g-cursor{0%,35%{fill:#9C998C}37%,70%{fill:var(--f-refuse)}78%,100%{fill:#9C998C}}
.g-chip{animation:g-chip 5.4s linear infinite 1.35s}
@keyframes g-chip{0%,35%{stroke:#D8C58E;stroke-opacity:.22}
  37%,70%{stroke:var(--f-refuse);stroke-opacity:.75}78%,100%{stroke:#D8C58E;stroke-opacity:.22}}

.gcard--refused{animation:g-card 5.4s linear infinite 1.35s}
@keyframes g-card{0%,35%{border-color:var(--rule-soft);background-color:rgba(233,215,158,.022)}
  37%,70%{border-color:var(--f-refuse);background-color:rgba(239,111,94,.07)}
  78%,100%{border-color:var(--rule-soft);background-color:rgba(233,215,158,.022)}}

/* Reduced motion keeps the meaning and drops the movement: the refusal is shown, held. */
@media (prefers-reduced-motion:reduce){
  .g-dot,.g-flash,.gcard--refused,.g-burst,.g-cursor,.g-chip{animation:none}
  .g-dot{opacity:0}
  .g-tag,.g-red{animation:none; opacity:1}
  .g-cursor{fill:var(--f-refuse)}
  .g-chip{stroke:var(--f-refuse); stroke-opacity:.75}
  .gcard--refused{border-color:var(--f-refuse); background-color:rgba(239,111,94,.07)}
}

@media (max-width:900px){
  /* Stacked, the demo sits directly under the buttons rather than away to the side, so the
     extra quarter of space the wide layout needs only pushes it off a phone screen. */
  .gstage{grid-template-columns:minmax(0,1fr); gap:16px; margin-top:48px}
  .gscene{order:-1}
  .gcol{gap:16px}
}

/* ---------- stage ---------- */
.stagecap{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10px; letter-spacing:.11em;
  color:var(--faint); text-align:center; margin:13px 0 0}

/* ---------- sections ---------- */
section.band{border-top:1px solid var(--rule-soft); margin-top:74px; padding-top:44px}
/* features */
.feats{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:0;
  border:1px solid var(--rule-soft); margin-top:40px; counter-reset:feat}
/* Each tile draws its own left and top rule; the first column drops its left and the first
   row drops its top, so the grid's own border is the outside. The resets are repeated per
   breakpoint because which tile starts a row changes with the column count. */
.feat{background:var(--glass); padding:22px 22px 26px; counter-increment:feat;
  border-left:1px solid var(--rule-soft); border-top:1px solid var(--rule-soft)}
.feat:nth-child(3n+1){border-left:0}
.feat:nth-child(-n+3){border-top:0}
/* The rail beside this grid says "06 capabilities" and nothing on the tiles counted. The
   number comes from the tile's position rather than the markup, so the rail and the grid
   cannot drift apart when one is edited. */
.feat::before{content:"0" counter(feat); display:block; margin-bottom:12px;
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:21px; letter-spacing:.15em;
  color:var(--accent-text)}
.feat .h3{color:var(--capability)}
.feat p{margin:9px 0 0; font-size:14.5px; line-height:1.58; color:var(--dim)}

/* ---------- showcase: copy beside an oversized screenshot ---------- */
/* The shot is deliberately wider than its column: the panel clips it, so the screen reads as
   a window onto the app rather than a thumbnail of it. */
.showcase{border-top:0; padding-top:0; margin-top:30px}
.showcase + .showcase{margin-top:20px}
.panel{background:var(--glass); border:1px solid var(--rule); border-radius:26px;
  overflow:hidden; position:relative}
.panel .inner{display:grid; grid-template-columns:minmax(0,41fr) minmax(0,59fr);
  gap:40px; align-items:center; padding:54px 0 54px 54px}
.panel .copy{display:flex; flex-direction:column; gap:13px; min-width:0}
.panel .copy .eyebrow{display:block}
.panel .h2{max-width:14ch}
.panel .body,.panel .small{max-width:46ch}
.bleed{min-width:0}
.shot{background:#000; border:1px solid var(--rule); border-radius:13px; padding:8px}
.shot img{display:block; width:100%; height:auto; border-radius:7px}
.bleed .shot{width:880px; max-width:none}
.caption{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:9.5px; letter-spacing:.13em;
  color:var(--faint); margin:2px 0 0}

/* the two modes, each cropped to its first screenful */
.modes{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:18px; margin-top:26px}
.mode{background:var(--glass); border:1px solid var(--rule); border-radius:20px;
  overflow:hidden; padding:20px 20px 0}
.mode .tag{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:9.5px; letter-spacing:.14em;
  color:var(--accent-text); display:block; margin-bottom:14px; font-weight:500}
.mode .clip{max-height:330px; overflow:hidden; background:#000; border:1px solid var(--rule);
  border-bottom:0; border-radius:12px 12px 0 0; padding:8px 8px 0}
.mode .clip img{display:block; width:100%; height:auto; border-radius:6px 6px 0 0}

/* ---------- why: the reason the thing exists ---------- */
/* A dark sheet like the hero field, fixed dark in both themes. The bird has its own grid column
   and bleeds off the sheet's bottom-right corner — it never sits behind a line of copy. */
.why{border-top:0; padding-top:0; margin-top:30px}
/* The panel itself. The About page is its only user, and .sheet.about lays out what is
   inside it; what is left here is the surface — fixed dark in both themes, and clipping,
   which is what lets the mark run past the corner. */
.sheet{--why-bird:#E8D083; position:relative; overflow:hidden;
  background:var(--f-ground); color:var(--f-ink);
  border:1px solid #1D1C16; border-radius:26px}
.sheet .copy{min-width:0}
.sheet .eyebrow{color:var(--stage-accent); display:block; margin:0 0 34px}
.sheet h2,.sheet h3{font-size:17px; font-weight:600; letter-spacing:-.002em; color:var(--f-ink); margin:0 0 8px}
.sheet p,.sheet li{font-size:16.5px; line-height:1.64; color:#B9B6A8}
.sheet p{margin:0}
.sheet .part + .part{margin-top:30px}
.sheet .part ul + p{margin-top:14px}
.sheet ul{list-style:none; margin:14px 0 0; padding:0; border-top:1px solid var(--f-rule)}
.sheet li{padding:10px 0; border-bottom:1px solid var(--f-rule)}
.sheet li b{color:var(--f-ink); font-weight:600}

/* ---------- About ----------
   One container. Everything lives inside .sheet, which is a fixed dark screen in both themes,
   so every color here comes from the --f-* field tokens rather than the theme ones — the
   same trap that made the home page's hero copy unreadable in a light theme. */
.sheet.about{display:block; padding:0}
.about__hero,.about__why,.about__beliefs,.about__nest{padding:0 56px}
.about__hero{display:grid; grid-template-columns:minmax(0,1fr) minmax(300px,.85fr);
  gap:30px; align-items:center; padding-top:58px}
.about .serif{font-family:"Newsreader",Georgia,serif; font-style:italic; font-weight:400;
  font-size:clamp(38px,5.4vw,66px); line-height:1.04; letter-spacing:-.012em;
  color:var(--f-ink); margin:0 0 20px}
.about .storylede{font-size:14.5px; line-height:1.62; color:var(--f-dim); max-width:46ch; margin:0}
.about__mark{display:grid; justify-items:center; gap:12px}
/* the mark carries the page, so it is sized against the heading rather than tucked in a corner */
/* The mask is declared once. Each url() here is inlined as its own base64 copy when the
   artifact preview is built, and this file carried four of a 51KB image — 260KB of a bird
   for a page that has none. */
.bird{aspect-ratio:729/463; background:var(--why-bird);
  -webkit-mask:url(bird-mask.webp) center/contain no-repeat;
  mask:url(bird-mask.webp) center/contain no-repeat}
.about__mark .bird{width:min(100%,460px); margin:0}
.about__mark .aboutwordmark{width:min(100%,460px); height:auto; display:block; margin:-6px 0 0}
.about__mark .stamp{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:9.5px;
  letter-spacing:.22em; color:var(--f-faint); margin:0}

.about .eyebrow{display:block; color:var(--stage-accent); margin:0 0 22px}
.about__why{margin-top:56px}
.about__why h3{font-size:17px; font-weight:600; color:var(--f-ink); margin:0 0 8px}
.about__why p{font-size:16.5px; line-height:1.64; color:#B9B6A8; margin:0}
.about__why .part + .part{margin-top:30px}

/* The beliefs are cards so they read as a set rather than as more paragraphs. The first one
   is lifted and warm, which gives the row somewhere to start.

   They are two tiers, not seven cards. The three name what the product is for; the four say
   how it is built. Seven boxes of identical weight in a 3-then-4 grid read as one seven-card
   grid that happened to wrap, which is what the page did and the design did not. The design
   separates them with a rule — gold over the three, nothing over the four — so that is the
   device here too, with real space between the rows to make the break structural rather
   than only tonal.

   border-top-width/color rather than the border-top shorthand: --lead sets border-color for
   all four sides, and a longhand at this specificity wins the top edge whatever the source
   order. The shorthand would have made that a question about which rule came first. */
.about__beliefs{margin-top:98px}
.bcards{display:grid; gap:14px}
.bcards--three{grid-template-columns:repeat(3,minmax(0,1fr))}
.bcards--four{grid-template-columns:repeat(4,minmax(0,1fr)); margin-top:34px}
.bcard{background:var(--glass); border:1px solid var(--rule-soft); border-radius:12px; padding:18px 18px 20px}
.bcards--three .bcard{border-top-width:3px; border-top-color:var(--f-rule)}
.bcards--three .bcard h3{font-size:18px; margin-bottom:7px}
.bcard--lead{background:rgba(232,208,131,.075); border-color:rgba(232,208,131,.3)}
.bcard h3{font-size:16px; font-weight:600; color:var(--f-ink); margin:0 0 6px; letter-spacing:-.005em}
.bcard p{font-size:13.5px; line-height:1.55; color:var(--f-dim); margin:0}
.about .pull{margin:40px 0 0; padding-left:18px; border-left:2px solid var(--why-bird);
  font-family:"Newsreader",Georgia,serif; font-style:italic; font-size:clamp(21px,2.3vw,27px);
  line-height:1.25; color:var(--f-ink)}

.about__nest{margin-top:98px}
.about__nest .eyebrow{margin-bottom:12px}
.about .nesttitle{font-size:clamp(25px,3vw,34px); line-height:1.14; letter-spacing:-.018em;
  font-weight:700; color:var(--f-ink); margin:0 0 28px}
.nestcards{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:24px}
.nestcards article{border-top:1px solid var(--f-rule); padding-top:15px}
.nestcards h3{font-size:16.5px; font-weight:600; color:var(--f-ink); margin:0 0 7px}
.nestcards > article > p{font-size:14px; line-height:1.58; color:var(--f-dim); margin:0}
.inprod{margin-top:15px; padding-left:13px; border-left:2px solid var(--why-bird)}
.inprod .lab{display:block; font-family:"JetBrains Mono",ui-monospace,monospace; font-size:9.5px;
  letter-spacing:.14em; color:var(--stage-accent); margin:0 0 6px}
.inprod p{font-size:13.5px; line-height:1.55; color:var(--f-dim); margin:0}

/* The closing line sits on its own. No rule beside it and nothing opposite it: it is the last
   thing on the page and has nothing to be separated from. One column, because the mark that
   used to run into the bottom-right corner is gone. */
.about__closer{padding:88px 0 0 56px}
.about .motto{margin:0 0 56px; padding:0; border:0;
  font-family:"Newsreader",Georgia,serif; font-style:italic; font-size:clamp(24px,2.6vw,30px);
  line-height:1.2; color:var(--f-ink)}

@media (max-width:860px){
  .about__hero,.about__why,.about__beliefs,.about__nest{padding:0 26px}
  .about__hero{grid-template-columns:1fr; padding-top:40px; gap:22px}
  .about__mark .bird{width:min(100%,340px)}
  .bcards--three,.bcards--four,.nestcards{grid-template-columns:1fr}
  .about__closer{padding:69px 0 0 26px}
  .about .motto{margin:0 26px 0 0}
}

/* footer */
/* Four columns of links beside the mark, then a bar with what governs the site and the
   marks that say who made it. The mark sits on its own fixed-dark panel: the bird is one
   gold, and a gold drawn for a near-black page is not a shape you can read on a light one. */
footer{margin-top:84px; border-top:1px solid var(--rule-soft); padding:40px 0 34px}
.fmain{display:grid; grid-template-columns:auto minmax(0,1fr); gap:34px 40px; align-items:start}
.fbrand{--why-bird:#E8D083; background:var(--glass); border:1px solid #221F18; border-radius:12px;
  padding:26px 26px 18px; width:244px; display:grid; justify-items:center; gap:18px}
/* the one .bird mask declaration in this file is reused; a second url() here would be a
   second base64 copy of a 51KB image in the artifact build */
.fbrand .bird{width:100%}
/* The wordmark is artwork and is never set in type: this was "MOCKINGBYRD" in JetBrains Mono
   with the tracking opened up, which is a different set of letterforms wearing the name. The
   card is fixed dark in both themes, so the white artwork needs no second variant and no mask.
   EST. 2026 is not part of the wordmark, so it stays type. */
.fbrand .fwordmark{width:100%; height:auto; display:block; margin-top:-4px}
.fbrand .stamp{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:9px;
  letter-spacing:.2em; color:#6A6759; margin:0; text-align:center}
.fcols{display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:30px 24px}
.fcol .fhead{font-size:13.5px; font-weight:600; color:var(--ink); margin:0 0 15px;
  letter-spacing:-.002em}
.fcol ul{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:9px}
.fcol li{margin:0}
.flink{font:inherit; font-size:13.5px; color:var(--accent-text); text-decoration:none;
  background:none; border:0; border-bottom:1px solid transparent; padding:0 0 2px; cursor:pointer}
a.flink:hover{color:var(--ink); border-bottom-color:var(--accent)}
.flink[aria-current="page"]{color:var(--ink); border-bottom-color:var(--accent)}
/* Shown, not clickable, not focusable. These name parts of the product that have no page
   yet; a link that goes nowhere is worse than plain text, and a span cannot be tabbed to
   or clicked by someone who never sees the cursor. */
span.flink.off{color:var(--faint); cursor:default}

.fbar{display:grid; grid-template-columns:1fr auto; align-items:center; gap:16px 20px;
  margin-top:38px; padding-top:22px; border-top:1px solid var(--rule-soft)}
.flegal{display:flex; flex-wrap:wrap; align-items:center; gap:10px 22px}
.fcopy{grid-column:1/-1; margin:0; text-align:center;
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10.5px;
  letter-spacing:.09em; color:var(--faint); line-height:1.7}
.ficons{justify-self:end; display:flex; align-items:center; gap:13px}
.ficons a{display:grid; place-items:center; color:var(--dim); border-radius:8px}
.ficons a:hover{color:var(--ink)}
.ficons svg{width:19px; height:19px; fill:currentColor; display:block}
footer a:focus-visible{outline:2px solid var(--accent); outline-offset:3px}

/* request dialogs */
dialog.ask{padding:0; border:1px solid var(--rule); border-radius:14px; background:var(--surface);
  color:var(--ink); width:min(440px, calc(100% - 32px)); box-shadow:0 24px 60px rgba(0,0,0,.34)}
dialog.ask::backdrop{background:rgba(6,6,4,.62)}
dialog.ask .box{padding:26px 26px 22px; position:relative}
dialog.ask h2{font-size:21px; line-height:1.2; font-weight:600; font-stretch:110%;
  margin:0 0 9px; max-width:24ch; padding-right:26px}
dialog.ask .dlede{font-size:14.5px; line-height:1.55; color:var(--dim); margin:0 0 17px; max-width:46ch}
dialog.ask .close{position:absolute; top:11px; right:11px; width:28px; height:28px; line-height:1;
  border-radius:7px; border:1px solid transparent; background:none; color:var(--faint);
  font-size:19px; cursor:pointer}
dialog.ask .close:hover{color:var(--ink); border-color:var(--rule)}
dialog.ask form{display:flex; gap:9px; flex-wrap:wrap}
dialog.ask input{flex:1 1 190px; min-width:0; font:inherit; font-size:14.5px; padding:10px 12px;
  border-radius:7px; border:1px solid var(--rule); background:var(--ground); color:var(--ink)}
dialog.ask input::placeholder{color:var(--faint)}
dialog.ask input:focus-visible,dialog.ask .btn:focus-visible,dialog.ask .close:focus-visible{
  outline:2px solid var(--accent-deep); outline-offset:2px}
dialog.ask .msg{font-size:13.5px; line-height:1.5; margin-top:13px; display:none}
dialog.ask .msg.on{display:block}
dialog.ask .msg.ok{color:var(--accent-text)}
dialog.ask .msg.err{color:var(--flag)}
dialog.ask .note{font-size:12px; color:var(--faint); margin:15px 0 0}

/* ---------- motion ---------- */
@keyframes rise{from{opacity:0; transform:translateY(14px)} to{opacity:1; transform:none}}
@keyframes fade{from{opacity:0} to{opacity:1}}
.herotext > *{animation:rise .62s cubic-bezier(.2,.7,.3,1) both}
.herotext > *:nth-child(2){animation-delay:.07s}
.herotext > *:nth-child(3){animation-delay:.13s}
.herotext > *:nth-child(4){animation-delay:.19s}
.herotext > *:nth-child(5){animation-delay:.25s}
.gstage{animation:fade .8s .18s both}
@media (prefers-reduced-motion:reduce){
  .herotext > *,.gstage{animation:none}
}

/* ---------- responsive ---------- */
@media (max-width:900px){
  .feats{grid-template-columns:repeat(2,minmax(0,1fr))}
  /* :nth-child(n) and not .feat, because the three-column resets above are (0,2,0) and a bare
     class cannot put a rule back that they took away, whatever the order. */
  .feat:nth-child(n){border-left:1px solid var(--rule-soft);
    border-top:1px solid var(--rule-soft)}
  .feat:nth-child(2n+1){border-left:0}
  .feat:nth-child(-n+2){border-top:0}
  .panel .inner{grid-template-columns:1fr; gap:26px; padding:34px 30px}
  .bleed .shot{width:100%}
  .panel .h2,.panel .body,.panel .small{max-width:none}
}
@media (max-width:760px){
  .field::before{
    -webkit-mask-image:linear-gradient(to bottom, transparent 88px, #000 112px,
      #000 calc(100% - 34px), transparent 100%);
    mask-image:linear-gradient(to bottom, transparent 88px, #000 112px,
      #000 calc(100% - 34px), transparent 100%)}
  .feats{grid-template-columns:1fr}
  .feat:nth-child(n){border-left:0; border-top:1px solid var(--rule-soft)}
  .feat:nth-child(1){border-top:0}
  .modes{grid-template-columns:1fr}
  .navlinks{display:none}

  /* Bigger targets on a phone. The underline moves from border-bottom to text-decoration so
     it stays tight under the words while the padding grows the tap area to 44px — a border
     sits on the padding edge and would drift a finger's width below the text. Row gap goes
     to zero because the padding is now doing that spacing. */
  /* The hero's text links, same reasoning as the footer's. These already underline with
     text-decoration rather than a border, so the padding can grow the target without the
     line drifting away from the words. The row gap drops to 0 because the padding now
     supplies the space between the build line and the links under it. */
  /* The Copy buttons beside the install commands were 48x28 — the one target on the site
     that the earlier sweeps never reached, because they covered the home page and the forms
     and not this one. */
  .brewcopy{padding:12px 14px; font-size:12.5px}

  .linkbtn{font-size:14.5px; padding:13px 2px}

  /* The feedback form's Upload control came to 40px. The pattern underneath it is already
     the right one — a styled span with the real file input laid over it at zero opacity, so
     the span is the target and the input covers it exactly — it was simply four pixels
     short. min-height rather than more padding, so the icon and label stay where they are
     and only the box grows. The score page's upload has measured 49px since the last sweep;
     this is the same control on the one page that sweep did not cover. */
  .fb .up{min-height:44px}

  /* The three icon targets. The marks themselves stay 19 and 21px — only the box around
     them grows, so nothing looks different, there is just something to hit. The footer pair
     sat at 19 and 22px, which is half a fingertip. */

  /* The columns go two-up — four of them at 375px is four words a line — and the mark
     leads. Targets grow to 44px; the underline moves to text-decoration so it stays tight
     under the words while the padding grows the box. The dead items get no padding: they
     are not targets, and spacing them like one invites a tap that does nothing. */
  .fmain{grid-template-columns:1fr; justify-items:center; gap:30px}
  .fcols{grid-template-columns:repeat(2,minmax(0,1fr)); gap:26px 20px; width:100%}
  .fcol ul{gap:0}
  a.flink{font-size:15px; padding:11px 2px; border-bottom:0; display:inline-block;
    text-decoration:underline; text-decoration-color:var(--rule); text-underline-offset:3px;
    text-decoration-thickness:1px}
  a.flink:hover,.flink[aria-current="page"]{text-decoration-color:var(--accent)}
  span.flink.off{font-size:15px; padding:6px 2px; display:inline-block}
  .fbar{grid-template-columns:1fr; justify-items:center}
  .ficons{justify-self:center}
  .ficons a{width:44px; height:44px}
  .flegal{gap:6px 18px; justify-content:center}
}

/* ---------- inner pages: about, feedback ---------- */
/* The clip on .field is there for one thing: the stage's perspective floor bleeds past the
   hero's viewBox and has to stop at the section edge. No slim field has a stage, so the clip
   has nothing to do there except cut the nav dropdown off at the band's bottom edge - which
   is what it was doing on all 26 sub pages. */
.field.slim{padding-bottom:34px; overflow:visible}
.pagehead{padding:26px 0 6px; display:flex; flex-direction:column; gap:14px}
.pagehead .h1{max-width:18ch}
.pagebody{margin-top:44px}
.pagebody .why{margin-top:0}

/* feedback form */
.fb{max-width:640px; display:flex; flex-direction:column; gap:30px}
.fb .q{display:flex; flex-direction:column; gap:10px; margin:0; padding:0; border:0; min-width:0}
.fb .q > label,.fb .q > legend{font-size:17px; font-weight:600; letter-spacing:-.002em; color:var(--ink); padding:0}
.fb .req{color:var(--faint); font-weight:500; margin-left:2px}
.fb .hint{font-size:13.5px; color:var(--faint); margin:-4px 0 0}
.fb input[type=text],.fb input[type=email],.fb select,.fb textarea{
  font:inherit; font-size:15.5px; color:var(--ink); background:var(--glass-raised);
  border:1px solid var(--rule); border-radius:9px; padding:11px 13px; width:100%}
.fb textarea{min-height:148px; resize:vertical; line-height:1.55}
.fb select{appearance:none; -webkit-appearance:none; padding-right:38px; cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--dim) 50%),linear-gradient(135deg,var(--dim) 50%,transparent 50%);
  background-position:calc(100% - 19px) 52%,calc(100% - 14px) 52%; background-size:5px 5px; background-repeat:no-repeat}
.fb select:invalid{color:var(--faint)}
.fb ::placeholder{color:var(--faint)}
.fb input:focus-visible,.fb select:focus-visible,.fb textarea:focus-visible,.fb .up:focus-within,
.fb .tick:focus-within{outline:2px solid var(--accent-deep); outline-offset:2px}
.fb .drop{display:flex; flex-wrap:wrap; align-items:center; gap:12px; background:var(--glass-raised);
  border:1px solid var(--rule-soft); border-radius:11px; padding:10px}
.fb .up{position:relative; display:inline-flex; align-items:center; gap:8px; font-size:14.5px; font-weight:600;
  color:var(--ink); background:var(--glass-raised); border:1px solid var(--rule); border-radius:8px; padding:9px 14px; cursor:pointer}
.fb .up:hover{border-color:var(--ink)}
.fb .up svg{width:15px; height:15px; fill:none; stroke:currentColor; stroke-width:1.6}
/* The invisible input has to cover the border box, not the padding box. inset:0 resolves
   against the padding box of the positioned parent, so the control's 1px border was a ring
   that looked like part of the button and opened nothing — and it meant the target measured
   two pixels under whatever the button measured. */
.fb .up input{position:absolute; inset:-1px; opacity:0; cursor:pointer}
.fb .limits{font-size:13.5px; color:var(--dim)}
.fb .files{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:6px}
.fb .files li{display:flex; align-items:center; gap:10px; font-size:14px; color:var(--dim);
  border-bottom:1px solid var(--rule-soft); padding:6px 0}
.fb .files .fn{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--ink)}
.fb .files .fs{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11.5px; color:var(--faint)}
.fb .files button{font:inherit; font-size:13px; color:var(--faint); background:none; border:0; cursor:pointer;
  text-decoration:underline; text-underline-offset:3px; padding:0}
.fb .files button:hover{color:var(--flag)}
.fb .tick{display:flex; align-items:center; gap:12px; background:var(--glass-raised); border:1px solid var(--rule-soft);
  border-radius:11px; padding:11px 13px; cursor:pointer; font-size:15.5px; color:var(--ink)}
.fb .q > .tick{font-size:15.5px; font-weight:400; padding:11px 13px}
/* First and last sit on one row on a desktop and stack on a phone: two fields that are one
   piece of information should not read as two questions. */
.fb .q2{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:16px}
@media (max-width:560px){ .fb .q2{grid-template-columns:minmax(0,1fr)} }
/* The interest list is a fieldset so the legend is the question for a screen reader, which a
   bare label above a group of checkboxes is not. */
.fb fieldset.q{border:0; margin:0; padding:0; min-width:0; display:flex; flex-direction:column; gap:9px}
.fb fieldset.q legend{padding:0; font-size:15px; font-weight:600; color:var(--ink); margin-bottom:3px}
.fb fieldset.q .tick{font-size:15px; font-weight:400; padding:11px 13px}
.fb [hidden]{display:none}
.fb .tick input{width:18px; height:18px; margin:0; accent-color:var(--accent-deep); cursor:pointer}
.fb .send{display:flex; flex-direction:column; align-items:flex-start; gap:14px}
.fb .send .btn[disabled]{opacity:.6; cursor:progress}
.fb .msg{font-size:14.5px; line-height:1.5; display:none; margin:0}
.fb .msg.on{display:block}
.fb .msg.err{color:var(--flag)}
.thanks{max-width:640px; display:none; flex-direction:column; gap:12px}
.thanks.on{display:flex}
.thanks .h2{max-width:none}

/* ---------- legal: terms and privacy, generated by scripts/build-legal.py ---------- */
/* Long documents read on the page's own ground rather than in a dark sheet: a legal text is
   scanned for one clause, so it wants a plain measure and headings you can anchor to. */
.legal{max-width:76ch}
.legal .eyebrow{display:block; color:var(--accent-text); margin:0 0 16px}
.legal h1{font-size:clamp(28px,3.6vw,40px); line-height:1.1; font-weight:600; font-stretch:110%;
  letter-spacing:-.012em; margin:0 0 12px; text-wrap:balance}
.legal .effective{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10.5px;
  letter-spacing:.14em; color:var(--faint); margin:0 0 30px}
.legal .intro{font-size:17px; line-height:1.6; color:var(--dim);
  padding-bottom:28px; border-bottom:1px solid var(--rule); margin-bottom:8px}
.legal .intro p{font-size:inherit; line-height:inherit; margin:0}
.legal h2{font-size:17.5px; font-weight:600; color:var(--ink); margin:34px 0 10px;
  scroll-margin-top:28px}
.legal p{font-size:15.5px; line-height:1.62; color:var(--dim); margin:0 0 12px}
.legal strong{color:var(--ink); font-weight:600}
/* Inline links in prose. .legal had this treatment and nothing else did, so a link in a
   lede or a form's small print fell through to the browser's default blue — which on these
   pages reads as a mistake, and in the dark theme is the one bright blue on the page.
   Buttons and footer links carry their own classes and are excluded. */
.legal a,
.lead a:not([class]), .small a:not([class]), .body a:not([class]),
.note a:not([class]), .dlede a:not([class]), .mb-lede a:not([class]),
.intro a:not([class]), .about__why a:not([class]), .about__nest a:not([class]),
.bcard a:not([class]), .mb-faq__a a:not([class]){color:var(--accent-text); text-decoration:none;
  border-bottom:1px solid var(--rule)}
.legal a:hover,
.lead a:not([class]):hover, .small a:not([class]):hover, .body a:not([class]):hover,
.note a:not([class]):hover, .dlede a:not([class]):hover, .mb-lede a:not([class]):hover,
.intro a:not([class]):hover, .about__why a:not([class]):hover,
.about__nest a:not([class]):hover, .bcard a:not([class]):hover,
.mb-faq__a a:not([class]):hover{border-bottom-color:var(--accent)}
.legal a:visited,
.lead a:not([class]):visited, .small a:not([class]):visited, .body a:not([class]):visited,
.note a:not([class]):visited, .dlede a:not([class]):visited, .mb-lede a:not([class]):visited,
.intro a:not([class]):visited, .about__why a:not([class]):visited,
.about__nest a:not([class]):visited, .bcard a:not([class]):visited,
.mb-faq__a a:not([class]):visited{color:var(--accent-text)}
/* the hero field is fixed dark in both themes, so it needs the bright gold rather than
   the light theme's deep one, which would be near-black on near-black */
.field .lead a:not([class]),.field .small a:not([class]),
.field .lead a:not([class]):visited,.field .small a:not([class]):visited{
  color:var(--stage-accent); border-bottom-color:var(--f-rule)}
.legal ul{list-style:none; margin:0 0 14px; padding:0; border-top:1px solid var(--rule-soft)}
.legal li{font-size:15.5px; line-height:1.6; color:var(--dim); padding:11px 0;
  border-bottom:1px solid var(--rule-soft)}
.legal .tablewrap{overflow-x:auto; margin:4px 0 18px}
.legal table{width:100%; border-collapse:collapse; min-width:660px}
.legal th{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:9.5px; letter-spacing:.12em;
  color:var(--faint); font-weight:500; text-align:left; padding:0 16px 8px 0;
  border-bottom:1px solid var(--rule)}
.legal td{font-size:13.5px; line-height:1.5; color:var(--dim); padding:11px 16px 11px 0;
  border-bottom:1px solid var(--rule-soft); vertical-align:top}
.legal td:first-child{color:var(--ink); font-weight:600}
.legal th:last-child,.legal td:last-child{padding-right:0}

/* On a phone this stops being a table. Five columns need 660px and the column is 319, so
   .tablewrap scrolled sideways and three of the five — including the legal basis and how
   long the data is kept — sat off the right edge of a document somebody is meant to read.
   Each row becomes a block instead, and each value is labeled with its column from the
   data-label scripts/build-legal.py writes into the markup.

   The heading row goes to a clip rect rather than display:none: it still names the columns
   for a screen reader walking the table, and a table whose thead is display:none is a table
   that has lost its header. */
@media (max-width:720px){
  .legal .tablewrap{overflow-x:visible}
  .legal table{min-width:0; display:block}
  .legal thead{position:absolute; width:1px; height:1px; overflow:hidden;
    clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap}
  .legal tbody,.legal tr,.legal td{display:block}
  .legal tr{border:1px solid var(--rule-soft); border-radius:11px;
    padding:4px 14px 6px; margin:0 0 10px}
  .legal td{border-bottom:0; padding:7px 0; font-size:14.5px}
  .legal td + td{border-top:1px solid var(--rule-soft)}
  .legal td::before{content:attr(data-label);
    font-family:"JetBrains Mono",ui-monospace,monospace; font-size:9.5px; letter-spacing:.12em;
    color:var(--faint); text-transform:uppercase; display:block; margin:0 0 3px}
  /* the first cell is the row's subject, so it reads as the block's title and says so once */
  .legal td:first-child{font-size:15.5px; padding-top:10px}
}

/* A warning the reader needs before they act, rather than a note under the button that
   commits them. Used for the attachment warning on /feedback/ and the security route on
   /contact/ — both of which sat last, after Submit, where they inform nobody. */
.warnbox{border-left:2px solid var(--accent-deep); padding:2px 0 2px 14px; margin:14px 0 0;
  max-width:var(--measure)}
.warnbox strong{color:var(--ink)}

/* ---------- Install page: the step rail and the two ways in ----------
   The three steps read left to right along one line, because they happen in that
   order and the order is the whole point. The rule behind the markers is drawn
   from the first marker to the last, not edge to edge, so it never appears to
   continue past step three. On a narrow screen the rail turns vertical — the
   same rule, rotated — rather than shrinking three columns into illegibility. */
.steprail{list-style:none; margin:26px 0 0; padding:0; display:grid;
  grid-template-columns:repeat(3,1fr); gap:0 22px; position:relative; max-width:760px}
.steprail li{position:relative; padding-right:8px}
/* one segment per gap, anchored to the markers themselves, so the rule can never
   run past the last step however wide the columns end up */
.steprail li:not(:last-child)::after{content:""; position:absolute; top:15px;
  left:39px; right:-14px; height:1px; background:var(--rule)}
.steprail .n{position:relative; z-index:1; display:grid; place-items:center;
  width:31px; height:31px; border-radius:50%; background:var(--glass);
  border:1px solid var(--rule); color:var(--ink);
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:12.5px; font-weight:600}
.steprail li:first-child .n{background:var(--accent); border-color:var(--accent); color:var(--accent-ink)}
.steprail h3{margin:13px 0 5px; font-size:14.5px; font-weight:650; color:var(--ink); letter-spacing:-.005em}
.steprail p{margin:0; font-size:12.5px; line-height:1.55; color:var(--faint)}
.steprail strong{color:var(--dim); font-weight:600}
@media (max-width:640px){
  .steprail{grid-template-columns:1fr; gap:20px 0}
  .steprail li{padding-left:44px; padding-right:0}
  .steprail li:not(:last-child)::after{top:39px; bottom:-28px; left:15px;
    right:auto; width:1px; height:auto}
  .steprail .n{position:absolute; left:0; top:0}
  .steprail h3{margin-top:5px}
}

/* The two ways in are siblings, not a card and an afterthought. */
.way{margin-top:38px; padding-top:26px; border-top:1px solid var(--rule)}
.way > h2{display:flex; align-items:center; gap:10px; margin:0 0 8px;
  font-size:19px; font-weight:650; color:var(--ink); letter-spacing:-.01em}
.way > h2 svg{width:17px; height:17px; flex:none; fill:none;
  stroke:var(--faint); stroke-width:1.6}
.way > h2 svg.solid{fill:var(--faint); stroke:none}
.way .pick{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10.5px;
  letter-spacing:.15em; text-transform:uppercase; color:var(--accent-text); font-weight:500;
  margin:0 0 9px}
.way > p{font-size:14.5px; line-height:1.6; color:var(--dim); max-width:var(--measure); margin:9px 0 0}
.way .act{margin:18px 0 0}
.way .meta{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11.5px;
  color:var(--faint); margin:10px 0 0}
.way .brewcmd{margin-top:16px}
.way .note{margin-top:22px; padding:14px 16px; border:1px solid var(--rule-soft);
  border-radius:9px; background:var(--glass-raised)}
.way .note h3{margin:0 0 6px; font-size:12.5px; font-weight:650; color:var(--ink)}
.way .note p{font-size:12.5px; color:var(--faint); line-height:1.55; margin:8px 0 0; max-width:none}
.way .note .brewcmd{margin-top:10px}


/* ---------- Mobile: three measured defects ----------
   1. .mb-wrap nests inside .wrap, so the mb- sections paid both paddings: 28px + 24px a
      side. Every other block on the page got a 28px gutter and those got 52px, which on a
      375px phone left them 271px of content against everyone else's 319px. Same 48px loss
      on desktop, 976px against 1024px. The nested one keeps its max-width and drops the
      padding the parent already applied.
   2. A long unbroken token — the published sha256 on the install page — has no break
      opportunity, so it pushed the document 155px wider than the phone and every page
      scrolled sideways. Code spans may break anywhere rather than drag the page with them.
   3. Anything that can still exceed its column scrolls inside its own box. */
.wrap .mb-wrap{padding-left:0; padding-right:0}

code, .mb-mono, .brew code{overflow-wrap:anywhere}
.brewcmd code{overflow-wrap:normal}          /* commands stay copyable: the block scrolls */
code#shaval{overflow-wrap:anywhere}          /* a checksum is read, not run: it wraps */
.brewcmd{overflow-x:auto}


/* The contact form's honeypot. Clipped rather than display:none — a bot that parses CSS
   skips what is not displayed, and this field only works if it looks fillable. Clipped and
   not left:-9999px, because an element parked off-screen still widens the document: that one
   cost the page a horizontal scrollbar before anyone typed anything. The wrapper carries
   aria-hidden, so a screen reader never reaches it either. */
.fb{position:relative}
.fb .hp{position:absolute; width:1px; height:1px; margin:-1px; padding:0; border:0;
  overflow:hidden; clip-path:inset(50%); white-space:nowrap}

/* ---------- The pilot call to action ----------
   Outside .navlinks for the same reason as the theme control: that collapses under 760px, and
   this is the one thing on the page we want a visitor to find. It is outlined rather than
   filled, matching the hero's ghost button: the hero's own filled "Start Your Pilot" is the
   page's single solid call, and two filled copies of it in one viewport competed. On a phone
   it drops to its own row under the logo rather than squeezing the logo, which is already at
   its minimum width. */
.navcta{margin-left:18px; flex:none; font-size:13.5px; font-weight:600; letter-spacing:.005em;
  white-space:nowrap; text-decoration:none; color:var(--accent-ink); background:var(--accent);
  border:1px solid var(--accent); border-radius:7px; padding:7px 15px}
.navcta:hover{background:var(--accent-deep); border-color:var(--accent-deep);
  color:var(--accent-ink)}
.navcta:focus-visible{outline:2px solid var(--accent-deep); outline-offset:3px}
/* Five links, the logo, this badge and the theme control are a tight fit: at about 1000px
   "Score your settings" wrapped onto two lines. The links never wrap now; between 960 and
   1180px the logo and the gaps give a little; under 960px the links go and the badge stays.
   They are not in the footer, so this is the same trade the phone layout already makes. */
.navlinks a{white-space:nowrap}
@media (max-width:1180px){.brand .lockup{width:clamp(180px,19vw,232px)} .navlinks{gap:16px}}
@media (max-width:960px){.navlinks{display:none}.navcta{margin-left:auto}}
/* The menu button and its panel are built by nav.js. Without it (no script) none of this
   exists, and the badge stays in the bar. With it, under 960px the badge moves into the menu. */
.nav{position:relative}
.menutoggle{display:none; place-items:center; width:34px; height:34px; padding:0; margin-left:6px;
  border:1px solid transparent; border-radius:9px; background:none; cursor:pointer;
  color:var(--dim); flex:none}
.field .menutoggle{color:var(--f-dim)}
.menutoggle:hover{color:var(--ink); border-color:var(--rule)}
.field .menutoggle:hover{color:var(--f-ink)}
.menutoggle:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.menutoggle svg{width:19px; height:19px; fill:none; stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; display:block}
.navmenu{position:absolute; right:0; top:100%; z-index:30; min-width:230px; margin-top:4px; padding:8px;
  display:flex; flex-direction:column; background:var(--panel); border:1px solid var(--panel-edge);
  border-radius:14px; box-shadow:var(--panel-shadow)}
.navmenu[hidden]{display:none}
.navmenu a{padding:12px 14px; border-radius:8px; font-size:15px; color:var(--ink); text-decoration:none}
.navmenu a:hover,.navmenu a:focus-visible{background:var(--surface-2); outline:0}
.navmenu .sep{height:1px; margin:6px 8px; background:var(--rule)}
.navmenu .menucta{font-weight:600}
@media (min-width:961px){.menutoggle,.navmenu{display:none !important}}
@media (max-width:960px){
  .nav.has-menu .menutoggle{display:grid}
  .nav.has-menu .navcta{display:none}
}
@media (max-width:560px){.nav.has-menu{flex-wrap:nowrap}.nav.has-menu .brand{min-width:0}.nav.has-menu .lockup{max-width:100%}}
@media (max-width:560px){
  .nav{flex-wrap:wrap}
  .navcta{order:3; flex-basis:100%; text-align:center; margin-left:0; padding:10px 15px}
}

/* The form buttons — Send, Submit, and the hero's pair — measured 40px on a phone: 11px of
   padding either side of a 14.5px line. Same placement reasoning as the toggle above: after
   the base rule, not with the earlier mobile block. */
@media (max-width:760px){.btn{padding:13px 20px}}

/* ---------- header menus ----------
   Four groups instead of four links. The panel ships `hidden` and nav.js opens it, so a page
   with no script shows the buttons and nothing drops; every one of these links is also in the
   footer, which is the no-script path and the reason this is safe. */
.navitem{position:relative}
.navtop{appearance:none; background:none; border:0; cursor:pointer; padding:6px 2px;
  display:inline-flex; align-items:center; gap:6px; font:inherit; font-size:14px;
  color:var(--dim); border-bottom:1px solid transparent}
.navtop svg{width:9px; height:6px; fill:none; stroke:currentColor; stroke-width:1.6;
  stroke-linecap:round; stroke-linejoin:round; transition:transform .15s ease}
.navtop:hover{color:var(--ink)}
.navtop[aria-expanded="true"]{color:var(--ink)}
.navtop[aria-expanded="true"] svg{transform:rotate(180deg)}
.navpanel{position:absolute; top:calc(100% + 10px); left:-14px; z-index:60;
  min-width:224px; display:grid; gap:1px; padding:8px; border-radius:12px;
  background:var(--surface); border:1px solid var(--rule);
  box-shadow:0 18px 40px rgba(0,0,0,.55)}
/* `hidden` is a UA rule and `display:grid` on a class outranks it, so the panels would ship
   open. This line is what actually closes them. */
.navpanel[hidden]{display:none}
.navpanel a{display:block; padding:8px 12px; border-radius:7px; font-size:14px;
  color:var(--dim); text-decoration:none; border-bottom:0; white-space:nowrap}
.navpanel a:hover{color:var(--ink); background:var(--surface-2)}
.navmenu .menuhead{margin:14px 0 4px; font-family:"JetBrains Mono",ui-monospace,monospace;
  font-size:10px; letter-spacing:.14em; text-transform:uppercase; color:var(--faint)}
.navmenu .menuhead:first-child{margin-top:0}
