/* ============================================================
   feed.css — the v2 Feed, APPENDED to signal.css by the packager.

   SCOPING IS THE LAW OF THIS FILE. These rules ride at the end of the
   shared stylesheet and therefore load on EVERY page of the site —
   article pages, v1 tag rivers, the lot. Two disciplines:
     1. Shell rules (viewport lock, flex column) live under body.feedhome,
        which only index.hbs sets. An unscoped html/body overflow here
        would freeze scrolling on every article page.
     2. Vocabulary v1 also owns (.card, .dek, .cred, .trail, .quote, .wim,
        .acts, .inst, .dev, .rcpb…) is scoped to the v2 CONTAINERS —
        :is(.app, .deckroot, .recwrap, .recdoc) — so the Feed's grammar can
        never restyle a v1 surface.
        CONTAINERS, not body classes, and this bit twice in one day: a
        channel deck extends v1's layout, so its body never carries
        feedhome. Scoped to the body class, a deck lost the why-block's
        box and — worse — showed the visually-hidden headline as type
        directly under the plate that already carried it.
   Everything else (pg*, rec*, brkbar, u-*, story*, tl/bd/brep) is
   v2-unique and safe bare.
   ============================================================ */

/* ---- v2 tokens ----
   Scoped to .sg, not :root, because that is where this theme keeps every
   token (a layer outside .sg paints with undefined variables — the iOS
   transparent-sheet incident). Two families:

   MOTION. Measured off Flipboard first (2026-09-07) — card-level moves
   ~160ms, the article push ~200ms — then tuned by the owner on the phone
   to 140ms for card-level, which is where it stopped feeling like a
   transition and started feeling like a cut. The layer push stays at the
   measured 200ms: it travels the full width of the screen, and the same
   duration that reads as crisp over a page height reads as a snatch over
   a whole viewport.

   NEITHER OF THESE IS THE SNAP. The pager's physics belong to the browser
   and expose no timing at all — which is the entire reason the flick feels
   right and the reason the fold was deleted. These tokens govern only the
   motion we own: the cover-to-deck transition and the breaking bar.

   THE BREAKING BAND, designed for both grounds. It cannot use --ink,
   which inverts to near-white in dark mode and would flip the bar's
   ground to paper. Dark is now the default surface, so the band is an
   elevated dark strip under a red rule; light keeps the ink band. */
.sg{
  --t-card:140ms; --t-layer:200ms; --ease-card:cubic-bezier(.3,.7,.25,1);
  --brk-bg:#131211; --brk-fg:#FFFFFF; --brk-hot:#FF6A54; --brk-rule:transparent;
  /* On paper the tile is white with a hairline, or it disappears into the
     page it is supposed to sit on. */
  --srcchip:#FFFFFF; --srcchip-ln:rgba(19,18,17,.16);
}
.sg[data-mode="dark"]{
  --brk-bg:#1B1B20; --brk-fg:#F7F5F0; --brk-hot:#FF6A54; --brk-rule:#E8412B;
  /* A DIMMED neutral, not paper white (owner, 2026-09-07: "drop the chip
     from cream to a dimmer neutral, so three little tiles don't
     out-brighten the deks on a very dark cover"). Bright enough that a
     light publisher mark still reads on it, dark enough to sit under the
     dek rather than in front of it. */
  --srcchip:#CFCAC2; --srcchip-ln:transparent;
}

/* ---- shell: header row, breaking bar, then the pager owns the rest ----
   SCOPE NOTE, twice revised.
   2026-09-07 (morning): shell CHILDREN were scoped to the v2 containers
   (.app on the cover, .deckroot on a channel deck) rather than to
   body.feedhome, because a channel deck extends v1's layout and its body
   class never carries feedhome — that mistake cost the deck its header
   and brief twice in one day.
   2026-09-07 (later): the HEADER's own rules are now scoped to NOTHING,
   because .fhead renders on every page of the site — post pages, reporter
   dossiers, About, the 404 — as of the chrome standardization. Container
   scoping would have left it unstyled on exactly the pages that needed
   fixing. That is safe here and only here: .fhead, .fwm, .hbtn, .qform,
   .chbtn, .chsheet, .chip and .chx are v2-unique, verified as ZERO hits
   each in v1's signal.css. Everything that is genuinely v1-shared
   vocabulary (.card, .cred, .trail, .quote, .wim, .inst, .dev) stays
   container-scoped and a test refuses it bare. */
body.feedhome{height:100%;overflow:hidden}
/* --shellh, set by fitShell() from visualViewport.height, is the height
   that actually holds: svh over-reported on the owner's iPhone under
   Safari's expanded bottom chrome and pushed the deck bar off-screen.
   The svh below it is the PRE-JS value and must stay — it is what paints
   before feed.js measures.
   Why the fallback is svh and not dvh (owner caught content under the
   Safari toolbar, 2026-09-07): dvh tracks the toolbar and shrinks AFTER
   layout, so a page
   laid out with the toolbar hidden gets clipped when it slides back in.
   svh is the smallest viewport: the page always fits, at the cost of a
   little unused space when the toolbar is away. For a pager where a
   clipped sentence is a defect, that is the right trade. */
.feedhome .sg{height:100vh;height:100svh;height:var(--shellh,100svh);display:flex;flex-direction:column}
.feedhome .app{flex:1;min-height:0;display:flex;flex-direction:column;width:100%;max-width:760px;
  margin:0 auto;background:var(--paper)}
.fhead{flex:none;position:relative;z-index:60;background:var(--paper);border-bottom:1px solid var(--ink)}
.fwm{font-family:var(--display);font-size:20px;font-weight:800;letter-spacing:-.042em;color:var(--ink);text-decoration:none}
.fwm i{font-style:normal;font-weight:400;color:var(--ink2)}
/* THE WAY BACK ALSO LIVES AT THE TOP (same report as the .dbar note).
   The header is the one edge the browser's chrome never occupies, and the
   wordmark was already the ruled way home — owner, 2026-09-07: "The
   Fabric.Media logo should always take you to the top of the cover." So
   it wears the arrow rather than competing with a second control, and the
   arrow teaches what the wordmark already did. Only inside a deck: on the
   cover there is nowhere back to. */
/* THE ARROW SHOWS ON EVERY PAGE THAT IS NOT THE COVER (owner, 2026-09-09,
   landing on a shared signal: "when I land on that share there is no way
   to get back to The Signal"). It was scoped to the two DECK states, which
   was right when a deck was the only place you could be lost — but a share
   link now lands readers on post pages, story records and dossiers, and on
   every one of them the wordmark was an unmarked link. body.feedhome is
   the cover document and the only page with nowhere to go back to. */
/* THE SLOT IS ALWAYS THERE; ONLY THE ARROW COMES AND GOES (owner,
   2026-09-09: "What I don't like is that the logo moves"). It did —
   prefixing the wordmark shifted it ~24px the moment you left the cover,
   so the one fixed landmark in the chrome was the thing that jumped.
   A nav bar reserves its leading slot whether or not there is a back
   control in it, and the title holds still. Same here: the glyph is
   rendered on every surface and merely made invisible on the cover, so
   the wordmark sits at one x from the cover to a record. */
.fwm::before{content:"\2190";margin-right:9px;font-family:var(--mono);
  font-size:15px;font-weight:400;color:var(--ink3);vertical-align:1px;visibility:hidden}
