/* ============================================================
   v3 — standalone. Does NOT use the elainehe design system.

   Palette borrowed from the Greymac reference:
   · near-black bezel surrounding everything
   · deep navy for the anchor cards
   · pearl-grey cards with a diagonal light sheen
   · one oxblood accent, distributed across wordmark, card kickers
     and interactive states — the interface carries the visual energy
     because the photography (greyscale until hovered) cannot.

   Structure: a full-viewport floating gallery, then cards that
   stack over it via position:sticky (works with JS off).
   ============================================================ */

:root{
  --bezel:#08090a;
  --navy-1:#0b1f2f;
  --navy-2:#16394f;
  --navy-3:#1d4b66;
  --pearl-1:#eceded;
  --pearl-2:#f7f7f7;
  --pearl-3:#dfe1e3;
  --ink:#15171a;
  --ink-2:#4a5057;
  --ink-3:#8b9199;
  --light:#f2f4f6;
  --light-2:#aab4bd;
  /* OXBLOOD. Chosen for this palette, not inherited.
     Fully monochrome was tried and abandoned: WSM and Schupfer can strip
     the interface bare because their photography is vivid and carries the
     whole page. Elaine's images are dark, low-contrast and greyscaled —
     a neutral interface plus quiet content leaves nothing carrying it.
     So the energy goes where it can be controlled: the interface.
     Oxblood over the old #e84e14 terracotta for three reasons — it reads
     editorial rather than startup-orange, it sits against near-black and
     navy instead of vibrating against them, and it is the same hue family
     as the red-light photographs, so the colour revealed on hover belongs
     to a world the interface already established. */
  --accent:#9e2b2b;
  --accent-soft:#b84a4a;   /* hover / lighter states */

  --serif:'Cormorant Garamond',Garamond,'Times New Roman',serif;
  --sans:'Work Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,sans-serif;
  --mono:ui-monospace,SFMono-Regular,'SF Mono',Menlo,Consolas,monospace;

  /* The covering card carries the big radius; a card that has receded
     behind the next one takes the smaller one. */
  --radius:clamp(26px,3.4vw,46px);
  --radius-back:clamp(18px,2.2vw,30px);
  /* ---- bang metrics ----
     Both widths are DERIVED from the two padding knobs below, so the
     flat always hugs its content. Nothing here is a guessed pixel.

     --mark-half half the wordmark's LAYOUT width (ink 40.8 / 2). The
                 mark's box measures 46.2 because letter-spacing trails
                 the last glyph; margin-right:-.2em cancels it, so the
                 width it occupies in flow is 40.8.
     --mark-pad  side padding in the COLLAPSED state. Was 5.6; tightened
                 to 3 so the bang closes down snugly around EH.
     --nav-gap   space between any two adjacent items when expanded.
     --nav-text  summed link widths of the WIDER group, measured at
                 14px Work Sans 400: left (Writing/Signl/Don't Die SF)
                 is 166.1, right (Record/Subscribe/Contact) is 169.6.
                 The tab is centred and symmetric, so it must fit the
                 wider one; the left side ends up 3.5px roomier, which
                 is below the threshold of noticing.
                 RE-MEASURE THIS if the link weight, size, or wording
                 changes — going to weight 900 alone moved it to 174.2.
     --nav-edge  clearance from the outermost link to the flat edge when
                 expanded. Was gap/2; tightened to .35 gap. Because the
                 shoulder slopes outward as it rises, the clearance the
                 eye reads at the text's own height is larger than this
                 number — the "closer edge vs further edge" difference.

     Collapsed half = mark-half + mark-pad
     Expanded  half = mark-half + gap + (nav-text + 2 gaps) + nav-edge

     Neither touches --cap-w or --notch-h, so the corner radius and the
     depth are untouched by any of it: narrowing a flat only slides the
     two shoulders toward each other, it never reshapes them. */
  --nav-gap:clamp(16px,2.4vw,38px);
  --mark-half:20.4px;
  --mark-pad:3px;
  --nav-edge:calc(var(--nav-gap) * .35);
  --notch-w:calc(2 * (var(--mark-half) + var(--mark-pad)));
  --nav-text:169.6px;
  --notch-w-open:min(calc(2 * (var(--mark-half) + var(--nav-text) + 3 * var(--nav-gap) + var(--nav-edge))),76vw);
  --notch-h:46px;
  /* Shoulder width. Authored 1:1 with the cap SVG (81x46) so background-
     size is a no-op — the curve renders exactly as drawn. This is the
     CORNER RADIUS knob: radius grows with the SQUARE of the shoulder,
     R = cap-w^2 / 96 at the handle ratio below. History: 52px gave
     R=23 (too tight — read as a rounded tab), 66px gave R=45, and 81px
     gives R=68, the current setting. Resize --notch-h and you must
     re-derive from R = 3a^2 / 2h, where a = cap-w/2 and h = notch-h
     minus the 10px strip. */
  --cap-w:81px;
  /* Shoulder cap. ONE cubic from strip to base, horizontal tangents at
     both ends: P0(0,10) C1(40.5,10) C2(40.5,46) P3(81,46).

     Handles at 50% of the width — the longest they can be WITHOUT
     crossing. Crossed handles were the original sin: the old path put
     them at 63% (C1 x=53, C2 x=31 of 84), which forces every degree of
     bend into the middle, leaves the ends dead flat, and makes the
     arrival at the base turn ~70deg over a couple of px. The eye reads
     that as a tight corner radius. Non-crossing handles spread the
     curvature evenly, which is what makes GM's silhouette flow.

     That path was also drawn 84 wide and squeezed into 46px, so it
     rendered ~1.8x steeper than authored — 68deg, not the 53.6deg the
     old comment claimed. Now 1:1, steepest 41.6deg.
     dx/dt stays positive throughout, so it never folds. */
  --cap:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='81' height='46'%3E%3Cpath d='M0,0 L0,10 C40.5,10 40.5,46 81,46 L81,0 Z' fill='%2308090a'/%3E%3C/svg%3E");
  --gap:10px;
  --dwell:85svh;   /* still-time between cards; raise to slow the stack */
  --pad:clamp(24px,4.4vw,72px);
  --ease:cubic-bezier(.22,.61,.24,1);
}

