/* ==========================================================================
   plate-page.css - layout for the per-plate landing pages at /p/<design>/
   Loaded AFTER /styles.css, which supplies every token, both webfonts, the
   header, the footer and the shared .btn/.buy/.plate-no/.binomial/.quip roles.
   Nothing here invents a hue: navy, brick, cream and the :root tints only.

   The one rule this file exists to serve: THE PLATE IS THE PAGE. On desktop it
   takes the left ~62% of the measure and runs past the fold; on a phone it is
   sized off the viewport height so the name, the deadpan line and the buy
   action still land above it. Everything else is a caption.
   ========================================================================== */

.pp-body {
  --pp-col: clamp(28px, 3.4vw, 54px);   /* hero column gap */
  --pp-row: clamp(22px, 2.4vw, 32px);   /* hero row gap    */
}

/* ---------- breadcrumb ---------- */

.pp-crumbs {
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
}
.pp-crumbs ol {
  list-style: none;
  margin: 0;
  padding: 2px 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 9px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.pp-crumbs li { display: flex; align-items: center; gap: 9px; min-width: 0; }
.pp-crumbs li + li::before {
  content: "\203A";
  color: var(--rule-strong);
  font-size: 13px;
}
.pp-crumbs a {
  color: var(--ink);
  text-decoration: none;
  padding: 5px 0;
  min-height: 24px;
  display: inline-flex;
  align-items: center;
}
.pp-crumbs a:hover { color: var(--brick-deep); text-decoration: underline; }
.pp-crumbs [aria-current] {
  color: var(--ink-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 44ch;
}

/* ---------- hero: plate left, specimen record right ---------- */

.pp-hero {
  display: grid;
  grid-template-columns: minmax(0, 1.82fr) minmax(0, 1fr);
  grid-template-areas:
    "plate label"
    "plate buy"
    "plate more";
  grid-template-rows: auto auto 1fr;
  column-gap: var(--pp-col);
  row-gap: var(--pp-row);
  align-items: start;
  padding-block: clamp(10px, 1.2vw, 16px) clamp(40px, 5.5vw, 72px);
}
.pp-label { grid-area: label; }
.pp-plate { grid-area: plate; }
.pp-buy   { grid-area: buy; }
.pp-more  { grid-area: more; }

/* The artifact. Borderless on purpose: the plate scan's own ground is
   rgb(240,233,205) and the page is #F2E8CF, so a frame, a shadow or a tinted
   box would only announce that the artwork is a picture of a thing rather
   than the thing. */
.pp-plate {
  margin: 0;
  min-width: 0;
}
.pp-plate:focus { outline: none; }
.pp-plate:focus-visible { outline: 2px solid var(--brick); outline-offset: 6px; }
.pp-plate-img {
  width: 100%;
  height: auto;
  display: block;
  margin-inline: auto;
  background: none;
  border: 0;
  box-shadow: none;
}
.pp-plate-cap {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: center;
  margin: 6px 0 0;
}

/* ---------- the record ---------- */

.pp-label .plate-no {
  font-size: 13px;
  letter-spacing: .16em;
  margin: 0 0 12px;
}
.pp-name {
  font-size: clamp(26px, 3.1vw, 40px);
  line-height: 1.06;
  letter-spacing: -.012em;
  font-weight: 800;
  margin: 0 0 10px;
  text-wrap: balance;
}
.pp-label .binomial {
  font-size: clamp(18px, 1.6vw, 21px);
  margin: 0 0 12px;
}
.pp-label .quip {
  font-size: clamp(16px, 1.4vw, 18.5px);
  line-height: 1.5;
  color: var(--ink);
  margin: 0;
}

/* ---------- price + buy ---------- */

/* A hairline between the record and the transaction, the way an accession
   label rules off its provenance block. */
.pp-buy { border-top: 1px solid var(--rule); padding-top: clamp(16px, 1.8vw, 22px); }

.pp-price {
  font-size: 18.5px;
  margin: 0 0 6px;
  line-height: 1.3;
}
.pp-price b { font-weight: 600; }
.pp-fine {
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: .04em;
  color: var(--ink-soft);
  margin: 0 0 14px;
}
.pp-buys { display: flex; flex-direction: column; gap: 10px; }
.pp-buys .buy {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 13px 14px;
  border-radius: var(--r-md);
  font-size: 12.5px;
  letter-spacing: .1em;
}

/* ---------- observations / colours: the label furniture ---------- */

.pp-obs, .pp-colours { margin: 0 0 26px; }
.pp-h {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 14px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--rule);
}
.pp-obs-list { list-style: none; margin: 0; padding: 0; }
.pp-obs-list li {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  gap: 11px;
  align-items: start;
  margin: 0 0 12px;
}
/* The brick disc echoes the numbered markers printed on the plate itself. */
.pp-n {
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--brick); color: var(--cream);
  font-family: var(--mono); font-size: 12px; line-height: 1;
  display: grid; place-items: center;
  margin-top: 2px;
}
.pp-t { font-size: 15.5px; line-height: 1.46; overflow-wrap: anywhere; }
.pp-sp {
  font-family: var(--mono); font-weight: 600;
  font-size: 13px; letter-spacing: .05em;
}
.pp-ep { color: var(--brick-deep); font-style: italic; }
.pp-ep::before { content: "\2014\00a0"; color: var(--ink-soft); font-style: normal; }
.pp-obs-note {
  font-family: var(--mono); font-size: 12px; line-height: 1.5;
  letter-spacing: .04em; color: var(--ink-soft); margin: 0;
}