:is(.app.indeck,.deckroot) .fwm::before,
body:not(.feedhome) .fwm::before{visibility:visible}
.hbtn{font-family:var(--mono);font-size:9px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink3);border:1px solid var(--ln2);background:transparent;padding:7px 9px;cursor:pointer;text-decoration:none}
.hbtn:hover{border-color:var(--ink);color:var(--ink)}
/* THE CHROME ALIGNS TO THE PAGE'S OWN COLUMN, whichever that is (QA,
   2026-09-07). Standardizing the header onto every page introduced the
   exact defect the owner reported that morning about the deck — "still
   seeing 'back' and the record way out on the width border" — on a new set
   of pages. Measured at 1440 on a post page: .fhead spanned the full 1440
   with the wordmark at 16px while the article's content started at 112,
   misaligned by 96px, and .ffoot had NO padding at all because its only
   rule was scoped to the v2 containers.
   Three columns exist on this site and the chrome now matches each:
     v1-templated pages  .in, max-width var(--wrap) + var(--pad)  -> 112 @1440
     the cover / a deck  the 760px shell, 16px inset
     inside a deck       .pgin's 620px reading column
   Base rule is the .in column with a 16px floor, so nothing moves below
   the width where --wrap binds. */
.fhead .r1{display:flex;align-items:center;gap:10px;
  padding:9px max(16px, calc((100% - var(--wrap)) / 2 + var(--pad)))}
/* A v2 shell IS already a 760px column; its chrome sits at the shell's own
   inset, matching the cover's text. */
:is(.app,.deckroot) .fhead .r1{padding-inline:16px}
/* ---- SEARCH: AN ICON THAT BECOMES A FIELD ----
   The row is three controls wide on a 375px phone and the field was
   spending half of it on a placeholder. Collapsed it is a 34px button;
   .fhead.searching gives it the row and stands the channel chip down,
   because expanded field + chip + wordmark do not fit a phone and
   squeezing all three is how the field got small enough to be useless.
   The input stays in the DOM at every state — it is a real form, it still
   submits without JS, and collapsing is a width change rather than a
   teardown, so a half-typed query survives an accidental collapse. */
.qform{flex:none;margin:0;display:flex;align-items:center;min-width:0;
  transition:flex-grow 140ms var(--ease-card,ease)}
.qbtn{flex:none;width:34px;height:32px;display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--ln2);background:transparent;color:var(--ink2);cursor:pointer;padding:0}
.qbtn:hover{border-color:var(--ink);color:var(--ink)}
.qform input{width:0;flex:1;min-width:0;padding:0;border:0;background:var(--el);color:var(--ink);
  font-family:var(--mono);font-size:9.5px;letter-spacing:.08em;text-transform:uppercase;
  opacity:0;pointer-events:none;transition:opacity 120ms linear}
.qform input::placeholder{color:var(--ink3);text-transform:uppercase}
.qform input:focus{outline:none}
.fhead.searching .qform{flex:1 1 auto}
.fhead.searching .qbtn{border-right:0}
.fhead.searching .qform input{width:auto;opacity:1;pointer-events:auto;padding:8px 10px;
  border:1px solid var(--ln2);border-left:0}
.fhead.searching .chbtn{display:none}
@media (prefers-reduced-motion:reduce){.qform,.qform input{transition:none}}
.chbtn{white-space:nowrap;flex:none}
.chsheet{position:absolute;left:0;right:0;top:100%;border-top:1px solid var(--ln);background:var(--el);
  padding:12px 16px 14px;box-shadow:0 14px 28px rgba(19,18,17,.12);z-index:61}
.chsheet .chips{display:flex;flex-direction:column;gap:2px}
.chip{display:flex;width:100%;justify-content:flex-start;font-family:var(--mono);font-size:10.5px;
  font-weight:600;letter-spacing:.16em;text-transform:uppercase;padding:11px 10px;border:0;
  border-bottom:1px solid var(--ln);color:var(--ink2);text-decoration:none}
.chip.on{background:var(--el2);color:var(--ink)}
.chip .dot{display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--cc,var(--ink3));
  margin-right:6px;align-self:center}
.chx{display:flex;gap:8px;margin-top:12px}

/* ---- the breaking bar (design pass, 2026-09-07) ----
   Measured on the live bar with a real breaking story up: 44 of 82
   headline characters were clipped to one ellipsized line, the page
   counter was overlapping what survived, there was no time at all, and a
   full-bleed saturated red band sat directly above a saturated channel
   plate — two big colour fields fighting for the same screen.

   Four decisions:
   1. THE GROUND IS INK, NOT RED. The theme already speaks in inverted
      ink bands (footer, units, follow bar), and ink does not compete with
      six channel hues. Red stays reserved and therefore precious: it is
      the pip and the word, not the field.
   2. THE HEADLINE NEVER CLIPS. Two lines, clamped — a breaking headline
      is the last text on the site that should be truncated.
   3. THE TIME IS THE NEWS. "Breaking" in red says the class; HH:mm says
      how breaking. v1's strip carried a time and the port dropped it.
      Colour never carries the meaning alone (the word is still there).
   4. THE BAR YIELDS. Its job is to point at something NOT on your screen;
      once you reach that signal the plate's own red frame and chip say it
      twice over, so the bar collapses to a hairline (.seen) and stops
      taxing 4.6% of every full-viewport page for 24 hours. */
.brkbar{flex:none;display:grid;grid-template-columns:auto 1fr;gap:5px 12px;align-items:baseline;
  padding:9px 15px 11px;background:var(--brk-bg);color:var(--brk-fg);text-decoration:none;
  border-bottom:2px solid var(--brk-rule);
  overflow:hidden;max-height:110px;
  transition:padding var(--t-card) ease,max-height var(--t-card) ease,background var(--t-card) ease}
.brkbar .k{grid-column:1;display:flex;align-items:center;gap:7px;font-family:var(--mono);font-size:8.5px;
  font-weight:600;letter-spacing:.2em;text-transform:uppercase;color:var(--brk-hot)}
.brkbar .k::before{content:"";width:5px;height:5px;border-radius:50%;background:#E8412B;flex:none;
  box-shadow:0 0 0 3px rgba(232,65,43,.28);animation:brkpip 2.4s ease-in-out infinite}
.brkbar .tm{grid-column:2;justify-self:end;font-family:var(--mono);font-size:8.5px;letter-spacing:.12em;
  color:color-mix(in srgb, var(--brk-fg) 52%, transparent);font-variant-numeric:tabular-nums}