*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--bezel);color:var(--ink);font-family:var(--sans);font-size:17px;line-height:1.55;-webkit-font-smoothing:antialiased}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
a{color:inherit}

/* ---------- notch ("the bang") ----------
   A fixed bezel strip that dips down in the centre for the wordmark and
   joins the card top with concave fillets, drawn with radial-gradients.
   It never moves with the cards. On hover the tab widens into the nav —
   the fillets are attached to the tab, so they travel with it. */
.notch{position:fixed;top:0;left:0;right:0;z-index:70;height:var(--gap);background:var(--bezel);pointer-events:none}
.notch__tab{position:absolute;top:0;left:50%;transform:translateX(-50%);
  height:var(--notch-h);width:var(--notch-w);background:var(--bezel);
  display:flex;align-items:center;justify-content:center;gap:0;
  color:var(--light);pointer-events:auto;
  /* Belt and braces with the cap overlap below: paints a 1px bezel
     column either side of the tab, so if sub-pixel rounding ever does
     open a seam, what shows through is black rather than the card.
     Horizontal offsets only — no spread, so the base stays flush with
     the caps' base. */
  box-shadow:1px 0 0 var(--bezel),-1px 0 0 var(--bezel);
  transition:width .5s var(--ease),gap .5s var(--ease)}
.notch__bg{display:none}

/* Shoulders. Each is a fixed 52x52 SVG cap so the curve never distorts
   when the tab widens — only the flat centre stretches.

   (This block used to describe two tangent arcs. That approach was
   replaced by the single cubic defined in --cap above; the arcs were
   tangent-continuous but not curvature-continuous and read as a bump.
   Left as a note so nobody reintroduces them.) */
/* Each cap is 1px wider than --cap-w so it overlaps the tab's solid
   background. Butted exactly edge-to-edge, the tab's animating width
   lands on fractional pixels and for a frame neither the cap nor the
   body fully covers that column — the card behind shows through as a
   thin vertical line on each side. The overlap removes the boundary.
   The cap's inner edge is solid full-height, so it is invisible. */
.notch__tab::before,.notch__tab::after{content:'';position:absolute;top:0;
  width:calc(var(--cap-w) + 1px);height:var(--notch-h);
  background:var(--cap) no-repeat 0 0/100% 100%}
