/* Volley journal — Court & Garden, "Bento" direction (1g).
   Built from design_handoff_journal_bento. Tokens are the handoff's, verbatim.

   ONE DEPARTURE, AND IT IS DELIBERATE: the handoff's photo slots are empty
   placeholders and it says so — "real garment flat-lays are still needed". We
   have none. Rather than borrow an ambient scene (the hard rules say no people
   and only garments, and our scene library is rooms, not clothes), every photo
   slot renders as the tint wall it will sit inside. The layout is final; the
   plates are waiting. */

:root {
  /* grounds and fills */
  --cream: #F6F1E6;        /* page ground (journal only) */
  --card: #FFFFFF;
  --tint: #F5EFDF;
  --sage: #E9EEDC;
  --pink-soft: #F8E6EB;
  --blush: #F6E2E7;
  /* Court & Garden: a FIELD colour, never a button. Declared for the 1h
     sticker layer (260925 journal bento); matches tokens.json color.court-pink. */
  --court-pink: #E8A6B8;
  --line: #E6E1D0;
  --pine: #2F4023;
  --grass: #5E7E44;
  --rose: #C25E7E;
  /* rose-as-type. #C25E7E is 3.59 on cream - below the 4.5 a body line needs.
     S2 from the Sep 25 sync: rose that carries WORDS is rose-deep. */
  --rose-deep: #963955;
  --ball: #D9E48A;         /* court ball — house token, added 260929 */
  /* text */
  --ink: #2E3A22;          /* no black anywhere */
  --sub: #5C6252;
  --rose-deep: #963955;
  --grass-text: #4C6636;
  /* marks, never text */
  --fog: #7C8370;
  /* radii by role */
  --r-depict: 6px;
  --r-control: 14px;
  --r-surface: 22px;
  --r-pill: 999px;
  /* shadows: single source, pine-tinted, never grey */
  --sh-tile: 0 18px 36px rgba(47,64,35,.14);
  --sh-mat: 0 16px 32px rgba(47,64,35,.10);
  --sh-label: 0 10px 24px rgba(47,64,35,.06);
  --sh-rose: 0 8px 20px rgba(194,94,126,.28);
  --sh-grass: 0 8px 20px rgba(94,126,68,.30);
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: Archivo, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: 19px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: 1280px; margin: 0 auto; padding: 0 48px; }

a { color: inherit; }
a:focus-visible, button:focus-visible, input:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* ── type ──────────────────────────────────────────────────────────────── */
.fr { font-family: Fraunces, Georgia, "Times New Roman", serif; }
.mono {
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  font-size: 10.5px; color: var(--sub);
}

/* ── nav ───────────────────────────────────────────────────────────────── */
.nav { display: flex; align-items: center; gap: 24px; padding: 32px 0 8px; flex-wrap: wrap; }
.mark { font-family: Fraunces, Georgia, serif; font-weight: 600; font-size: 28px; letter-spacing: -.02em; text-decoration: none; }
.mark::after { content: ""; display: block; width: 40px; height: 2px; background: var(--rose); margin-top: 4px; }
.tabs {
  display: flex; align-items: center; gap: 0; height: 56px; padding: 0 22px;
  border: 1.5px solid var(--line); border-radius: var(--r-pill); background: transparent;
}
.tabs a { text-decoration: none; font-size: 15px; padding: 0 14px; }
.tabs a[aria-current] { font-weight: 700; }
.tabs .dot { width: 4px; height: 4px; border-radius: 50%; background: var(--fog); }
.navspace { flex: 1 1 auto; }

/* ── buttons ───────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 52px; padding: 0 26px; border-radius: var(--r-pill);
  font-family: Archivo, system-ui, sans-serif; font-weight: 700; font-size: 16px;
  text-decoration: none; border: 0; cursor: pointer; white-space: nowrap;
  transition: transform .22s cubic-bezier(.2,.7,.1,1);
}
.btn-rose { background: var(--rose); color: var(--cream); box-shadow: var(--sh-rose); }
.btn-grass { background: var(--grass); color: var(--cream); box-shadow: var(--sh-grass); }
.btn-quiet { background: transparent; color: var(--ink); border: 1.5px solid var(--line); }
.btn:hover { transform: translateY(-3px); }
.btn:active { transform: scale(.99); }

/* ── header ────────────────────────────────────────────────────────────── */
.jhead { display: flex; align-items: flex-end; justify-content: space-between; gap: 40px; margin: 40px 0 28px; flex-wrap: wrap; }
.jhead h1 { font-family: Fraunces, Georgia, serif; font-weight: 800; font-size: 132px; line-height: .82; letter-spacing: -.05em; margin: 0; }
.jhead .letter { display: flex; align-items: center; gap: 18px; max-width: 460px; }
.jhead .letter p { margin: 0; font-size: 17px; color: var(--sub); }

/* ── bento ─────────────────────────────────────────────────────────────── */
/* minmax(0,…) rather than bare fr: a grid item's default min-width is auto,
   so a long unbroken title can push a column wider than its track and shove
   the others off. The design source uses minmax for the same reason. */
.bento { display: grid; grid-template-columns: minmax(0, 1.36fr) minmax(0, 1.24fr) minmax(0, .72fr); grid-auto-rows: 520px 350px; gap: 10px; }
.tile { border-radius: var(--r-surface); overflow: hidden; position: relative; transition: transform .22s cubic-bezier(.2,.7,.1,1), box-shadow .22s; }
a.tile { text-decoration: none; color: inherit; }
a.tile:hover { transform: translateY(-3px); box-shadow: var(--sh-tile); }
a.tile:active { transform: scale(.99); }
.tile-lead { grid-row: span 2; background: var(--tint); display: flex; align-items: flex-end; }
.tile-sage { background: var(--sage); padding: 32px; display: flex; flex-direction: column; }
.tile-photo { background: var(--tint); display: flex; align-items: flex-end; padding: 18px; }
.tile-pine { background: var(--pine); padding: 28px; display: flex; flex-direction: column; justify-content: space-between; }