.pp-crow { margin: 0 0 14px; }
.pp-crow:last-child { margin-bottom: 0; }
.pp-clabel {
  font-family: var(--mono); font-size: 12px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--ink-soft); margin: 0 0 8px;
}
.pp-cnum { color: var(--ink); }
.pp-dots {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 4px 14px;
}
.pp-dots li {
  display: flex; align-items: center; gap: 7px;
  min-height: 24px;
  font-family: var(--mono); font-size: 12px; letter-spacing: .04em;
  color: var(--ink-soft);
}
.pp-dot {
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--sw, var(--paper));
  border: 1px solid var(--rule-strong);
  flex: 0 0 auto;
}

.pp-guide-line .btn { padding: 13px 22px; }

/* ---------- on the garment: the one dark band ---------- */

/* Navy, because the mockups are photographed on a grey studio ground. On
   cream that ground reads as a muddy box (the exact complaint against the
   card grid); on navy it reads as a photograph. */
.pp-garment {
  background: var(--navy);
  color: var(--cream);
  padding-block: var(--sec-pad);
}
.pp-band-head { max-width: 62ch; margin: 0 0 clamp(22px, 3vw, 34px); }
.pp-band-h {
  font-size: clamp(24px, 2.9vw, 34px);
  font-weight: 800; letter-spacing: -.01em;
  margin: 0 0 8px;
}
.pp-garment .pp-band-h { color: var(--cream); }
.pp-band-note {
  margin: 0;
  /* styles.css publishes solid cream-over-navy ink steps (--on-navy /
     --on-navy-soft) with their contrast ratios measured; use those rather
     than a second hand-picked tint, so the navy band stays inside the locked
     palette. The literal is only a fallback if piece 1 ever drops the token. */
  color: var(--on-navy, #E9DFC4);
  font-size: 16.5px;
  line-height: 1.55;
}
.pp-shots {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(16px, 2.2vw, 32px);
  max-width: 940px;
}
.pp-shot { margin: 0; }
.pp-shot img {
  width: 100%; height: auto;
  border: 1px solid rgba(242, 232, 207, .3);
  border-radius: var(--r-md);
}
.pp-shot figcaption {
  font-family: var(--mono); font-size: 12px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--on-navy-soft, #CFC1A0);
  margin-top: 11px; line-height: 1.45;
}
.pp-facts {
  list-style: none; margin: clamp(26px, 3vw, 38px) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px 30px;
  border-top: 1px solid rgba(242, 232, 207, .26);
  padding-top: 20px;
}
.pp-facts li {
  display: flex; align-items: baseline; gap: 9px;
  font-family: var(--mono); font-size: 12px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--cream); line-height: 1.45;
}
.pp-fmark { color: var(--on-navy-soft, #CFC1A0); font-size: 12px; flex: 0 0 auto; }

/* ---------- filed nearby ---------- */

.pp-related { padding-block: clamp(40px, 5vw, 68px); }
.pp-related .pp-band-h { margin-bottom: clamp(20px, 2.6vw, 30px); }
/* Flex, not auto-fill: a two-item row in a six-column track read as four
   empty cells. Here two related plates grow to a confident 250px and six
   members still land on one line. */
.pp-rel-row {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap;
  gap: clamp(16px, 2.2vw, 30px);
}
.pp-rel-row > li { flex: 1 1 150px; max-width: 280px; min-width: 0; }
/* A short shelf -- a group plate whose set is only partly live -- centres
   itself under a centred heading and takes a larger thumbnail, so it reads as
   a deliberate pair rather than as a row that ran out. */
.pp-related-short .pp-band-h { text-align: center; }
.pp-related-short .pp-rel-row { justify-content: center; }
.pp-related-short .pp-rel-row > li { flex: 0 1 280px; max-width: 300px; }
/* Related plates are shown as PLATES, not as mockups: the plate scans carry
   the same cream ground as the page, so a row of them reads as an index
   rather than as a row of grey boxes. */
.pp-rel {
  display: block; text-decoration: none; color: var(--ink);
  border-bottom: 1px solid var(--rule);
  padding-bottom: 12px;
}
.pp-rel img {
  width: 100%; height: auto; display: block;
  transition: transform .18s ease;
}
.pp-rel-name {
  display: block; margin-top: 10px;
  font-family: var(--mono); font-size: 12px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-soft); line-height: 1.4;
}
.pp-rel:hover { border-bottom-color: var(--navy); }
.pp-rel:hover img { transform: translateY(-3px); }
.pp-rel:hover .pp-rel-name { color: var(--brick-deep); }

/* ---------- turn the page ---------- */

.pp-turn {
  border-top: 1px solid var(--rule);
  background: var(--paper-warm);
}
.pp-turn-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px;
  padding-block: clamp(22px, 3vw, 32px) clamp(26px, 3.4vw, 38px);
}
.pp-turn .btn {
  display: flex; flex-direction: column; gap: 3px;
  padding: 12px 18px; min-width: 0; text-transform: none; letter-spacing: 0;
}
.pp-turn-next { text-align: right; align-items: flex-end; }
.pp-turn-dir {
  font-family: var(--mono); font-size: 12px; letter-spacing: .1em;
  text-transform: uppercase; color: inherit;
}
.pp-turn-name {
  font-family: var(--serif); font-size: 15.5px; font-weight: 600;
  letter-spacing: .01em; line-height: 1.25; color: inherit;
}
.pp-turn-gap { flex: 0 0 1px; }
.pp-turn-all {
  font-family: var(--mono); font-size: 12px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink);
  padding: 12px 4px; min-height: 24px; display: inline-flex; align-items: center;
  text-align: center;
}
.pp-turn-all:hover { color: var(--brick-deep); }

