/* ─────────────────────────────────────────────────────────────────────────
   DARKROOM — the shared half of the identity.
   Type: Instrument Serif (display) / Newsreader (prose) / JetBrains Mono (data)
   One signal colour. No cards. No radius. Hairlines and register marks.

   This sheet owns the tokens and the chrome every page wears: masthead,
   ribbon, dist-tag row, disclaimer strip, section heads, footer. A page's own
   furniture lives in cc-home.css or cc-detail.css, loaded after this one.

   Ported from notes/mockups/redesign-2026-08/a-darkroom.html and c-changelog.html.
   ───────────────────────────────────────────────────────────────────────── */

:root{
  --sig:#ff5b2e;
  --sig-dim:rgba(255,91,46,.30);
  --sig-ghost:rgba(255,91,46,.09);
  --ease:cubic-bezier(.22,.61,.36,1);
  --measure:1340px;
  --pad:40px;
}

/* The quiet end of the scale sits one rung up from where it started: ink-3
   clears 4.5:1 in both themes, which is the whole reason it moved. The
   relationships between the four rungs are unchanged.

   The add/del pair is the one place this identity carries a second and third
   hue, and it is here rather than in prompts.css because a token that only
   exists in one sheet cannot flip with the theme. A diff is the one thing on
   this site a reader arrives already knowing how to read, and green-for-added
   is the convention they arrive with; spending the signal orange on it instead
   would be a house style that costs comprehension to save a colour. The red is
   pushed to a rose hue on purpose: the signal is orange at 13 degrees, and a
   deletion that lands within a few degrees of it reads as an accent rather
   than a removal. Both clear 4.5:1 on their own theme's background, and colour
   is never the only signal on a line that uses them. */
html[data-theme="dark"]{
  --bg:#0a0a0b; --bg-2:#0f0f11; --raise:#141416;
  --ink:#ece7dd; --ink-2:#a5a098; --ink-3:#8a857c; --ink-4:#706b64;
  --rule:#1d1d20; --rule-2:#2a2a2e;
  --add:#63c98a; --add-dim:rgba(99,201,138,.30); --add-ghost:rgba(99,201,138,.11);
  --del:#f2637e; --del-dim:rgba(242,99,126,.30); --del-ghost:rgba(242,99,126,.11);
  --grain:.035;
  color-scheme:dark;
}
html[data-theme="light"]{
  --bg:#f4f1ea; --bg-2:#eeeae1; --raise:#e7e2d7;
  --ink:#16150f; --ink-2:#4e4a41; --ink-3:#6f6a60; --ink-4:#8f8a7c;
  --rule:#dcd6c8; --rule-2:#c8c1af;
  --add:#137a4a; --add-dim:rgba(19,122,74,.26); --add-ghost:rgba(19,122,74,.09);
  --del:#b8213f; --del-dim:rgba(184,33,63,.24); --del-ghost:rgba(184,33,63,.08);
  --grain:.05;
  color-scheme:light;
}

