/* ═══════════════════════════════════════════════════════════════════
   board.css — the studio chrome, and the three billboard directions.

   Every measurement inside an artwork is in `cqh` (1% of the artwork's
   own height), because on a board the spec is letter HEIGHT: a 14-foot
   bulletin with 3-foot copy is 21cqh, at any output resolution. The
   artwork element is a size container, so the same numbers hold in the
   contact sheet, on screen at 1:1, and in a 2400px export.

   Each direction is composed THREE times, not scaled three times —
   §Hotline, §Dial and §Object each carry their own bulletin, square and
   portrait layout, and the differences are compositional (what bleeds,
   what crops, what gets cut) rather than a change of font-size.
   ═══════════════════════════════════════════════════════════════════ */

/* ───────────────────────── 0 · studio chrome ────────────────────── */

body.studio{
  background:#0d0d0f; color:#f0f0f0;
  font-family:Selecta,'Helvetica Neue',sans-serif;
  display:grid; grid-template-columns:236px 1fr; min-height:100vh;
}
@media (max-width:900px){ body.studio{ grid-template-columns:1fr } }

.rail{
  position:sticky; top:0; align-self:start; height:100vh; overflow-y:auto;
  padding:20px 18px 24px; border-right:1px solid rgba(255,255,255,.10);
  background:#111113; display:flex; flex-direction:column; gap:20px;
}
@media (max-width:900px){ .rail{ position:static; height:auto; border-right:0; border-bottom:1px solid rgba(255,255,255,.1) } }

.rail-home{
  display:flex; align-items:center; gap:7px; color:#f0f0f0; text-decoration:none;
  font-family:Board,sans-serif; font-weight:700; text-transform:uppercase;
  letter-spacing:.11em; font-size:13px; opacity:.72;
}
.rail-home:hover{ opacity:1 }
.rail-group{ display:flex; flex-direction:column; gap:7px }
.rail-label{ color:rgba(255,255,255,.42); font-size:11px; letter-spacing:.18em }
.rail-note{ color:rgba(255,255,255,.36); font-size:10.5px; letter-spacing:.06em; text-transform:none; margin:2px 0 0 }

