/* ==========================================================================
   Steve Salgado — built on the Stash design system (stash.cool)
   1. Tokens & base   2. Header   3. Shared   4. Home   5. Index rows
   6. Project         7. Galleries   8. Information   9. Footer   10. Motion
   ========================================================================== */

/* 1. Tokens & base ———————————————————————————————————————————————————————— */
:root {
  --u: clamp(1px, calc(0.212px + 0.0769vw), 1.5px);
  --hh: calc(43 * var(--u));
  --pad: 20px;
  --col: 246px;
  --gap: clamp(20px, 2vw, 40px);
  --bg: #fff; --fg: #000; --muted: #8a8a8a; --line: #000; --blue: #0000ff; --wash: #f1f1f1;
  --ease: cubic-bezier(.7, 0, .2, 1);
  --sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: var(--sans);   /* no monospace on this site: what used Space Mono is set in Helvetica */
  --t: calc(12 * var(--u));
  --display: clamp(34px, 5.4vw, 92px);
  --r: 10px;                             /* corner radius for images and video */
  color-scheme: light;
}
:root[data-theme="dark"] { --bg: #0b0b0b; --fg: #f2f2f2; --line: #454545; --blue: #4d4dff; --wash: #1a1a1a; color-scheme: dark; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --bg: #0b0b0b; --fg: #f2f2f2; --line: #454545; --blue: #4d4dff; --wash: #1a1a1a; color-scheme: dark; }
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { overflow-x: clip; }   /* nothing (mid-animation prints, zooms) can ever make the page scroll sideways */
html { overscroll-behavior-y: none; -webkit-font-smoothing: antialiased; scroll-padding-top: calc(var(--hh) + 12px); }
body { background: var(--bg); color: var(--fg); font: 400 calc(16 * var(--u))/1.2 var(--sans); }
a { color: inherit; text-decoration: none; }
img, video { display: block; width: 100%; height: auto; background: var(--wash); }
.skip { position: fixed; left: 12px; top: -60px; z-index: 100; padding: 8px 12px; background: var(--fg); color: var(--bg); font: var(--t) var(--mono); }
.skip:focus { top: 10px; }
main { padding-top: var(--hh); }
h1, h2, h3 { font-weight: 400; text-wrap: balance; }
p { text-wrap: pretty; }
:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }

/* 2. Header ——————————————————————————————————————————————————————————————— */
.site-head { position: fixed; inset: 0 0 auto; z-index: 10; height: var(--hh); display: grid; grid-template-columns: var(--col) 1fr 1fr auto;
  align-items: center; padding: 0 var(--pad); font-size: var(--t); background: var(--bg); }
.site-head > a:hover { opacity: .5; }
.h-open { display: flex; align-items: center; gap: 10px; }
.theme-btn { width: 13px; height: 13px; padding: 0; border: 1px solid var(--fg); cursor: pointer; flex: none;
  background: linear-gradient(90deg, var(--fg) 50%, var(--bg) 50%); transition: transform .3s var(--ease); }
.theme-btn:hover { border-color: var(--blue); background: linear-gradient(90deg, var(--blue) 50%, var(--bg) 50%); }
:root[data-theme="dark"] .theme-btn { transform: rotate(180deg); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .theme-btn { transform: rotate(180deg); } }
.nav { display: flex; gap: clamp(18px, 2vw, 36px); justify-self: end; }
.nav a { position: relative; }
.nav a::after { content: ""; position: absolute; left: 0; right: 0; bottom: -3px; height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: left; transition: transform .35s var(--ease); }
.nav a:hover::after, .nav a[aria-current]::after { transform: scaleX(1); }

/* 3. Shared ——————————————————————————————————————————————————————————————— */
.display { font-size: var(--display); line-height: .98; letter-spacing: -.035em; font-weight: 400; }
.muted { color: var(--muted); }
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }   /* read by screen readers and search, not shown */
.lbl { display: block; font: var(--t)/1.35 var(--mono); color: var(--muted); margin-bottom: 10px; text-transform: none; }
.ln { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; text-decoration-color: var(--muted); transition: color .2s, text-decoration-color .2s; }
.ln:hover { color: var(--blue); text-decoration-color: currentColor; }
.sec-top { display: flex; justify-content: space-between; align-items: flex-end; padding: 12px 0 10px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  font-size: var(--t); line-height: 1.35; }
.sec-top h2 { font-size: inherit; }
.sec-top .muted { font-family: var(--mono); }
.page-head { padding: 64px var(--pad) 40px; display: flex; justify-content: space-between; align-items: flex-end; gap: 20px; flex-wrap: wrap; }
.page-head .muted { font-size: var(--t); font-family: var(--mono); }

/* All-caps fitted page title (Photography, Feed): the same word treatment as the project pages */
.page-word { padding: 0 var(--pad); margin-bottom: 40px; }
.page-word .b-word { padding: 48px 0 0; }
.page-sub { margin-top: 18px; font: var(--t) var(--mono); }

/* 4. Home ————————————————————————————————————————————————————————————————— */
.intro { padding: 64px var(--pad) 72px; }
.intro .display { max-width: 15ch; font-size: clamp(40px, 7.4vw, 132px); }
.work { padding: 12px var(--pad) 96px; }
/* Home hero (the Photography card): full width above the Selected work bar, its caption set on the photo */
.home-hero { margin-bottom: 40px; }
.home-hero .card-m { aspect-ratio: auto; height: calc(100vh - var(--hh) - 12px - var(--pad)); height: calc(100svh - var(--hh) - 12px - var(--pad)); position: relative; border-radius: var(--r); }   /* fills the first screen, with the side margin as the bottom edge */
.home-hero .card { position: relative; display: block; width: 100%; }
.home-hero .card-m { width: 100%; }
.home-hero .card-m .m { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }   /* fills the frame; never sizes the frame from its own shape */
/* On scroll the frame opens from the line width out to the full width of the screen (corners square off) over
   the first half screen of scroll, then scrolls away; the photo drifts slower than the page inside it. Driven by
   the page scroll itself, so it can't lag. Without scroll timelines it simply stays at the line width. */