.notch__tab::before{left:calc(var(--cap-w) * -1)}
.notch__tab::after{right:calc(var(--cap-w) * -1);transform:scaleX(-1)}
/* Only width animates. An earlier `gap` here looked like it controlled
   nav spacing but could not — the navs are absolutely positioned, so
   the tab's only in-flow child is the wordmark and there is nothing to
   put a gap between. Nav rhythm lives entirely in --nav-gap. */
.notch:hover .notch__tab,.notch__tab:focus-within{width:var(--notch-w-open)}

/* Tried and rejected: the .card__title ("Field notes") treatment —
   Cormorant 300 at 34px/.08em. It's elegant at title size, but as a
   46px-tall monogram reversed out of near-black it reads too skinny;
   light weights thin optically against a dark ground. 600 holds up.

   The mark sizes the flat centre of the bang — if you change this,
   change --notch-w to match, or the flat stops hugging the wordmark.
   Measured ink width at these settings is 40.8px.

   margin-right cancels the trailing letter-space. CSS puts tracking
   AFTER every glyph including the last, so a tracked mark carries .2em
   of dead air on its right and sits visibly left of centre in a flex
   box. Pulling back one tracking unit re-centres it optically. */
.notch__mark{font-family:var(--serif);font-size:27px;font-weight:700;
  letter-spacing:.2em;margin-right:-.2em;white-space:nowrap;flex:none}

/* The nav is revealed by widening a clipped box, so while that box is
   only a few pixels wide it would show a vertical sliver of the first
   glyph — which flashes as a thin bar. visibility is therefore held
   until the box has opened, and dropped before it closes again, so no
   partial glyph is ever painted. */
/* The nav is revealed by widening a clipped box. While that box is
   narrow it shows a vertical slice of the first glyph on each side —
   "W" of Writing, "Re" of Record — which reads as white bars beside
   the wordmark. Reproduced directly at a 14px clip width.

   visibility therefore holds until the tab is essentially fully open
   (0.46s of a 0.5s width transition) and drops almost immediately on
   close, so the nav is only ever painted while the box is wide enough
   for whole words. Nothing is visible through a narrow clip in either
   direction. */
/* The nav is NOT clipped. Earlier versions revealed it by widening an
   overflow:hidden box, which meant that while the box was narrow it
   showed a vertical slice of the first glyph — the white bars beside
   the wordmark. No amount of delay tuning removes that; it only makes
   the window smaller.

   The navs are therefore taken out of flow entirely and anchored either
   side of the wordmark. They are always at their natural width, so
   there is no clip window and no slice can exist at any timing. They
   simply fade. When the tab is collapsed they overflow it, which is
   invisible because they are hidden. */
.notch__nav{position:absolute;top:0;height:100%;
  display:flex;align-items:center;gap:var(--nav-gap);
  opacity:0;visibility:hidden;pointer-events:none;white-space:nowrap;
  transition:opacity .12s var(--ease),visibility 0s linear .12s}
/* Anchored one gap clear of the wordmark, not a flat 30px. The old
   value left only 30 - 20.4 = 9.6px beside the mark, so "Don't Die SF"
   and "Record" crowded it while every other pair sat up to 38px apart.
   Offsetting by half the mark plus one gap makes the mark space exactly
   like any other item in the row. */
.notch__nav:first-of-type{right:calc(50% + var(--mark-half) + var(--nav-gap));justify-content:flex-end}
.notch__nav:last-of-type{left:calc(50% + var(--mark-half) + var(--nav-gap))}
.notch:hover .notch__nav,.notch__tab:focus-within .notch__nav{
  opacity:1;visibility:visible;pointer-events:auto;
  transition:opacity .26s var(--ease) .3s,visibility 0s linear .3s}
/* Tried and rejected: font-weight:900. Too heavy at 14px, and because
   Work Sans is variable, 900 redraws the letterforms rather than just
   thickening them — closed apertures, wider characters — so it read as
   a different typeface. It also outweighed the wordmark, inverting the
   hierarchy. Left at the inherited 400. */
.notch__nav a{color:var(--light);text-decoration:none;font-family:var(--sans);font-size:14px;white-space:nowrap;opacity:.86;transition:opacity .2s var(--ease)}
.notch__nav a:hover{opacity:1}