*{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
body{
  background:var(--bg); color:var(--ink);
  font-family:"Newsreader",Georgia,serif;
  font-size:17px; line-height:1.55;
  font-variant-numeric:tabular-nums;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

/* film grain — the darkroom */
body::after{
  content:""; position:fixed; inset:-50%; pointer-events:none; z-index:9999;
  opacity:var(--grain);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  mix-blend-mode:overlay;
}

::selection{background:var(--sig);color:#0a0a0b}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit}

:where(a,button,input,textarea,[tabindex]):focus-visible{
  outline:1px solid var(--sig); outline-offset:2px;
}

.mono{font-family:"JetBrains Mono",ui-monospace,Menlo,monospace}

/* Every page here quotes real identifiers, and some of them are longer than a
   phone is wide. Inline code does not wrap by default, so one flag name ran
   past the edge and gave a whole release page a horizontal scroll: 3px at
   375px and 58px at 320px, measured 2026-08-16. Break inside the token rather
   than past the edge. A `pre` block is excluded and keeps whatever scroll its
   own sheet gives it, because a wrapped command line is one nobody can copy. */
code{overflow-wrap:anywhere}
pre code{overflow-wrap:normal}
.lbl{
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10.5px; font-weight:500;
  letter-spacing:.19em; text-transform:uppercase; color:var(--ink-3);
}
.shell{max-width:var(--measure); margin:0 auto; padding:0 var(--pad)}

/* Reachable by keyboard and by nothing else, so the first tab on a 358-entry
   page is not "step through the whole masthead". */
.skip{
  position:absolute; left:-9999px; top:0; z-index:200;
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11px; letter-spacing:.14em;
  text-transform:uppercase; background:var(--bg-2); color:var(--ink);
  border:1px solid var(--sig); padding:10px 14px;
}
.skip:focus{left:12px; top:12px}

/* Read aloud and indexed, never drawn. Two places need it: the release page's
   h1, which shows "v2.1.228" and has to say "Claude Code v2.1.228", and the
   archive's ledger heading, which the kicker already carries visually.
   Off-screen would be read by a screen reader too, but it also scrolls the
   page when one of these takes focus, which this does not. */
.vh{
  position:absolute !important; width:1px; height:1px;
  padding:0; margin:-1px; overflow:hidden; border:0; white-space:nowrap;
  clip:rect(0 0 0 0); clip-path:inset(50%);
}

/* ── masthead ───────────────────────────────────────────────────────── */
header.mast{position:sticky; top:0; z-index:60; background:var(--bg); border-bottom:1px solid var(--rule)}
.top{display:flex; align-items:center; gap:28px; height:72px}
/* `overflow:hidden` because the name is `white-space:nowrap`: on the narrowest
   phones the wordmark and the three controls genuinely do not both fit, and
   without this the name paints straight over the search field. Clipped to an
   ellipsis it degrades instead of colliding. */
.mark{display:flex; align-items:center; gap:12px; margin-right:auto; min-width:0; overflow:hidden}
/* The nav's own band. It carries the masthead's background and a hairline of
   its own, so the two rows read as one object rather than as a header with a
   toolbar stuck under it. */
.navrow{display:flex; align-items:center; min-height:34px; padding-block:4px; border-top:1px solid var(--rule-2)}
/* The mark is what sets `.top`'s height, so this number and that one move
   together. `width:auto` overrides the intrinsic width attribute the markup
   carries for layout stability; without it the image would render at its own
   131px and squash. */
.mark .logo{height:48px; width:auto; flex:none; display:block}
.mark .name{font-family:"Instrument Serif",serif; font-size:25px; letter-spacing:.005em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.mark .name em{font-style:italic; color:var(--ink-2)}

nav.site{display:flex; align-items:center; flex-wrap:wrap; gap:6px 23px; width:100%}
nav.site a{
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--ink-3); padding:4px 0;
  border-bottom:1px solid transparent; transition:color .18s, border-color .18s; white-space:nowrap;
}
nav.site a:hover,nav.site a.on{color:var(--ink); border-color:var(--sig)}

/* It takes the whole rest of the row and right-aligns inside it, rather than
   shrinking to its own content. Sized to content it was as wide as the search
   input's *intrinsic* width, which for an `<input>` is its `size` attribute and
   not its stylesheet: `flex-basis` on the field below then had nothing to
   expand into and the box stayed a 20-character stub at every width. */
.acts{display:flex; align-items:center; justify-content:flex-end; gap:9px; flex:1 1 auto; min-width:0}
/* Global search, in the chrome every page wears. Same hairline register as the
   theme toggle beside it, so the masthead stays one object rather than growing
   a widget.

   It is still the only thing in the masthead allowed to shrink, and it now
   shares the row with nothing but the wordmark, so it can be wide enough to
   read a flag name back at any desktop width. The floor below is what stops it
   pushing the wordmark, which is `white-space:nowrap` and would overprint the
   controls rather than give way. */
.msearch{display:flex; align-items:center; flex:0 1 440px; min-width:0}
.msearch input{
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10.5px; letter-spacing:.05em;
  background:var(--bg-2); color:var(--ink); border:1px solid var(--rule-2); border-radius:0;
  padding:6px 9px; width:100%; min-width:90px; line-height:1.35; transition:border-color .18s, background .18s;
  -webkit-appearance:none; appearance:none;
}
.msearch input:focus{outline:0; border-color:var(--sig-dim); background:var(--bg)}
.msearch input::placeholder{color:var(--ink-4); letter-spacing:.08em}
/* The one outbound invitation in the chrome. As a 30px grey square holding an
   11px glyph it read as a third piece of furniture beside the theme toggle and
   the burger, which is to say as something to skip. It carries its own word
   now and the signal colour it is asking for a click with, and it inverts on
   hover rather than tinting. Below 860px the word goes and it is a square
   again, because a phone masthead has no room for it. */
.xb{
  display:flex; align-items:center; gap:8px; height:30px; padding:0 11px;
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10px; letter-spacing:.14em;
  text-transform:uppercase; white-space:nowrap;
  border:1px solid var(--sig-dim); background:var(--sig-ghost); color:var(--sig);
  transition:color .18s, border-color .18s, background .18s;
}
.xb:hover{color:var(--bg); border-color:var(--sig); background:var(--sig)}
.xb svg{width:13px; height:13px; fill:currentColor; display:block; flex:none}
/* The Discord button is the follow button with one colour changed. Blurple is
   fixed rather than a token because it is somebody else's brand and it must not
   move with the theme. */
.xb.dc:hover{border-color:#5865f2; background:#5865f2; color:#fff}
.tog{
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--ink-3); background:none; border:1px solid var(--rule-2); padding:6px 9px; cursor:pointer;
  transition:color .18s, border-color .18s; white-space:nowrap;
}
.tog:hover{color:var(--ink); border-color:var(--ink-3)}
.tog i{font-style:normal}

/* The drawer button. Hidden until the nav stops fitting, which is the only
   place it does anything. */
.burger{
  display:none; width:34px; height:28px; border:1px solid var(--rule-2); background:none;
  cursor:pointer; place-items:center; color:var(--ink-3);
}
.burger:hover{color:var(--ink); border-color:var(--ink-3)}
.burger i{display:block; width:14px; height:1px; background:currentColor; position:relative}
.burger i::before,.burger i::after{content:""; position:absolute; left:0; width:14px; height:1px; background:currentColor; transition:transform .2s var(--ease)}
.burger i::before{top:-5px}
.burger i::after{top:5px}
header.mast[data-nav="open"] .burger i{background:transparent}
header.mast[data-nav="open"] .burger i::before{transform:translateY(5px) rotate(45deg)}
header.mast[data-nav="open"] .burger i::after{transform:translateY(-5px) rotate(-45deg)}

/* ── status ribbon ──────────────────────────────────────────────────── */
.ribbon{position:relative; border-bottom:1px solid var(--rule); background:var(--bg-2)}
/* It scrolls sideways at every width, not just on a phone. Folded into one row
   the cells run past the measure from about 1200px down, and `overflow:hidden`
   would silently cut the feed links off the right-hand end with nothing to say
   they were there. The scrollbar itself is hidden, so a wide screen sees no
   trace of it. */
.ribbon .shell{
  display:flex; align-items:center; gap:0; height:34px;
  overflow-x:auto; overflow-y:hidden; scrollbar-width:none; -ms-overflow-style:none;
}
.ribbon .shell::-webkit-scrollbar{display:none}
.rb{
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10.5px; letter-spacing:.13em;
  text-transform:uppercase; color:var(--ink-3); white-space:nowrap;
  padding-right:20px; margin-right:20px; border-right:1px solid var(--rule);
}
.rb b{color:var(--ink); font-weight:500}
.rb:last-child{border:0; padding-right:0; margin-right:0}
.live{display:inline-block; width:5px; height:5px; background:var(--sig); border-radius:50%; margin-right:8px; vertical-align:middle; animation:pulse 2.4s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.25}}

/* The dist-tags and the feeds share the ribbon now rather than holding a band
   of their own. They keep a lighter ink than the machine-state cells to its
   left, which is what is left of the two registers once the row is folded. */
.tg{
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10.5px; letter-spacing:.13em;
  text-transform:uppercase; color:var(--ink-4); white-space:nowrap;
  padding-right:20px; margin-right:20px; border-right:1px solid var(--rule);
}
.tg a{color:var(--ink-2); border-bottom:1px solid var(--rule-2); padding-bottom:1px; transition:color .18s, border-color .18s}
/* A tag npm has published that this site has not read yet: named, not linked. */
.tg .none{color:var(--ink-3); border-bottom:1px dotted var(--rule-2); padding-bottom:1px}
.tg a:hover{color:var(--sig); border-color:var(--sig)}
.tg.feeds{margin-left:auto; padding-right:0; margin-right:0; border-right:0; display:flex; align-items:center; gap:16px}
.tg.feeds a{color:var(--sig); border-bottom-color:var(--sig-dim)}
.tg.feeds a:hover{border-bottom-color:var(--sig); background:var(--sig-ghost)}

/* ── the live band ──────────────────────────────────────────────────────
   What the pipeline is doing right now, on every page, and only while it is
   doing something. It borrows the ribbon's geometry on purpose: same 34px row,
   same monospace micro-caps, same sideways scroll rather than an `overflow:
   hidden` that would cut a cell off with nothing to say it was there. The
   signal orange and the pulsing dot are the ribbon's own; nothing new is
   invented here, because the band should read as a row that was always in the
   chrome and happens to be lit.

   The row is `min-height` rather than `height`, so a cell that grows or
   disappears as the run advances never resizes the band and never moves the
   page under a reader's cursor. The band appearing or vanishing between two
   page loads is a real reflow and is meant to be: it is a strip of chrome, in
   flow, exactly like the disclaimer under it. */
.pline{position:relative; border-bottom:1px solid var(--rule); background:var(--bg-2)}
.pline .shell{
  display:flex; align-items:center; gap:0; min-height:34px;
  overflow-x:auto; overflow-y:hidden; scrollbar-width:none; -ms-overflow-style:none;
}
.pline .shell::-webkit-scrollbar{display:none}
.pl{
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:10.5px; letter-spacing:.13em;
  text-transform:uppercase; color:var(--ink-3); white-space:nowrap;
  padding-right:20px; margin-right:20px; border-right:1px solid var(--rule);
}
.pl:last-child{border-right:0; padding-right:0; margin-right:0}
.pl[hidden]{display:none}
/* The headline is the one cell that is a sentence rather than a reading, so it
   keeps the ink the ribbon reserves for values. */
.pl.hd b{color:var(--ink); font-weight:500}
/* A note is prose the pipeline wrote, so it is the one cell that is not
   shouted, and the one allowed to run long enough to be worth reading. */
.pl.note{text-transform:none; letter-spacing:.02em; font-size:11px; color:var(--ink-2)}

/* A hairline that fills. No radius and no gradient: it is the same rule the
   rest of the chrome is drawn with, one shade brighter. */
.pl.bar{width:96px; height:3px; padding-right:0; margin-right:20px; border-right:0; background:var(--rule-2)}
.pl.bar i{display:block; height:100%; background:var(--sig); transition:width .4s var(--ease)}

/* Failed says so in the deletion hue rather than in the signal, which
   everywhere else on this site means "look here", not "this went wrong". The
   dot stops pulsing, because nothing is running. */
.pline[data-state="failed"] .live{background:var(--del); animation:none}
.pline[data-state="failed"] .pl.hd b{color:var(--del)}
/* Deferred is a wait rather than work: the dot is lit and still. */
.pline[data-state="deferred"] .live{animation:none}

@media(max-width:1200px){
  .pl{padding-right:14px; margin-right:14px}
  .pline::after{
    content:""; position:absolute; top:0; right:0; bottom:0; width:34px; pointer-events:none;
    background:linear-gradient(to right, transparent, var(--bg-2));
  }
}

@media(max-width:860px){
  .pl{padding-right:16px; margin-right:16px}
  .pl.bar{width:64px}
}

/* ── the honesty strip ──────────────────────────────────────────────── */
/* It sits in the chrome under the masthead because it qualifies the whole site
   rather than one release, and a reader crossing between two pages should meet
   one strip, not two. */
.honest{background:var(--bg-2); border-bottom:1px solid var(--rule)}
.honest .shell{padding-block:11px}
.honest p{font-size:11.4px; line-height:1.56; color:var(--ink-2); font-weight:300}
.honest .t{color:var(--sig); margin-right:9px; font-size:9px; position:relative; top:-.5px}
.honest b{color:var(--ink); font-weight:500}

/* ── section heads ──────────────────────────────────────────────────── */
.head{display:flex; align-items:center; gap:20px; margin-bottom:8px}
.head h2{
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:12px; font-weight:700;
  letter-spacing:.24em; text-transform:uppercase; color:var(--ink); white-space:nowrap;
}
.head .ln{flex:1; height:1px; background:var(--rule-2)}
.head .ct{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11px; letter-spacing:.12em; color:var(--ink-3); white-space:nowrap}
.head .ct b{color:var(--sig); font-weight:500}
.sub{font-size:17px; color:var(--ink-2); max-width:74ch; margin-bottom:38px; font-weight:300; line-height:1.6}
.sub b{color:var(--ink); font-weight:400}

/* ── the ledger ─────────────────────────────────────────────────────── */
/* One row per published version. The homepage shows the last thirty and the
   archive shows all 457, so the row treatment is shared rather than restated
   in two sheets that would drift. */
.mk-gap{color:var(--sig)}

.rel{border-top:1px solid var(--rule)}
.rr{
  display:grid; grid-template-columns:118px 92px 1fr 210px 46px; gap:26px; align-items:baseline;
  padding:16px 12px 16px 0; border-bottom:1px solid var(--rule); transition:background .18s;
}
.rr:hover{background:var(--bg-2)}
.rr .vv{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:16px; font-weight:500; padding-left:12px}
.rr .vv.new{color:var(--sig)}
.rr .dd{font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11px; color:var(--ink-4); letter-spacing:.06em}
.rr .hh{
  font-size:16.5px; font-weight:300; color:var(--ink-2); line-height:1.45;
  display:-webkit-box; -webkit-line-clamp:1; line-clamp:1; -webkit-box-orient:vertical; overflow:hidden;
}
.rr .cc{display:flex; gap:14px; font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11px; color:var(--ink-3); justify-content:flex-end; white-space:nowrap}
.rr .cc b{color:var(--ink); font-weight:500}
.rr .cc .dk{color:var(--sig)}
.rr .oo{text-align:right; font-family:"JetBrains Mono",ui-monospace,monospace; font-size:13px; color:var(--ink-4)}
.rr .oo.avail{color:var(--ink-2)}
.rr .oo.gap{color:var(--sig)}

.more{margin-top:30px; font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11px; letter-spacing:.14em; text-transform:uppercase}
.more a{color:var(--sig); border-bottom:1px solid var(--sig-dim); padding-bottom:2px}
.more a:hover{border-color:var(--sig)}

/* ── footer / method ────────────────────────────────────────────────── */
footer.method-foot{margin-top:96px; border-top:1px solid var(--rule-2); padding:44px 0 80px}
.fgrid{display:grid; grid-template-columns:1fr 380px; gap:72px}
.method{font-size:16.5px; line-height:1.65; color:var(--ink-2); font-weight:300; max-width:62ch}
.method p+p{margin-top:16px}
.method b{color:var(--ink); font-weight:650}
.method h3{
  font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11px; font-weight:700;
  letter-spacing:.2em; text-transform:uppercase; color:var(--ink); margin-bottom:10px;
}
.method h3+p{margin-top:0}
.meta{display:grid; grid-template-columns:auto 1fr; gap:9px 22px; font-family:"JetBrains Mono",ui-monospace,monospace; font-size:11px}
.meta dt{color:var(--ink-4); letter-spacing:.1em; text-transform:uppercase; font-size:10px}
.meta dd{color:var(--ink-2); overflow-wrap:anywhere}
.meta a{color:var(--sig); border-bottom:1px solid var(--sig-dim)}
.meta a:hover{border-color:var(--sig)}
.meta.contact{margin-top:26px; padding-top:22px; border-top:1px solid var(--rule)}
.meta.contact dd{line-height:1.7}

/* ── responsive chrome ──────────────────────────────────────────────── */

/* Where the folded status row stops fitting. The cells tighten and the right
   edge fades so the row reads as continuing rather than as cut off: the feed
   links live at that end and this row is the only place on the page that
   offers them. */
@media(max-width:1200px){
  .rb,.tg{padding-right:14px; margin-right:14px}
  .ribbon::after{
    content:""; position:absolute; top:0; right:0; bottom:0; width:34px; pointer-events:none;
    background:linear-gradient(to right, transparent, var(--bg-2));
  }
}

@media(max-width:1080px){
  :root{--pad:28px}
  .fgrid{grid-template-columns:1fr; gap:44px}

  /* The headline and the counts take a row of their own rather than being
     squeezed to nothing, and the register mark stays on the version's line. */
  .rr{grid-template-columns:104px 1fr 46px; gap:6px 16px}
  .rr .vv{padding-left:0}
  .rr .dd{grid-column:2; justify-self:start}
  .rr .hh,.rr .cc{grid-column:1 / -1; text-align:left; justify-content:flex-start}
  .rr .oo{grid-column:3; grid-row:1}
}

/* Below this the nav does not fit, so it becomes a drawer rather than
   disappearing. A site whose navigation vanishes on a phone has no navigation. */
@media(max-width:860px){
  :root{--pad:18px}
  /* `padding-block`, not the shorthand: `.top` shares its element with
     `.shell`, so `padding:8px 0` here zeroed the sides and stood the
     wordmark and both buttons flush against the screen edges on every
     phone, while the nav row under them kept their inset. */
  .top{height:auto; min-height:52px; gap:10px 14px; flex-wrap:wrap; padding-block:8px}
  .mark .logo{height:38px}
  .mark .name{font-size:19px}
  .burger{display:grid}
  .tog{padding:6px 7px; font-size:9px}
  /* The search takes a line of its own rather than a slot on the wordmark's.
     Sharing that line it was 83px wide at 375px and 58px at 320px, which is a
     box that shows "Search a" and holds about six characters of what a reader
     types: the control the site is for, rendered as a stub. `display:contents`
     on the group lets the four controls wrap as children of the masthead row
     itself, so the wordmark keeps the first line whole and the field spans the
     width under it. It stays out of the burger menu on purpose: search is the
     reason a reader lands here, and a control behind a menu is a control
     nobody finds. */
  .acts{display:contents}
  .msearch{order:5; flex:1 0 100%}
  .msearch input{min-width:0; padding:7px 9px}
  /* Glyph only. The word costs about 60px, which on a phone is the difference
     between the search field being usable and being a stub. */
  .xb{padding:0 8px; height:28px}
  .xb span{display:none}

  /* The nav's band disappears as a box, so the masthead is one 52px row again
     and the drawer below hangs off its bottom edge. `contents` rather than
     `none`: the nav itself must stay displayable for the burger to open it. */
  .navrow{display:contents}
  nav.site{
    display:none; position:absolute; left:0; right:0; top:100%;
    flex-direction:column; flex-wrap:nowrap; align-items:stretch; gap:0;
    background:var(--bg); border-bottom:1px solid var(--rule-2);
    padding:6px var(--pad) 14px; max-height:calc(100dvh - 52px); overflow:auto;
  }
  header.mast[data-nav="open"] nav.site{display:flex}
  nav.site a{
    font-size:12px; letter-spacing:.16em; padding:13px 0;
    border-bottom:1px solid var(--rule); border-top:0;
  }
  nav.site a:hover,nav.site a.on{border-color:var(--rule); color:var(--ink)}
  nav.site a.on{color:var(--sig)}

  .rb,.tg{padding-right:16px; margin-right:16px}
  .tg.feeds{margin-left:24px; gap:12px}
  .honest p{font-size:12px}
  footer.method-foot{margin-top:64px; padding:34px 0 56px}
  .method{font-size:16px}
  /* The count on the right is nowrap, so on a phone it used to run off the
     side and give the whole page a horizontal scroll. Let it drop to its own
     line under the rule instead. */
  .head{gap:4px 12px; flex-wrap:wrap}
  .head h2{font-size:11px; letter-spacing:.18em}
  .head .ln{min-width:24px}
  .head .ct{font-size:10px}
  .sub{font-size:16px; margin-bottom:28px}

  .rr{padding:14px 0; gap:5px 12px}
  .rr .vv{font-size:15px}
  .rr .hh{font-size:15.5px; -webkit-line-clamp:2; line-clamp:2}
  .rr .cc{font-size:10.5px; gap:12px; flex-wrap:wrap}
}

/* The narrowest phones still in use. "Source Intelligence" plus three controls
   do not both fit at 320, and the wordmark loses: it sits under `margin-right:
   auto` with `white-space:nowrap`, so it silently overprints the controls
   instead of wrapping. The site's name is the thing worth keeping, so the
   toggle drops its words and keeps the sun; its aria-label still says which
   way it goes. */
@media(max-width:420px){
  :root{--pad:14px}
  .mark{gap:9px}
  .mark .logo{height:32px}
  .mark .name{font-size:17px}
  .tog{padding:6px 8px; font-size:12px; letter-spacing:0}
  .tog i{display:none}
}

@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms !important; animation-iteration-count:1 !important; transition-duration:.001ms !important}
}