/* ---------- widths ---------- */

@media (max-width: 1200px) {
  .pp-hero { grid-template-columns: minmax(0, 1.62fr) minmax(0, 1fr); }
}

/* Below 900 the record column would be narrower than its own buttons, so the
   page stacks: name and deadpan line first, then the plate, then the action. */
@media (max-width: 900px) {
  .pp-hero {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "label" "plate" "buy" "more";
    grid-template-rows: auto;
    row-gap: clamp(18px, 3vw, 26px);
  }
  /* WIDTH, not `width:auto`. A height-capped image with an auto width has no
     definite size until the bytes arrive, so the pending <img> lays out 0x0
     and the price and the buy button sit 422px too high, then jump when the
     plate lands (measured CLS 0.32 at 390, 0.31 at 768). Naming the width
     lets the 880x1100 attribute ratio reserve the exact box from first
     paint; the height cap below is then arithmetically redundant and kept
     only as a guard. min() keeps it inside the column on a narrow screen. */
  .pp-plate-img {
    width: min(100%, calc(58vh * 880 / 1100));
    max-width: 100%;
    max-height: 58vh;
  }
  /* Stacked, the caption sat between the plate and the price and bought
     nothing; the height it costs is worth more given to the plate (33.5% ->
     38.3% of a 768x1024 viewport, measured). */
  .pp-plate-cap { display: none; }
  .pp-buy, .pp-more { max-width: 620px; }

  /* Stacked, the sale caveat between the price and the button pushed the
     button off a 844px phone. DOM order is unchanged (price, caveat, buttons);
     only the painted order moves, and nothing here is focusable. */
  .pp-buy { display: flex; flex-direction: column; padding-top: 16px; }
  .pp-price { order: 1; }
  .pp-buys { order: 3; margin-top: 2px; }
  .pp-fine { order: 4; margin: 12px 0 0; }
  /* Added after the orders above were written, so it had no order and
     defaulted to 0 - which floated 174px of reassurance ABOVE the price
     and pushed both buy buttons 113px off an 844px phone. It belongs
     after the offer it is reassuring about. */
  .pp-trust { order: 5; }
    .pp-shots { gap: 18px; }
  .pp-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 700px) {
  .pp-crumbs ol { padding: 1px 0; font-size: 12px; gap: 0 8px; }
  .pp-crumbs li:last-child { display: none; }
  .pp-crumbs a { padding: 4px 0; }

  .pp-hero { padding-block: 10px clamp(34px, 7vw, 48px); row-gap: 14px; }
  .pp-label .plate-no { margin-bottom: 9px; letter-spacing: .14em; }
  .pp-name { font-size: 26px; margin-bottom: 8px; }
  .pp-name-long { font-size: 23px; line-height: 1.08; }
  .pp-label .binomial { margin-bottom: 9px; }

  /* Sized off the viewport, not the column: the plate takes ~43% of a
     390x844 screen and the name, the deadpan line, the price and the buy
     button all still land above the fold (measured, tools/shoot_plate.py). */
  .pp-plate-img {
    width: min(100%, calc(50vh * 880 / 1100));
    max-height: 50vh;
  }
  .pp-plate-cap { display: none; }

  .pp-price { font-size: 17px; }
  .pp-fine { margin-bottom: 11px; }
  .pp-buys .buy { min-height: 48px; padding: 12px 10px; }

  .pp-obs, .pp-colours { margin-bottom: 22px; }
  .pp-t { font-size: 15px; }

  .pp-shots { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .pp-facts { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .pp-rel-row { gap: 16px; }
  .pp-rel-row > li { flex: 1 1 128px; max-width: 190px; }

  .pp-turn-inner { flex-wrap: wrap; gap: 10px; }
  .pp-turn .btn { flex: 1 1 46%; }
  .pp-turn-all { flex: 1 1 100%; order: 3; justify-content: center; }
}

/* Nothing under 12px on a phone: every mono label on this page is already
   12px or larger, and styles.css's own 620px block leaves them there. */

@media (prefers-reduced-motion: reduce) {
  .pp-rel img { transition: none; }
  .pp-rel:hover img { transform: none; }
}



/* ==========================================================================
   Funnel layer (2026-09-08)
   ========================================================================== */

/* Risk reversal where the decision happens, not three screens away. */
.pp-trust {
  list-style: none; margin: 14px 0 0; padding: 0;
  display: grid; gap: 8px;
}
.pp-trust li {
  position: relative; padding-left: 20px;
  font-size: 15px; line-height: 1.5; color: var(--ink-soft);
}
.pp-trust li::before {
  content: ""; position: absolute; left: 2px; top: .62em;
  width: 7px; height: 7px; border-radius: 50%; background: var(--brick);
}

/* The product's own film, on the navy board. Heading and film share a centred
   column on desktop: left-aligned copy over a centred video left a wide void
   down the left of the band. */
.pp-video { margin-top: 0; }
/* CENTRED AS A BLOCK, not just centred text. .pp-band-head is capped at 62ch,
   so `text-align: center` centred the words inside a 527px box that was still
   pinned to the LEFT edge of the 1180px wrap - while the film below it is
   centred in the full wrap. Measured at 1440: the heading spanned 130-657
   (centre 393) and the film 550-890 (centre 720), a 327px mismatch that reads
   as two unrelated blocks. It gets worse the wider the screen. */
.pp-video .pp-band-head { text-align: center; margin-inline: auto; }
.pp-video .pp-band-note { margin-inline: auto; max-width: 46ch; }
.pp-video-el {
  display: block; width: min(100%, 340px); height: auto; margin: 26px auto 0;
  border-radius: var(--r-md); background: var(--paper-deep);
  box-shadow: var(--shadow-photo);
}

/* Always-visible buy bar on a phone. The page reserves room for it so nothing
   is ever hidden underneath. */
.pp-sticky { display: none; }
@media (max-width: 860px) {
  .pp-sticky {
    display: flex; align-items: center; gap: 12px;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    padding: 10px 14px calc(10px + env(safe-area-inset-bottom, 0px));
    background: var(--paper);
    border-top: 1px solid var(--rule-strong);
    box-shadow: 0 -8px 24px -18px rgba(31,58,95,.6);
  }
  .pp-sticky-name {
    flex: 1 1 auto; min-width: 0;
    font-family: var(--serif); font-weight: 700; font-size: 15px;
    color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .pp-sticky .buy { flex: 0 0 auto; margin: 0; padding: 12px 14px; font-size: 13px; }
  /* Two buttons now. The plate name yields before either of them does. */
  .pp-sticky { gap: 8px; }
  .pp-sticky .buy + .buy { margin-left: 2px; }
  .pp-sticky-price { opacity: .85; }
  .pp-body { padding-bottom: 84px; }
  .pp-video-el { width: min(100%, 300px); }
}

.pp-guide-line { margin: 0 auto clamp(40px, 6vw, 72px); text-align: center; }

/* Mono is a LABEL face. These two were carrying 17- and 18-word sentences at
   77-81 characters per line (typography audit). */
.pp-fine, .pp-obs-note {
  font-family: var(--serif); font-size: 14.5px; letter-spacing: normal;
  text-transform: none; line-height: 1.5;
}
/* The garment photographs sit on the same band as the film, which is
   elevated; they were flat. */
.pp-shot img { box-shadow: var(--shadow-photo); }

/* A landscape phone is 390px tall: a 66px sticky header plus a 68px fixed buy
   bar was eating 34% of the screen permanently. */
@media (max-height: 460px) {
  .pp-sticky { display: none; }
  .pp-body { padding-bottom: 0; }
}

/* The film speaks the four observations, which are printed directly above it.
   Said out loud so the relationship is not left to be inferred. */
.pp-video-note {
  margin: 14px auto 0; max-width: 46ch; text-align: center;
  font-size: 14.5px; color: var(--on-navy-soft);
}

/* The buy bar was giving the plate name a fixed 116px at 390 and 46px at 320,
   because the button was flex:0 0 auto at a constant 234px: 97 of 125 names
   truncated, and golden-retriever and goldendoodle both became "THE GOLDE...".
   The verb is dropped on narrow screens; the name gets the room back. */
.pp-sticky-short { display: none; }
@media (max-width: 430px) {
  .pp-sticky-full { display: none; }
  .pp-sticky-short { display: inline; }
  .pp-sticky .buy { padding: 12px 12px; }
}
.pp-sticky .buy { min-width: 0; }
.pp-sticky-name { min-width: 0; flex: 1 1 auto; }

/* Two-line names split the row heights (254/270/277px) and knocked the
   underline rules of side-by-side items out of alignment. */
.pp-rel-row { align-items: start; }
.pp-rel-name { display: block; min-height: 2.6em; }

/* --- the navy seam ------------------------------------------------------
   .pp-video and .pp-garment are both var(--navy) and both padded --sec-pad,
   so at 1440 they merged into a 1,981px slab whose seam was 259px of empty
   colour. Collapse the doubled pad and mark the break the way every other
   chapter in the guide is marked: one hairline. The pair is adjacent on all
   125 pages, so the sibling selector always applies. */
.pp-video + .pp-garment {
  border-top: 1px solid var(--rule-on-navy);
  padding-top: clamp(30px, 3.6vw, 54px);
}
.pp-video { padding-bottom: clamp(34px, 4vw, 60px); }

/* .pp-trust bottom and .pp-fine top measured at exactly the same y (676px at
   1440): the fine print sat flush against the last trust bullet and read as a
   fourth bullet that had lost its dot. */
.pp-fine { margin-top: 14px; }

/* At 430 and below the buy bar shows Tee/Crew rather than the full verb, and
   the plate name is dropped entirely below 380 - two priced buttons matter
   more on a 320px screen than a name that is already the page's H1. */
@media (max-width: 379px) {
  .pp-sticky-name { display: none; }
}

/* WCAG 2.2 SC 2.4.11 Focus Not Obscured (AA). The buy bar is `position: fixed`
   at the bottom, so the browser's scroll-into-view would happily park a
   newly-focused element underneath it: measured at 390x844, focusing "Shop the
   crewneck on Etsy" left it entirely behind the bar, and the tee button three
   corners under it. scroll-padding-bottom reserves the bar's height (68px) plus
   a margin, so anything receiving focus lands above it. */
@media (max-width: 860px) {
  html { scroll-padding-bottom: 92px; }
}

/* ---- LANDSCAPE PHONES -------------------------------------------------
   The single-column hero is selected by WIDTH (max-width: 900px) but the
   plate is sized by HEIGHT (58vh / 50vh). On a landscape phone the height is
   small and the column is wide, so the two rules fight and the plate collapses
   to a stamp. Measured against its own column on /p/office/:

       667x375   150px in 635px   24%
       844x390   181px in 812px   22%
       896x414   192px in 864px   22%
       900x400   186px in 868px   21%
       905x400   521px in 521px  100%   <- two-column layout engages

   So rotating an iPhone 14 to landscape SHRANK the hero plate from 338px to
   181px, on the pages single-design ads land on, and the four numbered
   observations - the joke, and the reason to buy - became unreadable. The
   natural response to art too small to read is to rotate the phone, which
   made it smaller still.

   The vh cap exists to keep the price and buy button above the fold on a
   PORTRAIT phone, so it is now scoped to portrait. In landscape the plate is
   sized from its column like every other surface, and the fold argument does
   not apply because the buy block sits beside it in the reading order anyway.
   The width stays definite either way, so the no-CLS guarantee above holds. */
@media (max-width: 900px) and (orientation: landscape) {
  /* Two columns, as on a desktop. A landscape phone is SHORT and WIDE: the
     stacked layout gives the plate a 812px column it cannot use (the vh cap
     holds it to ~340px) and wastes 500px of cream either side. Side by side,
     the plate gets roughly half the width and the record sits beside it,
     which is the shape this viewport actually has. */
  .pp-hero {
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
    grid-template-areas:
      "plate label"
      "plate buy"
      "plate more";
    grid-template-rows: auto auto 1fr;
    column-gap: var(--pp-col);
  }
  .pp-plate-img {
    /* Column-led, with a generous height ceiling so a very short viewport
       still cannot make it taller than about one and a half screens. */
    width: min(100%, calc(150vh * 880 / 1100));
    max-width: 100%;
    max-height: none;
  }
  .pp-plate-cap { display: block; }
}

/* ---- the colour picker becomes a real control ------------------------- */
.pp-cshot {
  margin: 0 0 16px; max-width: 320px;
  border: 1px solid var(--rule); border-radius: var(--r-md);
  background: var(--paper-warm); overflow: hidden;
}
.pp-cshot img { display: block; width: 100%; height: auto; }
.pp-cshot-cap {
  padding: 8px 10px; border-top: 1px solid var(--rule);
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-soft);
}
.pp-dot-btn {
  display: inline-flex; align-items: center; gap: 7px;
  background: none; border: 0; margin: 0;
  /* 28px tall, not 23. WCAG 2.2 SC 2.5.8 wants 24x24 minimum for a pointer
     target and qa_gate.py blocked the page at 23px - a defect I introduced
     turning these from inert spans into controls. */
  min-height: 28px; padding: 3px 6px 3px 2px;
  font: inherit; color: inherit; cursor: pointer; border-radius: var(--r-sm);
  text-align: left;
}
.pp-dot-btn:hover { background: var(--paper-warm); }
.pp-dot-btn:focus-visible { outline: 2px solid var(--brick); outline-offset: 1px; }
.pp-dot-btn[aria-pressed="true"] .pp-dot { box-shadow: 0 0 0 2px var(--paper), 0 0 0 3px var(--navy); }

/* ---- the plate stays with you --------------------------------------------
   In the two-column hero the record column (label, buy, observations, colours)
   runs about 620px longer than the plate, so scrolling to read the
   observations left the plate behind and 620px of bare cream in its place -
   the emptiness Jason spotted at 1850px. Adding the colour picker made the
   right column taller and the gap worse.

   Sticky rather than taller: the artwork is the product, and keeping it on
   screen while the buyer reads the notes and picks a colour is worth more than
   filling the space. Scoped to the two-column layout - stacked, there is no
   second column to scroll past. The top offset clears the fixed chrome. */
@media (min-width: 901px) {
  .pp-plate {
    position: sticky;
    /* The HEADER height, not the whole chrome: the announce strip scrolls
       away, so offsetting by chrome-h left a 54px gap under a header that was
       no longer there, and cost 54px of the plate's travel. */
    top: calc(var(--head-h, 66px) + 14px);
    align-self: start;
  }
}


/* ---------- ENLARGE on the plate page (test, 2026-09-13) ----------
   In the TEXT column under the quip, never on the artwork: a control pinned to
   the plate's bottom-right sat on callout 4, which every plate prints there
   (it covered "enormous" on the beagle). Up here it is above the fold at every
   desktop height, and the plate itself is also a click target (cursor: zoom-in),
   so the big discoverable target is the art and this is the labelled one. The
   lightbox itself is styles.css .lightbox*. */
.pp-controls {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin: 14px 0 0;
}
.pp-enlarge {
  display: inline-block; margin: 0;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--navy);
  background: var(--paper); border: 1px solid var(--navy);
  padding: 9px 14px; min-height: 36px; cursor: pointer; border-radius: 2px;
}
.pp-enlarge:hover { background: var(--navy); color: var(--cream); }
.pp-enlarge:focus-visible { outline: 2px solid var(--brick); outline-offset: 2px; }
/* Share: same weight as ENLARGE, one step quieter (no border until hover), so
   the row reads Plate/Film, ENLARGE, then the lesser action. */
.pp-share {
  display: inline-block; margin: 0;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-soft);
  background: transparent; border: 1px solid transparent;
  border-bottom-color: var(--rule);
  padding: 9px 6px; min-height: 36px; cursor: pointer; border-radius: 0;
}
.pp-share:hover { color: var(--navy); border-bottom-color: var(--navy); }
.pp-share:focus-visible { outline: 2px solid var(--brick); outline-offset: 2px; }
@media (max-width: 760px) {
  /* Plate/Film takes the full row; ENLARGE and Share split the next one, so
     a third control costs no extra height above the buy buttons. */
  .pp-controls > * { flex: 1 1 100%; }
  .pp-controls > .pp-enlarge, .pp-controls > .pp-share { flex: 1 1 0; min-height: 44px; }
  .pp-share { border: 1px solid var(--rule); text-align: center; }
  .pp-enlarge { display: block; width: 100%; text-align: center; min-height: 44px; }
}