/* the notched title tab, cut into the lead tile's bottom-left */
.tab {
  background: var(--cream); max-width: 470px; padding: 26px 30px 24px;
  border-top-right-radius: var(--r-surface);
  -webkit-mask-image: radial-gradient(circle at 100% 0, transparent 21.5px, #000 22px);
  mask-image: radial-gradient(circle at 100% 0, transparent 21.5px, #000 22px);
}
.tab h2 { font-family: Fraunces, Georgia, serif; font-weight: 800; font-size: 50px; line-height: 1.02; letter-spacing: -.035em; margin: 8px 0 0; }
.pill-meta {
  position: absolute; top: 18px; left: 18px; z-index: 2;
  background: var(--cream); border-radius: var(--r-pill); padding: 7px 14px;
}

.tile-sage .kicker { margin-bottom: 10px; }
.tile-sage h3 { font-family: Fraunces, Georgia, serif; font-weight: 700; font-size: 46px; line-height: 1.02; letter-spacing: -.035em; margin: 0 0 12px; }
.tile-sage .dek { font-size: 17px; color: var(--sub); margin: 0 0 auto; }
.rowlist { margin-top: 24px; }
.rowlist .row {
  display: flex; justify-content: space-between; align-items: center; gap: 16px;
  border-top: 1.5px solid var(--ink); padding: 14px 0 12px;
  font-family: Fraunces, Georgia, serif; font-weight: 500; font-size: 17px;
  text-decoration: none; transition: color .16s;
}
.rowlist .row:hover { color: var(--rose-deep); }

.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  border-radius: var(--r-pill); padding: 8px 15px; font-size: 14px;
  border: 1.5px solid rgba(246,241,230,.35); color: var(--cream); text-decoration: none;
}
.chip[aria-current] { background: #D9E48A; color: var(--ink); border-color: #D9E48A; } /* chartreuse only on pine */
.pinecount { display: flex; align-items: center; gap: 14px; color: var(--cream); }
.ball { width: 56px; height: 56px; border-radius: 50%; background: #D9E48A; flex: none; }

/* ── THE MATTED PLATE (design: 24px mat, radius 6, inside the tint wall) ──
   This is what makes borrowed photography sit correctly beside our cream: the
   photo is an OBJECT on a mat, not the page's ground, so its own grey or linen
   never competes with ours. Stock is licensed free for commercial use
   (Unsplash), garments only, no people and no third-party marks — the three
   things that killed the SS27 carousel on rights. */
.plate { position: absolute; inset: 0; padding: 24px; background: var(--tint); }
.plate img {
  width: 100%; height: 100%; object-fit: cover;
  /* NOT `center`. These are full-length frames — a runway shot or a hanging
     garment is 3:4 or taller, and a centred crop lands on the middle of a
     skirt. Anchoring at 28% keeps the part of the garment that carries the
     picture (neckline, shoulder, the place the eye goes) inside the plate. */
  object-position: center 28%;
  border-radius: var(--r-depict); box-shadow: var(--sh-mat); display: block;
}
.plate-lead { padding: 0; }
.plate-lead img { border-radius: 0; box-shadow: none; }

/* ── A FIGURE INSIDE THE PROSE (2026-09-29) ────────────────────────────────
   `.plate` is absolutely positioned inside a fixed frame at the top of a
   piece. A photograph in the BODY is a different object: it sits in the text
   flow, keeps its own aspect, and is never cropped — because a picture the
   writer chose to put beside a sentence is chosen for its whole frame, not
   for the part a 28% anchor happens to keep.

   `max-height` rather than a fixed one: the two Cavalli frames are 3:4 and
   2:3, and a runway shot allowed to run its full height at body width pushes
   the paragraph after it off the screen entirely on a phone.

   NO UPSCALING PAST THE PIXELS. `cavalli-peacock-SMALL.jpg` is 365x547 and
   its name says so. `max-width: 365px` on that one frame is not a style
   choice, it is the file's own ceiling — the repo already carries what
   ignoring one costs (cutouts fed from 360px thumbnails at 3.15x upscale). */
.fig { margin: 36px 0; }
.fig img {
  display: block; width: 100%; height: auto; max-height: 70vh;
  object-fit: contain;
  border-radius: var(--r-depict); box-shadow: var(--sh-mat); background: var(--tint);
}
.fig figcaption {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--fog); margin-top: 10px;
}
.fig-small img { max-width: 365px; margin: 0 auto; }

/* the empty-photo treatment — see the header note */
.slot { position: absolute; inset: 0; background: var(--tint); }
.slot::after {
  /* bottom-left, not top-left: the meta pill lives at top-left on the lead
     tile and the two collided in the first render. */
  content: attr(data-note); position: absolute; left: 20px; bottom: 16px;
  font-family: "JetBrains Mono", ui-monospace, monospace; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; font-size: 9.5px; color: var(--fog);
}

/* ── the note under the grid ───────────────────────────────────────────── */
.sofar { margin: 28px 0 0; font-size: 17px; color: var(--sub); }

/* ── everything else (design: 4 columns grouped by kind) ───────────────── */
.everything { margin: 96px 0 0; }
.everything h3 { margin: 0 0 24px; }
.ecols { display: grid; grid-template-columns: repeat(4, 1fr); gap: 40px; align-items: start; }
.ecol h4 { font-family: Fraunces, Georgia, serif; font-weight: 700; font-size: 26px; letter-spacing: -.02em; margin: 0 0 10px; padding-bottom: 12px; border-bottom: 1.5px solid var(--ink); display: flex; justify-content: space-between; align-items: baseline; }
.ecount { font-family: "JetBrains Mono", ui-monospace, monospace; font-weight: 700; font-size: 11px; color: var(--sub); }
.ecol-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 13px 0; border-bottom: 1px solid var(--line); text-decoration: none; font-family: Fraunces, Georgia, serif; font-weight: 500; font-size: 17px; line-height: 1.25; transition: color .16s; }
.ecol-row:hover { color: var(--rose-deep); }
.ecol-row .mono { flex: none; }

@media (max-width: 860px) {
  .ecols { grid-template-columns: 1fr; gap: 32px; }
  .everything { margin-top: 56px; }
}

/* ── footer ────────────────────────────────────────────────────────────── */
/* ── on the desk: the Spotify player on the front page (2026-10-05) ──────── */
.jplay { margin: 56px auto 0; max-width: 720px; display: flex; flex-direction: column; gap: 16px; align-items: center; text-align: center; }
.jplayhead { display: flex; flex-direction: column; gap: 6px; align-items: center; }
.jplayframe { width: 100%; }
.jplayhead h2 { margin: 0; font-weight: 800; font-size: clamp(26px, 3.2vw, 36px); line-height: 1.1; }
.jplayframe { display: block; border: 0; border-radius: var(--r-control); background: var(--tint); }
.jplaynote { margin: 0; font-size: 14px; color: var(--sub); }
.jplaynote a { color: var(--rose-deep); }


/* ── piece ─────────────────────────────────────────────────────────────── */
.progress { position: fixed; top: 0; left: 0; height: 2px; background: var(--grass); width: 0; z-index: 9; }
.titlerow { display: grid; grid-template-columns: 1.15fr 1fr; gap: 10px; margin: 28px 0 56px; }
.titletile { background: var(--sage); border-radius: var(--r-surface); padding: 40px; }
.titletile h1 { font-family: Fraunces, Georgia, serif; font-weight: 800; font-size: 104px; line-height: .92; letter-spacing: -.05em; margin: 18px 0 18px; }
.titletile h1.t-mid  { font-size: 76px; }
.titletile h1.t-long { font-size: 58px; line-height: .98; letter-spacing: -.035em; }
.titletile .dek { font-size: 21px; color: var(--sub); margin: 0; }
.metapills { display: flex; gap: 8px; flex-wrap: wrap; }
.metapills span { background: var(--cream); border-radius: var(--r-pill); padding: 7px 14px; }

.bodygrid { display: grid; grid-template-columns: 260px 1fr 260px; gap: 40px; align-items: start; }
.walllabel, .curators {
  background: var(--card); border-radius: var(--r-depict); padding: 22px 20px;
  box-shadow: var(--sh-label); font-size: 14px; color: var(--sub);
}
.walllabel h4 { font-family: Fraunces, Georgia, serif; font-weight: 300; font-size: 22px; color: var(--ink); margin: 10px 0 8px; letter-spacing: -.01em; }
.curators { border-left: 2px solid var(--grass); }
.curators h4 { margin: 8px 0 8px; font-family: Fraunces, Georgia, serif; font-weight: 300; font-size: 20px; color: var(--ink); }
.body { max-width: 65ch; }
.body p { margin: 0 0 22px; }
.body h2 { font-family: Fraunces, Georgia, serif; font-weight: 700; font-size: 40px; line-height: 1.08; letter-spacing: -.03em; margin: 56px 0 18px; }
.body em { color: var(--sub); }
.body a { color: var(--rose-deep); }

.quotewall { background: var(--sage); border-radius: var(--r-surface); padding: 64px; margin: 72px 0; }
.quotewall blockquote { margin: 0; font-family: Fraunces, Georgia, serif; font-weight: 300; font-style: italic; font-size: 62px; line-height: 1.06; letter-spacing: -.03em; }

.closing { font-family: Fraunces, Georgia, serif; font-weight: 700; font-size: 30px; line-height: 1.22; letter-spacing: -.02em; margin: 48px 0 28px; }
.endmark { width: 22px; height: 22px; border: 2px solid var(--grass); border-radius: 50%; }


.share { margin-top: 56px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* ── phone ─────────────────────────────────────────────────────────────── */
@media (max-width: 860px) {
  body { font-size: 17px; line-height: 1.6; }
  .wrap { padding: 0 12px; }
  .nav { gap: 14px; padding-top: 18px; }
  .tabs { display: none; }
  .jhead { margin: 22px 0 18px; align-items: flex-start; }
  .jhead h1 { font-size: 62px; }
  .jhead .letter { max-width: none; flex-direction: column; align-items: flex-start; gap: 12px; }
  .bento { grid-template-columns: 1fr 1fr; grid-auto-rows: auto; }
  .tile-lead { grid-column: 1 / -1; grid-row: auto; min-height: 400px; }
  .tile-sage, .tile-photo, .tile-pine, .tile-blush, .tile-tintpiece { grid-column: span 1; min-height: 300px; }
  .tab h2 { font-size: 32px; }
  .titlerow { grid-template-columns: 1fr; margin-bottom: 32px; }
  .titletile { padding: 24px; }
  .titletile h1 { font-size: 44px; }
  .titletile h1.t-mid { font-size: 38px; }
  .titletile h1.t-long { font-size: 32px; }
  .titletile .dek { font-size: 18px; }
  .bodygrid { grid-template-columns: 1fr; gap: 28px; }
  .walllabel { display: none; }        /* the room label is desktop chrome */
  .quotewall { padding: 28px; margin: 44px 0; }
  .quotewall blockquote { font-size: 30px; }
  .closing { font-size: 24px; }
}

/* AX1 and up: chrome changes shape rather than shrinking */
@media (max-width: 860px) and (min-resolution: 1x) {
  .jhead .letter .btn { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
  a.tile:hover { transform: none; }
}

/* ── 1h · THE STICKER BOARD (Tate 2026-09-25, star in COURT-PINK) ─────────
   He chose 1h over the clean 1g, with one amendment: the star is court-pink
   #E8A6B8, not chartreuse. The README asked for chartreuse and said out loud
   that it "bends a rule" — chartreuse off pine — naming court-pink or cream as
   the fallbacks. He took court-pink, so nothing bends. Worth recording because
   nothing here would have caught it: "chartreuse only on pine" is a FEEL-lens
   item in CLAUDE.md, a human check, and the pre-cut sweep runs on app builds,
   not on this site.

   EVERY STICKER IS DECORATION. `pointer-events: none` so a tap always reaches
   the tile underneath, and the markup carries `aria-hidden="true"` so a screen
   reader never reads one. The prototype set pointer-events and NOT aria-hidden;
   the README claims both. Both are here.

   NONE OF THEM CARRIES MEANING, which is the README's binding rule for this
   layer, so the 4.5:1 contrast floor does not apply to them — they are marks,
   not type to be understood. The one that comes closest is the ticket stub,
   because it names a read time, and it is therefore only ever placed on a tile
   that HAS one. */
/* The minmax() columns moved UP to the base `.bento` rule (search "minmax").
   THEY CANNOT LIVE DOWN HERE. This block is appended AFTER the
   `max-width: 860px` media query, and a later rule of equal specificity wins
   regardless of the media query — so a `.bento { grid-template-columns: … }`
   at the end of the file silently overrode the phone's two-column collapse
   and left the bento at three columns on a 375px screen. It looked perfect on
   desktop. Caught by emulating a phone, not by reading the diff. */

.sticker { position: absolute; pointer-events: none; z-index: 3; }
.sticker svg { width: 100%; height: 100%; display: block; }

/* The star, and the pin through it. */
.sticker-star {
  top: 26px; right: 30px; width: 150px; height: 150px;
  transform: rotate(14deg);
  filter: drop-shadow(0 6px 8px rgba(47, 64, 35, .28));
}
.sticker-pin {
  top: 52px; right: 92px; width: 34px; height: 34px;
  filter: drop-shadow(3px 5px 3px rgba(47, 64, 35, .35));
}

/* The polaroid lead: a white border and one degree off square. The rotation is
   on the TILE, so its hover lift has to restate it or the tile snaps straight
   on hover — which is the kind of thing that looks like a bug and is a missing
   transform. */
.tile-polaroid {
  border: 10px solid #FFF;
  box-shadow: 0 14px 30px rgba(47, 64, 35, .16);
  transform: rotate(-1deg);
}
a.tile-polaroid:hover { transform: rotate(-1deg) translateY(-3px); }
a.tile-polaroid:active { transform: rotate(-1deg) scale(.99); }

/* The two tiles the grid always had room for and never had. */
.tile-blush, .tile-tintpiece {
  display: flex; flex-direction: column; justify-content: flex-end;
}
.tile-blush { background: var(--blush); overflow: visible; }
.tile-tintpiece { background: var(--tint); }
/* THE PHOTO FILLS THESE TILES, so the shared `.plate` rule has to be undone
   here. `.plate` is written for the piece-page hero: `padding: 24px` and
   `background: var(--tint)`. On a bento tile that does two wrong things at
   once — it insets the photograph by 24px on every side, AND it paints tint
   over the tile's own colour, which is why the blush tile came out looking
   tint. `.plate-lead` already solved this for the lead tile with `padding: 0`;
   these two need the background cleared as well, because unlike the lead they
   sit on a tile whose colour is part of the design. */
.tile-blush .plate, .tile-tintpiece .plate { padding: 0; background: transparent; }
.tile-blush .plate img, .tile-tintpiece .plate img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  border-radius: 0; box-shadow: none;
}
/* ── THE UNDERWEAR TILE SHOWS HER FACE (Tate, 2026-10-02) ──────────────────
   "lower it a bit so we can see her face but ensure the sticker isn't placed
   over the bra."

   MEASURED rather than nudged. The box is 435×190 and the frame is 933×1400,
   so `cover` scales to the width and hides 463px of height. At the inherited
   `28%` the visible band was source 20%–49% — her face sits at about 11% and
   was cut off entirely, and the burgundy bra landed dead centre under the
   sticker. At 10% the band is 7%–36%: the face is in, the bra sits in the
   lower half, and nothing else on the page moves because this is scoped to the
   one tile rather than to `.plate img`. */
.tile-tintpiece .plate img { object-position: 50% 10%; }
.tiletext {
  position: relative; z-index: 2; margin: 0 18px 18px;
  background: var(--cream); border-radius: var(--r-depict); padding: 16px 18px;
}
.tiletext .kicker { margin-bottom: 8px; }
.tiletext h3 {
  font-family: Fraunces, Georgia, serif; font-weight: 700; font-size: 26px;
  line-height: 1.04; letter-spacing: -.03em; margin: 0;
}

/* "on loan" — it overhangs the tile corner, which is why .tile-blush is
   overflow:visible and not hidden like every other tile. */
.sticker-onloan {
  top: -14px; right: -10px; width: 96px; height: 96px; border-radius: 50%;
  background: var(--court-pink); border: 5px solid #FFF; box-sizing: border-box;
  transform: rotate(-12deg);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-style: italic; font-size: 19px; color: var(--ink);
  box-shadow: 0 4px 10px rgba(47, 64, 35, .18);
}

/* The ticket stub. Only ever on a tile with a real read time. */
.sticker-stub {
  /* Moved out of the middle of the frame, 2026-10-02. At `right:88px; top:74px`
     it sat at box x191–349 / y65–121, and with the crop raised the bra lands at
     roughly x200–280 / y111–144 — an overlap of the one thing the piece is
     about. Top right puts it over the dark doorway instead, which is the only
     quiet corner this photograph has. */
  right: 14px; top: 14px; white-space: nowrap; transform: rotate(7deg);
  background: #FFF; border: 2px dashed var(--fog); border-radius: var(--r-depict);
  padding: 8px 14px; font-weight: 700; font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink);
}

/* ── the header doodles ─────────────────────────────────────────────────── */
.jtitle { position: relative; }
.doodle { position: absolute; pointer-events: none; overflow: visible; z-index: 0; }
.doodle-loop { left: -30px; top: -40px; width: 560px; height: 210px; }
.jtitle h1 { position: relative; z-index: 1; }
.doodle-note {
  position: absolute; font-style: italic; font-weight: 500; white-space: nowrap;
  pointer-events: none;
}
.doodle-note-new { left: 470px; top: -18px; transform: rotate(-6deg); font-size: 22px; color: var(--rose-deep); }
.letterwrap { position: relative; display: inline-flex; align-items: center; }
.doodle-arrow { left: -128px; top: -30px; width: 120px; height: 90px; }
.doodle-note-sched { left: -330px; top: -44px; transform: rotate(-4deg); font-size: 20px; color: var(--grass-text); }

@media (max-width: 860px) {
  /* Phone keeps the star and the pin and drops the rest — the README's call.
     A doodle positioned off the left of a 375px viewport is a horizontal
     scrollbar, not a decoration. */
  .doodle, .doodle-note, .sticker-stub { display: none; }
  .sticker-star { width: 84px; height: 84px; top: 16px; right: 18px; }
  .sticker-pin { top: 32px; right: 54px; }
  .sticker-onloan { width: 72px; height: 72px; font-size: 15px; top: -10px; right: -6px; }
}

/* ── A PHONE GETS ONE COLUMN, NOT TWO (2026-09-25) ───────────────────────
   The 860px block collapses the bento from three columns to two. At 375px that
   is two ~170px tracks, and `.tile-sage h3` is 46px Fraunces — so "Notes about
   the closet you already have" set one word per line and "already" ran out past
   the tile's right edge. PRE-EXISTING, not introduced by the sticker work: the
   sage tile has been in that two-column collapse since the bento shipped. It
   surfaced now only because emulating a phone is what finally happened.

   Two columns is right for a tablet and wrong for a phone, so the breakpoint
   splits rather than the type shrinking twice. Below 640px everything stacks
   full width, which is also what the handoff's phone index draws. */
@media (max-width: 640px) {
  .bento { grid-template-columns: 1fr; }
  .tile-lead, .tile-sage, .tile-photo, .tile-pine,
  .tile-blush, .tile-tintpiece { grid-column: 1 / -1; }
  .tile-sage { padding: 24px; }
  .tile-sage h3 { font-size: 32px; }
  .tile-sage .dek { font-size: 16px; }
  .tiletext h3 { font-size: 22px; }
  /* The polaroid's tilt costs horizontal room it does not have at 375px, and a
     rotated full-bleed tile is what puts a sideways scrollbar on a phone. */
  .tile-polaroid { transform: none; border-width: 8px; }
  a.tile-polaroid:hover, a.tile-polaroid:active { transform: none; }
}

/* ── HOUSE ART IS CONTAINED, NOT COVERED (260926 art placement) ──────────────
   `.plate img` covers at `center 28%` because it was written for photographs —
   loose full-length frames that are meant to be cropped. The nine A1–A9
   artworks are COMPOSED: a3a is a horizontal strip of three numbered moves, and
   covering it into the near-square piece-page plate cropped the first and third
   away, leaving a reader two and a half of the three moves the article teaches.
   Contained art letterboxes onto the tint the plate already paints, which reads
   as deliberate rather than as a crop that went wrong. */
.plate-art img { object-fit: contain; object-position: center; }

/* ══ PANTONE EDGE SLIVERS — variant B (Tate, 2026-09-26) ════════════════════
   "pantone color strips along the left and right hand side of the screen as the
   user scrolls down, the color splotches we name." Three variants were built and
   he chose B: flush to the page edge, name set vertically, rather than chips in
   the margin or one continuous rail. Quieter, and it never borrows from the text
   column — which is what makes it survive a narrow window.

   THE SLIVERS ARE POSITIONED AGAINST `.bodygrid`, which is inside `.wrap`
   (max-width 1280, padding 0 48px). `left:-48px` therefore lands them on the
   page edge at any width up to 1280 and tucks them just outside the column
   beyond it, which is the behaviour we want in both directions.

   `--i` AND `--n` DO THE STAGGER so the rhythm follows the palette instead of a
   fixed cadence: ten SS27 colours pack, five AW26 colours breathe, with no
   second rule. Each sliver sits at `(i + .5) / n` of the body's height. */
.palrail { position: absolute; inset: 0; pointer-events: none; }
.bodygrid { position: relative; }
.pal {
  position: absolute; width: 22px; height: 168px; border-radius: 3px;
  top: calc((var(--i) + .5) / var(--n) * 100%);
  opacity: 0; transition: opacity .5s ease, transform .6s cubic-bezier(.22,.7,.3,1);
}
.pal-l { left: -48px; transform: translateX(-16px); }
.pal-r { right: -48px; transform: translateX(16px); }
.pal.in { opacity: 1; transform: none; }
.pal-nm {
  position: absolute; top: 0; font-size: 9px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--sub); white-space: nowrap;
  writing-mode: vertical-rl;
}
.pal-l .pal-nm { left: 28px; }
.pal-r .pal-nm { right: 28px; transform: rotate(180deg); }

