/* ---------------------------------------------------------------------------
   Slate — brand surface.

   Two grounds, and the split is not decorative. The firmware has exactly two
   worlds and it reboots between them: in the air, where the only interface is
   16 monochrome characters over your video feed, and at the bench, where you
   set the thing up on a white page in daylight. The dark bands are the air.
   The paper bands are the bench. Section eyebrows say which one you are in.

   Paper tokens are lifted unchanged from the module's own settings page, so
   the site and the product are the same object.
--------------------------------------------------------------------------- */
:root{
  --ink:#0E1116;          /* air ground */
  --ink-2:#161A21;        /* raised panel on air */
  --ink-line:#252B34;
  --air:#F2F4F7;          /* type on air */
  --air-2:#8B94A0;

  --paper:#FFFFFF;
  --surface:#F5F6F8;
  --line:#DFE3E8;
  --line-2:#C9CFD6;
  --text:#14171C;         /* type on paper */
  --text-2:#5B636E;

  --signal:#0F8A4A;  --signal-air:#35C77C;
  --warn:#A35C00;    --warn-air:#E3A54B;
  --fault:#C2331F;   --fault-air:#F0664F;

  --sans:"Archivo","Helvetica Neue",Arial,sans-serif;
  --mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace;

  /* Type steps. The hero is cut from --u because it is pinned to the viewport
     and has to fit a screen whole; everything below it scrolls, so height
     cannot constrain it and width is the only thing worth measuring. Hence vw.

     One ramp, scaled. Body is 17px at 1280 and 21.5px at 1920, and every other
     step is a fixed proportion of it, so the hierarchy holds at every width.
     It did not before: the body was fluid and the forty sizes under it were
     fixed px, so the further the window opened the flatter the page read.

     The floors are what a phone gets, and nothing is allowed under 12px.

     JetBrains Mono sits a shade smaller than Archivo at the same size, so mono
     borrows the step above its sans rank -- code and table data take --t-small
     where the sans of the same rank takes --t-meta. */
  --t-body:clamp(17px,calc(0.75vw + 8.4px),22.5px);
  --t-lede:clamp(19px,calc(0.94vw + 8px),27px);
  --t-small:clamp(15px,calc(0.68vw + 8px),20.5px);
  --t-meta:clamp(14px,calc(0.6vw + 7.5px),19px);
  --t-label:clamp(12.5px,calc(0.5vw + 6.5px),16px);
  --t-h2:clamp(30px,calc(2.5vw + 14px),62px);
  --t-h3:clamp(17px,calc(0.78vw + 9px),24px);

  --gut:clamp(20px,4.6vw,76px);
  --maxw:1760px;
  /* The nav's own height, stated once. The pin sticks at exactly this offset,
     which is where the hero already sits at rest -- so it is held from the
     first pixel of scroll instead of after the nav's height of free play. */
  --nav:clamp(84px,calc(2.6vw + 50px),120px);
  /* How far the hero holds still while the board turns. */
  --hero-pin:70vh;
  /* One unit, and the whole hero is cut from it.

     The board used to be sized in vh while the type scaled in vw. Widening the
     window grew the text and left the board alone; heightening it did the
     reverse. Nothing in the hero moved together, which is what made every
     window size look like a different design rather than the same one.

     `--u` takes whichever of the two is scarcer, so the hero always scales by
     its tightest dimension: on a short window everything shrinks together and
     still fits the viewport it is pinned to, and on a narrow one likewise. The
     title, the padding, the gaps and the board are all multiples of it, so
     their proportions to each other never change at any size.

     0.46 is the canvas aspect, and it is not a taste decision: the camera
     frames 1.72 board-lengths vertically and the board is 0.744 wide, so the
     board projects across 0.43 of the canvas height. Anything wider than that
     is margin -- and margin here sits exactly between the title and the thing
     it is supposed to run behind. The wires spread less than the board does,
     so the board sets the number. */
  --u:min(1vw,1.7vh);
  --board-h:min(calc(var(--u) * 52),740px,66vh);
  --board-w:calc(min(var(--u) * 52,740px,66vh) * 0.46);
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  margin:0;background:var(--ink);color:var(--air);
  font:400 var(--t-body)/1.62 var(--sans);
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-x:clip;
}
img,svg{max-width:100%}
a{color:inherit}

/* -- type roles ----------------------------------------------------------- */
.eyebrow{
  font:500 var(--t-label)/1.35 var(--mono);letter-spacing:.2em;text-transform:uppercase;
  color:var(--air-2);display:flex;align-items:center;gap:10px;margin:0 0 22px;
}
.eyebrow::before{content:"";width:22px;height:1px;background:currentColor;flex:none;opacity:.6}
.paper .eyebrow{color:var(--text-2)}

h1,h2,h3{margin:0;font-family:var(--sans);font-variation-settings:"wdth" 112}
h1{
  /* Sized from what is left, not from the viewport. The title, the board and
     a fixed 44px of overlap add up to the container, so the title is
     container - board + overlap; 6.48 is the measured width of "THE SLATE" in
     this italic, in ems.

     Tying it to --u meant chasing a moving target: the board stops growing at
     its cap while the container does not, and no single multiplier kept the
     overlap positive at both 1280 and 1920. This is exact at every size by
     construction. */
  font-size:clamp(4.2rem,calc((100cqw - var(--board-w) + 44px) / 6.48),13rem);
  font-weight:800;line-height:.88;
  letter-spacing:-.015em;text-transform:uppercase;font-style:italic;
  font-variation-settings:"wdth" 116;
}
h2{
  font-size:var(--t-h2);font-weight:700;line-height:1.04;
  letter-spacing:-.02em;max-width:19ch;
}
h3{font-size:var(--t-h3);line-height:1.28;font-weight:700;letter-spacing:-.005em;font-variation-settings:"wdth" 100}
p{margin:0 0 1.1em}
.lede{font-size:var(--t-lede);line-height:1.5;color:var(--air-2);max-width:56ch}
.paper .lede{color:var(--text-2)}
strong,b{font-weight:700;color:var(--air)}
.paper strong,.paper b{color:var(--text)}
code,.mono{font-family:var(--mono);font-size:.95em}