/* ---------- fixed chrome ----------
   difference blending keeps it readable on the white hero and on the
   dark cards without any JavaScript. */
.chrome{position:fixed;top:calc(var(--gap) + clamp(18px,2.6vw,34px));right:clamp(20px,3.4vw,52px);z-index:65;margin:0;
  display:flex;align-items:center;gap:10px;color:#fff;mix-blend-mode:difference;
  font-size:14px;letter-spacing:.01em;pointer-events:none}
.dot{width:7px;height:7px;border-radius:99px;background:currentColor;display:inline-block}
@media(max-width:640px){.chrome{display:none}}

/* ---------- hero card — WSM style ----------
   The hero is the first card in the stack, so the bezel, corner radius
   and bang all belong to it exactly as they do to every card below. */
.card--hero .card__inner{background:#fff;color:var(--ink);
  display:grid;grid-template-rows:auto auto 1fr auto;justify-items:stretch;
  padding:clamp(56px,9vh,120px) 0 0;gap:0}

.mark{margin:0;text-align:center;font-family:var(--serif);font-weight:300;
  font-size:clamp(52px,11vw,178px);line-height:.9;letter-spacing:-.012em;color:var(--ink);text-transform:lowercase}
/* The surname carries the accent. Largest single appearance of the
   colour on the site, which is what makes the rest of it read as
   deliberate rather than incidental. */
.mark__accent{color:var(--accent)}
.mark__sub{margin:22px 0 0;text-align:center;font-size:11px;text-transform:uppercase;letter-spacing:.24em;color:var(--ink-3)}
/* NOTE: do not put --accent on .chrome or .dot. The chrome uses
   mix-blend-mode:difference so it stays legible on white and navy alike,
   and terracotta differenced against white inverts to cyan. The dot must
   stay currentColor. */

/* the reel */
/* min-height:0 is load-bearing. A grid item defaults to min-height:auto,
   which means the row grows to fit its content and overflow:hidden never
   gets a chance to clip — the reel then rides up over the wordmark. */
.reel{align-self:end;min-height:0;overflow:hidden;padding-bottom:clamp(28px,5vh,60px);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent)}
.reel__track{display:flex;align-items:flex-end;gap:clamp(30px,4.2vw,78px);width:max-content;
  animation:reel 96s linear infinite;will-change:transform}
@keyframes reel{from{transform:translate3d(-50%,0,0)}to{transform:translate3d(0,0,0)}}
.reel:hover .reel__track{animation-play-state:paused}

.plate{margin:0;flex:none}
/* Greyscale by default, true colour on hover.
   This is the consistency mechanism: photos shot in different light with
   different casts cannot clash if none of them has a hue at rest. The
   original colour becomes a reward for looking rather than a problem to
   be graded away — which also means new photos need no colour matching
   before they can go in.
   Pairs with .reel:hover pausing the track, so the plate you're pointing
   at stops AND comes alive. */
.plate__img{display:block;width:100%;aspect-ratio:var(--ar,4/5);background:linear-gradient(150deg,var(--a),var(--b));
  background-size:cover;background-position:center;border-radius:3px;
  filter:grayscale(1) contrast(1.02);transition:filter .5s var(--ease)}
.plate:hover .plate__img{filter:grayscale(0) contrast(1)}
/* Sized so roughly FOUR plates are visible at once, as on the WSM
   reference. Fewer and larger reads as a gallery; more and smaller reads
   as a filmstrip.

   Each width is min()'d against a vh value. Without that second term the
   plates size purely off viewport WIDTH, so on a short window they grow
   taller than the row that holds them, the grid row expands to fit, and
   the reel rides up over the wordmark. Because aspect-ratio ties height
   to width, capping the width is how you cap the height:
     4/5   -> height = width x 1.25, so width <= 0.80 x available
     16/10 -> height = width x 0.625, so width <= 1.60 x available
     1/1   -> height = width */
/* Aspect ratio lives on --ar and is applied to the IMAGE, not the figure.
   The figure now also holds a caption, so if the ratio sat on the figure
   the caption would eat into the picture. */
.plate--tall{width:min(clamp(230px,26vw,430px),34vh);--ar:4/5;margin-bottom:clamp(24px,4vh,64px)}
.plate--wide{width:min(clamp(300px,34vw,560px),62vh);--ar:16/10}
.plate--sq  {width:min(clamp(210px,23vw,380px),36vh);--ar:1/1;margin-bottom:clamp(44px,7vh,104px)}