/* A PHONE HAS 12px OF GUTTER — `.wrap` drops to `padding: 0 12px` at 860, so a
   22px labelled sliver would sit ON the text. It becomes an unlabelled 7px tick
   flush to the edge instead: the colour still arrives as she scrolls, and every
   name is already written out in the prose a few centimetres away. */
@media (max-width: 860px) {
  .pal { width: 7px; height: 100px; }
  .pal-l { left: -12px; }
  .pal-r { right: -12px; }
  .pal-nm { display: none; }
}

/* Court & Garden: motion is never the only carrier. With reduce-motion the
   swatches are simply present from the start — no slide, no fade. */
@media (prefers-reduced-motion: reduce) {
  .pal { opacity: 1; transform: none; transition: none; }
}

/* The proxy the observer actually watches — see `palette_rail` in build.py.
   1px, transparent, and positioned INSIDE the text column so it is on screen
   while its parent sliver is still parked past the page edge. */
.pal-hit { position: absolute; top: 0; width: 1px; height: 100%; }
.pal-l .pal-hit { left: 64px; }
.pal-r .pal-hit { right: 64px; }

/* ── J2 · MORE TO READ (design_handoff_journal_index, 2026-09-30) ───────── */
.j2{ display:flex; flex-direction:column; gap:18px; padding-top:28px;
     border-top:1px solid #DDD3BA; margin-top:12px;
     /* THE ROWS BLEED TO THE EDGE (.j2scroll has margin:0 -20px) AND THAT MADE
        THE WHOLE PAGE SCROLL SIDEWAYS ON A PHONE — measured at 390px: the
        scroller's right edge landed at 398. `clip` contains the bleed without
        creating a scroll container, so the rows still scroll horizontally
        inside themselves and the page no longer does. */
     overflow-x:clip; }