.brkbar .h{grid-column:1/-1;font-family:var(--display);font-size:15px;font-weight:700;letter-spacing:-.022em;
  line-height:1.2;color:var(--brk-fg);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
@keyframes brkpip{0%,100%{opacity:1}50%{opacity:.3}}
@media (prefers-reduced-motion:reduce){.brkbar,.brkbar .k::before{transition:none;animation:none}}
/* Yielded: the reader has reached (or tapped through to) the signal the
   bar was pointing at. .instant is the already-read-on-arrival case — the
   bar should render small, not animate down while you watch. */
.brkbar.instant{transition:none}
.brkbar.seen{max-height:4px;padding:0;background:#E8412B}
.brkbar.seen>*{opacity:0}
/* The counter clears the bar. :has() rather than a JS class — the bar's
   presence is a fact about the document, and the overlap was a live
   defect the port introduced by carrying the offset only in the
   prototype. */

/* ---- the pager ---- */
#app.fpager{flex:1;min-height:0;position:relative;overflow-y:auto;
  scroll-snap-type:y mandatory;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;scrollbar-width:none}
#app.fpager::-webkit-scrollbar{width:0}
.pg{height:100%;scroll-snap-align:start;scroll-snap-stop:always;border-bottom:1px solid var(--ln);
  overflow:hidden;position:relative;content-visibility:auto}
.pg[hidden]{display:none}
.pgin{height:100%;display:flex;flex-direction:column;max-width:620px;margin:0 auto;width:100%;
  padding:14px 16px calc(14px + env(safe-area-inset-bottom))}
.pg.card{cursor:pointer;padding:0}
.pg.card:focus-visible{outline:2px solid var(--acc);outline-offset:-2px}
.pg .pgh{margin:0;font-family:var(--display);font-size:24px;font-weight:800;letter-spacing:-.035em;line-height:1.06}
.pg .pgh a{color:var(--ink);text-decoration:none}
.pg .kick{margin-bottom:10px;flex:none}
.pg .plate{aspect-ratio:16/9;flex:none}
/* ---- the watch affordance ----
   A video signal keeps its plate (identity + headline) and gains a play
   control; playing swaps the plate for the iframe in place. The control
   is a real <button> so the page-wide record tap leaves it alone. */
.cardlink.haswatch{position:relative}
.playbtn{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:4;
  display:inline-flex;align-items:center;gap:9px;padding:11px 16px 11px 13px;cursor:pointer;
  background:rgba(10,10,12,.72);border:1px solid rgba(255,255,255,.55);color:#fff;
  backdrop-filter:blur(3px);font-family:var(--mono);font-size:9px;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase}
.playbtn:hover{background:rgba(10,10,12,.88);border-color:#fff}
.playbtn i{width:0;height:0;border-left:11px solid #fff;border-top:7px solid transparent;
  border-bottom:7px solid transparent;flex:none}
.pg .watch{margin:0;flex:none}
.pg .watch iframe{display:block;width:100%;aspect-ratio:16/9;height:auto;border:0;background:#000}
/* The chart is DATA, so it is never cropped: it keeps its own aspect ratio
   inside the space the plate had, and the caption is the publication's own
   words. A chart cropped to 16/9 is a chart with its axis cut off. */
.chartbtn b{width:13px;height:13px;flex:none;position:relative}
.chartbtn b::before,.chartbtn b::after{content:"";position:absolute;bottom:0;width:3px;background:#fff}
.chartbtn b::before{left:1px;height:7px}
.chartbtn b::after{left:6px;height:13px}
.pg .chartfig{display:flex;flex-direction:column;gap:7px;min-height:0;overflow:hidden}
.pg .chartfig img{display:block;width:100%;height:auto;max-height:46vh;object-fit:contain;
  background:var(--el2);border:1px solid var(--ln)}
.pg .chartfig figcaption{font-family:var(--mono);font-size:8.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink3);line-height:1.5}
.pg .chartfig.failed{border:1px dashed var(--ln2);padding:18px;align-items:center;justify-content:center}
.pg .chartfig.failed p{margin:0;font-family:var(--mono);font-size:9px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink3)}
@media (max-height:700px){.pg .plate{aspect-ratio:16/8}}
/* WHICH TEXT MAY BE CLAMPED, AND WHY (2026-09-07). Both of these had
   fixed clamps and both were being cut mid-line once the breaking bar
   took 75px off the page. They are not equal, though: the dek is
   reproduced in full inside the Record's lead card, while the why was
   cut from the Record on 2026-09-01 and exists ONLY here. So the dek is
   the single flexible item — it absorbs all the slack, and feed.js sets
   its clamp from the space actually available (--dl) so the cut always
   lands on a line boundary instead of through a word. */
.pg .dek{font-family:var(--body);font-size:16.5px;line-height:1.47;color:var(--ink2);margin:14px 0 0;
  /* SHRINK, NEVER GROW. flex-grow:1 made the dek's BOX taller than its
     text once the clamp was computed, opening a dead gap between the dek
     and the why (owner screenshot, 2026-09-07). The clamp already fits
     the space; the box must not claim more than its lines. */
  flex:0 1 auto;min-height:0;overflow:hidden;
  display:-webkit-box;-webkit-line-clamp:var(--dl, 5);-webkit-box-orient:vertical}
.pg .dev{flex:none;margin:0 0 10px}
/* The why is NEVER truncated — it has no full copy anywhere else. */
.pg .wim{flex:none;margin-top:13px}
.pg .cred{flex:none}
.pgfoot{margin-top:auto;flex:none;display:flex;gap:8px;align-items:stretch;padding-top:14px}
.pgfoot .orig{flex:1;display:flex;align-items:center;justify-content:center;gap:7px;padding:12px 13px;
  font-family:var(--mono);font-size:9.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;
  border:1px solid var(--acc);color:var(--acc);text-decoration:none;text-align:center}
.pgfoot .orig:hover{background:var(--acc-t)}
.pgfoot .orig.dis{border-color:var(--ln2);color:var(--ink3);opacity:.55}
.pgfoot .shr{flex:none;display:flex;align-items:center;justify-content:center;padding:11px 15px;
  border:1px solid var(--ln2);background:transparent;cursor:pointer;color:var(--ink3)}
.pg--fin{display:flex;flex-direction:column;justify-content:flex-end;overflow-y:auto}
.pgcount{position:fixed;right:10px;top:calc(60px + var(--brk-h, 0px) + 8px);z-index:40;pointer-events:none;
  font-family:var(--mono);font-size:8.5px;letter-spacing:.12em;color:var(--ink3);
  background:var(--paper);border:1px solid var(--ln);padding:4px 7px}
.reccue{position:absolute;right:0;top:14px;font-family:var(--mono);font-size:9px;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;color:var(--ink3)}

/* ---- the Feed's page/card grammar, scoped to v2 contexts only ---- */
:is(.app,.deckroot,.recwrap,.recdoc) .card h3.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
:is(.app,.deckroot,.recwrap,.recdoc) .cardlink{display:block;text-decoration:none;color:inherit}
:is(.app,.deckroot,.recwrap,.recdoc) .card .tier.brk{color:#E8412B;border-color:#E8412B}
:is(.app,.deckroot,.recwrap,.recdoc) .card .plate .brk-x::after{content:none}
.recwrap .card,.recdoc .card{display:block;border-bottom:0;padding:0 0 8px}
.recwrap .card .plate,.recdoc .card .plate{aspect-ratio:16/9}
.recwrap .card .dek,.recdoc .card .dek{font-family:var(--body);font-size:16.5px;line-height:1.47;color:var(--ink2);margin:14px 0 0}
:is(.app,.deckroot,.recwrap,.recdoc) .wim{padding:12px 14px;border-left:3px solid var(--acc);background:var(--el2)}
:is(.app,.deckroot,.recwrap,.recdoc) .wim .lb{display:block;font-family:var(--mono);font-size:9px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:var(--acc);margin-bottom:5px}
:is(.app,.deckroot,.recwrap,.recdoc) .wim p{margin:0;font-family:var(--body);font-size:15.5px;line-height:1.45;color:var(--ink)}
:is(.app,.deckroot,.recwrap,.recdoc) .cred{margin:16px 0 0;padding-top:13px;border-top:1px solid var(--ln);position:relative}
:is(.app,.deckroot,.recwrap,.recdoc) .cred .lb{display:block;font-family:var(--mono);font-size:9px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:var(--ink3);margin-bottom:7px}
:is(.app,.deckroot,.recwrap,.recdoc) .cred .ln{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap}
:is(.app,.deckroot,.recwrap,.recdoc) .cred .who{font-family:var(--display);font-size:15px;font-weight:700;
  letter-spacing:-.018em;color:var(--ink);border-bottom:1.5px solid var(--acc);padding-bottom:1px;text-decoration:none}
:is(.app,.deckroot,.recwrap,.recdoc) .cred .at{font-family:var(--mono);font-size:10px;letter-spacing:.05em;color:var(--ink2);text-decoration:none}
:is(.app,.deckroot,.recwrap,.recdoc) .cred .more{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink3)}
:is(.app,.deckroot,.recwrap,.recdoc) .cred .ext i{font-style:normal;font-size:.85em;margin-left:4px;opacity:.65}
:is(.app,.deckroot,.recwrap,.recdoc) .dev{display:flex;align-items:center;gap:9px;font-family:var(--mono);font-size:9px;
  font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:var(--acc)}
:is(.app,.deckroot,.recwrap,.recdoc) .dev .pip{width:6px;height:6px;border-radius:50%;background:var(--acc);flex:none}
:is(.recwrap,.recdoc) .acts{display:grid;grid-template-columns:1fr auto;gap:8px;margin-top:14px}
:is(.recwrap,.recdoc) .acts>*{display:flex;align-items:center;justify-content:center;gap:7px;padding:12px 13px;
  font-family:var(--mono);font-size:9.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;
  border:1px solid var(--ln2);background:transparent;cursor:pointer;color:var(--ink3);text-decoration:none}
:is(.recwrap,.recdoc) .acts .orig{border-color:var(--acc);color:var(--acc)}
:is(.recwrap,.recdoc) .rcpb{margin:12px 0 0;padding:14px;background:var(--el2);border-left:2px solid var(--ln2)}
:is(.recwrap,.recdoc) .rgh{display:flex;width:100%;align-items:baseline;gap:10px;padding:11px 0;border:0;
  background:transparent;cursor:pointer;text-align:left;font-family:var(--mono);font-size:9.5px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink2)}
:is(.recwrap,.recdoc) .rgh .ct{margin-left:auto;font-weight:400;letter-spacing:.08em;color:var(--ink3)}
:is(.recwrap,.recdoc) .rgh .pm{flex:none;width:11px;text-align:center;color:var(--acc)}
:is(.recwrap,.recdoc) .rgrp>.trail{display:none;padding:0 0 13px}
:is(.recwrap,.recdoc) .rgrp.on>.trail{display:grid}
:is(.recwrap,.recdoc) .trail{list-style:none;margin:0;padding:0;display:grid;gap:11px}
:is(.recwrap,.recdoc) .trail li{display:grid;grid-template-columns:auto 1fr;gap:10px;align-items:start}
:is(.recwrap,.recdoc) .trail .ty{font-family:var(--mono);font-size:8.5px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;padding:3px 6px;border:1px solid var(--ln2);color:var(--ink3);white-space:nowrap}
:is(.recwrap,.recdoc) .trail .ty.f{color:var(--acc);border-color:var(--acc)}
:is(.recwrap,.recdoc) .trail .no{font-family:var(--body);font-size:14.5px;line-height:1.35;color:var(--ink2)}
:is(.recwrap,.recdoc) .trail .no i{font-style:normal;display:block;font-family:var(--mono);font-size:9px;
  letter-spacing:.1em;color:var(--ink3);margin-top:4px}
:is(.recwrap,.recdoc) .trail .no a{color:var(--ink);text-decoration:none}
:is(.recwrap,.recdoc) .trail li.roll{grid-template-columns:1fr;font-family:var(--mono);font-size:9.5px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--acc)}
:is(.recwrap,.recdoc) .quote{margin:14px 0 0;padding:12px 14px;background:var(--paper);border-left:2px solid var(--acc)}
:is(.recwrap,.recdoc) .quote p{margin:0;font-family:var(--body);font-style:italic;font-size:14.5px;line-height:1.5;color:var(--ink)}
:is(.recwrap,.recdoc) .quote .h{font-family:var(--mono);font-style:normal;font-size:9px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:var(--ink3);margin-bottom:8px}
:is(.recwrap,.recdoc) .quote .cite{display:block;margin-top:9px;font-family:var(--mono);font-size:9px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink3);font-style:normal}
:is(.recwrap,.recdoc) .method{margin:13px 0 0;font-family:var(--body);font-size:14px;line-height:1.5;color:var(--ink2)}
:is(.recwrap,.recdoc) .inst{list-style:none;margin:18px 0 0;padding:13px 0 0;border-top:1px solid var(--ln)}
:is(.recwrap,.recdoc) .inst .h{font-family:var(--mono);font-size:9px;font-weight:600;letter-spacing:.2em;
  text-transform:uppercase;color:var(--ink3);margin:0 0 9px}