@supports (animation-timeline: scroll()) {
  .home-hero .card { margin-inline: calc(-1 * var(--pad)); width: auto; }   /* full bleed box, clipped back to the line at rest */
  .home-hero .card-m { animation: hero-open linear both; animation-timeline: scroll(root); animation-range: 0 50vh; overflow: hidden; border-radius: 0; }
  .home-hero .card-m .m { top: -10%; height: 120%; animation: hero-drift linear both; animation-timeline: scroll(root); animation-range: 0 100vh; }
  .home-hero .card-t { animation: hero-cap linear both; animation-timeline: scroll(root); animation-range: 0 50vh; }
  @keyframes hero-open { from { clip-path: inset(0 var(--pad) 0 var(--pad) round var(--r)); } to { clip-path: inset(0 0 0 0 round 0); } }
  @keyframes hero-drift { from { transform: translateY(0) scale(1.04); } to { transform: translateY(14%) scale(1); } }
  @keyframes hero-cap { from { left: var(--pad); right: var(--pad); } to { left: 0; right: 0; } }   /* the caption stays inset from the frame's edges as it opens */
}
@media (prefers-reduced-motion: reduce) { .home-hero .card-m, .home-hero .card-m .m, .home-hero .card-t { animation: none; } }
.home-hero .card-t { position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; padding: clamp(12px, 1.4vw, 22px) clamp(14px, 1.6vw, 24px);
  color: #fff; text-shadow: 0 1px 8px rgba(0,0,0,.35); grid-template-columns: 1fr auto; }
.home-hero .card-t .c-k { color: rgba(255,255,255,.75); }
.home-hero .card:hover .card-t > span:first-child { color: #fff; }
@media (max-width: 700px) { .home-hero .card-m { height: 72svh; } }
.cards { display: grid; grid-template-columns: 1fr 1fr; gap: 56px var(--gap); padding-top: 24px; }
.card { display: block; animation: in .6s var(--ease) backwards; animation-delay: var(--d); }
.card:first-child { grid-column: 1 / -1; }
.card-m { overflow: hidden; background: var(--wash); aspect-ratio: 4 / 3; }
.card:first-child .card-m { aspect-ratio: 21 / 9; }
/* the first tile spans the row, so an even count leaves the last one alone: it spans too */
.card:last-child:nth-child(even) { grid-column: 1 / -1; }
.card:last-child:nth-child(even) .card-m { aspect-ratio: 21 / 9; }
.card-m .m { width: 100%; height: 100%; object-fit: cover; aspect-ratio: auto !important; transition: transform .8s var(--ease); }
.card:hover .card-m .m { transform: scale(1.03); }
.card-t { display: grid; grid-template-columns: 1fr auto; gap: 10px; padding: 10px 0 0; font-size: var(--t); line-height: 1.35; border-top: 0; }
.card-t > span:first-child { transition: color .2s; }
.card:hover .card-t > span:first-child { color: var(--blue); }
.c-n { font-family: var(--mono); color: var(--muted); }
.c-k { color: var(--muted); }

/* 5. Index rows (Stash's table) ——————————————————————————————————————————— */
.dir { padding: 0 var(--pad) 120px; }
.table { font-size: var(--t); }
.thead, .row { display: grid; grid-template-columns: 52px minmax(150px, 1.4fr) minmax(0, 1fr) minmax(0, 1fr) 20px; gap: 16px; align-items: center; }
.thead { padding: 14px 0 8px; border-bottom: 1px solid var(--line); color: var(--muted); }
.row { position: relative; isolation: isolate; padding: 9px 0 8px; border-bottom: 1px dotted var(--line); animation: in .5s var(--ease) backwards; animation-delay: var(--d); }
.row::before { content: ""; position: absolute; inset: -1px -8px; background: var(--fg); z-index: -1; clip-path: inset(50% 0 50% 0); transition: clip-path .35s var(--ease); }
.row > span { transition: color .2s, transform .35s var(--ease); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.row:hover::before, .row:focus-visible::before { clip-path: inset(0); }
.row:hover, .row:focus-visible { color: var(--bg); outline: 0; }
.row:hover .c-n, .row:hover .c-k { color: inherit; }
.row:hover > span:not(.c-x) { transform: translateX(8px); }
.row .c-x { text-align: right; }
.info + .dir .row, .dir .row:has(.wide) { grid-template-columns: 52px minmax(150px, 1fr) minmax(0, 3fr) 20px; }

/* 6. Project ——————————————————————————————————————————————————————————————
   Blocks follow the old Squarespace pages: full-bleed by default, no gaps between them; inset runs sit
   inside the page margins with air above and below. */
/* Header: Stash's detail bar. Sticky breadcrumb path ruled top and bottom, then the project's row */
.proj { padding-top: 0; }   /* the breadcrumb bar starts where it sticks, right under the top bar: no slip before it pins */
.proj-head { position: sticky; top: var(--hh); z-index: 6; padding: 0 var(--pad); background: var(--bg); font-size: var(--t); line-height: 1.35; }
.d-path { display: flex; justify-content: space-between; align-items: center; gap: 16px; padding: 9px 0 8px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.d-crumbs { display: flex; align-items: baseline; gap: 8px; min-width: 0; white-space: nowrap; overflow: hidden; }
.d-crumbs a { color: var(--muted); }
.d-crumbs a:hover { color: var(--fg); text-decoration: underline; }
.d-crumbs i { font-style: normal; color: var(--muted); }
.d-crumbs span { overflow: hidden; text-overflow: ellipsis; }
.d-caret { display: inline-block; width: 7px; height: 12px; background: var(--fg); transform: translateY(2px); animation: blink 1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }
.d-step { display: flex; gap: 4px; font-family: var(--mono); }
.d-step a { padding: 0 6px; }
.d-step a:hover { background: var(--blue); color: #fff; }
.d-row { display: grid; grid-template-columns: 52px minmax(150px, 1.1fr) minmax(120px, .8fr) minmax(0, 2.4fr); gap: 16px; align-items: baseline;
  padding: 9px 0 8px; border-bottom: 1px solid var(--line); }
.d-row h1 { font-size: inherit; }
.d-row .c-n { color: var(--fg); }
.d-row .c-n::before { content: "▶\FE0E "; font-size: calc(8 * var(--u)); vertical-align: 1px; }
.blocks { padding: 0 var(--pad); display: grid; gap: var(--r); }   /* everything sits on the top bar's line width */
/* Hero (project pages): the word drifts slower than the page while the first image rides up over it,
   growing from the line width to full bleed. boot.js sets --p (0 → 1) from scroll. */
.b-word { position: relative; z-index: 0; will-change: transform; }
.b-hero { position: relative; z-index: 1; margin-inline: calc(-1 * var(--pad));
  --x: calc(var(--pad) * (1 - var(--p, 0))); --rr: calc(var(--r) * (1 - var(--p, 0)));
  clip-path: inset(0 var(--x) round var(--rr)); }
.b-hero.b-crop, .b-hero .m { border-radius: 0; }
.blocks > :not(.b-word):not(.b-hero) { position: relative; z-index: 1; }

/* Palette block: four live colour bars with their values */
.b-palette { display: flex; flex-direction: column; overflow: hidden; border-radius: var(--r); }
.pal-row { flex: 1; display: flex; min-height: 0; }
.pal-name { position: absolute; left: clamp(12px, 1.6vw, 24px); top: clamp(12px, 1.6vw, 22px); font-size: var(--t); line-height: 1.2; white-space: nowrap; }
.pal-col { flex: var(--g, 1) 1 0; min-width: 0; display: flex; flex-direction: column; }
.pal-col > .pal { min-height: 0; }
.pal.is-white { box-shadow: inset 0 0 0 1px rgba(0,0,0,.08); }   /* white on a white page needs an edge */
.pal { flex: var(--g, 1) 1 0; min-width: 0; overflow: hidden; position: relative; background: var(--c); color: var(--ink); transform-origin: 50% 100%; }
.pal dl { position: absolute; left: clamp(12px, 1.6vw, 24px); white-space: nowrap; bottom: clamp(12px, 1.6vw, 24px);   /* a fixed inset (same as the left), so values line up across swatches of different heights */ display: grid; grid-template-columns: auto auto; gap: 2px 1.2em;
  font: calc(9.5 * var(--u))/1.3 var(--mono); }
.pal dt { opacity: .7; }
@media (max-width: 700px) { .b-palette:not(.has-rows) .pal-row { flex-direction: column; } .b-palette:not(.has-rows) { aspect-ratio: 3 / 4 !important; } .b-palette.has-rows .pal-row { flex-wrap: wrap; } .b-palette.has-rows .pal { flex-basis: 50%; } .b-palette.has-rows { aspect-ratio: 3 / 4 !important; } .pal dl { font-size: 7.5px; gap: 1px .9em; } }

/* Stack block: prints dropped onto a pile. Without JS they sit fanned on the pile, all visible at rest */
.b-stack { position: relative; height: 100vh; height: 100svh; background: var(--sbg); border-radius: var(--r); overflow: hidden; }
.slot { position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none; }
.print { margin: 0; padding: 0; background: none; overflow: hidden;
  box-shadow: 0 0 0 .5px rgba(0,0,0,.12), 0 1px 3px rgba(0,0,0,.08);   /* hairline edge, barely any blur */
  transform: translate(var(--dx), var(--dy)) rotate(var(--r)); will-change: transform; }
.print .m { width: auto; height: auto; max-height: 64svh; max-width: min(56vw, 720px); border-radius: 0; aspect-ratio: auto !important; }   /* fits both ways */
@media (max-width: 700px) { .print .m { max-height: 56svh; max-width: 70vw; } }

/* TRA site comp (Trade Gothic Bold Extended, from Steve's library): sized in container units so it scales as
   one piece. js/fx.js places it in the expand stage; the video becomes its hero. */
.site-comp { position: relative; container-type: inline-size; aspect-ratio: 2500 / 1663; margin-top: var(--gap); border-radius: var(--r); overflow: hidden;
  display: grid; grid-template-columns: 38.75% 1fr; background: #151515; color: #D4D2CB; }
.tx { display: block; fill: currentColor; }   /* Trade Gothic lettering, drawn as outlines (scripts/outline.py): the font file is never published */
.sc-panel { position: relative; background: #151515; z-index: 1; }
.sc-logo { position: absolute; left: 5.6cqw; top: 4.4cqw; width: 11.6cqw; }
.sc-logo svg { display: block; width: 100%; height: auto; fill: #D4D2CB; }
.sc-about { position: absolute; left: 5.7cqw; top: 39.03cqw; width: 20cqw; }   /* ABOUT's cap top lines up with the headline's */
.sc-about h3 { font-size: 1.3cqw; line-height: 1; margin-bottom: 3.6cqw; }
.sc-about p { font: .78cqw/1.55 var(--sans); color: #b9b7b0; }
.sc-hero { position: relative; background: #555 url(/assets/media/tra/prime-still.webp) center / cover; }   /* still for no-JS; the video covers it */
.sc-nav { position: absolute; right: 4.8cqw; top: 5.4cqw; display: flex; gap: 4.4cqw; font-size: 1.5cqw; z-index: 2; }
.sc-nav span { position: relative; }
.sc-rule { position: absolute; left: 0; right: .1em; bottom: -.7em; height: 1px; background: #D4D2CB; transform-origin: 0 50%; }   /* under the active item (About) */
.sc-head { position: absolute; left: 4cqw; top: 39cqw; font-size: 4.6cqw; line-height: 1; z-index: 2; margin: 0; }
.sc-line { display: block; overflow: hidden; padding-bottom: .06em; }
.sc-line > span { display: block; }
/* inside the stage the comp sits over the video; its hero is see-through so the video shows in it */
.st-stage .site-comp { position: absolute; margin: 0; z-index: 3; background: transparent; pointer-events: none; }
.st-stage .sc-hero { background: none; }

.b-mat { background: var(--wash); border-radius: var(--r); padding: clamp(24px, 7%, 110px); }
.b-mat .m { border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,.06), 0 12px 32px -18px rgba(0,0,0,.18); }
.b-tiles { display: grid; gap: var(--r); }
.t-row { display: flex; gap: var(--r); align-items: flex-start; }
.t-tile { min-width: 0; }
.t-tile .m { width: 100%; height: auto; }

/* Stagger block: a visual break with white space. Left image, open space, right image set lower */
.b-stagger { display: flex; flex-direction: column; padding: clamp(80px, 12vw, 200px) 0; }
.b-stagger > figure { width: calc(50% - var(--gap) / 2); margin: 0; }
.b-stagger .m { transform-origin: 50% 60%; }
.b-stagger > figure + figure { margin-top: clamp(48px, 7vw, 120px); }
.st-r { align-self: flex-end; }
.b-stagger figcaption { padding-top: 10px; }
/* square crops; "focus" in the data (object-position, e.g. "52% 40%") sets where each crop centres */
.b-stagger .m { aspect-ratio: 1 / 1 !important; width: 100%; height: auto; object-fit: cover; object-position: var(--focus, 50% 50%); }
.st-ph { aspect-ratio: 1 / 1; }
/* Expand stage (js/fx.js): full-bleed, one screen tall; the media fills it and is windowed by clip-path */
.st-wrap { width: 100vw; margin: clamp(48px, 7vw, 120px) 0 0 calc(50% - 50vw); }   /* carries the spacing + full-window width */
.st-stage { position: relative; height: 100vh; height: 100svh; width: 100%; margin: 0; overflow: hidden; }   /* no margins: GSAP pins it flush at the top */
.st-stage .m { position: absolute; inset: 0; width: 100%; height: 100%; aspect-ratio: auto !important; object-fit: cover; border-radius: 0; }
.st-stage figcaption { position: absolute; margin: 0; }   /* small mono credit under each image */
.st-ph { aspect-ratio: 4 / 5; border-radius: var(--r); background: var(--wash); display: grid; place-items: center;
  font: var(--t) var(--mono); color: var(--muted); }
@media (max-width: 700px) { .b-stagger { padding: 64px 0; } .b-stagger > figure { width: 72%; } .b-stagger > figure + figure { margin-top: 40px; } }

/* Breadcrumb-only bar on project pages: the project row under the breadcrumb is hidden */
[data-page="project"] .d-row { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }   /* title, type and tagline: for screen readers and search, the big word shows the name */

html.hero-pending [data-page="project"] .b-word-t { visibility: hidden; }   /* until js/hero.js is ready */

/* Project hero letters (js/hero.js splits the word so they can rise in) */
.hs-l { display: inline-block; will-change: transform, opacity; }

/* Nav hides on scroll down, returns on scroll up (project pages; boot.js toggles html.nav-hidden) */
.site-head, .proj-head { transition: transform .45s var(--ease); }
.nav-hidden .site-head { transform: translateY(-100%); }
.nav-hidden .proj-head { transform: translateY(calc(-100% - var(--hh) - 2px)); }

/* Rounded corners: every image and video, and any block that crops its media */
.m, .card-m, .b-crop, .b-stage, .b-fade, .info-portrait .m { border-radius: var(--r); overflow: hidden; }
.b-stage > .m, .b-crop .m, .b-frame .m, .card-m .m { border-radius: 0; }
.b-stage-in .m { border-radius: var(--r); }
.b-run { gap: var(--r); }
.blocks img, .blocks video { background: none; }
.b-full .m { width: 100%; }
.b-run { display: grid; gap: var(--r); padding: 0; }
.b-run:has(.b-row, .b-text) { padding: 48px 0; }   /* only text/label rows need air; images use the standard gap */
.b-crop { overflow: hidden; }
.b-crop .m { width: 100%; height: 100%; object-fit: cover; aspect-ratio: auto !important; }
.b-word { padding: 48px 0 32px; overflow: hidden; }   /* fits inside the page margins, flush with the rules */
.b-word-t { display: inline-block; font: 400 20vw/.8 var(--sans); letter-spacing: -.045em; white-space: nowrap; }
.b-narrow { width: 76%; margin: 0 auto; }
.b-text { max-width: none; padding-top: 28px; font-size: clamp(16px, 1.25vw, 21px); line-height: 1.4; }
.b-text p { max-width: 62ch; }
/* Prism: icon + wordmark, labelled */
.b-row { display: grid; grid-template-columns: 30fr 53fr; gap: 7%; padding-bottom: 64px; align-items: start; }
.b-row figcaption { font: var(--t)/1.35 var(--mono); color: var(--muted); padding: 0 0 16px; }
/* Stage: background image under a 45% black wash (as on Squarespace), social card centered */
.b-stage { position: relative; aspect-ratio: 1440 / 1091; overflow: hidden; }
.b-stage > .m { width: 100%; height: 100%; object-fit: cover; aspect-ratio: auto !important; filter: brightness(.55); }
.b-stage-in { position: absolute; left: 50%; top: 50%; height: 65%; aspect-ratio: 9 / 16; transform: translate(-50%, -50%); }
.b-stage-in .m { width: 100%; height: 100%; object-fit: cover; aspect-ratio: auto !important; box-shadow: 0 20px 60px rgba(0,0,0,.35); }
/* Carousel: centered slide at 85% with neighbours peeking, snap scrolling */
/* Slider (js/fx.js): one rounded frame, slides stacked inside; a quiet mono bar underneath */
.sl-frame { display: grid; gap: var(--r); }
.sl-slide .m { width: 100%; height: auto; border-radius: var(--r); }
.b-slider.is-live .sl-frame { display: block; position: relative; aspect-ratio: var(--ar); overflow: hidden; border-radius: var(--r); cursor: grab; touch-action: pan-y; }
.b-slider.is-live .sl-frame:active { cursor: grabbing; }
.b-slider.is-live .sl-slide { position: absolute; inset: 0; overflow: hidden; visibility: hidden; }
.b-slider.is-live .sl-slide.is-on { visibility: visible; }
.b-slider.is-live .sl-in { position: absolute; inset: 0; will-change: transform; }
.b-slider.is-live .sl-slide .m { width: 100%; height: 100%; object-fit: cover; aspect-ratio: auto !important; border-radius: 0; user-select: none; -webkit-user-drag: none; pointer-events: none; }
.sl-bar { display: none; }
.b-slider.is-live .sl-bar { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 16px; padding-top: 10px; font: var(--t)/1 var(--mono); color: var(--muted); }
.sl-count b { font-weight: 400; color: var(--fg); }
.sl-progress { position: relative; height: 1px; background: var(--line); opacity: .25; }
.sl-progress i { position: absolute; left: 0; top: 0; bottom: 0; background: var(--fg); width: 100%; transform-origin: 0 50%; transform: scaleX(var(--sp, 0)); }
.b-slider.is-live .sl-progress { opacity: 1; background: color-mix(in srgb, var(--line) 25%, transparent); }
.sl-nav { display: flex; gap: 4px; }
.sl-nav button { font: inherit; color: var(--fg); background: none; border: 0; padding: 4px 8px; cursor: pointer; }
.sl-nav button:hover { background: var(--blue); color: #fff; }
/* Fade: frames stacked, one visible, crossfading */
.b-fade { position: relative; aspect-ratio: 16 / 10; overflow: hidden; }
.b-frame { position: absolute; inset: 0; opacity: 0; transition: opacity 1.2s var(--ease); }
.b-frame.on { opacity: 1; }
.b-frame .m { width: 100%; height: 100%; object-fit: cover; aspect-ratio: auto !important; }
/* About / Credits: label column, then text (old site: 2–17% / 18–70%, credits 18–50% and 54–94%) */
.proj-info { display: grid; grid-template-columns: var(--col) 1fr; column-gap: var(--gap); row-gap: 40px; margin: 96px var(--pad) 0; padding-top: 14px; border-top: 1px solid var(--line); }
.proj-info > .lbl { margin: 4px 0 0; }
.proj-about { max-width: 62ch; font-size: clamp(16px, 1.25vw, 21px); line-height: 1.4; }
.proj-about p + p { margin-top: 1em; }
.proj-credits { display: grid; grid-template-columns: 1fr 1fr; gap: 28px var(--gap); font-size: var(--t); line-height: 1.55; }
.proj-credits dd { white-space: pre-line; }
.more { margin: 96px var(--pad) 0; padding-bottom: 96px; }
.more-cards { grid-template-columns: repeat(3, 1fr); gap: 40px var(--gap); }
.more-cards .card:first-child, .more-cards .card:last-child:nth-child(even) { grid-column: auto; }   /* no full-width tiles in this row */
.more-cards .card-m, .more-cards .card:first-child .card-m, .more-cards .card:last-child:nth-child(even) .card-m { aspect-ratio: 4 / 3; }
@media (max-width: 1000px) { .more-cards { grid-template-columns: 1fr 1fr; } .more-cards .card:nth-child(3) { display: none; } }
@media (max-width: 700px) { .more { margin-top: 64px; padding-bottom: 56px; } .city .more { margin-top: 20px; padding-bottom: 32px; }   /* photo pages: the grid's own gap, not a second one */ .more-cards { grid-template-columns: 1fr; } .more-cards .card:nth-child(3) { display: block; } }
.pager { display: grid; grid-template-columns: 1fr 1fr; margin: 96px var(--pad) 0; border-top: 1px solid var(--line); }
.pager a { padding: 14px 0 96px; }
.pager a:last-child { text-align: right; }
.pager-t { font-size: clamp(22px, 2.4vw, 40px); letter-spacing: -.02em; transition: color .2s; }
.pager a:hover .pager-t { color: var(--blue); }

/* 7. Galleries ———————————————————————————————————————————————————————————— */
.photo-sec { padding: 96px var(--pad) 0; }
.masonry { columns: 3; column-gap: var(--gap); padding-top: 24px; }
.masonry.wide { padding: 0 var(--pad) 40px; columns: 4; }
.masonry figure { break-inside: avoid; margin-bottom: var(--gap); }
figcaption { font: var(--t)/1.35 var(--mono); color: var(--muted); padding-top: 8px; }

/* Photography: series list. Core photos alternate margins and swell to the full line width as they pass the
   middle of the screen (js/photo.js sets --w as a share of the line, --o for the label). No overlap. */
.ph-hero { padding: 0 var(--pad); margin-bottom: var(--gap); }   /* same gap as between the series */
.ph-hero .m { border-radius: var(--r); }
.series-list { padding: 0 var(--pad) 12vh; }
.series { display: flex; align-items: center; }
.series + .series { margin-top: var(--gap); }
.series.is-right { flex-direction: row-reverse; }
.series-img { display: block; width: var(--w, 60%); flex: none; cursor: zoom-in; }
.series-img { position: relative; }
/* the place name moves onto the photo as it expands: small white text, lower left (opacity from js/photo.js) */
.series-tag { position: absolute; left: clamp(14px, 1.6vw, 24px); bottom: clamp(12px, 1.4vw, 22px); z-index: 2; pointer-events: none;
  color: #fff; font-size: var(--t); line-height: 1.2; opacity: var(--in, 0); text-shadow: 0 1px 8px rgba(0,0,0,.35); }
.series-img .m { border-radius: var(--r); aspect-ratio: var(--ar, 1) !important; width: 100%; height: auto; object-fit: cover; }   /* square → own shape (js/photo.js) */
.series-lab { flex: 1; min-width: 0; text-align: center; font-size: var(--t); line-height: 1.35; opacity: var(--o, 1); white-space: nowrap; overflow: hidden; }
.series-lab:hover { color: var(--blue); }
/* Series grid: full-screen overlay with every photo in the series */
.series-grid { position: fixed; inset: 0; z-index: 60; background: var(--bg); overflow-y: auto; overscroll-behavior: contain; padding: 0 0 80px; }
.series-grid[hidden] { display: none; }
.series-grid { scroll-timeline: --sg block; }   /* the grid's own scroll drives the title parallax */
.sg-word { padding: 24px var(--pad) 40px; position: relative; z-index: 0; overflow: visible; }   /* visible: not a scroll container, and never clips the drifting title */
.sg-word .b-word-t { will-change: transform; }
/* Parallax by the browser itself (scroll-driven animation): the title moves in the same frame as the scroll,
   so it can't lag or jitter. js/photo.js sets the distance (--sgd) and the scroll range (--sgr) on open. */
@supports (animation-timeline: scroll()) {
  .sg-word .b-word-t { animation: sg-drift linear both; animation-timeline: --sg; animation-range: 0px var(--sgr, 400px); }
  @keyframes sg-drift { to { transform: translate3d(0, var(--sgd, 0px), 0); } }
  .sg-page .sg-word .b-word-t { animation-timeline: scroll(root); }   /* Cook: the page itself scrolls */
}
@media (prefers-reduced-motion: reduce) { .sg-word .b-word-t { animation: none; } }
.sg-hero { position: relative; z-index: 1; }   /* rides up over the title (js/photo.js drifts the title) */   /* the fitted all-caps title, same as the project pages */
.sg-top { position: sticky; top: 0; z-index: 2; display: flex; justify-content: space-between; align-items: center; margin: 0 var(--pad) 24px;
  padding: 14px 0 10px; border-bottom: 1px solid var(--line); background: var(--bg); font-size: var(--t); }
.sg-top h2 { font-size: inherit; }
.sg-top .muted { font-family: var(--mono); margin-left: 10px; }
.sg-close { font: 16px var(--mono); background: none; border: 0; color: var(--fg); cursor: pointer; width: 36px; height: 36px; }
.sg-close:hover { background: var(--blue); color: #fff; }
.sg-big, .sg-mason { padding: 0 var(--pad); }
.sg-big { display: flex; margin: 0 0 var(--gap); }   /* one gap everywhere: same as between masonry columns and rows */
.sg-big.is-right { justify-content: flex-end; }
.sg-big figure { margin: 0; width: var(--w, 100%); flex: none; }   /* grows from half to the full line (js/photo.js) */
.sg-big .m { max-height: 92vh; object-fit: cover; }
.sg-mason figure { cursor: zoom-in; }
.sg-open figure { width: 100%; cursor: zoom-out; transform-origin: 0 0; }
/* full-width photos in a grid (hero, features, clicked-open): the caption moves onto the photo, white,
   lower left, like the place names on the Photography page. Features fade it in as they grow (--in). */
.sg-big figure { position: relative; }
.sg-big figcaption { position: absolute; left: clamp(14px, 1.6vw, 24px); bottom: clamp(12px, 1.4vw, 22px); z-index: 2; padding: 0;
  pointer-events: none; color: #fff; font: var(--t)/1.2 var(--sans); text-shadow: 0 1px 8px rgba(0,0,0,.35); opacity: var(--in, 1); }
.sg-open figcaption { animation: cap-in .4s .35s var(--ease) both; }
@keyframes cap-in { from { opacity: 0; transform: translateY(4px); } }
.sg-big figure .shield { height: 100%; }
.sg-mason figure, .sg-open figure { will-change: transform; }
.sg-open .m { max-height: 92vh; object-fit: cover; }   /* opened by a click: full width, capped at a screen like the features */
::view-transition-group(*) { animation-duration: .45s; animation-timing-function: cubic-bezier(.32, .72, 0, 1); }   /* full width, uncropped unless very tall */
.sg-mason { columns: 3; column-gap: var(--gap); padding-bottom: var(--gap); }
.sg-mason figure { margin-bottom: var(--gap); }   /* columns drop the last item's margin, so the run carries the gap itself */
.series-grid figure { animation: in .6s var(--ease) backwards; animation-delay: calc(min(var(--i, 0), 8) * 40ms); }
.series-grid.is-settled figure { animation: none; }   /* fade-in plays once; moving photos later must not replay it (that was the flash) */
@media (max-width: 700px) { .sg-mason { columns: 2; column-gap: 12px; padding-bottom: 12px; } .sg-mason figure { margin-bottom: 12px; } .sg-big { margin-bottom: 12px; } }
html.grid-open { overflow: hidden; }
@media (max-width: 700px) {
  .series-lab { font-size: 11px; }
}

/* Photo protection (Photography page): no select, no drag, no iOS long-press save. A transparent shield sits
   over each photo so right-click / inspect / drag hit it, not the image (clicks still reach the figure). */
[data-page="photography"] img, .sg-scope img { -webkit-user-drag: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; pointer-events: none; }
[data-page="photography"] .series-img, [data-page="photography"] .ph-hero, .sg-scope figure { position: relative; -webkit-touch-callout: none; user-select: none; -webkit-user-select: none; }
.shield { position: absolute; inset: 0; z-index: 1; background: transparent; }
.sg-scope figure .shield { bottom: auto; height: calc(100% - 2.2em); }   /* stop above the caption */

/* 8. Information ——————————————————————————————————————————————————————————— */
.info { padding: 24px var(--pad) 48px; }
.info-p { max-width: 60ch; font-size: var(--t); line-height: 1.4; }   /* the same size as the name in the header */
.info-p a { text-decoration: underline; text-underline-offset: 2px; }
.info-img { margin: 0 var(--pad) 72px; }
.info-img .m { width: 100%; height: auto; display: block; border-radius: var(--r); }
.words { padding: 0 var(--pad) 120px; }
.quotes { columns: 2; column-gap: calc(var(--gap) * 2); padding-top: 32px; }
blockquote { break-inside: avoid; margin-bottom: 48px; font-size: clamp(15px, 1.1vw, 19px); line-height: 1.45; }
cite { display: block; margin-top: 12px; font: normal var(--t)/1.35 var(--mono); color: var(--muted); }

/* 9. Footer ——————————————————————————————————————————————————————————————— */
.site-foot { padding: 0 var(--pad) 20px; font-size: var(--t); line-height: 1.5; }
.foot-grid { display: grid; grid-template-columns: var(--col) 1fr 1fr 1fr; gap: var(--gap); padding: 14px 0 64px; border-top: 1px solid var(--line); }
.foot-h { font-size: inherit; color: var(--muted); margin-bottom: 10px; font-weight: 400; }
.foot-links { display: flex; flex-direction: column; align-items: flex-start; }
.foot-links a:hover, .foot-base a:hover { background: var(--blue); color: #fff; }
.foot-base { display: flex; justify-content: space-between; padding-top: 10px; border-top: 1px dotted var(--line); font-family: var(--mono); color: var(--muted); }

/* 10. Motion & responsive ————————————————————————————————————————————————— */
@keyframes in { from { opacity: 0; transform: translateY(6px); } }
@view-transition { navigation: auto; }
.site-head { view-transition-name: site-head; }
::view-transition-group(site-head) { animation: none; }
::view-transition-old(root) { animation: none; }
::view-transition-new(root) { animation: vt-in .25s var(--ease) both; }
@keyframes vt-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .b-hero { clip-path: none; margin-inline: 0; }
  @view-transition { navigation: none; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

@media (max-width: 1000px) {
  .masonry.wide { columns: 3; }
  .foot-grid { grid-template-columns: 1fr 1fr 1fr; }
  .foot-grid > :first-child { grid-column: 1 / -1; }
}
@media (max-width: 700px) {
  :root { --pad: 16px; --col: 1fr; }
  /* phone rhythm: tighter section spacing so pages don't feel gappy on a small screen */
  .home-hero { margin-bottom: 20px; }
  .dir { padding-bottom: 56px; }
  .info { padding: 16px var(--pad) 32px; }
  .info-img { margin-bottom: 48px; }
  .words { padding-bottom: 72px; }
  .page-word .b-word { padding-top: 24px; }
  .site-head { grid-template-columns: 1fr auto auto; gap: 14px; }
  .hide-sm { display: none; }
  .nav { display: none; }

  .cards { grid-template-columns: 1fr; gap: 36px; }
  .card:first-child .card-m, .card:last-child:nth-child(even) .card-m { aspect-ratio: 4 / 3; }   /* one column: every card the same shape */
  .thead, .row, .info + .dir .row, .dir .row:has(.wide) { grid-template-columns: 34px 1fr auto 16px; }
  .row .hide-sm, .thead .hide-sm { display: none; }
  .row .c-k.wide { display: none; }
  .proj { padding-top: 0; }
  .d-row { grid-template-columns: 34px 1fr auto; }
  .d-row > span:last-child { display: none; }
  .proj-info { grid-template-columns: 1fr; row-gap: 12px; }
  .proj-info > .lbl:not(:first-child) { margin-top: 28px; }
  .proj-credits { grid-template-columns: 1fr; }
  .b-run:has(.b-row, .b-text) { padding: 32px 0; }
  .b-narrow { width: 100%; }
  .b-row { grid-template-columns: 1fr; gap: 32px; }
  .b-stage { aspect-ratio: 4 / 5; }
  .b-stage-in { height: 80%; }
  .masonry, .masonry.wide { columns: 2; column-gap: 12px; }
  .masonry figure { margin-bottom: 12px; }
  .quotes { columns: 1; }
  .foot-grid { grid-template-columns: 1fr 1fr; }
}

/* Phone menu (js/menu.js, after offmenu.design): a circle bottom right that springs open into a card */
.om { display: none; position: fixed; right: calc(var(--pad) - 8px); top: calc((var(--hh) - 36px) / 2); z-index: 60; transition: transform .45s var(--ease); }
.nav-hidden .om[data-state="rest"] { transform: translateY(calc(-100% - var(--hh))); }   /* rides away with the top bar */
.om-pill { position: relative; width: 36px; height: 36px; border-radius: 18px; background: transparent; color: var(--fg); overflow: hidden; transition: background-color .3s, color .3s; }
.om[data-state="open"] .om-pill { background: var(--fg); color: var(--bg); box-shadow: 0 0 0 1px color-mix(in srgb, var(--bg) 14%, transparent), 0 10px 30px rgba(0, 0, 0, .18); }
.om-btn { position: absolute; right: 0; top: 0; z-index: 2; width: 36px; height: 36px; padding: 0; border: 0; border-radius: 50%;
  background: transparent; color: inherit; cursor: pointer; display: grid; place-content: center; gap: 5px; -webkit-tap-highlight-color: transparent; }
.om-btn i { display: block; width: 18px; height: 1.5px; background: currentColor; transition: transform .35s cubic-bezier(.32, .72, 0, 1); }
.om[data-state="open"] .om-btn i:first-child { transform: translateY(3.25px) rotate(45deg); }
.om[data-state="open"] .om-btn i:last-child { transform: translateY(-3.25px) rotate(-45deg); }
.om-btn:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }
.om-card { position: absolute; right: 0; top: 0; width: var(--om-w, 340px); padding: 10px 22px 20px; display: flex; flex-direction: column;
  opacity: 0; pointer-events: none; transition: opacity .12s; }
.om[data-state="open"] .om-card { opacity: 1; pointer-events: auto; transition: opacity .25s .08s; }
.om-top { display: flex; justify-content: space-between; font: 11px var(--mono); text-transform: uppercase; opacity: .55; margin: 0 0 14px; }
.om-card ol { list-style: none; margin: 0; padding: 0; }
.om-card li { border-top: 1px solid color-mix(in srgb, var(--bg) 22%, transparent); }
.om-card li a { display: flex; align-items: baseline; gap: 10px; padding: 9px 0; font-size: 16px; line-height: 1.2; color: inherit; text-decoration: none; transition: padding .25s, color .2s; }
.om-card li a sup { font: 10px var(--mono); opacity: .5; letter-spacing: 0; }
.om-card li a[aria-current]::after { content: "●"; font-size: 7px; align-self: center; margin-left: auto; }
.om-card li a:active, .om-card li a:hover { color: var(--blue); padding-left: 6px; }
.om-home { margin-top: 14px; padding-top: 12px; border-top: 1px solid color-mix(in srgb, var(--bg) 22%, transparent); font: 12px var(--mono); color: inherit; text-decoration: none; text-transform: uppercase; }
@media print { .om { display: none; } }
@media (max-width: 700px) { .om { display: block; } .site-head { padding-right: calc(var(--pad) + 36px); } }

/* Pair: two images side by side on the line, the blocks' gap between them */
.b-pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--r); }
.b-pair > * { width: 100%; height: auto; display: block; border-radius: var(--r); }

.px-word [data-fit], .sg-word .b-word-t { will-change: transform; }   /* the big titles get their own layer, so they move without repainting */
@media (max-width: 700px) { .b-word { padding-top: 24px; padding-bottom: 14px; }   /* top and bottom only: the photo-grid titles keep their side margins */ .page-word .b-word { padding-top: 24px; } }   /* phone: even, tighter air around the big title (rule → title ≈ title → first image) */

/* Back office + owner button (ported from Stash) ———————————————————————————— */
.bo { padding: var(--hh) var(--pad) 80px; font-size: var(--t); min-height: 80vh; }
.bo.bo-loading { opacity: .4; pointer-events: none; transition: opacity .2s; }
.bo-top { position: sticky; top: var(--hh); z-index: 6; background: var(--bg); }
.bo-ctl { display: flex; align-items: center; gap: 14px; font-family: var(--mono); }
.bo-ctl button { font: inherit; background: none; border: 0; color: var(--muted); cursor: pointer; padding: 2px 4px; }
.bo-ctl button:hover { background: var(--blue); color: #fff; }
.bo-ctl button.on { color: var(--fg); text-decoration: underline; text-underline-offset: 4px; }
.bo-tabs { display: inline-flex; gap: 10px; margin-right: 18px; padding-right: 18px; border-right: 1px dotted var(--line); }
.bo-posts { display: flex; flex-direction: column; }
.bo-post { display: grid; grid-template-columns: minmax(180px, 260px) minmax(0, 1fr); gap: clamp(20px, 3vw, 48px); padding: 24px 0; border-bottom: 1px dotted var(--line); }
.bo-vid { width: 100%; aspect-ratio: 9 / 16; background: #000; display: block; border: 1px solid var(--fg); box-shadow: 4px 4px 0 var(--fg); }
.bo-post-txt { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.bo-post-meta { display: flex; flex-wrap: wrap; gap: 16px; font: calc(10 * var(--u)) var(--mono); text-transform: uppercase; color: var(--muted); }
.bo-status { color: var(--fg); }
.bo-status.is-posted { color: var(--blue); }
.bo-post h3 { font: 400 calc(18 * var(--u))/1.3 var(--mono); }
.bo-post h3 a:hover { background: var(--blue); color: #fff; }
.bo-post h3 i { font-style: normal; color: var(--muted); }
.bo-copy { display: flex; justify-content: space-between; align-items: baseline; border-bottom: 1px solid var(--line); padding-bottom: 4px; margin-top: 8px; }
.bo-copy button { font: calc(10 * var(--u)) var(--mono); text-transform: uppercase; background: none; border: 0; cursor: pointer; padding: 2px 0; }
.bo-copy button:hover { background: var(--blue); color: #fff; }
.bo-cap { white-space: pre-wrap; font: inherit; line-height: 1.55; max-width: 62ch; }
.bo-alt { color: var(--muted); max-width: 62ch; }
.bo-post-act { display: flex; gap: 12px; margin-top: 8px; }
@media (max-width: 700px) { .bo-post { grid-template-columns: 1fr; } .bo-vid { max-width: 260px; } .bo-tabs { margin-right: 6px; padding-right: 6px; } }
.bo-live { color: var(--fg); display: inline-flex; align-items: center; gap: 6px; }
.bo-live b { width: 6px; height: 6px; background: var(--blue); animation: blink 1s steps(1) infinite; }
.bo-kpis { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); border-bottom: 1px solid var(--line); }
.bo-kpis > div { padding: 18px 16px 16px 0; display: flex; flex-direction: column; gap: 8px; border-right: 1px dotted var(--line); }
.bo-kpis > div + div { padding-left: 16px; }
.bo-kpis > div:last-child { border-right: 0; }
.bo-kpis b { font: 400 clamp(28px, 3vw, 56px)/1 var(--mono); letter-spacing: -.04em; }
.bo-small { grid-template-columns: repeat(5, minmax(0, 1fr)); border-bottom: 0; }
.bo-small b { font-size: clamp(22px, 2vw, 36px); }
.bo-delta { font: calc(10 * var(--u)) var(--mono); color: var(--muted); }
.bo-delta.up { color: var(--blue); }
.bo-delta.down { color: var(--red); }
.bo-trend { display: flex; align-items: flex-end; gap: 2px; height: 90px; padding: 14px 0 0; border-bottom: 1px solid var(--line); }
.bo-trend span { flex: 1; height: var(--h); background: var(--fg); min-width: 2px; }
.bo-trend span:hover { background: var(--blue); }
.bo-trend span.is-pub { position: relative; }
.bo-trend span.is-pub::after, .bo-pubdot { content: ""; position: absolute; left: 50%; bottom: calc(100% + 4px); width: 5px; height: 5px; margin-left: -2.5px; background: var(--blue); }
.bo-pubdot { position: static; display: inline-block; margin: 0 6px 1px 0; vertical-align: middle; }
.bo-legend { margin-top: 8px; font-size: calc(11 * var(--u)); }
.bo-mins { height: 70px; }
.bo-visits { display: flex; flex-direction: column; }
.bo-visit { display: grid; grid-template-columns: minmax(180px, 260px) 1fr; gap: 24px; padding: 14px 0; border-bottom: 1px dotted var(--line); }
.bo-visit-meta { display: flex; flex-direction: column; gap: 4px; color: var(--muted); font: calc(11 * var(--u))/1.4 var(--mono); }
.bo-visit-meta b { color: var(--fg); font-weight: 400; font-size: var(--t); font-family: var(--sans); }
.bo-steps { list-style: none; display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 0; }
.bo-steps li + li::before { content: "→\FE0E"; color: var(--muted); margin: 0 10px; }
.bo-steps b { font-weight: 400; color: var(--blue); }
@media (max-width: 700px) { .bo-visit { grid-template-columns: 1fr; gap: 8px; } .bo-tabs { flex-wrap: wrap; } }
.bo-sec { margin-top: 56px; }
.bo-sec .sec-bar { position: static; }
.bo-note { color: var(--muted); }
.bo-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 0 48px; }
.bo-table { margin-top: 4px; }
.bo-row { display: grid; grid-template-columns: var(--cols); gap: 16px; align-items: center; padding: 8px 0 7px; border-bottom: 1px dotted var(--line); }
.bo-row > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bo-row > span:first-child { font-family: var(--mono); }
.bo-head { color: var(--muted); border-bottom: 1px solid var(--line); }
.bo-head > span:first-child { font-family: inherit; }
.bo-row a:hover { background: var(--blue); color: #fff; }
.bo-bar { display: block; height: 6px; width: var(--w); background: var(--blue); }
.bo-miss { font-weight: 400; color: var(--red); }
.bo-err { color: var(--red) !important; font-family: var(--mono); font-size: var(--t) !important; }
@media (max-width: 900px) {
  .bo-kpis { grid-template-columns: repeat(3, 1fr); }
  .bo-kpis > div:nth-child(3) { border-right: 0; }
  .bo-cols { grid-template-columns: 1fr; }
  .bo-ctl { gap: 8px; }
}

/* Consent bar (EU/UK) */
.consent { position: fixed; left: var(--pad); right: var(--pad); bottom: 14px; z-index: 30; display: flex; justify-content: space-between; align-items: center; gap: 20px;
  background: var(--bg); border: 1px solid var(--line); box-shadow: 4px 4px 0 var(--fg); padding: 12px 16px; font-size: var(--t); line-height: 1.45;
  animation: consent-in .5s var(--ease) both; }
@keyframes consent-in { from { transform: translateY(20px); opacity: 0; } }
.consent a { text-decoration: underline; text-underline-offset: 3px; }
.consent-btns { display: flex; gap: 16px; flex: 0 0 auto; }
.consent button { font: calc(11 * var(--u)) var(--mono); text-transform: uppercase; background: none; border: 0; color: var(--fg); cursor: pointer; padding: 3px 2px; }
@media (max-width: 600px) { .consent { flex-direction: column; align-items: flex-start; gap: 10px; } }

/* Card button: the consent-bar treatment (border + hard shadow) used for "Visit" on articles */
.btn-card { align-self: flex-start; display: inline-block; font: calc(11 * var(--u)) var(--mono); text-transform: uppercase; letter-spacing: .02em;
  background: var(--bg); color: var(--fg); border: 1px solid var(--line); box-shadow: 4px 4px 0 var(--fg); padding: 10px 14px 9px;
  transition: transform .15s var(--ease), box-shadow .15s var(--ease), background .15s, color .15s; }
.btn-card:hover, .mag-lead:hover .btn-card { background: var(--blue); color: #fff; border-color: var(--fg); }
.btn-card:active { transform: translate(4px, 4px); box-shadow: 0 0 0 var(--fg); }
.btn-card:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }
.art-rail .btn-card { margin: 4px 0 6px; }
.art-foot .btn-card { margin-bottom: 8px; }
@media (max-width: 900px) { .art-rail .btn-card { display: none; } }

/* Article headline typing (js/article.js). Hidden until the script takes over; the fallback
   animation shows it anyway if the script never runs. */
.js .art-head h1:not(.typed) { animation: h-show 0s 1.5s both; visibility: hidden; }
@keyframes h-show { to { visibility: visible; } }
.art-head h1.typed { position: relative; }
.h-ghost, .h-live { white-space: pre-line; }
.h-ghost { visibility: hidden; }
.h-live { position: absolute; inset: 0; white-space: pre; }   /* types into the final headline's measured lines */
.h-caret { width: .5em; height: .82em; margin-left: .08em; transform: translateY(.08em); }
.h-ghost .h-caret { margin-right: -.58em; }   /* on the finished headline it takes no room, so it can't push the last word over */

/* Owner button (js/owner.js): the Stash "s", bottom right, only for the signed-in owner.
   Rest: a circle. Open: a pill with Back office + Send a site. Add: the pill becomes a domain field. */
.own { position: fixed; right: 20px; bottom: 20px; z-index: 60; }
.own-pill { position: relative; width: 52px; height: 52px; border-radius: 26px; background: var(--fg); color: var(--bg); overflow: hidden;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .18), 0 2px 6px rgba(0, 0, 0, .12); }
.own-s { position: absolute; right: 0; bottom: 0; width: 52px; height: 52px; border: 0; border-radius: 50%; background: var(--fg); color: var(--bg); cursor: pointer; display: grid; place-items: center; padding: 0; }
.own-s svg { width: 15px; height: 23px; fill: currentColor; }
.own-acts, .own-form, .own-msg { position: absolute; left: 6px; bottom: 0; height: 52px; display: flex; align-items: center; gap: 4px; opacity: 0; pointer-events: none; transition: opacity .12s; }
.own[data-state="open"] .own-acts, .own[data-state="add"] .own-form, .own[data-state="done"] .own-msg { opacity: 1; pointer-events: auto; transition: opacity .25s .1s; }
.own-btn { width: 44px; height: 44px; border: 0; border-radius: 50%; background: transparent; color: inherit; display: grid; place-items: center; cursor: pointer; padding: 0; transition: background .2s; }
.own-btn:hover, .own-btn:focus-visible { background: var(--blue); color: #fff; outline: 0; }
.own-btn svg, .own-msg svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: square; }
.own-form { right: 52px; left: 14px; }
.own-form input { flex: 1; min-width: 0; height: 36px; border: 0; background: transparent; color: inherit; font: calc(13 * var(--u)) var(--mono); outline: 0; }
.own-form input::placeholder { color: color-mix(in srgb, var(--bg) 50%, transparent); }
.own-msg { left: 18px; gap: 8px; font: calc(12 * var(--u)) var(--mono); text-transform: uppercase; white-space: nowrap; }
.own.is-err .own-msg { color: var(--red); }
.own-s:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }
/* Live badge on the owner s: someone's on the site now. Yellow like the "new" dot; a small hop when it
   appears or the count goes up, then a quieter hop every few seconds while people are here. */
.own-live { position: absolute; right: -3px; top: -5px; z-index: 2; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: #ffff00; color: #000; font: 700 10px/18px var(--sans); text-align: center; box-shadow: 0 0 0 2px var(--bg);
  transform: scale(0); transition: transform .3s cubic-bezier(.3, 1.6, .5, 1); pointer-events: none; }
.own.is-live .own-live { transform: scale(1); animation: own-hop 4s 2s infinite; }
.own-live.is-bounce { animation: own-hop-big .7s, own-hop 4s 2.7s infinite !important; }
@keyframes own-hop { 0%, 88%, 100% { translate: 0 0; } 92% { translate: 0 -4px; } 96% { translate: 0 0; } 98% { translate: 0 -1.5px; } }
@keyframes own-hop-big { 0% { translate: 0 0; } 30% { translate: 0 -9px; } 55% { translate: 0 0; } 75% { translate: 0 -3px; } 100% { translate: 0 0; } }
/* The stats card (Analytics in the owner pill): the pill grows into a black card, always black whatever the
   theme, with a blue bar chart of the last 14 days. The s stays in its corner; the link sits beside it. */
.own[data-state="stats"] .own-pill, .own[data-state="stats"] .own-s { background: #0b0b0b; color: #f2f2f2; }
.own-pill, .own-s { transition: background-color .4s, color .4s, box-shadow .4s; }   /* the card's black eases in and out (dark mode's pill is white) */
.own[data-state="stats"] .own-live { display: none; }   /* the count shows inside the card */
.own[data-state="stats"] .own-pill { box-shadow: 0 0 0 1px #2a2a2a, 0 18px 50px rgba(0, 0, 0, .28); }
.own-stats { position: absolute; right: 0; bottom: 0; width: var(--ost-w, 336px); padding: 18px 26px 60px;   /* laid out at the card's final width, so its height is right before it opens */ display: flex; flex-direction: column; color: #f2f2f2;
  font: calc(11 * var(--u))/1.4 var(--mono); opacity: 0; pointer-events: none; transition: opacity .12s; }
.own[data-state="stats"] .own-stats { opacity: 1; pointer-events: auto; transition: opacity .3s .12s; }
.ost-top { display: flex; align-items: center; gap: 10px; min-height: 28px; }
.ost-lbl { text-transform: uppercase; letter-spacing: .06em; color: #8a8a8a; }
.ost-now { color: #8a8a8a; }
.ost-now:not(:empty)::before { content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: #ffff00; margin-right: 6px; transform: translateY(-1px); }
.ost-x { margin-left: auto; width: 28px; height: 28px; margin-right: -7px; }
.ost-x svg { width: 16px; height: 16px; }
.ost-big { display: flex; align-items: baseline; gap: 8px; margin-top: 10px; }
.ost-big b { font: 400 calc(52 * var(--u))/1 var(--mono); letter-spacing: -.04em; }
.ost-big span { color: #8a8a8a; }
.ost-chart { display: grid; grid-template-columns: repeat(14, 1fr); gap: 4px; align-items: end; height: 96px; margin-top: 18px; }
.ost-chart i { display: block; height: var(--h); min-height: 2px; background: #3333ff; transform-origin: 50% 100%; border-radius: 1px; }
.ost-chart i.is-today { background: #8080ff; }
.ost-chart i:hover { background: #6b6bff; }
.ost-axis { display: flex; justify-content: space-between; color: #8a8a8a; margin-top: 6px; border-top: 1px solid #2a2a2a; padding-top: 6px; }
.ost-top-pages { list-style: none; margin: 12px 0 0; padding: 0; }
.ost-top-pages li { display: flex; justify-content: space-between; gap: 12px; padding: 5px 0; border-bottom: 1px dotted #2a2a2a; }
.ost-top-pages span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ost-top-pages b { font-weight: 400; color: #8a8a8a; }
.ost-go { position: absolute; left: 14px; bottom: 6px; height: 40px; display: flex; align-items: center; padding: 0 12px; border-radius: 20px;
  text-transform: uppercase; letter-spacing: .04em; color: #f2f2f2; text-decoration: none; transition: background .2s; }
.ost-go:hover, .ost-go:focus-visible { background: #4d4dff; color: #fff; outline: 0; }
@media (prefers-reduced-motion: reduce) { .own.is-live .own-live, .own-live.is-bounce { animation: none !important; } }
@media print { .own { display: none; } }

/* Back office account button + menu */
.bo-acct { position: relative; margin-left: 6px; }
.bo-avatar { width: 26px; height: 26px; border-radius: 50%; border: 1px solid var(--line); padding: 0; overflow: hidden; background: var(--fg); color: var(--bg); cursor: pointer; display: grid; place-items: center; }
.bo-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.bo-avatar b { font: 400 12px var(--mono); }
.bo-avatar:hover { outline: 2px solid var(--blue); outline-offset: 2px; }
.bo-acct-menu { position: absolute; right: 0; top: calc(100% + 8px); min-width: 220px; background: var(--fg); color: var(--bg); padding: 12px 14px; display: none; flex-direction: column; gap: 10px; z-index: 20; }
.bo-acct.open .bo-acct-menu { display: flex; }
.bo-acct-menu span { display: flex; flex-direction: column; gap: 2px; font-family: var(--sans); }
.bo-acct-menu i { font-style: normal; color: color-mix(in srgb, var(--bg) 60%, transparent); font-size: .9em; }
.bo-acct-menu button { align-self: flex-start; font: inherit; font-family: var(--mono); background: none; border: 0; color: inherit; padding: 2px 0; cursor: pointer; }
.bo-acct-menu button:hover { background: var(--blue); color: #fff; }
.bo-reconnect { padding: 18vh 0 0; display: flex; flex-direction: column; align-items: flex-start; gap: 16px; }
.bo-reconnect p { color: var(--muted); }
.bo-q-new { color: var(--blue); }
.bo-row.is-done { color: var(--muted); }
.bo-q-act { display: flex; gap: 10px; }
.bo-q-act button { font: calc(10 * var(--u)) var(--mono); text-transform: uppercase; background: none; border: 0; color: inherit; cursor: pointer; padding: 2px 0; }
.bo-q-act button:hover { background: var(--blue); color: #fff; }

/* Back office on phones: crumbs + account on one row, tabs and controls on a swipeable row under it,
   KPIs in two columns, side-by-side sections stacked, wide tables scroll sideways */
@media (max-width: 760px) {
  .bo-top .d-path { position: relative; flex-wrap: wrap; row-gap: 10px; padding-bottom: 10px; }
  .bo-top .d-crumbs { flex: 1; min-width: 0; padding-right: 40px; }
  .bo-ctl { width: 100%; gap: 12px; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; padding-bottom: 2px; padding-right: 36px; }
  .bo-top .d-path::after { content: ""; position: absolute; right: 0; bottom: 10px; width: 44px; height: 30px; pointer-events: none;
    background: linear-gradient(90deg, transparent, var(--bg) 80%); }   /* fade hints there's more to swipe */
  .sb-canvas { --z: .72 !important; padding: 36px 24px 80px; gap: 28px; }
  .sb-canvas-wrap { height: 72vh; }
  .bo-ctl::-webkit-scrollbar { display: none; }
  .bo-ctl > * { flex: none; }
  .bo-tabs { flex-wrap: nowrap; gap: 14px; margin-right: 4px; padding-right: 12px; }
  .bo-acct { position: absolute; right: 0; top: 0; margin: 0; }
  .bo-kpis, .bo-small { grid-template-columns: 1fr 1fr; }
  .bo-kpis > div { padding: 14px 12px 12px 0; border-right: 0; border-bottom: 1px dotted var(--line); }
  .bo-kpis > div + div { padding-left: 0; }
  .bo-kpis > div:nth-child(odd) { border-right: 1px dotted var(--line); padding-right: 12px; }
  .bo-kpis > div:nth-child(even) { padding-left: 12px; }
  .bo-kpis b { font-size: 30px; }
  .bo-cols { grid-template-columns: 1fr; }
  .bo-sec { margin-top: 40px; }
  .bo-top + .bo-sec, .bo-top + * > .bo-sec:first-child { margin-top: 16px; }
  .bo-sec .sec-bar { flex-wrap: wrap; row-gap: 4px; }
  .bo-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .bo-table .bo-row { min-width: 520px; }
  .bo-reconnect { padding-top: 8vh; }
}

/* Back office sign-in: the round "s" pops up as a pill with Sign in with Google (no sign-in page) */
.own-gate { z-index: 70; }
.own-signin { position: absolute; left: 6px; top: 6px; height: 40px; display: flex; align-items: center; gap: 10px; padding: 0 16px 0 6px; border: 0; border-radius: 20px;
  background: transparent; color: var(--bg); font: calc(12 * var(--u)) var(--mono); text-transform: uppercase; letter-spacing: .02em; white-space: nowrap; cursor: pointer;
  opacity: 0; pointer-events: none; transition: opacity .2s .15s, background .2s; }
.own-signin svg { width: 28px; height: 28px; padding: 5px; background: #fff; border-radius: 50%; flex: none; }
.own-gate[data-state="open"] .own-signin { opacity: 1; pointer-events: auto; }
.own-signin:hover, .own-signin:focus-visible { background: var(--blue); color: #fff; outline: 0; }
.own-gate .own-msg { color: var(--red); white-space: nowrap; }

/* Directory record: over the screenshot, the cursor becomes an "Open" button that follows the mouse
   (js/index-list.js sets --x/--y). Touch screens show it fixed at the bottom instead. */
.d-shot { cursor: none; }
.d-body[data-resource="stash"] .d-shot { aspect-ratio: 24/13; }   /* Stash's own listing: the window matches its screen recording */
.d-open { position: absolute; left: var(--x, 50%); top: var(--y, 50%); transform: translate(-50%, -50%) scale(.6); opacity: 0; pointer-events: none;
  white-space: nowrap; background: var(--blue); color: #fff; transition: opacity .2s, transform .3s var(--ease); }
.d-shot:hover .d-open { opacity: 1; transform: translate(-50%, -50%) scale(1); }
@media (hover: none) { .d-shot { cursor: pointer; } .d-open { opacity: 1; left: 50%; top: auto; bottom: 16px; transform: translateX(-50%); } }
.d-head .c-dom { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }   /* keep the ↗ on the same line */
.d-body { padding-top: 6px; }                                                      /* record rows sit right under the header */

/* 404'd listings: the window crumbles into squares (js/grave.js). The canvas sits exactly over it. */
.grave-cv { position: fixed; left: 0; top: 0; z-index: 40; pointer-events: none; }
.d-win.is-gone { border: 1px dotted var(--muted); }   /* the empty frame left behind */
.d-win.is-crumbled { border-color: transparent; box-shadow: none; background: transparent; }
/* After a dead site's window falls away: a typed line under the notes, and no extra rule at the bottom */
.d-gone { font: var(--t)/1.5 var(--mono); margin-top: -8px; }
.d-gone .d-caret { margin-left: 3px; }
.d-gone-link { display: inline-block; margin-left: 14px; white-space: nowrap; color: var(--muted); text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 700px) { .d-gone-link { display: block; margin: 6px 0 0; width: fit-content; } }   /* own line on phones, no stray indent */

.sec-bar { position: sticky; top: var(--hh); z-index: 5; background: var(--bg); display: flex; justify-content: space-between; align-items: center; gap: 24px;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 10px 0 9px; font-size: var(--t); line-height: 1.35; }
.feat-h { font-weight: 400; font-size: inherit; }
.btn-card { align-self: flex-start; display: inline-block; font: calc(11 * var(--u)) var(--mono); text-transform: uppercase; letter-spacing: .02em;
  background: var(--bg); color: var(--fg); border: 1px solid var(--line); box-shadow: 4px 4px 0 var(--fg); padding: 10px 14px 9px;
  transition: transform .15s var(--ease), box-shadow .15s var(--ease), background .15s, color .15s; }
.btn-card:hover, .mag-lead:hover .btn-card { background: var(--blue); color: #fff; border-color: var(--fg); }
.btn-card:active { transform: translate(4px, 4px); box-shadow: 0 0 0 var(--fg); }
.btn-card:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }
.empty { padding: 40px 0; color: var(--muted); }
.empty a { text-decoration: underline; }
.d-lbl { display: block; font-size: calc(10 * var(--u)); text-transform: uppercase; color: var(--muted); margin-bottom: 6px; }
.own-mark { font: 500 21px/1 var(--sans); letter-spacing: -.02em; }   /* the "S" in the owner circle */
:root { --red: #e5484d; }

/* Phones: thumb-sized tap targets for the small text links (the arrows and the footer lists), without
   changing how they look: the padding is pulled back with negative margins */
@media (pointer: coarse), (max-width: 700px) {
  .d-step { gap: 8px; }
  .d-step a { display: inline-block; min-width: 28px; padding: 6px 8px; margin: -6px 0; text-align: center; }
  .foot-links a, .foot-base a { padding: 6px 0; }
}

/* Touch screens (iOS Safari): a title moved by script or a scroll timeline lands a frame behind Safari's own
   scrolling, so it shakes. There the title is pinned instead (sticky, at the spot it starts in: --pin, set by
   js/hero.js and js/photo.js) and the hero still rides up over it, with nothing animating per frame. The pin
   ends with the hero, because both sit in one wrapper (.b-lead / .sg-lead). */
.b-lead { display: grid; gap: var(--r); }
@media (hover: none) and (pointer: coarse) {
  .b-lead > .b-word, .sg-lead > .sg-word { position: sticky; top: var(--pin, 0px); }
  .sg-word .b-word-t { animation: none !important; }
}

/* Touch screens: the stack isn't pinned (js/fx.js), so it's a normal panel, prints sized to fit inside it */
.b-stack.is-touch { height: auto; aspect-ratio: 4 / 5; }
.b-stack.is-touch .print .m { max-width: 66vw; max-height: 92vw; }

/* Arrows (scripts/build.mjs turns ← → ↑ ↗ into these): a hairline stroke in the text colour, sized to the text */
.ar { display: inline-block; width: .78em; height: .78em; vertical-align: -.04em; fill: none; stroke: currentColor;
  stroke-width: 1.15px; vector-effect: non-scaling-stroke; stroke-linecap: square; overflow: visible; }

/* Photo-grid columns start where the build decided (scripts/build.mjs, balance()), so they end evenly */
/* Photo grids: 3 columns from 1450px, 2 below that, 1 on phones */
.sg-mason { columns: 2; }
@media (min-width: 1450px) { .sg-mason { columns: 3; } .sg-mason > .cb3 { break-before: column; -webkit-column-break-before: always; } }
@media (min-width: 701px) and (max-width: 1449px) { .sg-mason > .cb2 { break-before: column; -webkit-column-break-before: always; } }
@media (max-width: 700px) { .sg-mason { columns: 1; } }

/* A tall photo used as a grid feature: half the line (60% on phones), uncropped, on its side like the others */
.sg-big.is-tall figure { max-width: 50%; }
.sg-big.is-tall .m { max-height: none; }
@media (max-width: 700px) { .sg-big.is-tall figure { max-width: 64%; } }

/* Count block (TruAge): a black square with a number that rolls up, beside a square image */
.b-count > * { aspect-ratio: 1; object-fit: cover; }
.ct { background: #000; border-radius: var(--r); display: grid; place-items: center; overflow: hidden; }
.ct-n { width: 72%; height: auto; overflow: visible; fill: #fff; }   /* the 8 and 2 travel past the numerals' box; the square clips them */

/* Count's photo: the next photo wipes in from the left with the numerals' move (js/fx.js); without JS it shows */
.ct-pic { position: relative; overflow: hidden; border-radius: var(--r); }
.ct-pic .m { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 0; aspect-ratio: auto !important; }

/* Embedded site (js/fx.js sizes it): a desktop-width page scaled to the column, full length, on the grey mat */
.site-embed { position: relative; overflow: hidden; border-radius: 4px; background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.06), 0 12px 32px -18px rgba(0,0,0,.18); min-height: 200px; }
.site-embed iframe { position: absolute; top: 0; left: 0; border: 0; transform-origin: 0 0; display: block; }

/* Date → logo (TruAge): a white panel like the video it replaces, the lettering black */
.dl { background: #ECEBE8;   /* off-white panel, so the lettering sits on something */ border-radius: var(--r); aspect-ratio: 1920 / 1088; display: grid; place-items: center; overflow: hidden; }
.dl svg { width: 62%; height: auto; fill: #000; }

/* A self-running embedded piece in a fixed-shape window (TruAge app motion) */
.frame-embed { position: relative; border-radius: var(--r); overflow: hidden; background: #000; }
.frame-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }

/* Phones: palettes ignore their desktop weights (TruAge's black is 3.7× its neighbour), so every colour gets a
   readable share: two across, a stacked column counting as one */
@media (max-width: 700px) { .b-palette.has-rows .pal-row > * { flex: 1 1 50% !important; } }