.landing__scroll{margin:0;padding-bottom:clamp(14px,2.4vh,26px);text-align:center;font-size:15px;color:var(--ink-3)}

@media(prefers-reduced-motion:reduce){.reel__track{animation:none}}
@media(max-width:860px){
  .card--hero .card__inner{padding-top:clamp(40px,7vh,70px)}
  .mark__sub{font-size:10px;letter-spacing:.18em;padding:0 var(--pad)}
}

/* ---------- stacked cards ----------
   The CARD is sticky, not its inner. Every card pins at top:0 inside the
   shared .cards parent and stays pinned — so a card, including the hero,
   never moves again once it lands. Later cards simply paint over it.

   --dwell is scroll distance between cards: the current card sits
   completely still for that stretch before the next begins to rise. */
.cards{position:relative;z-index:5}
.card{position:sticky;top:0;height:100svh;padding:var(--gap);margin-bottom:var(--dwell);will-change:transform}
.card:last-child{margin-bottom:0}
.card__inner{height:100%;
  border-radius:var(--radius);padding:var(--pad);overflow:hidden;
  background:
    linear-gradient(118deg,rgba(255,255,255,.96) 0%,rgba(255,255,255,0) 42%),
    linear-gradient(200deg,var(--pearl-2),var(--pearl-1) 46%,var(--pearl-3));
  display:flex;flex-direction:column;justify-content:center;gap:var(--pad)}

.card--dark .card__inner{color:var(--light);
  background:
    linear-gradient(122deg,rgba(120,180,220,.16) 0%,rgba(120,180,220,0) 48%),
    radial-gradient(120% 90% at 30% 20%,var(--navy-3),var(--navy-2) 38%,var(--navy-1) 84%)}

.card__inner--center{align-items:center;text-align:center;justify-content:center}
.card__inner--split{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);align-items:start;gap:clamp(32px,6vw,110px);justify-content:initial}

/* Don't Die SF — the room, barely there.
   Greyscaled at source so the file is small; opacity stays in CSS so the
   strength is tunable without regenerating the asset. --ddsf-veil is the
   only knob: 0.10 reads as texture, past ~0.16 it starts competing with
   the copy and the card stops being a text card.
   isolation:isolate keeps the z-index:-1 pseudo-element inside this card
   rather than escaping behind the whole stack. */
.card--ddsf .card__inner{position:relative;isolation:isolate;--ddsf-veil:.10}
.card--ddsf .card__inner::before{content:'';position:absolute;inset:0;z-index:-1;
  background:url(assets/ddsf-room.jpg) center/cover no-repeat;
  opacity:var(--ddsf-veil)}

/* card 01 */
.card__rule{margin:0;display:flex;align-items:center;gap:22px;width:min(880px,100%);font-size:12px;text-transform:uppercase;letter-spacing:.2em;color:var(--light)}
.card__rule i{flex:1;height:1px;background:rgba(255,255,255,.28)}
.card__statement{margin:0;max-width:20ch;font-family:var(--serif);font-weight:300;font-size:clamp(30px,4.6vw,62px);line-height:1.1;letter-spacing:.005em}
.card__statement--sm{font-size:clamp(26px,3.4vw,44px);max-width:22ch}
.card__foot{margin:0;font-size:11px;text-transform:uppercase;letter-spacing:.2em;color:var(--light-2)}
.card__foot--wide{max-width:52ch;text-transform:none;letter-spacing:.01em;font-size:13px;line-height:1.6}

/* card 02 — intro + ghost names */
.card__lede{margin:0;max-width:22ch;font-family:var(--sans);font-weight:400;font-size:clamp(22px,3vw,40px);line-height:1.24;letter-spacing:-.01em;color:var(--ink);max-width:26ch}
.card__paren{font-family:var(--serif);font-size:.42em;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-3);margin-right:1.6em;vertical-align:.5em}
.ghosts{list-style:none;margin:0;padding:0;display:grid;gap:clamp(4px,1vw,14px)}
.ghosts li{display:flex;align-items:baseline;gap:14px;justify-content:flex-end}
.ghosts span{font-family:var(--serif);font-weight:300;font-size:clamp(34px,6.4vw,86px);line-height:1;color:rgba(21,23,26,.13)}
.ghosts i{font-style:normal;font-family:var(--mono);font-size:10px;letter-spacing:.1em;color:rgba(21,23,26,.28)}