:is(.recwrap,.recdoc) .inst li{display:grid;grid-template-columns:56px 1fr;gap:12px;padding:10px 0;border-top:1px solid var(--ln)}
:is(.recwrap,.recdoc) .inst li:first-of-type{border-top:0}
:is(.recwrap,.recdoc) .inst time{font-family:var(--mono);font-size:9.5px;color:var(--ink3);padding-top:2px}
:is(.recwrap,.recdoc) .inst h4{font-family:var(--display);font-size:14.5px;font-weight:600;letter-spacing:-.018em;
  line-height:1.25;margin:0;color:var(--ink2)}

/* ---- the record layer ---- */
.recwrap{position:fixed;inset:0;z-index:90;background:var(--paper);color:var(--ink);
  overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  transform:translateX(103%);transition:transform var(--t-layer) var(--ease-card);
  box-shadow:-18px 0 44px rgba(19,18,17,.28)}
.recwrap[hidden]{display:none}
.recwrap.on{transform:none}
/* The bar aligns to .recbody's 680px column, the same way the deck's
   chrome aligns to .pgin's 620 (owner, 2026-09-07: "still seeing 'back'
   and the record way out on the width border"). Its own padding is 18px,
   so that is the floor. Padding rather than max-width, so the bar's rule
   and sticky background stay full-bleed while its contents move. */
.rectop{position:sticky;top:0;z-index:5;display:flex;align-items:center;gap:10px;
  padding-block:8px;padding-inline:max(14px, calc((100% - 680px) / 2 + 18px));
  background:var(--paper);border-bottom:2px solid var(--ink)}
.recback{display:inline-flex;align-items:center;gap:8px;margin-left:-8px;padding:10px 12px;border:0;
  background:none;cursor:pointer;font-family:var(--mono);font-size:10px;font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;color:var(--ink)}
.rectop .rtl{margin-left:auto;font-family:var(--mono);font-size:9px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--ink3)}
/* Share sits at the far edge, opposite Back — the two things you can do
   with a record, at the two ends of its own bar. */
.rectop .rtl{margin-left:auto}
.recshr{display:inline-flex;align-items:center;gap:7px;margin-left:14px;padding:8px 11px;
  border:1px solid var(--ln2);background:transparent;cursor:pointer;color:var(--ink2);
  font-family:var(--mono);font-size:9px;font-weight:600;letter-spacing:.14em;text-transform:uppercase}
.recshr:hover{border-color:var(--ink);color:var(--ink)}
/* The confirmation a silent clipboard write never gave. */
.recshr.copied{border-color:var(--acc);color:var(--acc)}
.recshr.copied .rsl::after{content:" \2713"}
.pgfoot .shr.copied{border-color:var(--acc);color:var(--acc)}
@media (max-width:400px){.recshr .rsl{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}}
.recbody{max-width:680px;margin:0 auto;padding:6px 18px calc(40px + env(safe-area-inset-bottom))}
@media (prefers-reduced-motion:reduce){.recwrap{transition:none}}

/* ---- the record's document (layer AND story tag pages) ---- */
.recdoc{max-width:680px;margin:0 auto;padding:6px 18px 40px}
.story{padding:4px 0 10px}
.storyhd{border-bottom:2px solid var(--ink);padding-bottom:14px;margin-bottom:16px}
.storyhd .sr{display:flex;align-items:center;gap:8px;font-family:var(--mono);font-size:9px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:var(--cc,var(--ink3));margin-bottom:9px}
.storyhd .sr span{width:6px;height:6px;border-radius:50%;background:var(--cc,var(--ink3))}
.storyhd h1{font-family:var(--display);font-size:28px;font-weight:900;letter-spacing:-.042em;line-height:.98;
  margin:0 0 10px;color:var(--ink);text-wrap:balance}