/* -- layout --------------------------------------------------------------- */
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--gut)}
.band{padding:clamp(72px,9vw,170px) 0}
.paper{background:var(--paper);color:var(--text)}
.paper .lede,.paper p{color:var(--text-2)}
.paper h1,.paper h2,.paper h3{color:var(--text)}

/* -- mark ----------------------------------------------------------------- */
.mark{width:1em;height:1em;flex:none;color:inherit}

/* -- nav ------------------------------------------------------------------ */
.nav{
  position:sticky;top:0;z-index:50;background:rgba(14,17,22,.86);
  backdrop-filter:saturate(160%) blur(14px);
  border-bottom:1px solid var(--ink-line);
}
/* Three tracks, so the menu is centred on the bar rather than on whatever is
   left after the wordmark. The outer two are equal, which is what keeps the
   middle one actually centred when the wordmark and the Source pill are
   different widths. */
.nav .wrap{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  gap:20px;height:calc(var(--nav) - 1px)}
.nav .src-slot{justify-self:end}
.brand{
  display:flex;align-items:center;gap:9px;text-decoration:none;
  font:800 var(--t-body)/1 var(--sans);font-variation-settings:"wdth" 118;
  letter-spacing:.17em;text-transform:uppercase;
}
.brand .mark{font-size:1.4em}
.navlinks{display:flex;gap:clamp(20px,2vw,40px);align-items:center;justify-content:center}
.navlinks a{
  font:500 var(--t-meta)/1 var(--mono);letter-spacing:.11em;text-transform:uppercase;
  color:var(--air);text-decoration:none;transition:background .15s,color .15s;
  padding:10px 14px;border-radius:9px;
}
/* A target you can see, rather than dim text you have to aim at. */
.navlinks a:hover{background:rgba(255,255,255,.09)}
.navlinks a.src{border:1px solid var(--ink-line);border-radius:999px;padding:10px 18px}
.navlinks a.src:hover{border-color:var(--air-2);background:rgba(255,255,255,.09)}
/* The coffee pill is the same shape as Source and no louder: it is a request,
   not a call to action, and the header's job is to get people to the product.
   It goes on narrow screens, where two pills and the wordmark do not fit. */
@media(max-width:760px){.navlinks a.coffee{display:none}}
/* Under 480 the three tracks -- wordmark, menu, Source -- need about 406px of
   the 350 available, and the pill was leaving the wrap by 18px. The wordmark
   gives up a little size and tracking and the gaps close; measured to fit at
   390 with nothing clipped. */
@media(max-width:480px){
  .nav .wrap{gap:10px}
  .brand{font-size:15px;letter-spacing:.11em}
  .navlinks a.src{padding:8px 12px}
}
/* The bar carries three links now, not eight, so they survive far further down
   than the old rule assumed. Only About goes, and only when the wordmark and
   the Source pill start competing for the width: it is a section of the home
   page and the footer links it too. */
@media(max-width:470px){.navlinks{gap:16px}.navlinks a.opt{display:none}}

/* -- hero ----------------------------------------------------------------- */
/* The hero holds still for --hero-pin while the board turns 120 degrees, then
   releases and scrolls away normally. Native sticky: nothing intercepts the
   wheel, and the keyboard and scrollbar behave as they always did.

   The pinned block fills the screen (100vh less the nav it sticks under), so
   the section after it is a full screen below and cannot ride up over the hero
   during the hold -- it arrives exactly as the pin lets go.

   The travel has to be a real box inside the header, not padding on it: a
   sticky element is constrained to its containing block's *content* box, and
   padding sits outside that. */
.hero{padding:0}
.hero-release{height:0}
@media(min-width:961px) and (min-height:700px){
  .hero-pin{position:sticky;top:var(--nav);min-height:calc(100vh - var(--nav));
    display:flex;flex-direction:column;justify-content:center}
  /* `.wrap` carries `margin:0 auto`, and an auto cross-axis margin on a flex
     item cancels the stretch -- without this it stays content-sized. */
  .hero-pin > .wrap{width:100%}
  .hero-release{height:var(--hero-pin)}
}
.hero-pin{padding:clamp(28px,calc(var(--u) * 2.6),58px) 0 clamp(60px,calc(var(--u) * 7),140px)}
/* The board is lifted out of the flow and floated over the type rather than
   given a column of its own. Two columns meant the title could only ever be as
   wide as what was left after the board took its share, so every change to one
   was a fight with the other. Overlapping ends the argument: the title runs at
   whatever size it likes and the last of it passes behind the board, which is
   what puts the two of them in the same space instead of side by side.

   `pointer-events:none` because the canvas is a rectangle and most of that
   rectangle is empty: without it, an invisible box would be swallowing clicks
   and text selection over a large part of the hero. */
/* As tall as the board, so the hero's height is something coherent rather than
   whatever the paragraph happened to need, and the board stops hanging out of
   a box shorter than itself. The type centres against it. */
.hero-grid{position:relative;min-height:var(--board-h);
  display:flex;flex-direction:column;justify-content:center;
  /* So the title can be sized from the width actually left beside the board.
     100cqw is this element's content box -- the container the title and the
     board divide between them. */
  container-type:inline-size}
.hero-head{margin-bottom:clamp(18px,calc(var(--u) * 2.4),40px)}
.hero-body{max-width:52%}
.hero-grid .stage{position:absolute;right:var(--gut);top:50%;transform:translateY(-50%);
  width:var(--board-w);z-index:2;pointer-events:none}
/* On a phone the board goes between the headline and the explanation: the
   claim, the thing itself, then why it is true. Stacked in source order it
   would have landed a screen and a half below the fold. */
/* On a phone: name, then the board, then the description under it, centred.
   The board is the widest thing in the column, so everything reads to it. */
@media(max-width:960px){
  .hero-grid{text-align:center}
  .hero-grid .stage{position:static;transform:none;width:100%;margin-inline:auto}
  .hero-body{max-width:none}
  .hero-body{margin-top:10px}
  .hero .cta{justify-content:center}
  .hero .catch,.hero .lede{margin-inline:auto}
}
/* Mono at .2em tracking is wide. Tightened on a phone so the strip stays on
   one line; the version itself never breaks, wherever it lands. */