/* split cards */
.card__side{align-self:center}
/* Kickers carry the accent on every light card, which is what turns one
   coloured word in the hero into a system running down the page.
   --light stays neutral: oxblood on navy is muddy and unreadable. */
.card__kicker{margin:0;font-size:12px;text-transform:uppercase;letter-spacing:.22em;color:var(--accent)}
.card__kicker--light{color:var(--light-2)}
.card__title{margin:6px 0 0;font-family:var(--serif);font-weight:300;font-size:clamp(38px,5.4vw,74px);line-height:1;letter-spacing:.005em;color:var(--ink)}
.card--dark .card__title{color:var(--light)}
.card__blurb{margin:22px 0 0;max-width:34ch;font-size:15px;line-height:1.62;color:var(--ink-2)}
.card__main{align-self:center;width:100%}

.stat{display:flex;align-items:baseline;gap:20px;padding:20px 0;border-bottom:1px solid rgba(21,23,26,.1)}
.stat:first-child{border-top:1px solid rgba(21,23,26,.1)}
.stat b{font-family:var(--serif);font-weight:300;font-size:clamp(34px,4.4vw,58px);line-height:1;min-width:3.4ch;color:var(--ink)}
.stat span{font-size:14px;color:var(--ink-2);max-width:30ch}

.rows{list-style:none;margin:0;padding:0}
.rows li{border-bottom:1px solid rgba(21,23,26,.1)}
.rows li:first-child{border-top:1px solid rgba(21,23,26,.1)}
.rows li,.rows a{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr) auto;gap:20px;align-items:baseline;padding:18px 0;text-decoration:none}
.rows a{padding:0;border:0}
.rows li:has(a){padding:0}
.rows span{font-size:16px;color:var(--ink)}
.rows i{font-style:normal;font-size:11px;text-transform:uppercase;letter-spacing:.16em;color:var(--ink-3)}
.rows em{font-style:normal;font-family:var(--mono);font-size:10px;letter-spacing:.1em;color:var(--ink-3);text-align:right;white-space:nowrap}
.rows--links a:hover span{color:var(--accent)}

/* subscribe */
.sub{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;width:min(520px,100%)}
.sub__in{flex:1 1 240px;height:46px;padding:0 16px;border:1px solid rgba(255,255,255,.22);border-radius:8px;background:rgba(255,255,255,.06);color:var(--light);font-family:var(--sans);font-size:15px}
.sub__in::placeholder{color:rgba(255,255,255,.4)}
.sub__in:focus-visible{outline:2px solid var(--light);outline-offset:1px}
/* Solid accent — the one primary action on the site, so it earns the
   strongest treatment. Oxblood is dark enough that white type on it
   stays comfortably legible. */
.sub__go{height:46px;padding:0 26px;border:0;border-radius:8px;background:var(--accent);color:#fff;font-family:var(--sans);font-size:15px;font-weight:500;cursor:pointer;transition:filter .18s var(--ease)}
.sub__go:hover{background:var(--accent-soft)}
.sub__go:hover{filter:brightness(1.1)}
/* Reserves its line at all times so a reply does not shove the footnote
   and the social links downward. */
.sub__msg{flex:1 0 100%;min-height:1.35em;margin:2px 0 0;font-size:13px;line-height:1.35;
  color:var(--light-2);text-align:center}
.sub[data-state=error] .sub__msg{color:var(--accent-soft)}
.sub[data-state=error] .sub__in{border-color:var(--accent-soft)}
/* Success is Substack's page, not ours — the browser has navigated away
   by then, so there is no `done` state to style. */
.ends{display:flex;gap:26px;font-size:11px;text-transform:uppercase;letter-spacing:.2em}
.ends a{color:var(--light-2);text-decoration:none}
.ends a:hover{color:var(--light)}

@media(max-width:860px){
  /* Pinning is kept on phones — cards still stick and stack. Only the
     internal layout reflows. Dwell is shortened because a full 85svh of
     stillness reads as a dead zone on a short screen with thumb scrolling. */
  .card{--dwell:55svh}
  .card__inner{padding:clamp(22px,6vw,34px)}
  .card__inner--split{grid-template-columns:1fr;gap:28px;align-content:center}
  .card__inner--center{gap:24px}
  .ghosts li{justify-content:flex-start}
  .rows li,.rows a{grid-template-columns:1fr auto;gap:6px 14px}
  .rows i{grid-column:1/-1}
  .card__main{align-self:start}
}

/* Very short viewports: content must scroll inside the pinned card
   rather than being clipped by overflow:hidden. */
@media(max-height:620px){
  .card__inner{overflow-y:auto;-webkit-overflow-scrolling:touch}
}

@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
}