.j2head{ display:flex; justify-content:space-between; align-items:flex-end;
         gap:14px; flex-wrap:wrap; }
.j2headl{ flex:1 1 320px; min-width:0; display:flex; flex-direction:column; gap:6px; }
.j2eyebrow{ font-family:'JetBrains Mono',monospace; font-weight:700; font-size:11px;
            letter-spacing:.12em; color:var(--grass); }
.j2head h2{ margin:0; font-weight:800; font-size:clamp(30px,4vw,48px);
            line-height:1.05; letter-spacing:-.03em; text-wrap:balance; }
.j2chips{ display:flex; gap:8px; flex-wrap:wrap; }
.j2chip{ cursor:pointer; height:40px; padding:0 16px; border-radius:999px; border:0;
         font:inherit; font-weight:600; font-size:14px; white-space:nowrap;
         background:#fff; color:var(--ink); }
.j2chip.on{ background:var(--pine); color:#F6F1E6; }

.j2rows{ position:relative; display:flex; flex-direction:column; }
.j2deco{ position:absolute; z-index:3; pointer-events:none; }
.j2decostar{ left:12%; top:-6px; width:86px; height:86px; background:var(--rose);
  transform:rotate(14deg);
  clip-path:polygon(50% 0%,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%); }
.j2decopill{ right:8%; top:46%; background:#D9E48A; color:var(--pine); border-radius:999px;
  padding:8px 14px; font-family:Fraunces,serif; font-style:italic; font-weight:600;
  font-size:17px; white-space:nowrap; transform:rotate(-7deg);
  box-shadow:0 8px 18px rgba(46,58,34,.18); }

/* The scroller is the swipe surface; the track inside it is what drifts. */
.j2scroll{ overflow-x:auto; overflow-y:hidden; margin:0 -20px; padding:18px 20px 22px;
  scrollbar-width:none; -webkit-overflow-scrolling:touch;
  touch-action:pan-x pan-y; overscroll-behavior-x:contain; }
.j2scroll::-webkit-scrollbar{ display:none; }
.j2row{ display:flex; gap:18px; width:max-content; align-items:flex-start;
        animation-timing-function:linear; animation-iteration-count:infinite; }
/* ONE COPY OF EACH TILE, SO THE MOTION REVERSES INSTEAD OF LOOPING.
   A seamless marquee is a repeat by construction; with no repeats there is
   nothing to come round, so the rows drift and turn back. `alternate` keeps
   that continuous — no jump at either end — and the percentages are small
   enough to stay inside the row's own overflow at any width. */
.j2row{ animation-direction:alternate; }
.j2left{ animation-name:j2L; }
.j2right{ animation-name:j2R; }
.j2row:hover, .j2row.hold{ animation-play-state:paused; }

/* ── THE DRIFT USED TO PUT TILES WHERE NO SWIPE COULD REACH THEM ───────────
   Tate, 2026-10-02: "cuts off the first piece when it's at the beginning …
   same on desktop though, keep the two rows, just ensure no tile are cut off
   from screen."

   A TRANSFORM DOES NOT AFFECT SCROLLABLE OVERFLOW. That is the whole bug, and
   it is why the old values could not be nudged into working. The track was
   translated by a percentage of its own width — measured on a 375px phone,
   14% of a 2020px row is **283px** — and `scrollLeft` cannot go below 0, so
   every pixel the row moved left of its origin became unreachable. The
   right-hand row was worse: it STARTS at `-14%`, so its first tile was clipped
   on the very first paint, before any animation had run. That is the "at the
   beginning" in the report.

   Translating the other way does not help either: content pushed right of the
   box is just as unreachable, because the transform still does not grow
   `scrollWidth`.

   SO THE TRAVEL IS A FIXED LENGTH AND THE TRACK IS PADDED BY IT. Padding DOES
   affect layout, so the padded box is inside `scrollWidth` and every position
   the animation can reach is a position a finger can reach. One variable keeps
   the two in step — change the travel and the padding follows, which is what
   stops this coming back. */
.j2rows{ --j2travel:140px; }
.j2row{ padding-left:var(--j2travel); }
@keyframes j2L{ from{transform:translateX(0)} to{transform:translateX(calc(-1 * var(--j2travel)))} }
@keyframes j2R{ from{transform:translateX(calc(-1 * var(--j2travel)))} to{transform:translateX(0)} }

.j2tile{ flex:none; border-radius:26px; overflow:hidden; background:#fff; color:inherit;
  text-decoration:none; display:flex; flex-direction:column;
  box-shadow:0 14px 30px rgba(46,58,34,.12); transform:rotate(var(--r));
  animation-name:j2bob; animation-timing-function:ease-in-out;
  animation-iteration-count:infinite; }
.j2tile:hover{ animation-play-state:paused; box-shadow:0 22px 40px rgba(46,58,34,.2); }
@keyframes j2bob{ 0%,100%{transform:translateY(0) rotate(var(--r))}
                  50%{transform:translateY(-6px) rotate(var(--r))} }
.j2art{ position:relative; height:200px; overflow:hidden; display:flex;
        align-items:center; justify-content:center; }
.j2star{ position:absolute; width:160px; height:160px; background:#D9E48A;
  transform:rotate(-8deg);
  clip-path:polygon(50% 0%,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%); }
.j2glyph{ position:relative; font-family:Fraunces,serif; font-weight:800; line-height:.9;
          letter-spacing:-.04em; text-align:center; white-space:nowrap; }
.j2new{ position:absolute; left:14px; top:14px; background:#fff; color:var(--rose-deep);
  border-radius:999px; padding:4px 10px; font-family:'JetBrains Mono',monospace;
  font-weight:700; font-size:10px; letter-spacing:.12em; }
.j2meta{ padding:16px 18px 20px; display:flex; flex-direction:column; gap:6px; }
.j2kind{ font-family:'JetBrains Mono',monospace; font-weight:700; font-size:10px;
         letter-spacing:.12em; color:var(--grass); }
.j2title{ font-family:Fraunces,serif; font-weight:600; font-size:21px; line-height:1.15;
          letter-spacing:-.01em; text-wrap:balance; }
.j2tile[hidden]{ display:none; }

/* Reduce Motion: no drift and no bob. The rows stay swipeable, which is the
   point — the animation was never the only way to reach a tile. */
@media (prefers-reduced-motion:reduce){
  .j2row, .j2tile{ animation:none !important; }
  .j2tile{ transform:rotate(var(--r)); }
  /* No drift means no travel to make room for — without this the row would sit
     140px in and never come back, which is the cut-off wearing the other face. */
  .j2row{ padding-left:0; }
}
@media (max-width:560px){
  .j2decostar{ width:60px; height:60px; left:6%; }
  .j2decopill{ font-size:14px; right:4%; }
}

/* ── NAV SEARCH (2026-09-30) ────────────────────────────────────────────── */
.jsearch{ position:relative; display:flex; align-items:center; }
.jsicon{ position:absolute; left:14px; width:18px; height:18px; color:var(--sub);
         pointer-events:none; }
.jsearch input{ height:40px; width:230px; max-width:44vw; border-radius:999px;
  background:#fff; border:1.5px solid #DDD3BA; padding:0 16px 0 38px;
  font:inherit; font-size:14px; color:var(--ink); outline:none;
  -webkit-appearance:none; appearance:none; }
.jsearch input::-webkit-search-cancel-button{ -webkit-appearance:none; }
.jsearch input:focus{ border-color:var(--grass); }
.jsresults{ position:absolute; top:48px; right:0; min-width:290px; max-width:82vw;
  background:#fff; border-radius:20px; overflow:hidden; z-index:40;
  box-shadow:0 18px 40px rgba(46,58,34,.18); }
.jsrow{ display:flex; flex-direction:column; gap:2px; padding:12px 16px;
        text-decoration:none; color:inherit; }
.jsrow + .jsrow{ border-top:1px solid var(--line); }
.jsrow:hover{ background:var(--tint); }
.jst{ font-family:Fraunces,serif; font-weight:600; font-size:16px; line-height:1.2; }
.jsk{ font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em;
      text-transform:uppercase; color:var(--grass); }
.jsempty{ padding:14px 16px; font-size:14px; color:var(--sub); }
@media (max-width:860px){ .jsearch{ display:none; } }

/* ── FEATURED GRID HEIGHT TRIM (design_handoff_journal_index, 2026-09-30) ──
   The lead spans two rows, so its height is set by the middle and right
   columns rather than by itself. The handoff's trim works on those: shorter
   Fall art, no min-heights on Fall or the chips card, a fixed floor on Paris,
   and a tighter "What this is". Kept at the end of the file so the numbers
   sit together and the next trim is one block rather than six edits. */
.tile-tintpiece .plate img { max-height: 190px; }          /* Fall art */
.tile-tintpiece, .tile-pine { min-height: 0; }             /* Fall + chips card */
.tile-blush { min-height: 480px; }                         /* Paris */
.tile-sage { padding: 30px 34px; }                         /* What this is */
.tile-sage h3 { font-size: clamp(32px, 3vw, 44px); }
.tile-lead .plate img, .tile-lead img { min-height: 300px; }
@media (max-width: 900px){
  /* The floor is a desktop-column device; at one column it would only add
     dead space under the art. */
  .tile-blush { min-height: 0; }
  .tile-tintpiece .plate img { max-height: none; }
}

/* ── MOBILE JOURNAL INDEX (design_handoff_journal_index_mobile, 2026-09-30) ──
   "Mobile restacks the page; it isn't just the desktop scaled down." Everything
   below 768 is this block; above it, nothing here applies and the desktop
   layout is untouched. The wrapper added around the two photo tiles is
   display:contents up here precisely so the bento grid never sees it. */
.pair{ display:contents; }
.jsbtn{ display:none; }
.ecol > summary{ list-style:none; }
.ecol > summary::-webkit-details-marker{ display:none; }

@media (min-width:768px){
  /* The kind groups are a disclosure for mobile's sake; at desktop they are
     always open and the summary is just the heading it wraps. */
  .ecol > summary{ pointer-events:none; }
}

@media (max-width:767.98px){
  /* 1 · sticky top bar */
  /* FULL BLEED WITHOUT OVERFLOWING. `margin:0 -20px` makes the box wider than
     its parent, and a parent already at the viewport's width then overflows —
     which is how the page got a horizontal scrollbar back. 100vw with a
     centring negative margin is exactly the viewport, never more. */
  .nav{ position:sticky; top:0; z-index:60; background:var(--cream);
        border-bottom:1px solid var(--line); padding:8px 18px 10px;
        display:flex; flex-wrap:wrap; align-items:center; gap:10px;
        width:100vw; margin-left:calc(50% - 50vw); }
  .nav .mark{ font-size:22px; }
  .navspace{ flex:1; }
  .jsbtn{ display:flex; align-items:center; justify-content:center; width:44px; height:44px;
    flex:none; border-radius:50%; background:#fff; border:1.5px solid #DDD3BA;
    color:var(--ink); cursor:pointer; padding:0; }
  .jsbtn svg{ width:20px; height:20px; }
  .nav .btn{ height:44px; padding:0 14px; white-space:nowrap; flex:none;
             background:var(--pine); color:var(--cream); border:0; }
  /* the field drops below the row when the button is pressed */
  .jsearch{ display:none; order:9; flex:0 0 100%; }
  .jsearch.open{ display:flex; }
  .jsearch input{ width:100%; max-width:none; height:44px; font-size:16px;  /* 16px: no iOS zoom */
                  border-color:var(--ink); }
  .jsresults{ top:52px; left:0; right:0; min-width:0; max-width:none; }
  .jsrow{ min-height:44px; justify-content:center; }
  .tabs{ order:10; flex:0 0 100%; display:flex; gap:18px; overflow-x:auto;
         scrollbar-width:none; overscroll-behavior-x:contain; touch-action:pan-x pan-y; }
  .tabs::-webkit-scrollbar{ display:none; }
  .tabs .dot{ display:none; }
  .tabs a{ white-space:nowrap; padding-bottom:4px; }
  .tabs a[aria-current=page]{ border-bottom:2px solid var(--ink); }

  /* 2 · header — the oval and the note */
  .jhead{ display:block; padding-top:48px; position:relative; }
  .jtitle{ position:relative; display:inline-block; }
  .jtitle h1{ font-size:84px; line-height:.9; margin:0; position:relative; z-index:1; }
  .jtitle::before{ content:''; position:absolute; left:-26px; right:-26px; top:-16px; bottom:-14px;
    border:2.5px solid var(--rose); border-radius:50%; transform:rotate(-4deg); }
  .jhead .jnote, .jhead .note{ position:absolute; right:-6px; top:18px;
    font-family:Fraunces,serif; font-style:italic; font-size:17px; color:var(--rose-deep);
    transform:rotate(-8deg); white-space:nowrap; }

  /* The hand-drawn loop is replaced by the oval here, but the two written
     notes are part of the design's voice and stay — they are just repositioned
     for the narrow column. Their real classes are doodle-note-new and
     doodle-note-sched; the loop and arrow SVGs are what go. */
  .jtitle .doodle{ display:none; }
  .jhead{ position:relative; }
  /* `left` IS STILL SET FROM THE DESKTOP RULE, and an absolutely positioned
     box with both left and right and width:auto stretches between them — here
     that was left:470 against right:0 inside a 254px parent, which resolves to
     a 0px-wide element. It was on the page the whole time, measuring nothing.
     Clearing left is the fix, not raising the z-index or the font size. */
  .doodle-note-new{ position:absolute; left:auto; right:-4px; top:-26px; font-size:17px;
    color:var(--rose-deep); font-style:italic; transform:rotate(-8deg);
    white-space:nowrap; display:block; }

  /* 3 · letter card */
  .letter{ background:#fff; border-radius:24px; padding:18px; margin-top:26px;
           display:flex; flex-direction:column; gap:10px; position:relative; }
  .letter{ }
  .letter .doodle{ display:none; }
  /* display:contents so the note, the sentence and the button are all direct
     children of the card's flex column and `order` can actually reach them —
     the note ships inside .letterwrap, which would otherwise pin it below the
     sentence whatever order it is given. */
  .letterwrap{ display:contents; }
  .doodle-note-sched{ order:-1; position:static; transform:rotate(-2deg);
    align-self:flex-start; font-style:italic; font-size:17px; color:var(--grass);
    display:block; }
  .letter p{ order:0; }
  .letter .btn-rose{ order:1; }
  .letter .btn-rose{ display:flex; width:100%; height:52px; justify-content:center;
                     box-shadow:0 10px 22px rgba(194,94,126,.28); }

  /* 4-6 · the bento restacks */
  .bento{ display:flex; flex-direction:column; gap:16px; }
  .tile-lead{ order:1; }
  .pair{ order:2; display:flex; gap:12px; overflow-x:auto; scroll-snap-type:x mandatory;
         width:100vw; margin-left:calc(50% - 50vw); padding:0 20px; scrollbar-width:none;
         overscroll-behavior-x:contain; touch-action:pan-x pan-y; }
  .pair::-webkit-scrollbar{ display:none; }
  .pair > .tile{ flex:0 0 78%; height:420px; scroll-snap-align:start; min-height:0; }
  .tile-sage{ order:3; }
  .tile-pine{ order:4; }
  .tile-lead{ background:#fff; border-radius:26px; padding:10px; transform:rotate(-1.5deg); }
  .tile-lead .plate img{ min-height:380px; max-height:380px; object-fit:cover; border-radius:18px; }
  .tile-sage h3{ font-size:34px; }
  .tile-sage .row{ min-height:52px; }

  /* 7 · more to read */
  /* `flex:1 1 320px` ON .j2headl IS A WIDTH AT DESKTOP AND A HEIGHT HERE,
     because flex-basis follows the container's direction — turning the column
     gave the heading block a 320px floor and left a 240px hole between
     "Worth your ten minutes" and the chips. Measured: h2 ended at y1997 and
     the chips began at y2237 with a declared gap of 14. */
  .j2head{ flex-direction:column; align-items:flex-start; }
  .j2headl{ flex:0 0 auto; width:100%; }
  .j2head h2{ font-size:34px; }
  .j2chips{ flex-wrap:nowrap; overflow-x:auto; width:100%; scrollbar-width:none;
            overscroll-behavior-x:contain; padding-bottom:2px; }
  .j2chips::-webkit-scrollbar{ display:none; }
  .j2tile{ width:240px !important; }
  .j2tile:nth-child(3n+2){ width:220px !important; }
  .j2tile:nth-child(3n){ width:256px !important; }
  .j2art{ height:170px; }
  .j2decostar{ display:none; }
  .j2decopill{ top:-10px; right:10px; font-size:15px; }

  /* THE CHIPS CARD IS THE TOP BAR'S JOB NOW. It carries the same five section
     links the sticky bar carries, three screens further down; the mobile
     handoff's order has no such card, and two identical controls on one page
     is a worse answer than either alone. Its count moves into the Everything
     else header, where the design puts it. */
  .tile-pine{ display:none; }
  .sofar{ display:none; }
  .everything h3{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
  .ecount-all{ background:#D9E48A; color:var(--pine); border-radius:999px;
    padding:3px 11px; font-family:'JetBrains Mono',monospace; font-size:11px; }
  .everything::after{ content:'New tiles appear as they\2019re written.';
    display:block; margin-top:14px; font-size:14px; color:rgba(246,241,230,.72); }

  /* the rail bleeds like the bar and the pair: viewport width, never wider */
  .j2scroll{ width:100vw; margin-left:calc(50% - 50vw); margin-right:0; }

  /* 8 · everything else, inside the pine card */
  .everything{ background:var(--pine); border-radius:28px; padding:22px 18px;
               color:var(--cream); }
  .everything h3{ color:#D9E48A; }
  .ecols{ display:flex; flex-direction:column; gap:0; }
  .ecol{ border-top:1px solid rgba(246,241,230,.22); }
  .ecol > summary{ min-height:52px; display:flex; align-items:center; cursor:pointer; }
  .ecol h4{ color:var(--cream); font-size:20px; display:flex; align-items:center; gap:10px; }
  .ecount{ background:#D9E48A; color:var(--pine); border-radius:999px; padding:2px 10px;
           font-family:'JetBrains Mono',monospace; font-size:11px; }
  .ecol-row{ min-height:44px; display:flex; align-items:center; justify-content:space-between;
             gap:12px; color:var(--cream); }
  .ecol-row .mono{ color:#D9E48A; }
}

/* ── A SECTION LINK LOOKS PICKED (2026-09-30) ──────────────────────────── */
.tabs a.picked{ color:var(--pine); border-bottom:2px solid var(--grass); }
.chip.picked{ background:var(--grass); color:var(--cream); border-color:var(--grass); }
/* Landing below the sticky bar rather than under it. */
.everything{ scroll-margin-top:96px; }
@media (max-width:767.98px){
  .tabs a.picked{ border-bottom-color:var(--grass); color:var(--pine); }
  .everything{ scroll-margin-top:118px; }
}

/* ── A LIVE LEAD TILE (2026-10-02) ─────────────────────────────────────────
   Tate: "on the hero, is it possible to make that interactive like it is when
   you click in?"

   The base image is the closet with every piece plainly visible; this layer
   darkens all of it except a pool that follows the pointer. So the tile is the
   article's flashlight, and what it reveals is the same closet.

   IT STAYS A LINK. `pointer-events:none` on the overlay means the pointer
   never stops reaching the anchor underneath — move over it and the light
   moves, tap it and the piece opens. There is no new control, which is the
   only version of this worth shipping on an index.

   THE DEFAULT POSITION IS IN CSS, NOT JS. With no JavaScript, a cold cache or
   a pointer that has not arrived yet, the pool sits where the printed still
   has it and the tile looks deliberate rather than broken. */
/* NO `position:relative` HERE, AND THAT ONE WORD COST THE WHOLE TILE.
   `.plate` is already `position:absolute; inset:0` — it fills the tile. Adding
   `position:relative` dropped it back into normal flow, where it became a flex
   item inside `.tile-lead` and shrank to share the row with the headline: 345px
   wide became 118px, and on a phone that is a dark vertical strip with one
   garment in it. The absolute `.plate` is already a containing block for the
   overlay, so the relative was never needed in the first place.
   Found on mobile, where the squeeze is worst; it was wrong at every width. */
.plate-live{ overflow:hidden; }
/* `circle` TAKES A LENGTH, NOT A PERCENTAGE, and `circle 38%` is invalid — the
   whole `background` declaration was dropped and the overlay painted nothing.
   Caught by reading the computed style rather than the screenshot: the tile
   looked plausible because the base image under it is the closet either way.
   An ellipse accepts two percentages, which is what this wants anyway: the
   tile is taller than it is wide, so a circular pool would be a wide smear. */
.plate-live > .plate-dark{
  position:absolute; inset:0; pointer-events:none; transition:background .12s linear;
  background:radial-gradient(ellipse var(--prx,40%) var(--pry,34%) at var(--px,62%) var(--py,44%),
    rgba(35,28,20,0) 0%, rgba(35,28,20,.46) 44%, rgba(35,28,20,.88) 72%, rgba(35,28,20,.96) 100%); }
/* Touch gets a wider pool: a finger has no hover, so the first thing she sees
   after a tap-and-drag should be more of the closet, not less. */
@media (hover:none){ .plate-live > .plate-dark{ --prx:58%; --pry:48%; } }
@media (prefers-reduced-motion:reduce){ .plate-live > .plate-dark{ transition:none; } }

/* (the generated template's old `.receipts`/`.rtoggle` toggle and `.foot` row were
   removed in the 2026-10-06 sweep; every page now uses the two classes below.) */
/* ── ONE RECEIPTS CARD AND ONE FOOTER FOR EVERY DISPATCH (Tate, 2026-10-06:
   "sweep our dispatches to ensure they're all given the same footer treatment
   (footer and receipt section)"). Five dispatches had four treatments: a white
   <details> card with a claims count (instruments, counters), a bare <details>
   with no count (cavalli), a toggle <section> with no footer at all (demna) and
   the generated template's own toggle. These two classes are the one shape;
   hand-built pages and the generated template both emit them. The eyebrow
   counts what the receipts actually are — CLAIMS when they are enumerated,
   SOURCES when they are prose with links — rather than inventing a number. */
.jrec { background:#fff; border-radius:22px; overflow:hidden; margin-top:40px; }
.jrec > summary { list-style:none; cursor:pointer; padding:16px 20px; display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
.jrec > summary::-webkit-details-marker { display:none; }
.jrec > summary .t { font-family:Fraunces,Georgia,serif; font-weight:600; font-size:20px; color:var(--ink); }
.jrec > summary .jeye { font-family:'JetBrains Mono',ui-monospace,monospace; font-weight:700; font-size:10px; letter-spacing:.12em; color:var(--sub); }
.jrec > summary .ic { margin-left:auto; font-size:20px; color:var(--grass-text); font-weight:500; }
.jrec > summary .ic::before { content:"+"; }
.jrec[open] > summary .ic::before { content:"\2212"; }
.jrec .rows { padding:0 20px 16px; font-size:14px; line-height:1.6; color:var(--sub); }
.jrec .rows p { margin:0 0 12px; }
.jrec .rows ol { margin:0; padding-left:20px; }
.jrec .rows li { padding:8px 0; border-top:1px solid var(--line); }
.jrec .rows a { color:var(--rose-deep); }
.jfoot { display:flex; gap:12px; align-items:center; flex-wrap:wrap; margin-top:40px; padding:12px 0 60px; border-top:1px solid var(--line); font-size:14px; }
.jfoot span { color:var(--sub); }
.jfoot .sp { flex:1; }
.jfoot a { font-weight:600; color:var(--grass-text); text-decoration:none; }
.jfoot a.get { height:42px; padding:0 18px; border-radius:999px; background:var(--pine); color:var(--ball); font-weight:700; display:inline-flex; align-items:center; white-space:nowrap; }