.storyhd .comp{font-family:var(--mono);font-size:10px;letter-spacing:.06em;color:var(--ink3)}
.storyhd .comp b{color:var(--ink);font-weight:600}
.edcov{border-left:3px solid var(--acc);background:var(--el2);padding:16px 18px;margin:18px 0 22px}
.edcov .lb{font-family:var(--mono);font-size:9px;font-weight:600;letter-spacing:.2em;text-transform:uppercase;
  color:var(--acc);margin-bottom:10px}
.edcov p{font-family:var(--body);font-size:16px;line-height:1.52;color:var(--ink2);margin:0}
.edcov.empty{border:1px dashed var(--ln2);border-left:1px dashed var(--ln2);background:transparent;padding:15px 17px}
.edcov.empty .lb{color:var(--ink3)}
.edcov.empty p{font-size:15px;color:var(--ink3)}
.tl .tlh{display:flex;align-items:baseline;gap:10px;border-bottom:2px solid var(--ink);padding-bottom:8px}
.tl .tlh h2{font-family:var(--display);font-size:14px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;margin:0;color:var(--ink)}
.tl .tlh .ct{margin-left:auto;font-family:var(--mono);font-size:9px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink3)}
.bd{border-bottom:1px solid var(--ln);padding:14px 0}
.bd:last-child{border-bottom:0}
.bd.origin{background:var(--el2);margin:0 -14px;padding:14px}
.bsig{display:grid;grid-template-columns:58px 1fr;gap:12px;align-items:baseline}
.bsig .dt{font-family:var(--mono);font-size:9.5px;letter-spacing:.04em;color:var(--ink3)}
.bsig .hd{font-family:var(--display);font-size:16px;font-weight:700;letter-spacing:-.022em;line-height:1.24;color:var(--ink);text-decoration:none}
.brep{list-style:none;margin:8px 0 0;padding:0 0 0 70px}
.brep li{display:grid;grid-template-columns:50px 1fr;gap:10px;padding:5px 0}
.brep .dt{font-family:var(--mono);font-size:8.5px;color:var(--ink3)}
.brep .rp{font-family:var(--body);font-size:14px;line-height:1.36;color:var(--ink2)}
.brep .rp s{text-decoration:none;font-family:var(--mono);font-size:8.5px;color:var(--ink3);margin-left:7px}
.brep .rp em{font-style:normal;font-family:var(--mono);font-size:8px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink);margin-right:7px}
@media(max-width:560px){.brep{padding-left:0}.bsig{grid-template-columns:1fr;gap:3px}}
.storymast{padding:20px 0 18px;border-bottom:2px solid var(--ink)}
.storymast h1{font-family:var(--display);font-size:32px;font-weight:900;letter-spacing:-.042em;line-height:.98;
  margin:12px 0 0;color:var(--ink)}
.storymast .repnote{margin-top:12px}

/* ---- search results (in the record layer) ---- */
.qbar{display:flex;align-items:center;gap:10px;border:1px solid var(--ln2);background:var(--el);
  padding:11px 13px;margin:16px 0}
.qbar span{font-family:var(--body);font-size:16px;color:var(--ink)}
.qbar em{font-style:normal;margin-left:auto;font-family:var(--mono);font-size:9px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink3)}
.recwrap .res{display:block;border-bottom:1px solid var(--ln);padding:15px 0;text-decoration:none}
.recwrap .res .k{font-family:var(--mono);font-size:8.5px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;margin-bottom:6px}
.recwrap .res h4{font-family:var(--display);font-size:18px;font-weight:800;letter-spacing:-.028em;line-height:1.18;margin:0 0 6px;color:var(--ink)}
.recwrap .res p{font-family:var(--body);font-size:14.5px;line-height:1.42;color:var(--ink2);margin:0}