/* ---------- Plate / Film on the main image (test, 2026-09-13) ----------
   The film occupies the plate's frame; the chips sit under the caption. */
.pp-film-el {
  display: block; width: 100%; height: auto; max-height: 78vh;
  object-fit: contain; background: var(--navy); margin-inline: auto;
}
.pp-film-el[hidden], .pp-plate-img[hidden] { display: none !important; }
.pp-gal {
  display: inline-flex; gap: 2px; padding: 3px; margin: 0;
  border-radius: 20px; background: var(--paper-warm); border: 1px solid var(--rule);
}
.pp-gal-btn {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 32px; padding: 6px 14px; border: 0; border-radius: 18px;
  cursor: pointer; background: transparent; color: var(--ink-soft);
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase;
}
.pp-gal-btn.is-on { background: var(--navy); color: var(--cream); }
.pp-gal-btn:focus-visible { outline: 2px solid var(--brick); outline-offset: 1px; }
.pp-gal-tri {
  width: 0; height: 0;
  border-top: 5px solid transparent; border-bottom: 5px solid transparent;
  border-left: 8px solid currentColor;
}
@media (max-width: 760px) {
  .pp-gal { display: flex; }
  .pp-gal-btn { flex: 1 1 0; justify-content: center; min-height: 44px; padding: 10px 16px; }
}