/* ---------- reel with only a couple of pieces ----------
   A marquee of two images reading "sleep, red, sleep, red" looks broken,
   not deliberate. With fewer items than fill the viewport the track stops
   scrolling and centres instead. Remove .reel--few from the HTML once
   there are five or six pieces and the loop resumes untouched. */
/* The mask on .reel feathers the marquee where it enters and leaves the
   viewport. With a static, centred pair there is nothing entering or
   leaving — it just blurs the outer edges of both photographs. Turned
   off here; it comes back automatically when .reel--few is removed. */
.reel--few{-webkit-mask-image:none;mask-image:none}
.reel--few .reel__track{animation:none;width:100%;justify-content:center;
  align-items:flex-end;gap:clamp(30px,5vw,90px)}

/* Plates are now links. The whole tile is the target, the caption sits
   under it, and colour arrives on hover exactly as before. */
.plate__link{display:block;text-decoration:none;color:inherit}
.plate__link:focus-visible{outline:2px solid var(--accent);outline-offset:6px;border-radius:5px}
.plate__cap{margin:14px 0 0;font-family:var(--sans);font-size:13px;line-height:1.35;color:var(--ink-2);
  display:flex;flex-direction:column;gap:2px;
  opacity:0;transform:translateY(-4px);transition:opacity .3s var(--ease),transform .3s var(--ease)}
.plate__cap i{font-style:normal;font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--accent)}
.plate:hover .plate__cap,.plate__link:focus-visible .plate__cap{opacity:1;transform:none}
/* The tall plate keeps its stagger; this one drops a little further so the
   pair doesn't read as a matched set. */
.plate--drop{margin-bottom:0!important;align-self:flex-end}

/* Rows without a date column. .rows is a 3-column grid; dropping the
   third child would otherwise leave a dead column and push the middle
   label away from the right edge. */
.rows--nodate li,.rows--nodate a{grid-template-columns:minmax(0,1.5fr) minmax(0,1fr)}

/* Article thumbnails in the writing list. Grid gains a leading auto
   column; the rest of the row keeps its proportions. Greyscale-to-colour
   on hover mirrors the hero reel, so the same gesture does the same thing
   in both places. */
.rows--thumbs li,.rows--thumbs a{grid-template-columns:auto minmax(0,1.5fr) minmax(0,1fr) auto}
.row__thumb{width:clamp(44px,4vw,58px);aspect-ratio:4/5;border-radius:3px;align-self:center;
  background-size:cover;background-position:center;
  filter:grayscale(1);transition:filter .4s var(--ease)}
.rows--links a:hover .row__thumb{filter:grayscale(0)}

/* Signl — a band of protocol illustrations along the foot of the card.
   One illustration would say "a protocol"; a field says "a library", which
   is what the card is actually about. Full colour and full opacity: the
   illustrations are worth looking at, and a band gives them their own
   territory instead of making them fight the copy the way a full-bleed
   wash at this strength does. Tiles are tone-matched and cross-faded at
   source, so the field reads as continuous rather than as a grid.
   --signl-band is the only knob; content clears it via padding-bottom. */
.card--signl .card__inner{position:relative;isolation:isolate;
  --signl-band:34%;padding-bottom:calc(var(--signl-band) + 2vh)}
.card--signl .card__inner::before{content:'';position:absolute;inset:auto 0 0 0;z-index:-1;
  height:var(--signl-band);
  background:url(assets/signl-protocols-color.jpg) center/cover no-repeat;
  -webkit-mask-image:linear-gradient(180deg,transparent,#000 40%);
  mask-image:linear-gradient(180deg,transparent,#000 40%)}