/* ---- units: full-page dark interstitials ---- */
.pg--unit{background:#131211;border-bottom:1px solid rgba(255,255,255,.14)}
.pg--unit .pgin{justify-content:center}
.u{color:#F7F5F0;--uc:#E8412B}
.u .k{display:flex;align-items:center;gap:7px;font-family:var(--mono);font-size:8.5px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:rgba(255,255,255,.5);margin-bottom:14px}
.u .k::before{content:"";width:5px;height:5px;background:var(--uc);flex:none}
.u .k .fwm-u{font-family:var(--display);font-size:12px;font-weight:800;letter-spacing:-.03em;text-transform:none;color:#fff}
.u .k .fwm-u span{color:#7D93FF}
.u p{font-family:var(--body);font-size:16px;line-height:1.46;color:rgba(247,245,240,.82);margin:0 0 14px}
.u .unm{font-family:var(--display);font-weight:900;font-size:42px;letter-spacing:-.045em;line-height:.92;color:#fff;margin:0 0 12px}
.u .ulogo{display:block;margin:0 0 12px;max-width:170px}
.u .ulogo-tvrev{width:118px;height:20px;background:#fff;
  -webkit-mask:url(../img/tvrev-logo.svg) no-repeat left center/contain;
  mask:url(../img/tvrev-logo.svg) no-repeat left center/contain}
.u .ugo{display:inline-block;margin-top:12px;font-family:var(--mono);font-size:9px;font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;color:var(--uc);text-decoration:none}
.u-net{--uc:#4FC3A1} .u-measure{--uc:#53C6DE} .u-ispot{--uc:#84BD00} .u-analyst{--uc:#A9BAFF} .u-signal{--uc:#7D93FF}
.u-analyst blockquote{font-family:var(--body);font-size:21px;line-height:1.32;font-style:italic;color:#fff;margin:0 0 16px}
.u-analyst .who{display:flex;align-items:center;gap:11px;padding-top:14px;border-top:1px solid rgba(255,255,255,.14);text-decoration:none}
.u-analyst .who .av{width:38px;height:38px;border-radius:50%;overflow:hidden;flex:none}
.u-analyst .who .av img{width:100%;height:100%;object-fit:cover;display:block}
.u-analyst .who .wi{display:flex;flex-direction:column;gap:2px}
.u-analyst .who .n{font-family:var(--display);font-size:14px;font-weight:700;letter-spacing:-.02em;color:#fff}
.u-analyst .who .ro{font-family:var(--mono);font-size:8.5px;letter-spacing:.1em;text-transform:uppercase;color:rgba(255,255,255,.5)}
.u-analyst .who .ugo{margin:0 0 0 auto}

/* ---- the final page ---- */
:is(.app,.deckroot) .endcap{padding:30px 16px 40px;text-align:center;font-family:var(--mono);font-size:9.5px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--ink3)}
:is(.app,.deckroot) .endcap b{display:block;font-family:var(--display);font-size:17px;font-weight:700;
  letter-spacing:-.02em;text-transform:none;color:var(--ink2);margin-bottom:8px}
.ffoot{background:#131211;color:#F7F5F0;
  padding:30px max(18px, calc((100% - var(--wrap)) / 2 + var(--pad))) calc(34px + env(safe-area-inset-bottom))}
:is(.app,.deckroot) .ffoot{padding-inline:18px}
.ffoot .fbrand{font-family:var(--display);font-size:23px;font-weight:800;letter-spacing:-.042em;color:#fff}
.ffoot .fbrand span{color:#7D93FF}
.ffoot .ftag{font-family:var(--body);font-size:15px;line-height:1.46;color:rgba(247,245,240,.72);margin:9px 0 22px;max-width:44ch}
.ffoot .fcols{display:grid;grid-template-columns:1fr 1fr;gap:22px}
.ffoot .fcol{display:flex;flex-direction:column;gap:8px}
.ffoot .fcol h5{margin:0 0 3px;font-family:var(--mono);font-size:8.5px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:rgba(255,255,255,.45)}
.ffoot .fcol a{font-family:var(--body);font-size:15px;color:rgba(247,245,240,.9);text-decoration:none}

/* ===================== LEVEL 1: THE COVER =====================
   Scrolls; never pages. Read off Flipboard's For You: a hero card, two
   squares, then the sections grid, under ordinary vertical scrolling.
   Full-viewport paging starts inside a feed, not at the front door. */
.cover{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;padding-bottom:calc(30px + env(safe-area-inset-bottom))}
.cover[hidden]{display:none}
.hero{display:block;text-decoration:none;color:inherit;cursor:pointer;padding:0 0 4px}
/* The heading is in the DOM for crawlers and for a reader without JS; the
   plate carries it visually once dressed. Same pattern the pager uses. */
.cover h2.vh,.cover h3.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
.hero .plate{aspect-ratio:16/10}
.hero .dek{font-family:var(--body);font-size:16.5px;line-height:1.45;color:var(--ink2);
  margin:13px 0 0;padding:0 16px}
/* THE ITEM FOOT: outlet left, record door right. One row, because that is
   the row a signal page already makes of the same two facts — the credit
   line and its "The Record →" whisper. The cover is where a reader learns
   the page's grammar, so it uses the page's. */
:is(.hero,.feature) .itemfoot{display:flex;align-items:baseline;gap:12px;padding:11px 16px 0}
:is(.hero,.feature) .itemfoot .cue{margin-left:auto;padding:0}
:is(.hero,.feature) .src{font-family:var(--mono);font-size:9px;letter-spacing:.1em;color:var(--ink3);
  min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
:is(.hero,.feature) .src:empty{display:none}
.hero .cue{display:block;padding:11px 16px 0;font-family:var(--mono);font-size:9px;font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;color:var(--acc)}
/* Two squares, side by side — the shape the reference uses for the pair
   under the hero, and the reason the cover reads as an issue rather than
   a list: three items of two different weights. */
.sqs{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--ln);
  margin-top:20px;border-top:1px solid var(--ln);border-bottom:1px solid var(--ln)}
.sq{background:var(--paper);padding:0 0 12px;text-decoration:none;color:inherit;cursor:pointer;display:block}
.sq .plate{aspect-ratio:1/1}
/* ---- THE CHROME ALIGNS TO THE READING COLUMN, IN A DECK ----
   (owner, 2026-09-07: "maybe the top nav on the signal pages should align
   with the column width, not the browser width")
   Measured: the header row is inset 16px from the shell while .pgin caps
   at 620px centred inside 760, so a card's content starts 70px further in
   and the wordmark hangs 54px to its left. The inset below is exactly
   .pgin's own: (shell - 620)/2 + 16, floored at 16 so nothing changes
   below 652px, where the column already fills the shell.

   ONLY IN A DECK, and that is the whole subtlety. The COVER's text sits at
   16px — its plates are full-bleed to the shell — so the header cannot
   align to both surfaces at once. .indeck (set by showDeck) and .deckroot
   are exactly the two states where a reading column exists to align to.

   Padding rather than max-width, so the header's rule and the bar's band
   stay full-bleed while their contents move. */
:is(.app.indeck,.deckroot) .fhead .r1,
:is(.app.indeck,.deckroot) .dbar{
  padding-inline:max(16px, calc((100% - 620px) / 2 + 16px));
}

/* THE COVER'S PICTURES ARE CAPPED BY VIEWPORT HEIGHT (QA, 2026-09-07).
   Measured at 1440x900: the cover ran 1763px — 1.96 screens — and all six
   channel tiles sat 224px BELOW the fold, which is the one thing the
   rejected desktop grid had fixed. The arithmetic says why: hero 569 +
   squares 420 = 989px of a 900px viewport before the channels even start.

   The cause is that both plates are sized by ASPECT RATIO off their width
   while the constraint is height, so a wide, short window gets tall
   pictures. So they get a height cap as well. This is NOT the reflow the
   owner locked out: same ranks, same order, same composition, and the
   theme already does exactly this for pager plates at
   @media (max-height:700px).

   IT IS INERT ON A PHONE, which is the point. At 375x812 the ratio gives a
   234px hero plate and 40svh is 325 — the cap never binds, so the cover
   the owner approved is untouched. It only bites where the window is wide
   relative to its height, which is where the problem was.
   The headline is unaffected: dressPlate sizes it in cqw, which is WIDTH,
   and the bottom-anchored block still clears the shorter frame (measured
   227px of type in a 378px plate). */
.hero .plate{max-height:40svh}
.sq .plate{max-height:26svh}

/* The record's headline is a link now (see singleRecordHTML) — it is the
   way back up to the signal from a cold share link. It must read as the
   headline it is, not as a link, until you reach for it. */
:is(.recwrap,.recdoc) .storyhd h1 a.hd{color:inherit;text-decoration:none}
:is(.recwrap,.recdoc) .storyhd h1 a.hd:hover{text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:3px}
:is(.recwrap,.recdoc) .storyhd .dek{margin:10px 0 0;font-family:var(--body);font-size:16.5px;
  line-height:1.45;color:var(--ink2)}

/* THE ARTICLE HERO'S HEADLINE, BELOW 560px ONLY. dressPlate sizes every
   headline at 5.33% of its plate's width, which on a 311px phone plate is
   16.6px — the number the retired width floor was protecting readers from.
   Above 560px its own ratio is right and is left alone; this is scoped to
   exactly the case that was broken. 7.3cqw puts a phone hero at ~23px, the
   same weight the pager's cards carry, so the page, the card and the share
   image finally show one composition. */
@media (max-width:560px){
  .art-head .plate.dressed .cardhd{font-size:7.3cqw!important;line-height:1.05}
}

/* ---- THE SOURCE MARK ----
   The monogram IS the chip and the icon covers it: the letter is the
   element's own text, the <img> is absolutely positioned over it, and
   feed.js gives that img onerror="this.remove()". So an outlet with no
   file (7 of 73, tubefilter.com among them) shows a letter rather than a
   broken image, and the asset set is free to lag the catalogue.
   Scoped nowhere, because .smk is v2-unique — but it renders on the
   cover, on a signal page's credit row and in the record's trail, so its
   size is set once here and never per surface. */
.smk{position:relative;display:inline-flex;align-items:center;justify-content:center;
  width:17px;height:17px;flex:none;margin-right:7px;border-radius:4px;
  background:var(--srcchip);border:1px solid var(--srcchip-ln);box-sizing:border-box;
  font-family:var(--display);font-size:10px;font-weight:800;line-height:1;color:#131211;
  overflow:hidden;vertical-align:-4px}
.smk img{position:absolute;inset:0;width:100%;height:100%;padding:2px;
  object-fit:contain;box-sizing:border-box;background:var(--srcchip)}
/* The credit row and the trail lay their rows out as flex/grid lines; the
   mark must not stretch or push the baseline around in either. */
:is(.app,.deckroot,.recwrap,.recdoc) .cred .ln{display:flex;align-items:center;flex-wrap:wrap}
:is(.app,.deckroot,.recwrap,.recdoc) .trail .no{display:flex;align-items:center;min-width:0}
.sq .src .sw,:is(.hero,.feature) .src .sw{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* The outlet is a hostname and must read as one: lowercase, not the
   uppercase a channel word wanted. The separator carries the second fact
   at a lower weight so the outlet stays the thing you read first. */
.sq .src{display:block;padding:9px 11px 0;font-family:var(--mono);font-size:8.5px;letter-spacing:.1em;
  color:var(--ink3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sq .src:empty{display:none}
/* THE SMALL PLATES GET THEIR OWN HEADLINE RATIO. dressPlate types a plate
   headline at 5.33% of plate width — right for a 296px card and up, and
   ~10px on a 186px cover square. cqw against the plate's own container
   (the theme already sets container-type on .plate) puts it back in the
   readable range; !important because the fitter writes an inline size. */
/* THE HERO OUTRANKS THE SQUARES IN TYPE, not only in area (owner,
   2026-09-07: "The headline on the hero on the landing page can be bigger
   than the headlines on the two other tiles. Like Flipboard.").
   dressPlate sizes every headline at 5.33% of its plate's width, so the
   hero was only ~14% larger than a square — the squares already carry
   their own 9.4cqw override to fit a 1/1 plate, which had quietly closed
   the gap. At 8cqw against the squares' 9.4cqw OF A HALF-WIDTH CONTAINER,
   the hero reads about 1.7x, and the ratio holds at every width because
   both are container-relative.
   TUNED ON THE PHONE (owner, same day): "needs to be more anchored vs
   vertical center and it can be a bit smaller than the big you made" —
   8cqw down to 7, and the block dropped from the base 12.5cqw bottom to
   8cqw. Fewer lines sitting lower reads as anchored; the same lines
   centred read as floating, which is what four lines of 30px type did to
   a 234px plate. The bottom is free to use: .mk, the only thing that
   lives down there, is SHARE-ONLY (meta.plateCredit) and renders empty on
   the page.
   !important because dressPlate sets the size as an inline style, and an
   important declaration is the only thing that outranks one. That also
   means the JS step-down for a pathological title no longer applies here
   — the same trade the squares have been making since they shipped. */
:is(.hero,.feature) .plate.dressed .cardhd{font-size:7cqw!important;line-height:1.04;bottom:8cqw}
.sq .plate.dressed .cardhd{font-size:9.4cqw!important;line-height:1.06;
  display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden}
/* The type title is the no-JS and crawler copy; the dressed plate carries
   it visually, so it steps aside once the plate has it. */
.sq .sqt{display:block;padding:5px 11px 0;font-family:var(--display);font-size:14px;font-weight:700;
  letter-spacing:-.026em;line-height:1.14;color:var(--ink)}
.sq:has(.plate.dressed) .sqt{display:none}

/* ---- the feature (Ghost's own `featured` flag, one click in the editor) ----
   Wide, one example, above the channels: the cover's editorial slot, as
   distinct from the hero (which is simply the newest) and from the squares
   (which are the two behind it). Absent entirely when nothing is starred. */
.feature{display:block;text-decoration:none;color:inherit;cursor:pointer;
  margin-top:24px;padding:0 0 16px;border-top:1px solid var(--ln);border-bottom:1px solid var(--ln);
  background:var(--el)}
.feature .flab{display:block;padding:13px 16px 11px;font-family:var(--mono);font-size:8.5px;
  font-weight:600;letter-spacing:.2em;text-transform:uppercase;color:var(--acc)}
.feature .plate{aspect-ratio:16/9}
.feature .ftitle{display:block;padding:14px 16px 0;font-family:var(--display);font-size:22px;
  font-weight:800;letter-spacing:-.036em;line-height:1.08;color:var(--ink)}
.feature:has(.plate.dressed) .ftitle{display:none}
.feature .fdek{margin:11px 0 0;padding:0 16px;font-family:var(--body);font-size:15.5px;
  line-height:1.45;color:var(--ink2)}
/* THE FOOTER'S CHILDREN ARE UNSCOPED TOO (owner, 2026-09-09: "this footer
   is a mess too" — a story page, links running together in the system
   sans with no columns).
   Same bug as the header, one level down and shipped by the same hand: the
   chrome standardization unscoped .ffoot itself so the dark band appeared
   everywhere, and left every rule INSIDE it under :is(.app,.deckroot). So
   on any page without a v2 container — a story record, a post, a dossier,
   About — the footer had its background and none of its typography or
   layout. Container styled, contents naked.
   Safe for the same measured reason as the header: .fbrand, .ftag, .fcols,
   .fcol and .flg are v2-unique, zero hits each in v1's signal.css. Only
   .ffoot's own padding stays per-context, because that IS per-context —
   a v2 shell is already a 760px column.

   The legal bar closes the footer — copyright and cadence, the same two
   facts v1's .lg carries. Sits under the columns at a lower voltage. */
.ffoot .flg{display:flex;flex-wrap:wrap;gap:6px 18px;margin-top:26px;
  padding-top:16px;border-top:1px solid rgba(247,245,240,.14);
  font-family:var(--mono);font-size:9px;letter-spacing:.1em;text-transform:uppercase;
  color:rgba(247,245,240,.42)}

.covh{display:flex;align-items:baseline;gap:9px;padding:26px 16px 11px}
.covh h2{margin:0;font-family:var(--display);font-size:26px;font-weight:900;letter-spacing:-.042em;color:var(--ink)}
.covh .ct{margin-left:auto;font-family:var(--mono);font-size:9px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink3)}
.chgrid{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--ln);
  border-top:1px solid var(--ln);border-bottom:1px solid var(--ln)}
.chtile{background:var(--paper);padding:13px 12px 15px;text-decoration:none;display:flex;
  flex-direction:column;gap:6px;border-left:3px solid var(--cc,var(--acc));cursor:pointer}
.chtile:hover{background:var(--el)}
.chtile .n{font-family:var(--mono);font-size:8.5px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--cc,var(--acc))}
.chtile .nm{font-family:var(--display);font-size:17px;font-weight:800;letter-spacing:-.032em;color:var(--ink)}
.chtile .lt{font-family:var(--body);font-size:12.5px;line-height:1.32;color:var(--ink2);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ch-measurement{--cc:#4FC3A1} .ch-streaming{--cc:#A48CFF} .ch-creators{--cc:#F27BB0}
.ch-ad-tech{--cc:#7D93FF} .ch-retail-media{--cc:#53C6DE} .ch-agencies{--cc:#E8955A}

/* ============ ONE COMPOSITION AT EVERY WIDTH (owner, 2026-09-07) ======
   The cover does NOT reflow on a wide display. Hero full width, the two
   squares side by side under it, channels two across, the whole thing a
   760px column with the gutters growing as the display does. Phone to 5K,
   one layout.

   THIS REPLACED A DESKTOP GRID THAT SHIPPED AND WAS REMOVED THE SAME
   HOUR, and the reason is worth keeping because the measurements argued
   for the grid. At 1440x900 the column leaves 47% of the screen empty and
   needs 1.2-1.7 screens; a grid (hero left, squares as a rail, channels
   three across) closed the gutter to 22% and brought all six tiles above
   the fold. Better numbers, and the owner still chose the column after
   seeing the real page at ~1010px: the cover is an ISSUE, and an issue
   has one composition. A reader who moves between a phone and a desktop
   should recognise the same object, and a hero that becomes a rail is a
   different object.

   So a desktop change here is a change to the WHOLE cover, at every
   width, or it is not made. If the gutters ever need to earn their keep,
   the honest move is a wider column (raise the cap), never a reflow.
   ==================================================================== */

/* ============ A MOUSE GETS A FEED, A THUMB GETS A PAGER ==============
   (owner, 2026-09-07: "Any way to close up the vertical spacing of the
   cards in a browser so they are more of a feed, contiguous")
   Measured on the deck at 1440x1050 before this: a page 1050px tall
   holding 569px of content, so the card ended a third of the way down
   and "Read the original" was pinned 600px below it by margin-top:auto.
   On a phone that emptiness is the page and the flick fills it; on a
   desktop it is just a hole, and the taller the window the bigger it is.

   So the pager's physics are chosen by INPUT DEVICE, not by width:
     coarse pointer -> full-viewport pages, mandatory snap, snap-stop
                       always. One flick, one signal, nothing skimmed.
     fine pointer   -> cards size to their content and butt up against
                       each other, no snap at all. A wheel scrolls a feed.
   A touchscreen at 1200px keeps the thumb's physics, which is the whole
   reason this is not a width query.

   THE DEK CLAMP COMES OFF WITH THE PAGE HEIGHT. --dl is computed from the
   space a full-viewport page has left over (see fitDeks), and a
   content-height page has no leftover to measure — fitDeks would clamp
   every dek to its floor of 2 lines. Contiguous cards have room to simply
   show the dek, so they do.
   ==================================================================== */
@media (pointer:fine){
  #app.fpager{scroll-snap-type:none}
  #app.fpager .pg{height:auto;scroll-snap-align:none;scroll-snap-stop:normal;
    overflow:visible;content-visibility:visible}
  #app.fpager .pgin{height:auto;padding:18px 16px 20px}
  /* margin-top:auto is what pinned the exits to the bottom of a
     full-viewport page. In a feed they follow the credit row. */
  #app.fpager .pgfoot{margin-top:0;padding-top:16px}
  #app.fpager .dek{display:block;-webkit-line-clamp:unset;overflow:visible}
  /* The plate is the tallest thing on a card and 16/9 at 620px is 349px;
     a feed reads better with a slightly shorter picture, and it keeps
     three cards reachable in a 1050px window. */
  #app.fpager .pg .plate{aspect-ratio:16/8}
}
}

/* ============ LEVEL 2: A CHANNEL TAG PAGE IS A DECK ============
   tag.hbs still extends the v1 layout — one template serves channels,
   reporters and story records, and duplicating default.hbs to give the
   deck its own shell would buy two files that drift. Instead the deck
   marks itself with #chdeck and takes the viewport over, hiding the v1
   chrome around it. :has() is doing real work here: the deck's presence
   is a fact about the document, not a class someone has to remember to
   add. Reporter and story pages carry no #chdeck, so they keep the v1
   shell untouched. */
body:has(#chdeck){height:100%;overflow:hidden}
body:has(#chdeck) .sg{height:100vh;height:100svh;height:var(--shellh,100svh);display:flex;flex-direction:column}
/* THE RECORD LAYER IS THE EXCEPTION, and leaving it out cost the record
   entirely on every channel deck (owner, 2026-09-07: "can't seem to get to
   the record in the browser from here:
   /tag/streaming/#/s/story-netflix-prime-video-international-content-...").
   This rule exists so a channel deck can take the viewport from v1's
   chrome — the header, the v1 river, the footer that default.hbs renders
   around it. But the record mounts as a DIRECT CHILD of .sg (it has to:
   outside .sg it paints var(--paper) as invalid, which is the iOS
   transparent-sheet incident), so it was collected as v1 chrome and
   hidden. It opened, built its body, took the .on class, and was
   display:none the whole time — which is why the symptom was "nothing
   happens" rather than an error.
   The record worked from the cover throughout, because the cover document
   has no #chdeck and this rule never applied there. That asymmetry is why
   a whole surface can be dead while every test and every check passes. */
body:has(#chdeck) .sg>*:not(.deckroot):not(.recwrap){display:none}
.deckroot{flex:1;min-height:0;display:flex;flex-direction:column;width:100%;max-width:760px;
  margin:0 auto;background:var(--paper)}
.chmast{padding:2px 0 16px}
.chmast h1{margin:11px 0 0;font-family:var(--display);font-size:34px;font-weight:900;
  letter-spacing:-.045em;line-height:.96;color:var(--ink)}
.chmast .std{margin:11px 0 0;font-family:var(--body);font-size:15.5px;line-height:1.5;color:var(--ink2)}
/* The claim: the brief's own first sentence, shown only while it is
   closed. Body face rather than display — it is a sentence the desk
   wrote, not a headline someone set — and it sits under the lockup's
   own hairline so the block still reads as one object. */
.sopclaim{margin:12px 0 0;padding-top:12px;border-top:1px solid var(--ln);
  font-family:var(--body);font-size:16.5px;line-height:1.42;letter-spacing:-.006em;
  color:var(--ink);max-width:52ch}
.sop[aria-expanded="true"] .sopclaim{display:none}

/* PAGE ZERO IS A HEAD BLOCK, NOT A PAGE (owner, 2026-09-07). It takes only
   the height its content needs — the ident, the count and the CLOSED brief
   — so the first signal begins immediately beneath it and is visible
   without a flick. It keeps scroll-snap-align, so a flick still lands
   cleanly on signal one; it simply stops spending a whole viewport on a
   preamble. Expanding the brief grows the block, which is the right
   trade: a reader who opens it has asked for the room. */
.pg--sop{height:auto;overflow:visible}
.pg--sop .pgin{height:auto;padding-bottom:4px}

/* THE DECK'S BOTTOM BAR — the only persistent chrome inside a deck, and
   the answer to "where am I / how do I get out". Left: the way up.
   Right: sideways, without going up. */
/* THE BAR CLEARS THE BROWSER'S OWN CHROME (owner, 2026-09-07: "the
   browser chrome obscures abil to use the cover button" — in Safari; "I
   don't see it in Chrome").
   Not a transient overlap. iOS Safari retracts its floating bottom bar on
   a DOCUMENT scroll, and this page has none: body is locked and the pager
   scrolls an inner element, so that chrome stays expanded for the life of
   the session and sits on the deck bar the whole time. env(safe-area-
   inset-bottom) does not cover it either — that inset is the home
   indicator (~34px) and the expanded chrome measures ~87px on the owner's
   phone, which is where the 46px comes from.
   --chrome is set to 0 by fitShell() on any browser whose viewport
   already excludes its chrome, so only the browsers that need the
   clearance pay for it. */
.dbar{flex:none;display:flex;align-items:center;gap:10px;padding:8px 13px calc(8px + env(safe-area-inset-bottom));
  border-top:2px solid var(--ink);background:var(--paper)}
@supports (-webkit-touch-callout:none){
  .dbar{padding-bottom:calc(8px + env(safe-area-inset-bottom) + var(--chrome,46px))}
}
.dbar[hidden]{display:none}
.dbar .bk{display:inline-flex;align-items:center;gap:8px;padding:7px 4px;text-decoration:none;
  font-family:var(--mono);font-size:9.5px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink)}
.dbar .bk:hover{color:var(--acc)}
.dbar .id{margin-left:auto;display:inline-flex;align-items:center;gap:7px;border:0;background:none;
  cursor:pointer;font-family:var(--display);font-size:14px;font-weight:800;letter-spacing:-.028em;color:var(--ink)}
.dbar .id s{text-decoration:none;font-family:var(--mono);font-size:9px;color:var(--ink3)}

/* ---- the episode player, the audio member of the media family ---- */
.listenbtn b{width:13px;height:13px;flex:none;border-radius:50%;border:2px solid #fff;position:relative}
.listenbtn b::after{content:"";position:absolute;left:3.5px;top:2.5px;width:0;height:0;
  border-left:5px solid #fff;border-top:3.5px solid transparent;border-bottom:3.5px solid transparent}
.pg .listenfig{margin:0;flex:none;display:flex;flex-direction:column;gap:8px}
.pg .listenfig iframe{display:block;width:100%;height:192px;border:0;background:var(--el2)}
.pg .listenfig figcaption{font-family:var(--mono);font-size:8.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink3)}

/* ---- the transition between levels (owner build item) ----
   Cross-document, so the cover and the deck it opens are one movement
   rather than a blink. 160ms, the figure measured off the reference.
   Browsers without it simply cut, which is what they do today. */
@media (prefers-reduced-motion: no-preference){
  @view-transition{navigation:auto}
  ::view-transition-old(root),::view-transition-new(root){animation-duration:var(--t-card,160ms)}
}