@media(max-width:600px){
  .hero .tagline{letter-spacing:.12em;font-size:10.5px}
}
.tagline{font:500 var(--t-label)/1 var(--mono);letter-spacing:.2em;text-transform:uppercase;color:var(--air-2);margin:0 0 18px}
.tagline b{color:var(--signal-air);font-weight:500;white-space:nowrap}
.hero h1{margin-bottom:0}
/* The line that says what it does, now that the title only says what it is. */
.catch{font:600 clamp(1.2rem,1.85vw,1.7rem)/1.28 var(--sans);letter-spacing:-.012em;
  color:var(--air);margin:0 0 14px;max-width:36ch}
.hero .lede{margin-bottom:30px;max-width:46ch}
.cta{display:flex;flex-wrap:wrap;gap:12px;margin-bottom:38px}
.btn{
  font:600 var(--t-meta)/1 var(--sans);letter-spacing:.01em;text-decoration:none;
  padding:14px 22px;border-radius:10px;border:1px solid transparent;
  display:inline-flex;align-items:center;gap:9px;transition:background .15s,border-color .15s,color .15s;
}
.btn.solid{background:var(--air);color:var(--ink)}
.btn.solid:hover{background:#fff}
.btn.line{border-color:var(--ink-line);color:var(--air)}
.btn.line:hover{border-color:var(--air-2)}

/* -- anything on paper ----------------------------------------------------
   The bits that were built dark-first and have to be told otherwise on a light
   ground -- chiefly the solid button, which is white-on-dark everywhere else
   and would come out white on white here. Scoped to `.paper` rather than to
   the hero, because the hero stopped being the only light band on the site. */
.paper .tagline{color:var(--text-2)}
.paper .tagline b{color:var(--signal)}
.paper .catch{color:var(--text)}
.paper .btn.solid{background:var(--ink);border-color:var(--ink);color:var(--air)}
.paper .btn.solid:hover{background:#000}
.paper .btn.line{border-color:var(--line-2);color:var(--text)}
.paper .btn.line:hover{border-color:var(--text-2)}
.paper a:focus-visible,.paper button:focus-visible{outline-color:var(--signal)}

/* -- the board ------------------------------------------------------------
   Sized by aspect ratio, not pixels, so the canvas is never told twice what
   shape it is. The renderer gets the measured box size with updateStyle off,
   which makes these two rules the only thing setting it. */
.stage{position:relative}
#board{height:var(--board-h);width:var(--board-w);max-width:100%;margin-inline:auto}
/* Without this the column is sized by the caption, not the board: `auto` takes
   the widest thing in it, and the caption is a sentence. */
.hero-grid .stage{width:var(--board-w);max-width:100%}
#board canvas{display:block;width:100%;height:100%}
/* No WebGL: collapse to nothing rather than leave a broken frame. */
#board[data-state="unsupported"]{aspect-ratio:auto;height:0}
@media(max-width:960px){
  :root{--board-w:min(88vw,340px);--board-h:calc(min(88vw,340px) / 0.72)}
  .hero-grid .stage{width:100%}
  .stage{margin-top:2px}
}

.osd-split{display:grid;grid-template-columns:minmax(0,clamp(460px,36vw,600px)) minmax(0,1fr);
  gap:clamp(28px,4vw,60px);align-items:start}
@media(max-width:900px){.osd-split{grid-template-columns:1fr}}
.osd-copy h3{margin-bottom:9px}
.osd-copy p{font-size:var(--t-small);line-height:1.6;color:var(--air-2);margin-bottom:26px;max-width:60ch}
.osd-copy p:last-child{margin-bottom:0}

/* -- the OSD, which is the whole signature --------------------------------- */
.osd-card{border:1px solid var(--ink-line);border-radius:16px;background:var(--ink-2);overflow:hidden}
.osd-head{
  display:flex;justify-content:space-between;align-items:center;padding:13px 16px;
  border-bottom:1px solid var(--ink-line);
  font:500 var(--t-label)/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--air-2);
}
.osd-screen{
  position:relative;background:#000;aspect-ratio:16/9;padding:clamp(16px,3.4vw,26px);
  display:flex;flex-direction:column;justify-content:center;gap:2px;
  /* The rows are sized from the screen they sit in, not the window: this is a
     16:9 frame with an overlay on it, and an overlay that does not keep its
     share of the frame stops looking like one. 2.9vw hit its 21px ceiling at
     724px, so on every desktop the strip was a stamp in the corner. */
  container-type:inline-size;
}
.osd-screen::after{ /* corner brackets: this is a viewfinder, not a terminal */
  content:"";position:absolute;inset:11px;pointer-events:none;
  background:
    linear-gradient(#ffffff2e,#ffffff2e) 0 0/13px 1px no-repeat,
    linear-gradient(#ffffff2e,#ffffff2e) 0 0/1px 13px no-repeat,
    linear-gradient(#ffffff2e,#ffffff2e) 100% 0/13px 1px no-repeat,
    linear-gradient(#ffffff2e,#ffffff2e) 100% 0/1px 13px no-repeat,
    linear-gradient(#ffffff2e,#ffffff2e) 0 100%/13px 1px no-repeat,
    linear-gradient(#ffffff2e,#ffffff2e) 0 100%/1px 13px no-repeat,
    linear-gradient(#ffffff2e,#ffffff2e) 100% 100%/13px 1px no-repeat,
    linear-gradient(#ffffff2e,#ffffff2e) 100% 100%/1px 13px no-repeat;
}
.osd-row{
  font:500 clamp(15px,5.1cqw,30px)/1.5 var(--mono);color:#fff;white-space:pre;
  letter-spacing:.04em;text-shadow:0 0 1px #000,0 1px 2px #000;
}
.osd-foot{display:flex;align-items:center;gap:10px;padding:12px 16px;border-top:1px solid var(--ink-line);
  font:500 var(--t-label)/1.5 var(--mono);letter-spacing:.06em;color:var(--air-2);text-transform:uppercase}
.osd-foot .led{width:7px;height:7px;border-radius:50%;background:var(--air-2);flex:none;transition:background .2s}
.osd-foot .led.rec{background:var(--fault-air);box-shadow:0 0 9px var(--fault-air)}
.osd-foot .led.rdy{background:var(--signal-air)}

.switches{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:14px 16px 16px;border-top:1px solid var(--ink-line)}
.sw{
  appearance:none;font:inherit;cursor:pointer;text-align:left;
  background:var(--ink);border:1px solid var(--ink-line);border-radius:11px;padding:11px 13px;
  color:var(--air-2);transition:border-color .15s,color .15s,background .15s;
}
.sw:hover{border-color:var(--air-2)}
.sw:focus-visible{outline:2px solid var(--signal-air);outline-offset:2px}
.sw .k{display:block;font:500 var(--t-label)/1 var(--mono);letter-spacing:.17em;text-transform:uppercase;margin-bottom:7px;opacity:.75}
.sw .v{display:flex;align-items:center;gap:8px;font:600 var(--t-meta)/1 var(--sans);color:var(--air)}
.sw .dot{width:8px;height:8px;border-radius:50%;background:var(--air-2);flex:none;transition:background .15s,box-shadow .15s}
.sw[aria-checked="true"]{border-color:#3d4551;background:#1b2029}
.sw[aria-checked="true"] .dot{background:var(--signal-air);box-shadow:0 0 8px var(--signal-air)}
.sw#armSw[aria-checked="true"] .dot{background:var(--warn-air);box-shadow:0 0 8px var(--warn-air)}
.osd-note{padding:0 16px 16px;font-size:var(--t-meta);line-height:1.55;color:var(--air-2);margin:0}
.osd-note b{color:var(--air)}

/* -- generic content blocks ------------------------------------------------ */
.head{margin-bottom:clamp(40px,5vw,64px);max-width:62ch}
.head .lede{margin-top:18px}

.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(238px,1fr));gap:14px}
.card{border:1px solid var(--ink-line);border-radius:14px;padding:22px;background:var(--ink-2)}
.paper .card{border-color:var(--line);background:var(--paper)}
.card .tag{font:600 var(--t-label)/1 var(--mono);letter-spacing:.16em;color:var(--air-2);margin-bottom:14px;display:block}
.paper .card .tag{color:var(--text-2)}
.card h3{margin-bottom:9px}
.card p{font-size:var(--t-small);line-height:1.55;margin:0;color:var(--air-2)}
.paper .card p{color:var(--text-2)}
.card .def{color:var(--signal-air);font-weight:600}

.split{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,388px);gap:clamp(30px,4.5vw,58px);align-items:start}
@media(max-width:900px){.split{grid-template-columns:minmax(0,1fr)}}

.aside{border:1px solid var(--ink-line);border-radius:14px;padding:22px;background:var(--ink-2)}
.paper .aside{border-color:var(--line);background:var(--surface)}
.aside h3{margin-bottom:10px}
.aside p{font-size:var(--t-small);line-height:1.55;color:var(--air-2)}
.paper .aside p{color:var(--text-2)}
.aside p:last-child{margin-bottom:0}
.aside table{min-width:0}

/* -- tables ---------------------------------------------------------------- */
.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table{border-collapse:collapse;width:100%;min-width:440px;font-size:var(--t-small)}
th,td{text-align:left;padding:12px 14px;border-bottom:1px solid var(--line)}
th{font:600 var(--t-label)/1.3 var(--mono);letter-spacing:.15em;text-transform:uppercase;color:var(--text-2);
  border-bottom-color:var(--line-2)}
td .mono{font-size:var(--t-small)}
tbody tr:last-child td{border-bottom:none}
.dark-table th,.dark-table td{border-bottom-color:var(--ink-line)}
.dark-table th{color:var(--air-2)}

.pill{display:inline-flex;align-items:center;gap:7px;font:600 var(--t-label)/1 var(--mono);letter-spacing:.09em;
  text-transform:uppercase;padding:5px 10px;border-radius:999px;border:1px solid var(--line);white-space:nowrap}
.pill::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}
.pill.ok{color:var(--signal);border-color:#0f8a4a44}
.pill.exp{color:var(--warn);border-color:#a35c0044}
.pill.no{color:var(--fault);border-color:#c2331f44}

/* -- steps ----------------------------------------------------------------- */
.steps{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);border-radius:14px;overflow:hidden}
.step{background:var(--paper);padding:24px}
.step .n{font:600 var(--t-label)/1 var(--mono);letter-spacing:.16em;color:var(--text-2);display:block;margin-bottom:12px}
.step h3{margin-bottom:8px}
.step p{font-size:var(--t-small);line-height:1.55;margin:0}
@media(min-width:820px){.steps{grid-template-columns:repeat(3,1fr)}}
@media(min-width:820px){.steps.two{grid-template-columns:repeat(2,1fr)}}

/* -- the demo, in the section that explains it ----------------------------
   Same box as the home deck's reel. Capped rather than full-wrap: at the wrap's
   width a 16:9 clip is 730px tall and stops being an illustration. */
.reel-wide{margin:0 0 clamp(30px,4vw,56px);max-width:1040px}
.reel-wide figcaption{margin:14px 0 0;max-width:64ch;
  font-size:var(--t-meta);line-height:1.55;color:var(--air-2)}

/* -- setup: the phone, and the steps beside it -----------------------------
   Phone on the left, steps to its right, and the steps capped at 720px rather
   than taking whatever is left -- the pair sits against the left of the wrap
   and the spare width stays on the right. The steps stack into one column
   here whatever the width: three across would be cramped next to the phone,
   and a tall list of three beside a tall phone is the natural pairing. The
   picture carries width:100% for the reason the intro photograph does -- see
   that block. The phone is first visually via order, not in the markup, so a
   phone reads the steps first and then the page they lead to. */
.setup-grid{display:grid;grid-template-columns:clamp(220px,22vw,320px) minmax(0,720px);
  justify-content:start;gap:clamp(28px,4vw,64px);align-items:center}
.setup-grid .steps{grid-template-columns:1fr}
.phone{margin:0;order:-1}
.phone picture{display:block;width:100%}
.phone img{display:block;width:100%;height:auto;
  filter:drop-shadow(0 28px 36px rgba(20,23,28,.22))}
.phone figcaption{margin-top:16px;text-align:center;
  font-size:var(--t-meta);line-height:1.55;color:var(--text-2)}
@media(max-width:820px){
  .setup-grid{grid-template-columns:1fr}
  .phone{order:0;max-width:300px;margin:8px auto 0}
}

/* -- the channel picker, drawn exactly as the settings page draws it -------- */
.picker{border:1px solid var(--line);border-radius:14px;padding:20px;background:var(--paper)}
.picker .cap{font:600 var(--t-label)/1 var(--mono);letter-spacing:.15em;text-transform:uppercase;color:var(--text-2)}
.track{position:relative;height:44px;margin:15px 0 7px;background:var(--surface);
  border:1px solid var(--line);border-radius:9px;overflow:hidden}
.track .window{position:absolute;top:0;bottom:0;left:69%;right:7%;background:#14171c14;
  border-left:2px solid var(--text);border-right:2px solid var(--text)}
.track .marker{position:absolute;top:0;bottom:0;left:83%;width:2px;background:var(--signal);
  box-shadow:0 0 8px #0f8a4a99}
.ticks{display:flex;justify-content:space-between;font:500 var(--t-label)/1 var(--mono);color:var(--text-2)}
.picker .read{margin:14px 0 0;font-size:var(--t-small);line-height:1.55;color:var(--text-2)}

/* -- verification ledger --------------------------------------------------- */
.ledger{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(258px,1fr))}
.col{border:1px solid var(--ink-line);border-radius:14px;padding:22px;background:var(--ink-2)}
.col.v{border-top:2px solid var(--signal-air)}
.col.d{border-top:2px solid var(--warn-air)}
.col.n{border-top:2px solid var(--fault-air)}
.col .hd{font:600 var(--t-label)/1.4 var(--mono);letter-spacing:.14em;text-transform:uppercase;margin-bottom:18px;display:block}
.col.v .hd{color:var(--signal-air)}
.col.d .hd{color:var(--warn-air)}
.col.n .hd{color:var(--fault-air)}
.col ul{margin:0;padding:0;list-style:none}
.col li{font-size:var(--t-small);line-height:1.55;color:var(--air-2);padding:11px 0;border-top:1px solid var(--ink-line)}
.col li:first-child{border-top:none;padding-top:0}
.col li b{color:var(--air);font-weight:600}

/* -- roadmap ---------------------------------------------------------------
   Rows, not cards. The verification ledger above it is three columns because
   its three states are peers; this is a vertical list because its three tiers
   are ordered by how sure they are, and that order is the information.

   No signal colour anywhere in here. Green means confirmed, and nothing on a
   roadmap is confirmed. --------------------------------------------------- */
.road-items li{max-width:64ch}
.road-items li > b{display:block;color:var(--air);font-weight:600;font-size:var(--t-body);
  line-height:1.35;margin-bottom:6px}
.road-items li > span{display:block;font-size:var(--t-small);line-height:1.55;color:var(--air-2)}
/* The sequence, said out loud. An <em> rather than a span so the strike-through
   on a ticked item does not run through its own number. */
.road-items li .ms{display:block;font:700 var(--t-label)/1 var(--mono);letter-spacing:.18em;
  text-transform:uppercase;font-style:normal;color:var(--air);margin-bottom:11px}
.road-items li.done .ms{color:var(--signal-air)}

/* -- code ------------------------------------------------------------------ */
pre{
  background:var(--ink);color:#dfe3e8;border-radius:11px;padding:16px 18px;margin:0 0 14px;
  font:500 var(--t-small)/1.7 var(--mono);overflow-x:auto;-webkit-overflow-scrolling:touch;
}
pre .c{color:#7d879a}
.paper pre{border:1px solid var(--ink)}

/* -- caution --------------------------------------------------------------- */
.caution{border:1px solid #a35c0033;background:#a35c000a;border-radius:14px;padding:22px}
.caution h3{color:var(--warn);margin-bottom:12px}
.caution ul{margin:0;padding-left:1.15em}
.caution li{font-size:var(--t-small);line-height:1.55;color:var(--text-2);margin-bottom:9px}
.caution li:last-child{margin-bottom:0}

/* -- closing band ---------------------------------------------------------- */
.next{border-top:1px solid var(--ink-line);border-bottom:1px solid var(--ink-line)}
.next .wrap{display:flex;gap:clamp(24px,4vw,56px);align-items:flex-start;flex-wrap:wrap}
.next .mark{font-size:calc(var(--t-lede) * 2.1);color:var(--air);opacity:.92}
.next p{max-width:54ch;font-size:var(--t-lede);line-height:1.5;color:var(--air);margin:0}
.next p span{color:var(--air-2)}

footer{padding:44px 0 56px;font-size:var(--t-meta);color:var(--air-2)}
footer .wrap{display:flex;flex-wrap:wrap;gap:16px 30px;align-items:center}
footer a{color:var(--air-2);text-decoration:none;border-bottom:1px solid var(--ink-line)}
footer a:hover{color:var(--air)}
footer .fine{width:100%;font-size:calc(var(--t-meta) * .93);line-height:1.6;color:#6c7583;margin:0}

::selection{background:var(--signal-air);color:var(--ink)}
a:focus-visible,button:focus-visible{outline:2px solid var(--signal-air);outline-offset:3px;border-radius:4px}

@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{transition-duration:.001ms !important;animation-duration:.001ms !important}
}

/* -- brand shell ------------------------------------------------------------
   Added when the site grew a second level: SlateFPV owns the chrome, and a
   product is something the chrome contains. -------------------------------- */
.brand span{color:var(--air-2)}

.byline{font:500 var(--t-label)/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;
  color:var(--text-2);margin:14px 0 0}
.byline a{color:var(--text);text-decoration:none;border-bottom:1px solid var(--line-2)}
.byline a:hover{border-bottom-color:var(--text)}

/* -- home: the product, in a quad -------------------------------------------
   The photograph is the band, and the band is 16:6. It was shot for this: the
   quad sits in the right of the frame and the left is empty bench, which is
   where the copy goes -- so the type is not covering the subject.

   THE RULE THIS BAND EXISTS TO OBEY: the picture is only ever cut, never
   reshaped, and never turned into a keyhole. Those are two different failures
   and only the first one was fixed before. `cover` guarantees the pixels are
   never non-uniformly scaled -- but `cover` in a TALL box crops the other way,
   and a 1.5:1 photograph in a 390x760 band shows 34% of its width at 2.9x. A
   familiar object seen through a tall slot at three times life size reads as
   stretched even though nothing has been stretched. That is what "squeezed"
   meant, three times over.

   So the aspect is pinned, not inherited from the window: 16:6 while there is
   room for the copy on top of it, and the photograph's own 3:2 below that, with
   the copy moving underneath. The band never gets narrower than the picture.
-------------------------------------------------------------------------- */
.shot{
  position:relative;isolation:isolate;
  background:var(--ink);color:var(--air);
  display:grid;align-items:center;
  aspect-ratio:16/6;
}
.shot-bg{position:absolute;inset:0;z-index:0;display:block}
/* No width/height attributes reach this element and no other rule matches it --
   the two together are what make a non-uniform scale unreachable. 56% is the
   half that matters: the band is always wider than 3:2 here, so the crop is
   always vertical, and centred it would cut the camera off the quad. */
.shot-bg img,.shot > video{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:58% 56%}

/* Two gradients: one along the copy, one lifting the foot of the band into the
   section below it. The rake is held at .80 or darker across the copy column --
   the bench is a mid grey, and a gradient that has opened up by the end of the
   lede leaves it under 4.5:1. */
.shot::before{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(94deg,
      rgba(9,11,15,.90) 0%, rgba(9,11,15,.86) 30%, rgba(9,11,15,.80) 46%,
      rgba(9,11,15,.46) 62%, rgba(9,11,15,.14) 82%, rgba(9,11,15,0) 100%),
    linear-gradient(to top, rgba(9,11,15,.60) 0%, rgba(9,11,15,0) 34%);
}
/* width:100% is load-bearing. .wrap carries margin:0 auto, and an auto inline
   margin on a grid item cancels the default stretch -- the wrap then shrinks to
   its content and centres itself, which pulls the copy off the gutter and into
   the middle of the photograph. */
.shot > .wrap{position:relative;z-index:2;width:100%;
  padding-block:clamp(24px,2.6vw,52px)}

/* Wide enough that "The Slate" sets on one line, which is most of what lets the
   copy live inside a 16:6 band at all. The lede keeps its own measure. */
.pitch{max-width:min(64ch,50%)}
.pitch h1{font-size:clamp(2.4rem,calc(var(--u) * 6),5.6rem);line-height:.9;
  margin-bottom:14px}
.pitch .tagline{margin-bottom:12px}
.pitch .catch{margin-bottom:10px}
.pitch .beta{margin-bottom:14px}
.pitch .lede{max-width:40ch;margin-bottom:22px}
.pitch .cta{margin-bottom:0}

/* Under 900 the copy no longer fits on top of a 16:6 strip, and forcing it to
   would mean making the band taller -- which is exactly the keyhole. So the
   picture stops being a background and becomes a block at its OWN 3:2: the
   whole frame, cropped by nothing at all, with the copy underneath it on ink.
   A phone sees more of this photograph than a desktop does. */
@media(max-width:899px){
  .shot{aspect-ratio:auto;display:block;isolation:auto;
    padding-bottom:clamp(38px,7vw,60px)}
  .shot-bg{position:static;display:block;aspect-ratio:auto}
  /* No ratio imposed at all here: the picture sets its own height from its own
     file, so there is nothing left to crop and nothing left to stretch. Also
     display:block on the img -- an inline replaced element sits on a text
     baseline and the descender gap under it was making the box read 1.455
     against the file's 1.506. */
  .shot-bg img,.shot > video{position:static;display:block;width:100%;height:auto;
    aspect-ratio:auto;object-fit:cover;object-position:center}
  /* The copy is on ink now, so there is nothing to hold it off the picture. */
  .shot::before{content:none}
  .shot > .wrap{padding-block:clamp(28px,6vw,44px) 0}
  .pitch{max-width:none}
  .pitch h1{font-size:clamp(2.6rem,10.5vw,4.4rem);margin-bottom:16px}
  .pitch .lede{max-width:46ch}
}

/* -- home: the deck ---------------------------------------------------------
   Two cards in one grid cell, so the deck is as tall as the taller card and
   both are exactly the band. The card that is not showing waits one width to
   the right; when it is called it slides in OVER the current one, which stays
   put underneath until it is covered and only then snaps back out to the right
   -- invisibly, because by then there is a whole card on top of it. Two cards
   means the same move works in both directions forever.

   The cards share their copy on purpose. What changes between them is the
   picture: behind the copy on one, beside it on the other. Both keep 16:6, so
   nothing above or below the band moves when they swap.
-------------------------------------------------------------------------- */
.deck{position:relative;display:grid;overflow:hidden;background:var(--ink)}
.slide{grid-area:1/1;min-width:0;transform:translateX(100%);will-change:transform}
.slide.is-active{transform:none;z-index:2;
  transition:transform .8s cubic-bezier(.22,.61,.36,1)}
.slide.is-under{transform:none;z-index:1}

/* The demo card: no photograph and so no scrim; the copy in the left column
   at its natural width, the clip in the right. The box is 16:9, which is the
   clip's own shape, so it too is only ever cut, never reshaped. */
.slide.reel::before{content:none}
.slide.reel > .wrap{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(24px,4vw,64px);align-items:center}
.slide.reel .pitch{max-width:none;order:1}
.reel-box{order:2;aspect-ratio:16/9;border-radius:14px;overflow:hidden;background:#000;
  border:1px solid var(--ink-line);box-shadow:0 34px 60px -32px rgba(0,0,0,.85)}
.reel-box video{display:block;width:100%;height:100%;object-fit:cover}

/* Which card. Filled and bigger for the one showing, like the section rail.
   Right-aligned on the wide layout, where the copy's side of the band is busy
   and the picture's side has room under the quad and under the clip. */
.deck-nav{position:absolute;left:0;right:0;bottom:clamp(14px,1.8vw,26px);z-index:5;
  pointer-events:none}
.deck-nav .wrap{display:flex;justify-content:flex-end;align-items:center;gap:8px}
.deck-nav button{pointer-events:auto;width:30px;height:24px;padding:0;margin:0;border:0;
  background:none;cursor:pointer;display:grid;place-items:center;color:var(--air)}
.deck-nav button::before{content:"";width:8px;height:8px;border-radius:50%;
  background:currentColor;opacity:.45;
  transition:transform .28s cubic-bezier(.34,1.3,.5,1),opacity .28s}
.deck-nav button:hover::before{opacity:.8}
.deck-nav button[aria-selected="true"]::before{opacity:1;transform:scale(1.5)}
.deck-nav button:focus-visible{outline-offset:2px;border-radius:6px}

@media(max-width:899px){
  /* Stacked like the photograph card: clip at the top, edge to edge, copy
     under it on ink. The wrap keeps its gutters for the copy; the box takes
     them back with a negative margin so it meets the sides like the picture. */
  .slide.reel > .wrap{display:block;padding-top:0}
  .reel-box{margin-inline:calc(-1 * var(--gut));border-radius:0;border:0;box-shadow:none}
  .slide.reel .pitch{margin-top:clamp(28px,6vw,44px)}
  .deck-nav .wrap{justify-content:flex-start}
}

/* -- home: who is behind it -------------------------------------------------
   The photograph is on a pure white field, so the section is paper and the
   two meet with no edge at all -- no cutout, no card, no border. That is the
   whole reason this band is light while the ones around it are not. */
.about{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(28px,4vw,72px);align-items:center}

/* The copy is set to the right, so its ragged edge faces the photograph and the
   two share one clean gutter down the middle. Every block in the column carries
   a max-width -- 56ch on the prose, 19ch on the heading -- and a max-width on
   its own would leave them against the left of the column with the ragged edge
   pointing the wrong way, so each is pushed over as well. */
.intro-copy{text-align:right}
.intro-copy h2,.intro-copy p{margin-left:auto}
.intro-copy .eyebrow{justify-content:flex-end}

/* Fills whatever the copy leaves, at every width. The container caps at --maxw
   so the column tops out around 770px and the photograph never has to upscale
   past the 1440w asset behind it.

   The <picture> carries width:100% and that is the whole point of this block.
   Without it the picture is a shrink-to-fit box whose size comes from the
   image's DENSITY-CORRECTED INTRINSIC WIDTH -- `width:100%` on the img is 100%
   of the picture, and the picture's content size is the img, so the circle
   resolves through the intrinsic size and `max-width:100%` merely clamps it.
   That reads as correct on a fresh load only because `sizes` is deliberately a
   little wider than the column at every breakpoint. Drag the window narrow and
   back out and it breaks: the intrinsic width tracks `sizes`, and a browser
   that does not re-evaluate `sizes` upward for an already-loaded image (Safari
   does not) leaves it at the narrow value, so the photograph sits small and
   centred in a wide column until the page is reloaded. Sizing the picture from
   the column instead takes the intrinsic width out of layout entirely. */
.intro-shot{display:block}
.intro-shot picture{display:block;width:100%}
.intro-shot img{display:block;width:100%;height:auto}

@media(max-width:820px){
  .about{grid-template-columns:1fr}
  /* One narrow column, and a ragged left edge is hard to read down a phone. */
  .intro-copy{text-align:left}
  .intro-copy h2,.intro-copy p{margin-left:0}
  .intro-copy .eyebrow{justify-content:flex-start}
}
.about h3{margin-bottom:10px}
.about .pt p{font-size:var(--t-body);line-height:1.6;max-width:56ch}
.about .pt+.pt{margin-top:30px}

/* -- the section rail -------------------------------------------------------
   A line down the right, a dot on it for every section, and the titles to the
   left of it. The section you are in gets a filled circle and its title grows
   and brightens; everything else sits back in grey.

   No panel behind it. That means the rail has to survive both grounds on its
   own, and it does it by taking the colour of the section you are actually in
   -- which works here because the rail is centred on the same midline the spy
   measures, so the band it is coloured for is the band behind its middle. The
   colours transition, so crossing a boundary is a fade rather than a flip.
-------------------------------------------------------------------------- */
:root{
  --sn-w:150px;
  --sn-dot:14px;
  /* Tied to the window height: eight dots and seven gaps have to fit the
     shortest window the rail is allowed to appear in. */
  --sn-gap:clamp(22px,3.4vh,42px);
  /* Pinned to the window, not to the text column, so it sits at the same place
     on the glass at every width. */
  --sn-inset:clamp(16px,1.5vw,30px);
  --sn-lane:calc(var(--sn-inset) + var(--sn-w) + 28px);
}

.sidenav{
  display:none;
  position:fixed;z-index:40;
  right:var(--sn-inset);
  top:0;bottom:0;margin-block:auto;height:max-content;
  width:var(--sn-w);
  /* On the ink bands by default; the spy swaps this when you are on paper. */
  --sn-dim:var(--air-2); --sn-hi:var(--air); --sn-line:var(--ink-line);
  opacity:0;visibility:hidden;transition:opacity .18s,visibility .18s;
}
.sidenav[data-ground="paper"]{--sn-dim:var(--text-2);--sn-hi:var(--text);--sn-line:var(--line-2)}
.sidenav[data-show]{opacity:1;visibility:visible}
.sidenav:focus-within{opacity:1;visibility:visible}

.sn-list{list-style:none;margin:0;padding:0}
.sn-list li{position:relative}
.sn-list li:not(:last-child){padding-bottom:var(--sn-gap)}

.sn-list a{
  display:flex;align-items:center;justify-content:flex-end;gap:16px;
  min-height:20px;text-decoration:none;color:var(--sn-dim);
  transition:color .28s cubic-bezier(.4,0,.2,1);
}
.sn-label{
  font:500 var(--t-label)/1.15 var(--mono);letter-spacing:.14em;text-transform:uppercase;
  text-align:right;
  /* Grows towards the text, not away from the line it is anchored to. */
  transform-origin:right center;transform:scale(1);
  transition:transform .28s cubic-bezier(.4,0,.2,1),color .28s;
}
.sn-dot{
  flex:none;width:var(--sn-dot);height:var(--sn-dot);border-radius:50%;box-sizing:border-box;
  border:2px solid currentColor;background:transparent;
  transition:transform .28s cubic-bezier(.34,1.3,.5,1),background .28s,border-color .28s;
}

/* The run of line from this circle to the next. Drawn per item and stopped
   short at both ends, so it joins the dots rather than running behind them --
   including behind the current one, which is half again its own size. */
.sn-list li:not(:last-child)::after{
  content:"";position:absolute;right:6px;top:23px;bottom:4px;width:2px;
  background:var(--sn-line);
  transition:background .3s;
}
/* Behind you. :has() reads "a later item is the current one", which is the
   whole progress meter -- no measuring, no scroll handler. Where it is not
   supported the segments simply stay at rest. */
.sn-list li:has(~ li a[aria-current])::after{background:var(--sn-dim);opacity:.75}

.sn-list a:hover{color:var(--sn-hi)}
.sn-list a:hover .sn-dot{background:currentColor}

/* Where you are: filled, bigger, brighter. */
.sn-list a[aria-current]{color:var(--sn-hi)}
.sn-list a[aria-current] .sn-dot{background:currentColor;transform:scale(1.5)}
.sn-list a[aria-current] .sn-label{transform:scale(1.22);font-weight:700}

.sidenav a:focus-visible{outline-offset:2px;border-radius:4px}

/* The rail exists only where its lane can come out of the bands without
   squeezing them. Below that it is gone -- the header is the same on every
   page now, so there are no section links there to fall back to. */
@media (min-width:1180px) and (min-height:620px){
  .sidenav{display:block}
  /* The rail is measured from the window edge, so the text only has to give
     way by however much of the lane the outer margin does not already cover.
     Past 1760px + two lanes the wrap stops moving and this settles to --gut. */
  :root.has-sectionnav .band > .wrap,
  :root.has-sectionnav footer > .wrap{
    padding-right:max(var(--gut),calc(var(--sn-lane) - max(0px,(100% - var(--maxw)) / 2)));
  }
}

/* An anchored section would otherwise land behind the sticky header. */
.band[id],.hero[id]{scroll-margin-top:var(--nav)}

/* -- "out in beta now" ------------------------------------------------------
   One line, where the version chip used to do the whole job on its own. Amber
   because amber already means outstanding on this site -- armed, unsaved,
   bench-only -- and a beta is exactly that. */
.beta{display:inline-flex;align-items:center;gap:10px;margin:0 0 20px;
  font:600 var(--t-meta)/1.4 var(--sans);color:var(--air)}
.paper .beta{color:var(--text)}
.beta::before{content:"";width:8px;height:8px;border-radius:50%;flex:none;
  background:var(--warn);box-shadow:0 0 0 4px rgba(163,92,0,.16)}
.band:not(.paper) .beta{color:var(--air)}
.band:not(.paper) .beta::before{background:var(--warn-air);
  box-shadow:0 0 0 4px rgba(227,165,75,.18)}

/* -- disclosures ------------------------------------------------------------
   The page had more reasoning on it than anyone reads standing up. The lead
   stays in the open and the working goes behind this, so the detail is a
   choice rather than a wall -- and nothing had to be deleted to make the page
   shorter. */
.more{margin-top:clamp(22px,2.4vw,38px);border-top:1px solid var(--ink-line)}
.paper .more{border-top-color:var(--line)}
.more > summary{
  list-style:none;cursor:pointer;display:flex;align-items:center;gap:10px;
  padding:16px 0 0;font:600 var(--t-label)/1 var(--mono);letter-spacing:.15em;
  text-transform:uppercase;color:var(--air-2);transition:color .15s;
}
.paper .more > summary{color:var(--text-2)}
.more > summary::-webkit-details-marker{display:none}
.more > summary:hover{color:var(--air)}
.paper .more > summary:hover{color:var(--text)}
/* The chevron is the only thing that moves, and it says which way this goes. */
.more > summary::after{
  content:"";width:7px;height:7px;flex:none;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:rotate(45deg) translate(-1px,-1px);transition:transform .18s;
}
.more[open] > summary::after{transform:rotate(-135deg) translate(-2px,-2px)}
.more > summary:focus-visible{outline:2px solid var(--signal-air);outline-offset:3px;border-radius:4px}
.paper .more > summary:focus-visible{outline-color:var(--signal)}
.more-body{padding-top:18px}

/* -- roadmap: a line you can tick --------------------------------------------
   Each milestone is a node on a line. Add class="done" to an <li> in the source
   and it strikes through, the dot fills, and it is labelled as shipped -- so the
   roadmap becomes the changelog by being edited rather than rewritten.

   The line is drawn per item rather than as one spine down the list, so it
   always stops dead on the last dot however tall that last milestone runs. A
   single spine has to guess where the last dot is, and the guess is wrong the
   moment anyone edits the copy.
-------------------------------------------------------------------------- */
.road-items{list-style:none;margin:0;padding:0}
.road-items li{position:relative;padding:0 0 clamp(40px,3.8vw,68px) 42px}
.road-items li:last-child{padding-bottom:0}

/* The circle, sat on the label's centre line. The offset holds within a pixel
   across the whole range --t-label clamps to. */
.road-items li::before{
  content:"";position:absolute;left:0;top:-1px;width:16px;height:16px;
  border-radius:50%;box-sizing:border-box;
  border:2.5px solid color-mix(in srgb,var(--air) 60%,transparent);
  background:var(--ink);
}
.paper .road-items li::before{background:var(--paper);
  border-color:color-mix(in srgb,var(--text) 45%,transparent)}

/* The run of line to the next circle. */
.road-items li:not(:last-child)::after{
  content:"";position:absolute;left:7px;top:21px;bottom:2px;width:2px;
  background:color-mix(in srgb,var(--air-2) 42%,transparent);
}
.paper .road-items li:not(:last-child)::after{
  background:color-mix(in srgb,var(--text-2) 34%,transparent);
}

/* Ticked. The strike is deliberately faint: it should read as settled, not as
   struck out in anger. */
.road-items li.done::before{border-color:var(--signal-air);background:var(--signal-air)}
.paper .road-items li.done::before{border-color:var(--signal);background:var(--signal)}
.road-items li.done b,.road-items li.done span{
  text-decoration:line-through;
  text-decoration-color:color-mix(in srgb,currentColor 45%,transparent);
  text-decoration-thickness:1px;
}
.road-items li.done b{color:var(--air-2)}
.road-items li.done span{opacity:.62}
.road-items li.done b::after{
  content:"Shipped";margin-left:10px;vertical-align:1px;
  font:600 var(--t-label)/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;
  color:var(--signal-air);text-decoration:none;
}
.paper .road-items li.done b::after{color:var(--signal)}