.seg{ display:flex; gap:4px; flex-wrap:wrap }
.seg.col{ flex-direction:column; gap:3px }
.seg button{
  flex:1 1 auto; min-height:30px; cursor:pointer; text-align:left;
  background:rgba(255,255,255,.055); border:1px solid transparent; color:rgba(255,255,255,.66);
  border-radius:7px; padding:calc(6px + var(--cap-drop) * 13px) 9px 6px;
  font-family:Board,sans-serif; font-weight:500; font-size:12.5px;
  text-transform:uppercase; letter-spacing:.09em;
  transition:background .16s var(--ease), color .16s var(--ease);
}
.seg.col button{ text-align:left }
.seg button:hover{ background:rgba(255,255,255,.11); color:#fff }
.seg button[aria-selected="true"]{ background:#f0f0f0; color:#111; border-color:#f0f0f0 }
.seg button small{ display:block; font-weight:500; letter-spacing:.05em; text-transform:none; opacity:.55; font-size:10.5px; margin-top:1px }

.checks{ display:flex; flex-direction:column; gap:6px }
.checks label{ display:flex; align-items:center; gap:8px; cursor:pointer;
  font-family:Board,sans-serif; font-size:12.5px; text-transform:uppercase; letter-spacing:.09em;
  color:rgba(255,255,255,.66) }
.checks label:hover{ color:#fff }
.checks input{ accent-color:#f0f0f0; width:14px; height:14px }

.rail-foot{ margin-top:auto; color:rgba(255,255,255,.3); font-size:10.5px; letter-spacing:.06em; text-transform:none; line-height:1.7 }
.rail-foot kbd{ font:inherit; background:rgba(255,255,255,.1); border-radius:3px; padding:1px 4px; margin-right:2px }
.rail-trial{ color:#d9a34f; opacity:.7 }
body[data-view="sheet"] [data-only="single"]{ display:none }

.stage{ padding:26px; display:flex; flex-direction:column; gap:26px; min-width:0 }
body[data-view="sheet"] .stage{ padding:22px }

/* the brief panel: the direction's own argument, sat under the artwork */
.brief{ grid-column:2; padding:0 26px 46px; max-width:74ch }
@media (max-width:900px){ .brief{ grid-column:1 } }
.brief h2{ font-family:Kalice,Georgia,serif; font-weight:400; font-size:24px; margin:0 0 6px; letter-spacing:-.01em }
.brief p{ color:rgba(240,240,240,.6); font-size:14px; line-height:1.68; margin:0 0 10px }
.brief p strong{ color:#f0f0f0; font-weight:400 }
.brief p em{ font-style:italic; color:#f0f0f0 }
.brief .risk{ border-left:2px solid #d9a34f; padding-left:12px; color:rgba(240,240,240,.72) }

/* ─────────────────── 1 · the artwork frame + proofs ─────────────── */

.sheet{ display:grid; gap:22px 20px; grid-template-columns:1fr; }
.sheet-row{ display:grid; gap:16px; grid-template-columns:1fr; align-items:end }
@media (min-width:1100px){
  /* bulletin is 3.43:1, square 1:1, portrait 0.8:1 — give the bulletin
     its own full row and stand the square and portrait side by side, so
     nothing is judged at a size the medium never gets */
  .sheet-row{ grid-template-columns:1fr; }
  .sheet-row .pair{ display:grid; gap:16px; grid-template-columns:1fr 0.8fr; align-items:start }
}
.sheet-head{ display:flex; align-items:baseline; gap:12px; padding:6px 0 2px; border-bottom:1px solid rgba(255,255,255,.1) }
.sheet-head h2{ font-family:Kalice,Georgia,serif; font-weight:400; font-size:21px; margin:0 }
.sheet-head span{ color:rgba(255,255,255,.4); font-size:11px }

figure.art-wrap{ margin:0; display:flex; flex-direction:column; gap:7px; min-width:0 }
.art-cap{ color:rgba(255,255,255,.42); font-size:10.5px; letter-spacing:.15em; display:flex; gap:8px; flex-wrap:wrap }
.art-cap b{ color:rgba(255,255,255,.8); font-weight:500 }

.art{
  container-type:size; container-name:art;
  position:relative; width:100%; overflow:hidden;
  box-shadow:0 20px 50px -18px rgba(0,0,0,.9), 0 0 0 1px rgba(255,255,255,.09);
  isolation:isolate;
  /* Every artwork keeps its own type scale in cqh; nothing inherits a px
     size from the studio, or the contact sheet and the export disagree. */
  line-height:1;
}
.art[data-fmt="bulletin"]{ aspect-ratio:48 / 14 }
.art[data-fmt="square"]  { aspect-ratio:1 / 1 }
.art[data-fmt="portrait"]{ aspect-ratio:4 / 5 }

/* ⚠️  DIRECT children only. `.art *` absolutely positioned every
   DESCENDANT, which took the chrome-bevel number's own stacked spans out
   of flow — and an abspos box with `left:auto` takes its static position
   from `text-align`, so on the centred layouts the number's left edge
   landed on the box's centre line and the whole thing sat half its own
   width to the right. It looked like a centring bug and it was a
   selector-scope bug. */
.art > *{ position:absolute }
.art > .fill{ inset:0; width:100%; height:100% }

/* ── the photographic props ────────────────────────────────────────
   Cut-outs to transparent PNG/WebP. `object-fit:contain` reproduces what
   the SVGs did (preserveAspectRatio meet), so the per-format geometry
   below means the same thing it always did — but every box was
   re-measured, because a 2000×1616 photograph of a desk phone is
   landscape where the drawn one was portrait.

   THE SHADOW IS HERE, NOT IN THE BITMAP. That is the house asset rule,
   and it is the only way the same file can sit on video blue and on cream
   without a halo, and be aimed at the same declared light (upper left,
   about eleven o'clock) as everything else on the board. */
.art .prop{
  position:static; width:100%; height:100%; display:block;
  object-fit:contain; object-position:center;
  filter:drop-shadow(1.4cqh 2.4cqh 2.6cqh rgba(0,0,0,.34));
}
.art[data-dir="hotline"] .prop{
  /* on the dark field the cast shadow does nothing, so the budget goes on
     separating the object from the ground instead */
  filter:drop-shadow(1cqh 1.8cqh 3.4cqh rgba(0,0,0,.6));
}

/* proof helpers — L3's greyscale check and the squint test, on a switch */
body[data-grey="1"] .art{ filter:grayscale(1) }
body[data-squint="1"] .art{ filter:blur(0.9cqh) }
body[data-grey="1"][data-squint="1"] .art{ filter:grayscale(1) blur(0.9cqh) }
.safe{ inset:0; display:none; pointer-events:none; z-index:99 }
body[data-safe="1"] .safe{ display:block }
/* ⚠️  In `cqh`, not `%`. A percentage inset resolves against the box's own
   width horizontally and its height vertically, so on a 48:14 board
   `inset:6%` was 2.88 ft at the sides and 0.84 ft top and bottom — a
   3.43× asymmetry in the one instrument this whole production check
   depends on. The thing being protected (extrusion, frame, vinyl wrap) is
   the same width on all four edges, so the guide has to be too: 7.14cqh
   is one foot on a 14-ft board, and 2.86cqh is a little under five
   inches. Both hold at any output resolution. */
.safe .live{ position:absolute; inset:7.14cqh; border:1px dashed rgba(255,0,120,.8) }
.safe .trim{ position:absolute; inset:2.86cqh; border:1px solid rgba(0,220,255,.55) }
.safe .mid{ position:absolute; left:50%; top:0; bottom:0; width:1px; background:rgba(255,255,255,.28) }

/* ═══════════════ 3 · DIRECTION ONE — THE HOTLINE ═══════════════════
   Late-night television, 1991. Video blue, bevelled gold, the number
   bigger than the product, and a VHS pass over the lot: scanlines, a
   chroma split on the caption type, corner darkening, bloom.
   ═══════════════════════════════════════════════════════════════════ */

/* The deep end was #0a0d78 and the whole board measured a mean relative
   luminance of 0.170 against 0.68–0.70 for the other two — a 4.1×
   deficit. Under a bottom-lit bulletin's falloff the top-right corner
   came out at Y 0.016, which on a lit board is the signature of a dead
   luminaire: a board that reads as broken, on the one direction whose
   declared risk is reading as a scam. The deep end is lifted and the
   radial's reach pulled in. */
.art[data-dir="hotline"]{
  background:
    radial-gradient(126% 158% at 40% 30%, #343bf2 0%, var(--tv-blue) 52%, #1a20a8 100%);
  color:var(--tv-white);
  font-family:Board,'Helvetica Neue',sans-serif;
}
/* the VHS pass. Scanlines are sized in cqh so they are the same count on
   a phone-sized proof and a 2400px export — a px-sized scanline moirés
   the moment the artwork is scaled. */
/* The scanlines and the vignette are SCREEN artefacts and they belong on
   the two formats that live on screens. On the bulletin they are printed
   ink: a 0.47-inch dark stripe on a 1.21-inch pitch across 48 feet of
   vinyl is the textbook moiré condition against the substrate's own
   weave, and the vignette darkens precisely the two corners carrying the
   legal line and the mark. Both off on the bulletin — which is itself the
   "composed three times" thesis holding: the medium changes the artwork,
   not just its proportions. */
.art[data-dir="hotline"][data-fmt="bulletin"] .tv,
.art[data-dir="hotline"][data-fmt="bulletin"] .vig{ display:none }
.art[data-dir="hotline"] .tv{
  inset:0; z-index:40; pointer-events:none; mix-blend-mode:normal;
  background:repeating-linear-gradient(180deg,
    rgba(0,0,0,.20) 0 .28cqh, rgba(0,0,0,0) .28cqh .72cqh);
}
.art[data-dir="hotline"] .vig{
  inset:0; z-index:41; pointer-events:none;
  background:
    radial-gradient(126% 132% at 50% 48%, rgba(0,0,0,0) 52%, rgba(0,0,0,.5) 100%),
    linear-gradient(90deg, rgba(0,0,0,.28), rgba(0,0,0,0) 12%, rgba(0,0,0,0) 88%, rgba(0,0,0,.28));
}
.art[data-dir="hotline"] .obj{ z-index:10 }
.art[data-dir="hotline"] .obj svg{ position:static; width:100%; height:100%; display:block;
  /* `saturate(.86)` was here doing nothing measurable and is cut */
  filter:drop-shadow(0 3cqh 4cqh rgba(0,0,0,.55)) }

.art[data-dir="hotline"] .kicker{
  color:var(--tv-gold); font-weight:700; letter-spacing:.2em;
  text-shadow:0 .12em 0 rgba(0,0,0,.55);
}
.art[data-dir="hotline"] .head{
  font-weight:900; letter-spacing:.005em; color:#fff;
  /* The chroma split is CUT. At 20cqh on a 14-ft board a ±.022em offset
     is three quarters of an inch of red fringe left and cyan fringe right
     of every stem, on the one line that states the offer — and it bought
     nothing the palette, the face and the copy were not already saying.
     One hard drop shadow is what the type actually needs. */
  text-shadow:0 .05em .02em rgba(0,0,0,.65);
}
.art[data-dir="hotline"] .sub{
  font-weight:700; color:rgba(255,255,255,.86); letter-spacing:.03em;
  text-shadow:0 .06em .02em rgba(0,0,0,.5);
}
/* ⚠️  NOT Orleans. Orleans Fat ships oldstyle figures and no lining set —
   measured, its `1` and `0` are 78% the height of its `8` and sit 34px
   lower on a 120px em, so `1-800` renders as `ı-8oo`. A phone number is
   the one string where mixed figure sets are not a style choice, because
   the reader is copying characters rather than reading words. Publico
   Banner Ultra is the same register with uniform lining figures (81–85 on
   the same em) and it holds the gold bevel just as well. */
.art[data-dir="hotline"] .num{ font-family:Publico,Georgia,serif; z-index:30 }
.art[data-dir="hotline"] .legal{
  color:rgba(255,255,255,.72); font-weight:500; letter-spacing:.07em; line-height:1.35;
  text-transform:uppercase; text-shadow:0 .08em 0 rgba(0,0,0,.4);
}
.art[data-dir="hotline"] .mark{ z-index:30; opacity:.9 }
.art[data-dir="hotline"] .mark svg{ position:static; width:100%; height:auto; display:block }
.art[data-dir="hotline"] .mark path,
.art[data-dir="hotline"] .mark circle{ fill:var(--tv-white) }

/* Every headline and number box carries an explicit HEIGHT and hides its
   overflow, and js/board.js shrinks the type until the content fits both
   dimensions. So the size in this file is a CEILING, not a promise — a
   longer copy set or a longer vanity number can never push a line out of
   the board, which is the failure mode of a poster grid built on
   font-size alone. */
/* The boxes centre their content VERTICALLY. `fitBox` shrinks type to fit,
   so a headline that came down two steps used to sit at the top of a box
   sized for the ceiling and open a phantom gap under itself — which then
   read as a spacing mistake somewhere else entirely.

   ⚠️  `align-content` on a BLOCK box, not `display:flex`. Flex turned the
   headline's one `<em>` into a flex ITEM, so "Now taking *requests*." came
   out on three lines with the full stop alone on the last one. Block
   alignment centres the content without changing the formatting context,
   which is the whole point. */
.art .head, .art .num{ overflow:hidden; align-content:center }
.art .num{ white-space:nowrap }

/* — hotline · bulletin ————————————————————————————————————————————
   The desk set bleeds off the LEFT edge, cropped, so the eye enters on
   the object and exits on the number. That ordering is the only reason
   it is on the left rather than the right.                            */
/* The whole object, not a crop of it. Two passes bled the desk set off
   the left edge for the reading order — and what was left on the board
   was a keypad and one earpiece, which reads as an appliance. The eye
   still enters on the object and exits on the number; it just gets to
   see a telephone on the way. */
.art[data-dir="hotline"][data-fmt="bulletin"] .obj{
  left:0.5%; top:13%; width:19%; height:72%;
  transform:rotate(-3deg); transform-origin:50% 50%;
}
.art[data-dir="hotline"][data-fmt="bulletin"] .kicker{ left:21.5%; top:10%; font-size:7.4cqh }
.art[data-dir="hotline"][data-fmt="bulletin"] .head  { left:21.5%; top:19%; width:75%; height:17%; font-size:17cqh }
/* The sub is the only slot that says what the caller RECEIVES. It was
   display:none here, so the 48-foot execution — the lead format — had no
   word for the product on it at all. */
.art[data-dir="hotline"][data-fmt="bulletin"] .sub   { left:21.5%; top:37%; width:64%; font-size:6.2cqh }
.art[data-dir="hotline"][data-fmt="bulletin"] .num   { left:21%; top:46%; width:76%; height:33%; font-size:34cqh }
/* 5cqh on a 14-ft board is a 6-inch cap, legible at about 12 feet, which
   is not a distance anyone reads a bulletin from — and this is the one
   line the direction's own risk register says has to prove a company
   exists. Up to 7cqh (10-inch cap) and given the whole width. */
.art[data-dir="hotline"][data-fmt="bulletin"] .legal { left:21.5%; bottom:4%; width:64%; font-size:8cqh }
.art[data-dir="hotline"][data-fmt="bulletin"] .mark  { right:2.6%; bottom:5.5%; width:8% }

/* — hotline · square ——————————————————————————————————————————————
   The compilation-CD end card: sleeve art top-left in a hairline box,
   the offer beside it, the number across the full width underneath.  */
.art[data-dir="hotline"][data-fmt="square"] .plate{
  left:5.5%; top:8%; width:36%; height:30%; z-index:12;
  background:linear-gradient(200deg,#f6f3e6,#cfc7ad);
  border:.9cqh solid #f4f2ea; box-shadow:0 2cqh 3cqh rgba(0,0,0,.45);
}
.art[data-dir="hotline"][data-fmt="square"] .obj{ left:7%; top:9.4%; width:33%; height:27.2%; z-index:13 }
.art[data-dir="hotline"][data-fmt="square"] .kicker{ left:45%; top:9.5%; width:50%; font-size:3.4cqh }
.art[data-dir="hotline"][data-fmt="square"] .head  { left:45%; top:14.5%; width:51%; height:15%; font-size:7.4cqh; line-height:.94 }
.art[data-dir="hotline"][data-fmt="square"] .sub   { left:45%; top:32.5%; width:51%; font-size:3.9cqh; line-height:1.12 }
.art[data-dir="hotline"][data-fmt="square"] .num   { left:2%; top:43%; width:96%; height:22%; font-size:21cqh; text-align:center }
.art[data-dir="hotline"][data-fmt="square"] .legal { left:11%; top:68%; width:78%; font-size:2.7cqh; text-align:center }
.art[data-dir="hotline"][data-fmt="square"] .mark  { left:44.5%; bottom:6%; width:11% }

/* — hotline · portrait ————————————————————————————————————————————
   A full television screen held in the hand: everything centred, the
   product shot given real size because a story has time to look.     */
.art[data-dir="hotline"][data-fmt="portrait"] .kicker{ left:8%; top:6.5%; width:84%; font-size:3cqh; text-align:center }
.art[data-dir="hotline"][data-fmt="portrait"] .obj   { left:14%; top:10%; width:72%; height:31%; z-index:12 }
.art[data-dir="hotline"][data-fmt="portrait"] .head  { left:6%; top:44%; width:88%; height:12%; font-size:6.8cqh; text-align:center; line-height:.96 }
.art[data-dir="hotline"][data-fmt="portrait"] .num   { left:2%; top:57%; width:96%; height:17%; font-size:15.5cqh; text-align:center }
.art[data-dir="hotline"][data-fmt="portrait"] .sub   { left:8%; top:72.5%; width:84%; font-size:3.4cqh; text-align:center }
.art[data-dir="hotline"][data-fmt="portrait"] .legal { left:9%; bottom:8%; width:82%; font-size:2.15cqh; text-align:center }
.art[data-dir="hotline"][data-fmt="portrait"] .mark  { left:43%; bottom:3.4%; width:14% }

/* ═══════════════ 4 · DIRECTION TWO — THE DIAL ══════════════════════
   One object, drawn to survive being enlarged forty times. Cream
   ground, brushed steel, and the coincidence the campaign is built on:
   a dial is ten circles and the Wabi mark is five.
   ═══════════════════════════════════════════════════════════════════ */

/* Measured across the empty right two-thirds of the bulletin, the cream
   ramp quantised to 9 distinct levels over 21.8 ft — one visible step
   every 4.4 ft, in daylight, on the part of the board with nothing else
   to look at. The grain's own dither is about one level of amplitude and
   cannot break that. So the BULLETIN is flat cream and the two screen
   formats keep the ramp, which is the same format-aware split as the
   scanlines on direction one. */
.art[data-dir="dial"]{ background:var(--cream); color:var(--ink) }
.art[data-dir="dial"][data-fmt="square"],
.art[data-dir="dial"][data-fmt="portrait"]{
  background:radial-gradient(120% 130% at 30% 18%, #fffdf7 0%, var(--cream) 46%, #eee7d6 100%);
}
.art[data-dir="dial"] .grain{
  inset:0; z-index:40; pointer-events:none; opacity:.32; mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  background-size:26cqh 26cqh;
}
.art[data-dir="dial"] .obj{ z-index:10 }
.art[data-dir="dial"] .kicker{
  font-family:Board,sans-serif; font-weight:500; text-transform:uppercase;
  letter-spacing:.22em; color:var(--ink-45);
}
.art[data-dir="dial"] .head{
  /* Orleans Fat, freed up by the swap above. Its headline is all caps, so
     the oldstyle figures that disqualified it from the number cannot bite
     here — and it keeps the three directions in three type worlds. */
  font-family:Orleans,Georgia,serif; font-weight:400; line-height:.96;
  letter-spacing:-.018em; color:var(--ink);
}
.art[data-dir="dial"] .num{
  font-family:Board,sans-serif; font-weight:900; text-transform:uppercase;
  letter-spacing:-.005em; color:var(--ink);
}
.art[data-dir="dial"] .sub{
  font-family:Board,sans-serif; font-weight:500; text-transform:uppercase;
  letter-spacing:.2em; color:var(--ink-45);
}
.art[data-dir="dial"] .legal{
  font-family:Board,sans-serif; font-weight:500; text-transform:uppercase;
  letter-spacing:.2em; color:var(--ink-45);
}
.art[data-dir="dial"] .mark{ z-index:30 }
.art[data-dir="dial"] .mark svg{ position:static; width:100%; height:auto; display:block }
.art[data-dir="dial"] .mark path, .art[data-dir="dial"] .mark circle{ fill:var(--ink) }
/* 1.63:1 against the cream is a line that does not exist at any viewing
   distance, so the number read as a third line of the headline stack. */
.art[data-dir="dial"] .rule{ background:rgba(25,25,25,.55); height:.3cqh }

/* — dial · bulletin ———————————————————————————————————————————————
   The dial is 108% of the board's height, cropped top and bottom — but
   only by 4%, because the finger holes begin 6.5% in from the plate's
   edge and a crop that eats a numeral is a defect, not a decision. */
.art[data-dir="dial"][data-fmt="bulletin"] .obj{ left:0.5%; top:-6%; width:34.5%; height:112% }
.art[data-dir="dial"][data-fmt="bulletin"] .kicker{ left:36%; top:15%; font-size:4.6cqh }
/* The headline was carrying 1.7× the number's ink on the bulletin and
   3.2× on the portrait — a claim that requires a channel, with the
   channel as the second read. The number takes the space back. */
.art[data-dir="dial"][data-fmt="bulletin"] .head  { left:36%; top:22%; width:60%; height:24%; font-size:16cqh }
.art[data-dir="dial"][data-fmt="bulletin"] .rule  { left:36%; top:50%; width:60% }
.art[data-dir="dial"][data-fmt="bulletin"] .num   { left:36%; top:53%; width:61%; height:29%; font-size:28cqh }
/* "DESCRIBE IT" has no antecedent anywhere on the board — the sub holds
   the noun ("THE APP LINE") and was hidden on all three dial formats, so
   the pronoun resolved against the only object present and the board read
   as an advertisement for a telephone. */
.art[data-dir="dial"][data-fmt="bulletin"] .sub   { left:36%; top:8%; font-size:4.6cqh }
.art[data-dir="dial"][data-fmt="bulletin"] .legal { left:36%; bottom:7%; font-size:5.6cqh }
.art[data-dir="dial"][data-fmt="bulletin"] .mark  { right:3%; bottom:7.5%; width:7% }

/* — dial · square ————————————————————————————————————————————————
   Object first, then the words — the portrait's decision applied here,
   because in a feed the object is the scroll-stop and the headline is the
   second read. The square was the one artwork in this direction that had
   simply been re-stacked, and it is the one that runs as paid social.  */
.art[data-dir="dial"][data-fmt="square"] .obj   { left:9%; top:2%; width:82%; height:52% }
.art[data-dir="dial"][data-fmt="square"] .sub   { left:8%; top:55%; width:84%; font-size:2.1cqh; text-align:center }
.art[data-dir="dial"][data-fmt="square"] .kicker{ display:none }
.art[data-dir="dial"][data-fmt="square"] .head  { left:7%; top:58.5%; width:86%; height:13%; font-size:7cqh; text-align:center }
.art[data-dir="dial"][data-fmt="square"] .rule  { left:16%; top:73.5%; width:68% }
.art[data-dir="dial"][data-fmt="square"] .num   { left:4%; top:75.5%; width:92%; height:14%; font-size:13cqh; text-align:center }
.art[data-dir="dial"][data-fmt="square"] .legal { left:8%; bottom:9%; width:84%; font-size:2.3cqh; text-align:center }
.art[data-dir="dial"][data-fmt="square"] .mark  { left:46.5%; bottom:2.6%; width:7% }

/* — dial · portrait ———————————————————————————————————————————————
   Whole dial, high in the frame, and the type stacked under it. The
   first pass bled the dial off the top edge, which looked confident and
   sliced the 3, 4 and 5 clean off — so the portrait is the one format
   where the object is shown entire.                                  */
.art[data-dir="dial"][data-fmt="portrait"] .obj   { left:6%; top:4%; width:88%; height:47% }
.art[data-dir="dial"][data-fmt="portrait"] .sub   { left:8%; top:54.5%; width:84%; font-size:1.85cqh; text-align:center }
.art[data-dir="dial"][data-fmt="portrait"] .kicker{ left:8%; top:58%; width:84%; font-size:2.1cqh; text-align:center }
.art[data-dir="dial"][data-fmt="portrait"] .head  { left:6%; top:61%; width:88%; height:14%; font-size:6.2cqh; text-align:center }
.art[data-dir="dial"][data-fmt="portrait"] .rule  { left:14%; top:77%; width:72% }
.art[data-dir="dial"][data-fmt="portrait"] .num   { left:4%; top:79%; width:92%; height:11.5%; font-size:10.4cqh; text-align:center }
.art[data-dir="dial"][data-fmt="portrait"] .legal { left:8%; bottom:7.4%; width:84%; font-size:1.85cqh; text-align:center }
.art[data-dir="dial"][data-fmt="portrait"] .mark  { left:47%; bottom:2.4%; width:6% }

/* ═══════════════ 5 · DIRECTION THREE — OFF THE HOOK ════════════════
   Wabi's own two colours and one red object. The number is set as the
   headline, in Canela Black, because on this board the number IS the
   line — everything above it is a caption.
   ═══════════════════════════════════════════════════════════════════ */

.art[data-dir="object"]{
  background:var(--paper); color:var(--ink);
}
.art[data-dir="object"] .grain{
  inset:0; z-index:40; pointer-events:none; opacity:.2; mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
  background-size:20cqh 20cqh;
}
.art[data-dir="object"] .obj{ z-index:10 }
.art[data-dir="object"] .obj svg{ position:static; width:100%; height:100%; display:block; overflow:visible }

.art[data-dir="object"] .corner{
  font-family:Board,sans-serif; font-weight:500; text-transform:uppercase;
  letter-spacing:.2em; color:var(--ink-45); line-height:1.6; z-index:30;
}
.art[data-dir="object"] .corner.r{ text-align:right }
.art[data-dir="object"] .head{
  font-family:Canela,Georgia,serif; font-weight:300; color:var(--ink);
  line-height:1.04; letter-spacing:-.012em;
}
.art[data-dir="object"] .head em{ position:static; font-style:italic; font-weight:300 }
.art[data-dir="object"] .num{
  font-family:Canela,Georgia,serif; font-weight:800; color:var(--ink);
  line-height:.96; letter-spacing:-.024em;
}
.art[data-dir="object"] .sub{
  font-family:Selecta,sans-serif; font-weight:400; color:var(--ink-70); line-height:1.35;
}
.art[data-dir="object"] .legal{
  font-family:Board,sans-serif; font-weight:500; text-transform:uppercase;
  letter-spacing:.2em; color:var(--ink-45);
}
.art[data-dir="object"] .mark{ z-index:30 }
.art[data-dir="object"] .mark svg{ position:static; width:100%; height:auto; display:block }
.art[data-dir="object"] .mark path, .art[data-dir="object"] .mark circle{ fill:var(--ink) }

/* — object · bulletin —————————————————————————————————————————————
   The handset HANGS here too. Two passes turned it a quarter turn on the
   argument that a 48:14 board wants a horizontal object — and a handset
   lying flat with its cord running off stage left is a handset resting
   BESIDE a phone, which is the opposite state to the one the direction is
   named after. A slim vertical object at the left third is fine on a wide
   board when the type takes the rest of it, and the number still gets
   nearly the full 48 feet.                                            */
/* Cropped by the TOP edge on purpose. The photograph has a stub of cord
   and nothing to dangle from, so what sells "off the hook" is the frame
   cutting the mouthpiece end — the object is arriving from somewhere
   above. Same move on all three formats. */
.art[data-dir="object"][data-fmt="bulletin"] .obj     { left:3%; top:-16%; width:11%; height:112% }
.art[data-dir="object"][data-fmt="bulletin"] .corner.tl{ left:15%; top:10%; width:22%; font-size:5.4cqh }
/* the right-hand corner block is CUT on the bulletin: it sat at the same
   height as the right-aligned headline and the two collided. Everything
   it said is already in the bottom-right legal line. */
.art[data-dir="object"][data-fmt="bulletin"] .corner.tr{ display:none }
.art[data-dir="object"][data-fmt="bulletin"] .head    { left:40%; top:8%; width:57%; height:22%; font-size:15cqh; text-align:right }
.art[data-dir="object"][data-fmt="bulletin"] .num     { left:17%; top:43%; width:80%; height:40%; font-size:40cqh; text-align:center }
/* Same defect as the other two: the bulletin had no line saying software
   gets built. It goes under the headline on the right, where the eye is
   already going. */
.art[data-dir="object"][data-fmt="bulletin"] .sub     { right:3%; top:33%; width:44%; font-size:4.4cqh; text-align:right }
.art[data-dir="object"][data-fmt="bulletin"] .legal   { right:3%; bottom:6.5%; font-size:5.4cqh }
.art[data-dir="object"][data-fmt="bulletin"] .mark    { left:16.5%; bottom:9%; width:3% }

/* — object · square ——————————————————————————————————————————————
   Corner metadata, the object dead centre hanging from the top edge,
   the copy in the bottom third: the editorial poster layout, held.   */
.art[data-dir="object"][data-fmt="square"] .corner.tl{ left:6%; top:6%; width:34%; font-size:2.4cqh }
.art[data-dir="object"][data-fmt="square"] .corner.tr{ right:6%; top:6%; width:34%; font-size:2.4cqh }
.art[data-dir="object"][data-fmt="square"] .obj      { left:39%; top:-11%; width:22%; height:71% }
.art[data-dir="object"][data-fmt="square"] .head     { left:8%; top:64%; width:84%; height:10%; font-size:7.4cqh; text-align:center }
.art[data-dir="object"][data-fmt="square"] .num      { left:5%; top:74.5%; width:90%; height:13%; font-size:13cqh; text-align:center }
.art[data-dir="object"][data-fmt="square"] .legal    { left:8%; top:91.8%; width:84%; font-size:2cqh; text-align:center }
.art[data-dir="object"][data-fmt="square"] .sub      { left:8%; top:88.4%; width:84%; font-size:2.1cqh; text-align:center }
.art[data-dir="object"][data-fmt="square"] .mark     { left:47.4%; bottom:1.5%; width:5.2% }

/* — object · portrait —————————————————————————————————————————————
   The same idea with the cord given room to be long and to run off the
   top edge, which is the one thing a portrait can do that neither other
   format can.                                                        */
.art[data-dir="object"][data-fmt="portrait"] .corner.tl{ left:6%; top:5%; width:38%; font-size:2.1cqh }
.art[data-dir="object"][data-fmt="portrait"] .corner.tr{ right:6%; top:5%; width:38%; font-size:2.1cqh }
.art[data-dir="object"][data-fmt="portrait"] .obj      { left:39.5%; top:-9%; width:21%; height:68% }
.art[data-dir="object"][data-fmt="portrait"] .head     { left:8%; top:62%; width:84%; height:10%; font-size:6.4cqh; text-align:center }
.art[data-dir="object"][data-fmt="portrait"] .num      { left:5%; top:73%; width:90%; height:12%; font-size:11cqh; text-align:center }
.art[data-dir="object"][data-fmt="portrait"] .sub      { left:9%; top:87.4%; width:82%; font-size:2.15cqh; text-align:center }
.art[data-dir="object"][data-fmt="portrait"] .legal    { left:8%; top:91.2%; width:84%; font-size:1.8cqh; text-align:center }
.art[data-dir="object"][data-fmt="portrait"] .mark     { left:47.8%; bottom:1.3%; width:4.4% }

/* ─────────────────────── 6 · proof / export ─────────────────────── */
/* `?proof=1` (or P) strips the studio so a screenshot is the artwork and
   nothing else — and `tools/shot.mjs` drives the same route to write the
   real 2400px PNGs. */
body.proof{ display:block; background:#0d0d0f }
body.proof .rail, body.proof .brief, body.proof .art-cap, body.proof .sheet-head{ display:none }
body.proof .stage{ padding:0 }
body.proof .art{ box-shadow:none }
body.proof .sheet, body.proof .sheet-row, body.proof .pair{ display:block; gap:0 }
