/* ============ Tokens — from design.md §3–§5 ============ */
:root {
  --bg: oklch(0.18 0.02 65);
  --surface: oklch(0.24 0.025 60);
  --surface-2: oklch(0.30 0.03 62);
  --ink: oklch(0.94 0.02 85);
  --ink-muted: oklch(0.66 0.03 70);
  --accent: oklch(0.70 0.115 75);
  --accent-deep: oklch(0.53 0.10 70);   /* 4.59:1 on --wall, 4.87:1 on --wall-card (WCAG AA text) */
  /* Focus rings need 3:1 against their own background (WCAG 2.4.11 / 1.4.11).
     --accent is 6.94:1 on the dark shell but only 2.31:1 on the light wall, so
     the ring is picked per context rather than hard-coded. */
  --focus: var(--accent);
  --support: oklch(0.38 0.09 30);
  --wall: oklch(0.945 0.012 80);
  --wall-card: oklch(0.965 0.01 82);
  --wall-line: oklch(0.86 0.015 78);
  --ink-on-wall: oklch(0.25 0.025 60);
  --ink-on-wall-muted: oklch(0.47 0.03 65);
  --shadow: oklch(0.12 0.015 65 / 0.45);

  --t-hero: clamp(2.6rem, 5.4vw, 5.4rem);
  --t-h2: clamp(1.9rem, 3.5vw, 2.6rem);
  --t-h3: clamp(1.3rem, 2.2vw, 1.6rem);

  --container: 1440px;
  --pad-x: clamp(1.25rem, 4vw, 3rem);
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scrollbar-color: var(--surface-2) var(--bg); }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: "Source Serif 4", serif;
  font-size: 1.0625rem;
  line-height: 1.65;
  overflow-x: clip;
}
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; border-radius: 2px; }
.container { width: 90%; max-width: var(--container); margin-inline: auto; padding-inline: 0; }
h1, h2, h3 { font-family: "Marcellus", serif; font-weight: 400; }
.kicker {
  font-family: "Archivo", sans-serif; font-weight: 600;
  font-size: 0.75rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent);
}
.utility { font-family: "Archivo", sans-serif; }
.ph-copy { color: var(--ink-muted); }
.on-wall .ph-copy { color: var(--ink-on-wall-muted); }
/* ============ Media slots (real assets, wired in Step 4) ============ */
.ph {
  display: block; width: 100%;
  /* height:auto is load-bearing. These images carry width/height attributes for
     CLS, and without it the height attribute is used literally -- the declared
     aspect-ratio loses, and a 1122x1402 hero renders 1402px tall once the grid
     stacks and the desktop height:100% rule drops out. */
  height: auto;
  object-fit: cover;
  background: var(--surface);
  border: 0;
}
.on-wall .ph { background: oklch(0.90 0.015 80); }
/* ============ Buttons — design.md §8 ============ */
.btn {
  display: inline-block;
  border: 0; cursor: pointer; background: none;
  font-family: "Archivo", sans-serif; font-weight: 600;
  font-size: 0.8125rem; letter-spacing: 0.1em; text-transform: uppercase;
  padding: 0.9rem 1.6rem; border-radius: 4px;
  transition: background-color 200ms var(--ease), color 200ms var(--ease), border-color 200ms var(--ease);
}
.btn-primary { background: var(--accent); color: var(--bg); }
.btn-primary:hover { background: var(--accent-deep); color: var(--ink); }
.btn-ghost { border: 1px solid var(--accent); color: var(--accent); }
.btn-ghost:hover { border-color: var(--ink); color: var(--ink); }
.on-wall .btn-ghost { border-color: var(--accent-deep); color: var(--accent-deep); }
.on-wall .btn-ghost:hover { border-color: var(--ink-on-wall); color: var(--ink-on-wall); }
/* Text links draw their underline — design.md §7 */
.arrow-link {
  font-family: "Archivo", sans-serif; font-weight: 600;
  font-size: 0.78rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--accent); position: relative;
  /* WCAG 2.2 AA 2.5.8: pointer target at least 24x24 CSS px */
  display: inline-flex; align-items: center; min-height: 24px; padding-bottom: 3px;
}
.on-wall .arrow-link { color: var(--accent-deep); }
.arrow-link::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 1px; width: 100%;
  background: currentColor; transform: scaleX(0); transform-origin: left;
  transition: transform 200ms var(--ease);
}
.arrow-link:hover::after { transform: scaleX(1); }
/* ============ Header ============ */
/* The bar is SOLID at every scroll position -- never transparent, never a
   scrim, never translucent. It previously started transparent over the hero
   and settled to 85% with a backdrop blur, so the nav read differently
   depending on what happened to be behind it. One opaque ground, always.
   No backdrop-filter: nothing shows through an opaque bar, so the blur was
   only costing a compositing layer. */
.site-head {
  position: fixed; inset: var(--announce-h, 0px) 0 auto 0; z-index: 60;
  background: oklch(0.18 0.02 65);
  border-bottom: 1px solid oklch(0.30 0.03 62 / 0.6);
  transition: box-shadow 300ms var(--ease);
}
/* .scrolled no longer changes the ground -- it only lifts the bar off the
   content it now covers. */
.site-head.scrolled {
  box-shadow: 0 10px 30px oklch(0.12 0.015 65 / 0.35);
}

.site-head .bar {
  display: flex; align-items: center; gap: 1.25rem;
  min-height: 4.25rem;
  padding-block: 1.75rem;
}
.brand-lockup { display: flex; align-items: center; gap: 0.8rem; margin-right: auto; }
.brand-lockup > span:last-child { display: flex; flex-direction: column; }
/* The mark: black line art on white. On the dark shell we invert it and screen
   out the white ground, so the linework reads as Candlelight with no halo and
   no second asset to keep in sync. */
.logo-ph {
  width: 3.4rem; height: 3.4rem; border-radius: 50%;
  display: block; flex: none; overflow: hidden;
  background: none; outline: 0;
}
.logo-ph img {
  width: 100%; height: 100%; display: block; object-fit: contain;
  filter: invert(1) contrast(1.15);
  mix-blend-mode: screen;
}
/* on a lit wall the mark is used as drawn */
.on-wall .logo-ph img, .light .logo-ph img {
  filter: none; mix-blend-mode: normal;
}
.foot-brand .logo-mark {
  width: 3.4rem; height: 3.4rem; display: block; margin-bottom: 0.9rem;
  filter: invert(1); mix-blend-mode: screen;
}
.brand-name { font-family: "Marcellus", serif; font-size: 1.2rem; line-height: 1.1; }
.brand-tag { font-family: "Archivo", sans-serif; font-size: 0.62rem; font-weight: 500; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); margin-top: 2px; }
.site-nav { display: flex; gap: 1.6rem; }
.site-nav a {
  font-family: "Archivo", sans-serif; font-weight: 600;
  font-size: 0.75rem; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--ink); padding: 0.4rem 0; position: relative;
}
.site-nav a[aria-current="page"] { color: var(--accent); }
.site-nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 2px; background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  transition: transform 200ms var(--ease);
}
.site-nav a:hover::after, .site-nav a[aria-current="page"]::after { transform: scaleX(1); }
.site-nav a:hover { color: var(--accent); }
.menu-btn {
  display: none; background: none; border: 1px solid var(--surface-2); border-radius: 4px;
  color: var(--ink); font-family: "Archivo", sans-serif; font-weight: 600; font-size: 0.7rem;
  letter-spacing: 0.12em; text-transform: uppercase; padding: 0.55rem 0.9rem; cursor: pointer;
}
@media (max-width: 900px) {
  .logo-ph { width: 3rem; height: 3rem; }
  .site-nav { display: none; }
  .menu-btn { display: block; }
}
/* Mobile overlay menu */
.mobile-menu {
  position: fixed; inset: 0; z-index: 70; background: var(--bg);
  display: none; flex-direction: column; padding: 1.5rem var(--pad-x);
}
.mobile-menu.open { display: flex; }
.mobile-menu .close-row { display: flex; justify-content: flex-end; }
.mobile-menu nav { display: grid; gap: 0.5rem; margin-block: auto; }
.mobile-menu nav a {
  font-family: "Marcellus", serif; font-size: 2rem; padding: 0.4rem 0;
  border-bottom: 1px solid oklch(0.30 0.03 62 / 0.5);
}
.mobile-menu nav a:hover { color: var(--accent); }
/* ============ Hero ============ */
.hero {
  position: relative; min-height: 100svh;
  display: grid; align-items: center;
  padding-top: 9.5rem; padding-bottom: 4rem;
  overflow: clip;
}
.hero-grid {
  display: grid; grid-template-columns: minmax(0, 50fr) minmax(0, 50fr);
  gap: clamp(2rem, 4vw, 3.5rem); align-items: center;
}
.hero h1 {
  font-size: var(--t-hero); line-height: 1.08;
  text-wrap: pretty;                /* fill the column; balance made lines short */
  margin-block: 1.1rem 1.4rem;
}
.hero .lede { max-width: none; margin-bottom: 2rem; font-size: clamp(1.0625rem, 1.25vw, 1.2rem); }
.hero-actions { display: flex; gap: 1rem; flex-wrap: wrap; }
.hero-art { position: relative; }
@media (max-width: 899px) {
  .hero { padding-top: 10rem; min-height: 0; }
  .hero-grid { grid-template-columns: 1fr; }
  .hero-actions .btn { flex: 0 1 auto; }
}
.hero-art .ph { aspect-ratio: 4 / 3.3; border-radius: 6px; box-shadow: 0 30px 80px var(--shadow); }
/* the lamp: one warm pool of light behind the sculpture — the "lit subject" of design.md §6 */
.hero-art::before {
  content: ""; position: absolute; inset: -12% -18%;
  background: radial-gradient(closest-side at 55% 38%, oklch(0.34 0.055 70 / 0.55), transparent 70%);
  pointer-events: none;
}
.plaque {
  margin-top: 0.9rem; padding-top: 0.55rem;
  border-top: 2px solid var(--accent);
  font-family: "Archivo", sans-serif; font-weight: 600;
  font-size: 0.7rem; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--ink-muted);
  display: inline-block;
}
.on-wall .plaque { color: var(--ink-on-wall-muted); }
/* Anvil divider — signature, design.md §6 */
.flame-divider {
  display: flex; align-items: center; justify-content: center; gap: 1rem;
  color: var(--accent); padding-block: 0.5rem;
}
.flame-divider::before, .flame-divider::after {
  content: ""; height: 1px; width: 3.5rem; background: var(--accent); opacity: 0.7;
}
/* The flame replaced an inline SVG that inherited currentColor. This one is a
   full-colour raster, so it cannot: it sits at its own colour on every ground.
   Sized by height, since the graphic is 3.09:1 and the mark it replaced was
   1.44:1 -- matching height keeps the optical weight between the two rules. */
.flame-divider img { height: 1.75rem; width: auto; display: block; }

/* ---- Announcement bar ----------------------------------------------------
   For upcoming shows. Lives ABOVE the fixed header and pushes it down by its
   own height through --announce-h, which site.js measures and sets; heroes
   add the same variable to their top padding so nothing is covered. Dismissal
   is remembered per data-announce-id, so a NEW show reappears on its own. */
.announce {
  position: fixed; top: 0; left: 0; right: 0; z-index: 61;
  display: flex; align-items: center; justify-content: center; gap: 1rem;
  padding: 0.55rem clamp(1rem, 4vw, 2rem);
  background: var(--accent); color: var(--ground, #15100e);
  font-family: "Archivo", sans-serif; font-size: 0.78rem; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
}
.announce a { color: inherit; text-decoration: underline; text-underline-offset: 0.2em; }
.announce a:hover { text-decoration-thickness: 2px; }
.announce .announce-close {
  margin-left: auto; background: none; border: 0; color: inherit; cursor: pointer;
  font: inherit; font-size: 1.1rem; line-height: 1; padding: 0.2rem 0.4rem;
}
.announce .announce-close:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.hero, .page-hero { padding-top: calc(var(--hero-pt, 9.5rem) + var(--announce-h, 0px)); }
.page-hero { --hero-pt: 12.5rem; }
@media (max-width: 899px) { .hero, .page-hero { --hero-pt: 10rem; } }
/* ============ Sections ============ */
section { padding-block: clamp(4rem, 9vw, 6rem); }
.section-head { max-width: 44rem; margin-bottom: clamp(2rem, 5vw, 3.5rem); }
.section-head h2 { font-size: var(--t-h2); line-height: 1.15; margin-top: 0.6rem; text-wrap: balance; }
.section-head h2 + p { margin-top: 0.9rem; }
.on-wall, .light, .page-hero.light { --focus: var(--accent-deep); }
.on-wall { background: var(--wall); color: var(--ink-on-wall); }
/* Thesis moment */
.thesis { text-align: center; }
.thesis .flame-divider { margin-bottom: 1.6rem; }
.thesis blockquote {
  font-family: "Marcellus", serif; font-size: clamp(1.5rem, 3vw, 2.2rem);
  line-height: 1.3; max-width: 34ch; margin-inline: auto; text-wrap: balance;
}
/* Category mosaic — varied, not an identical grid */
.cat-mosaic {
  display: grid; gap: 1rem;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 11rem;
}
@media (max-width: 900px) {
  .cat-mosaic { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 9.5rem; }
}
/* Featured works — asymmetric editorial pair rows */
.works-flow { display: grid; gap: clamp(2.5rem, 6vw, 4rem); }
.work-row { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: clamp(1.5rem, 4vw, 3rem); align-items: end; }
.work-row:nth-child(even) { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
.work-row:nth-child(even) .work-media { order: 2; }
.work-media .ph { border-radius: 6px; }
.work-row:nth-child(odd) .work-media .ph { aspect-ratio: 16 / 10; }
.work-row:nth-child(even) .work-media .ph { aspect-ratio: 4 / 3; }
.work-text h3 { font-size: var(--t-h3); margin-bottom: 0.6rem; }
.work-text p { margin-bottom: 1.1rem; }
@media (max-width: 800px) {
  .work-row, .work-row:nth-child(even) { grid-template-columns: 1fr; }
  .work-row:nth-child(even) .work-media { order: 0; }
}
/* Public art band — one lit subject on Nocturne */
.public-art { position: relative; }
.pa-grid { display: grid; grid-template-columns: minmax(0, 55fr) minmax(0, 45fr); gap: clamp(2rem, 5vw, 4rem); align-items: center; }
.pa-media .ph { aspect-ratio: 16 / 11; border-radius: 6px; box-shadow: 0 30px 80px var(--shadow); }
.pa-stats { display: flex; gap: 2.5rem; margin-top: 1.8rem; flex-wrap: wrap; }
.pa-stat .num { font-family: "Marcellus", serif; font-size: 2rem; color: var(--accent); line-height: 1; }
.pa-stat .cap { font-family: "Archivo", sans-serif; font-size: 0.7rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-muted); margin-top: 0.35rem; }
@media (max-width: 899px) { .pa-grid { grid-template-columns: 1fr; } }
/* About John */
.about-grid { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 7fr); gap: clamp(2rem, 5vw, 4rem); align-items: center; }
.about-media .ph { aspect-ratio: 3.4 / 4; border-radius: 6px; }
.about-sig { font-family: "Marcellus", serif; font-size: 1.3rem; margin-top: 1.4rem; color: var(--ink-on-wall); }
@media (max-width: 899px) { .about-grid { grid-template-columns: 1fr; } }
/* News — numbered rows, mockup pattern */
.news-list { display: grid; }
.news-row {
  display: grid; grid-template-columns: 3.5rem minmax(0, 14rem) 1fr auto;
  gap: 1.5rem; align-items: center;
  padding-block: 1.6rem;
  border-top: 1px solid var(--wall-line);
}
.news-row:last-child { border-bottom: 1px solid var(--wall-line); }
.news-row .idx { font-family: "Marcellus", serif; font-size: 1.6rem; color: var(--accent-deep); }
.news-row .ph { aspect-ratio: 16 / 10; border-radius: 4px; }
.news-row h3 { font-size: 1.25rem; margin-bottom: 0.3rem; }
@media (max-width: 800px) {
  .news-row { grid-template-columns: 2.5rem 1fr; }
  .news-row .ph { display: none; }
  .news-row .arrow-link { grid-column: 2; justify-self: start; }
}
/* ============ Contact band + essentials ============ */
.cta-band { position: relative; overflow: clip; }
.cta-band .container { position: relative; }
.cta-bg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0.15; pointer-events: none;
}
.cta-inner {
  display: flex; align-items: center; gap: 2rem; flex-wrap: wrap;
  border-block: 1px solid oklch(0.30 0.03 62 / 0.7);
  padding-block: clamp(2.5rem, 6vw, 3.75rem);
}
.cta-icon {
  flex: none; width: 4rem; height: 4rem; border-radius: 50%;
  border: 1.5px solid var(--accent); display: grid; place-items: center; color: var(--accent);
}
.cta-copy { margin-right: auto; }
.cta-copy h2 { font-size: clamp(1.5rem, 3vw, 2.1rem); line-height: 1.2; }
.cta-copy p { color: var(--ink-muted); margin-top: 0.35rem; }
.essentials { padding-top: 0; }
.ess-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
.ess-card { background: var(--surface); border-radius: 6px; padding: 1.6rem; }
.ess-card h3 { font-size: 1.1rem; margin-bottom: 0.8rem; }
.ess-card .kicker { display: block; margin-bottom: 0.4rem; }
.ess-card p, .ess-card a.plain { color: var(--ink-muted); }
.ess-card a.plain:hover { color: var(--accent); }
.ess-card .ph { aspect-ratio: 16 / 8; border-radius: 4px; margin-top: 0.4rem; }
.ess-rows { display: grid; gap: 0.4rem; }
@media (max-width: 800px) { .ess-grid { grid-template-columns: 1fr; } }
/* ============ Footer ============ */
footer { border-top: 1px solid oklch(0.30 0.03 62 / 0.7); padding-block: 3.5rem 2.5rem; }
.foot-grid { display: grid; grid-template-columns: minmax(0, 2fr) 1fr 1fr 1fr; gap: 2.5rem; }
.foot-col h4 { font-family: "Archivo", sans-serif; font-weight: 600; font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); margin-bottom: 0.9rem; }
.foot-col nav { display: grid; gap: 0.45rem; }
.foot-col nav a { color: var(--ink-muted); font-size: 0.95rem; }
.foot-col nav a:hover { color: var(--ink); }
.foot-brand .brand-name { font-size: 1.35rem; }
.foot-brand p { color: var(--ink-muted); font-size: 0.95rem; margin-top: 1rem; max-width: 26ch; }
.foot-legal { margin-top: 2.5rem; padding-top: 1.25rem; border-top: 1px solid oklch(0.30 0.03 62 / 0.5); color: var(--ink-muted); font-size: 0.85rem; font-family: "Archivo", sans-serif; }
@media (max-width: 800px) { .foot-grid { grid-template-columns: 1fr 1fr; } }
/* ============ Motion — Smooth & premium (design.md §7) ============ */
/* Reveals: rise 12px + fade, 450ms, staggered, once */
/* Progressive enhancement: content is visible by default. It is only hidden for
   the reveal animation once JS has proven it is running (html.js), so a failed or
   blocked script can never leave the site blank. */
.rv { opacity: 1; transform: none; }
html.js .rv { opacity: 0; transform: translateY(12px); transition: opacity 450ms var(--ease), transform 450ms var(--ease); transition-delay: var(--d, 0ms); }
html.js .rv.in { opacity: 1; transform: none; }
/* Hero load-in (alive before first scroll) */
@keyframes rise-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.hero .load { opacity: 1; }
html.js .hero .load { opacity: 0; animation: rise-in 450ms var(--ease) forwards; animation-delay: var(--d, 0ms); }
/* Film grain: faint static texture over the whole page (kept still on purpose,
   design.md motion rule: nothing loops) */
.grain {
  position: fixed; inset: 0; z-index: 90; pointer-events: none;
  opacity: 0.05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 220px 220px;
}
/* Custom cursor: accent dot with a trailing ring (desktop fine pointers only) */
.cursor-dot, .cursor-ring {
  position: fixed; top: 0; left: 0; z-index: 95; pointer-events: none;
  border-radius: 50%; transform: translate(-50%, -50%);
  display: none;
}
.cursor-dot { width: 6px; height: 6px; background: var(--accent); }
.cursor-ring {
  width: 30px; height: 30px;
  border: 1px solid oklch(0.70 0.115 75 / 0.55);
  transition: width 220ms var(--ease), height 220ms var(--ease), border-color 220ms var(--ease);
}
.cursor-ring.grow { width: 48px; height: 48px; border-color: oklch(0.70 0.115 75 / 0.95); }
html.cursor-on .cursor-dot, html.cursor-on .cursor-ring { display: block; }
html.cursor-on body, html.cursor-on a, html.cursor-on button, html.cursor-on iframe { cursor: none; }
/* Micro-interactions */
.news-row { transition: background-color 200ms var(--ease); }
.news-row:hover { background: var(--wall-card); }
/* Whole news card is the click target ------------------------------------
   The row already had a hover state on the whole card, so it read as
   clickable while only the "Read Article" link actually was. Rather than
   wrap the card in a second <a> (which would nest links and make screen
   readers announce the headline, image and body copy as one long link),
   the existing anchor is stretched over the card with a pseudo-element.
   One link, one accessible name, whole-card hit area, no JS.
   Anything interactive added inside a card later must be given
   position:relative and z-index:2 to sit above this overlay. */
.news-row { position: relative; }
/* .arrow-link is position:relative and already spends its ::after on the
   animated underline, so the overlay cannot simply reuse it: it would be
   contained by the button instead of the card, and would erase the underline.
   Inside a news row the link goes position:static (so the overlay resolves
   against the card) and the underline is re-done with a background-size
   animation, which needs no positioning at all. */
.news-row .arrow-link {
  position: static;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px;
  transition: background-size 200ms var(--ease);
  padding-bottom: 3px;
}
.news-row:hover .arrow-link,
.news-row .arrow-link:hover { background-size: 100% 1px; }
/* The base .arrow-link::after sets width/height/background/transform for the
   underline; every one of them has to be unset or the overlay collapses to a
   1px strip (height:1px wins over inset's top/bottom). */
.news-row .arrow-link::after {
  content: "";
  position: absolute;
  inset: 0;
  width: auto;
  height: auto;
  background: none;
  transform: none;
  transition: none;
  z-index: 1;
}
/* The real focus ring lands on the small link; lift it to the whole card so
   keyboard users see the same target the mouse gets. */
.news-row:has(.arrow-link:focus-visible) {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 4px;
}
.news-row:has(.arrow-link:focus-visible) .arrow-link { outline: none; }

.news-row:hover h3 { color: var(--accent-deep); }
.news-row h3 { transition: color 200ms var(--ease); }
.ess-card { transition: transform 300ms var(--ease), box-shadow 300ms var(--ease); }
.ess-card:hover { transform: translateY(-2px); box-shadow: 0 14px 34px var(--shadow); }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .rv, .hero .load { opacity: 1 !important; transform: none !important; }
  .grain { display: none; }
}
/* ============ Inner pages (Step 6: full site) ============ */
/* Page hero: dark by default, .light for gallery-wall heroes */
.page-hero { position: relative; padding-top: 12.5rem; padding-bottom: clamp(2.5rem, 6vw, 4rem); overflow: clip; }
.page-hero .grid2 { display: grid; grid-template-columns: minmax(0, 48fr) minmax(0, 52fr); gap: clamp(2rem, 5vw, 4rem); align-items: center; }
.page-hero h1 { font-size: clamp(2.4rem, 4.6vw, 4.4rem); line-height: 1.1; margin-bottom: 1rem; text-wrap: balance; }
.page-hero .lede { max-width: 62ch; font-size: clamp(1.0625rem, 1.2vw, 1.15rem); }
.page-hero .hero-media { border-radius: 6px; }
.page-hero .hero-media img { border-radius: 6px; box-shadow: 0 30px 80px var(--shadow); }
.page-hero .hero-media > a { display: block; border-radius: 6px; }
.page-hero .hero-media > a:focus-visible { outline: 2px solid var(--focus); outline-offset: 4px; }
.page-hero .hero-media .plaque { margin-top: 0.9rem; }
.page-hero .hero-media img { display: block; width: 100%; height: 100%; object-fit: cover; aspect-ratio: 16 / 9.5; }

/* Top-anchored hero crop. The 16/9.5 band takes 25.8% of a 1.25 photo's
   height, and object-position's default (centre) splits that evenly — which
   on Dude Rancher clipped the rider's hat. Anchoring to the top keeps the
   figure whole and takes the whole loss off the bottom of the frame. */
.page-hero .hero-media--top img { object-position: top; }
/* Page heroes: a true 16 / 9 box. John supplies the About, News and Contact
   photographs already framed 16:9, so the box matches the source rather than
   the source being cropped to fit an arbitrary band (the default is 16 / 9.5). */
.page-hero .hero-media--wide img { aspect-ratio: 16 / 9; }

/* ---- Merged Trees page: three groupings on one page ---------------------
   The trees split three ways -- an ongoing sculpture series, the MCAD thesis
   exhibition, and the Lapham Peak park installation. They used to be three
   pages, which buried the relationship between them. One page, three labelled
   groups, with a jump nav so the distinction is legible before you scroll. */
.tree-jump { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }
.tree-jump a {
  display: inline-flex; align-items: baseline; gap: 0.45rem;
  padding: 0.42rem 0.85rem; border: 1px solid var(--rule-on-wall, rgba(0,0,0,0.18));
  border-radius: 999px; text-decoration: none;
  font-family: "Archivo", sans-serif; font-size: 0.74rem;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-on-wall); background: var(--wall-card);
  transition: border-color 160ms var(--ease), color 160ms var(--ease);
}
.tree-jump a:hover { border-color: var(--accent); color: var(--accent-deep); }
.tree-jump a span { font-variant-numeric: tabular-nums; opacity: 0.6; font-size: 0.68rem; }
.tree-group { scroll-margin-top: 6rem; }
.tree-group + .tree-group { padding-top: 0; }
.group-note {
  font-size: 0.92rem; color: var(--ink-on-wall-muted);
  margin: 0.35rem 0 1rem; max-width: 46ch;
}
.search-empty { margin-top: 1.2rem; color: var(--ink-on-wall-muted); }
.page-hero.light { background: var(--wall); color: var(--ink-on-wall); }
.page-hero .flame-divider { justify-content: flex-start; padding-block: 0.9rem; }
.page-hero .flame-divider::after { display: none; }
.page-hero .sig { font-family: "Marcellus", serif; font-size: 1.25rem; margin-top: 1.2rem; }
@media (max-width: 899px) { .page-hero { padding-top: 10rem; } .page-hero .grid2 { grid-template-columns: 1fr; } }
/* Search row */
.search-row { display: flex; justify-content: flex-end; margin-bottom: 2rem; }
.search-row input {
  width: min(22rem, 100%); padding: 0.7rem 1rem;
  font-family: "Archivo", sans-serif; font-size: 0.85rem;
  background: var(--wall-card); color: var(--ink-on-wall);
  border: 1px solid var(--wall-line); border-radius: 4px;
}
.search-row input::placeholder { color: var(--ink-on-wall-muted); }
.search-row input:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.dark-section .search-row input { background: var(--surface); color: var(--ink); border-color: var(--surface-2); }
.dark-section .search-row input::placeholder { color: var(--ink-muted); }
/* Work cards (category grids) */
.works-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
@media (max-width: 1000px) { .works-grid, .works-grid.cols3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .works-grid, .works-grid.cols3 { grid-template-columns: 1fr; } }
/* Photograph-pending frame: mat board, plaque data carries the card */
.photo-pending {
  width: 100%; aspect-ratio: 4 / 3.2;
  background: oklch(0.90 0.015 80);
  display: grid; place-items: center; color: oklch(0.7 0.025 75);
}
/* Installation / project cards */
.install-card { text-align: left; }
/* Resume highlights (about) */
.resume { border-top: 1px solid oklch(0.30 0.03 62 / 0.7); }
.resume h2 { text-align: center; font-size: var(--t-h2); margin-bottom: clamp(2rem, 5vw, 3rem); }
.resume-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.5rem, 4vw, 3rem); }
@media (max-width: 900px) { .resume-grid { grid-template-columns: 1fr; } }
.resume-col { text-align: center; }
.resume-col .col-icon { color: var(--accent); margin-bottom: 0.9rem; display: flex; justify-content: center; }
.resume-col h3 { font-family: "Archivo", sans-serif; font-weight: 600; font-size: 0.8rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); margin-bottom: 1.1rem; }
.resume-col ul { list-style: none; text-align: left; display: grid; gap: 0.7rem; }
.resume-col li { position: relative; padding-left: 1.1rem; font-size: 0.95rem; color: var(--ink-muted); }
.resume-col li::before { content: ""; position: absolute; left: 0; top: 0.55em; width: 5px; height: 5px; border-radius: 50%; background: var(--accent); }
.resume-col .arrow-link { display: inline-block; margin-top: 1.2rem; }
/* Contact form */
.form-wrap { max-width: 46rem; margin-inline: auto; }
.form-wrap h2 { text-align: center; font-size: var(--t-h2); margin-bottom: clamp(1.8rem, 4vw, 2.6rem); }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem 1rem; }
.form-grid .full { grid-column: 1 / -1; }
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }
.field label { display: block; font-family: "Archivo", sans-serif; font-weight: 600; font-size: 0.78rem; letter-spacing: 0.04em; margin-bottom: 0.4rem; color: var(--ink-on-wall); }
.field label .req { font-weight: 500; color: var(--ink-on-wall-muted); font-size: 0.72rem; }
.field input, .field select, .field textarea {
  width: 100%; padding: 0.75rem 0.9rem;
  font-family: "Source Serif 4", serif; font-size: 1rem;
  background: var(--wall-card); color: var(--ink-on-wall);
  border: 1px solid var(--wall-line); border-radius: 4px;
}
.field select { font-family: "Archivo", sans-serif; font-size: 0.9rem; }
.field textarea { min-height: 9rem; resize: vertical; }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.form-actions { text-align: center; margin-top: 1.6rem; }
.form-note { text-align: center; font-size: 0.85rem; color: var(--ink-on-wall-muted); margin-top: 0.9rem; font-family: "Archivo", sans-serif; }
.contact-lines { display: grid; gap: 0.9rem; margin-top: 1.6rem; }
.contact-lines .row { display: flex; align-items: center; gap: 0.8rem; }
.contact-lines .row svg { flex: none; color: var(--accent); }
.contact-lines a:hover { color: var(--accent); }
/* Links page */
.links-group { max-width: 46rem; }
.links-group + .links-group { margin-top: 2.5rem; }
.links-group h2 { font-size: var(--t-h3); margin-bottom: 0.9rem; }
.links-group ul { list-style: none; display: grid; gap: 0.6rem; }
.links-group li { border-bottom: 1px solid var(--wall-line); padding-bottom: 0.6rem; }
.links-group a { color: var(--accent-deep); }
.links-group a:hover { text-decoration: underline; }
.links-group .note { font-size: 0.85rem; color: var(--ink-on-wall-muted); font-family: "Archivo", sans-serif; }
/* Sub-collection blocks (trees) */
/* A hang needs the full measure. The section note sits above it, not beside it. */
.subcol { display: block; padding-block: clamp(2.5rem, 5vw, 4rem); border-top: 1px solid var(--wall-line); }
.subcol .side { max-width: 62ch; margin-bottom: clamp(1.75rem, 3vw, 2.5rem); }
.subcol .side figure { max-width: 34rem; }
.subcol:first-of-type { border-top: 0; }
.subcol h2 { font-size: var(--t-h3); margin-bottom: 0.8rem; }
.subcol .side p { font-size: 0.95rem; }
.subcol .side .sig { font-family: "Marcellus", serif; margin-top: 0.9rem; }
/* Featured works strip (portfolio) */
.feat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
@media (max-width: 900px) { .feat-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .feat-grid { grid-template-columns: 1fr; } }
/* Home-alt current work cards */
.cw-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
@media (max-width: 900px) { .cw-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .cw-grid { grid-template-columns: 1fr; } }
/* Donor tiers (Lapham Lodge) */
.donor-tiers { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: 2.5rem 2rem; }
.tier h3 { font-family: "Archivo", sans-serif; font-weight: 600; font-size: 0.8rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-deep); padding-bottom: 0.5rem; border-bottom: 2px solid var(--accent); margin-bottom: 0.8rem; display: inline-block; }
.tier-note { font-family: "Archivo", sans-serif; font-size: 0.75rem; color: var(--ink-on-wall-muted); margin: -0.4rem 0 0.6rem; }
.tier ul { list-style: none; display: grid; gap: 0.4rem; }
.tier li { font-size: 0.95rem; }
/* Each donor links to the tree they sponsored, as the old site did. The tree
   label sits after the name so the list still scans as names first. */
.tier li a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--accent); }
.tier li a:hover { color: var(--accent-deep); }
.donor-tree {
  display: block;
  font-family: "Archivo", sans-serif; font-size: 0.58rem;
  letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--ink-on-wall-muted); margin-top: 0.1rem;
}
/* The donor map is a wide diagram; unconstrained it ate most of a desktop
   screen. Cap it by height so it stays a reference rather than a billboard. */
.donor-map img {
  display: block; margin-inline: 0 auto;   /* left-aligned, not centred */
  /* BOTH auto, then clamp with the two maxima -- that is what keeps the
     ratio. width:100% with a max-height (and no height:auto) squashes it. */
  width: auto; height: auto;
  max-width: 100%; max-height: 60vh;
  border-radius: 6px;
}
/* Embedded map inside a work card */
.work-card iframe { width: 100%; aspect-ratio: 4 / 3; border: 0; display: block; }
/* The nineteen trees */
.tree-list { list-style: none; display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: 0 2rem; }
.tree-row { display: flex; align-items: baseline; gap: 0.9rem; padding: 0.85rem 0; border-bottom: 1px solid var(--wall-line); }
.tree-row .tnum { font-family: "Marcellus", serif; font-size: 1.15rem; color: var(--accent-deep); min-width: 1.8rem; }
.tree-row .tname { flex: 1; }
.tree-row .arrow-link { font-size: 0.68rem; }
/* News articles */
.article-body { max-width: 46rem; margin-inline: auto; }
.article-body p { margin-bottom: 1rem; }
.article-meta { font-size: 0.78rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-muted); }
.page-hero.light .article-meta { color: var(--ink-on-wall-muted); }
.source-card { margin-top: 2.2rem; padding: 1.5rem 1.6rem; background: var(--wall-card); border: 1px solid var(--wall-line); border-radius: 6px; }
.source-card .src-pub { font-family: "Marcellus", serif; font-size: 1.2rem; margin: 0.3rem 0 1rem; }
.article-pn { display: flex; justify-content: space-between; gap: 1.5rem; margin-top: 2.5rem; padding-top: 1.2rem; border-top: 1px solid var(--wall-line); }
@media (max-width: 640px) { .article-pn { flex-direction: column; gap: 0.8rem; } }
/* ---- Desktop hero: image bleeds the right edge and dissolves into the ground ---- */
@media (min-width: 900px) {
  .hero { position: relative; overflow: clip; }
  .hero-art {
    position: absolute; top: 0; right: 0; bottom: 0; left: 42%;
    margin: 0; z-index: 0; pointer-events: none;
  }
  .hero-art::before { display: none; }          /* retire the lamp-pool glow */
  .hero-art .ph {
    width: 100%; height: 100%;
    aspect-ratio: auto;
    object-fit: cover; object-position: 60% 50%;
    border-radius: 0; box-shadow: none;
  }
  /* the dissolve: solid ground at the left edge, clear photo at the right */
  .hero-art::after {
    content: ""; position: absolute; inset: 0;
    background: linear-gradient(90deg,
      oklch(0.18 0.02 65) 0%,
      oklch(0.18 0.02 65) 10%,
      oklch(0.18 0.02 65 / 0.86) 28%,
      oklch(0.18 0.02 65 / 0.42) 50%,
      oklch(0.18 0.02 65 / 0.10) 72%,
      oklch(0.18 0.02 65 / 0) 88%);
  }
  /* vertical feather so the image meets the sections above and below cleanly */
  .hero-art .ph { mask-image: linear-gradient(180deg, transparent 0%, #000 14%, #000 86%, transparent 100%); }
  /* grid must NOT be a positioned ancestor, or the figure stops at the container edge */
  .hero-grid { position: static; grid-template-columns: minmax(0, 63fr) minmax(0, 37fr); gap: clamp(1.5rem, 2.5vw, 2.5rem); }
  .hero-grid > div:first-child { position: relative; z-index: 2; }
  .hero-art { z-index: 0; }
  .hero-art .plaque { display: none; }
}
/* ============================================================
   THE HANG — constant optical weight, one shelf line.
   Every work is sized so w = C·√r and h = C/√r  =>  w·h = C².
   Flexbox gives this for free when flex-grow AND the basis
   coefficient are both √r. No JS, no crop, no letterbox.
   ============================================================ */
.hang{
  --shelf: 300px;
  --gap-x: clamp(1.25rem, 2.4vw, 1.75rem);
  --gap-y: clamp(3rem, 5.5vw, 5.5rem);
  --hang-min: 150px;
  --tower-h: clamp(26rem, 60vh, 40rem);
  --mat: oklch(0.925 0.012 80);
  display: flex; flex-wrap: wrap; align-items: flex-end;
  gap: var(--gap-y) var(--gap-x);
  margin: 0; padding: 0; list-style: none;
}
.on-dark .hang, .dark-section .hang{ --mat: oklch(0.215 0.02 65); }
.hang-item{
  container-type: inline-size; container-name: work;
  flex-grow: var(--u);
  flex-shrink: 1;
  flex-basis: max(calc(var(--u) * var(--shelf)), var(--hang-min));
  min-width: var(--hang-min);
  margin: 0;
}
.hang-item > .work{ display: block; text-decoration: none; color: inherit; }
.hang-item img{
  display: block; width: 100%; height: auto;
  aspect-ratio: var(--ar);
  background: var(--mat);
}
/* Mode B — THE COLUMN (r < 0.55): height-governed, stands on the same shelf */
.hang-item.is-tower{ flex-grow: 0; flex-shrink: 0; flex-basis: calc(var(--tower-h) * var(--ar)); }
.hang-item.is-tower img{ height: var(--tower-h); width: auto; max-width: 100%; }
/* Mode C — THE LONG VIEW (r >= 1.9): its own full-width band */
.hang-item.is-pano{ flex-grow: 1; flex-basis: 100%; }
/* Widow sentinels: soak the last row's slack so orphans keep natural size */
.hang-widow{ flex: 1000000 1 0; min-width: 0; height: 0; margin: 0; padding: 0; }
/* the plaque — design.md §6, hierarchy by TONE not size */
.hang .plaque{
  margin-top: max(0.6rem, 2.4cqi);
  padding-top: max(0.45rem, 1.8cqi);
  border-top: 2px solid var(--accent);
  font-family: "Archivo", sans-serif; display: block;
}
.hang .plaque .t{
  display: block; font-weight: 600; font-size: 0.75rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-on-wall);
}
.on-dark .hang .plaque .t, .dark-section .hang .plaque .t{ color: var(--ink); }
.hang .plaque .yr{ opacity: 0.6; }
.hang .plaque .r{
  display: block; margin-top: 0.3rem; font-weight: 500; font-size: 0.75rem;
  letter-spacing: 0.06em; line-height: 1.45; text-transform: none;
  color: var(--ink-on-wall-muted);
}
.on-dark .hang .plaque .r, .dark-section .hang .plaque .r{ color: var(--ink-muted); }
@container work (max-width: 285px){ .hang .plaque .dims{ display: none; } }
@container work (min-width: 560px){
  .hang .plaque{ display: grid; grid-template-columns: 1fr auto; column-gap: 1.5rem; align-items: baseline; }
  .hang .plaque .r{ margin-top: 0; text-align: right; }
}
/* hover: lift + a warm key bloom. NEVER scale — scaling inside a box IS cropping */
.hang-item .work{ position: relative; }
.hang-item .work::after{
  content: ""; position: absolute; inset: -6% -8% -2%;
  background: radial-gradient(closest-side at 50% 45%, oklch(0.34 0.055 70 / 0.5), transparent 70%);
  opacity: 0; pointer-events: none; z-index: -1;
}
@media (hover: hover) and (pointer: fine){
  .hang-item .work{ transition: transform 300ms var(--ease); }
  .hang-item .work::after{ transition: opacity 300ms var(--ease); }
  .hang-item .work:hover{ transform: translateY(-4px); }
  .hang-item .work:hover::after{ opacity: 1; }
}
.hang-item .work:focus-visible{ outline: 2px solid var(--focus); outline-offset: 6px; }
@media (max-width: 899px){ .hang{ --shelf: 240px; --tower-h: clamp(22rem, 52vh, 30rem); } }
@media (max-width: 560px){ .hang{ --shelf: 190px; --gap-y: 2.5rem; } }
/* ---- THE SHELF: the hang in one horizontal room (homepage) ---- */
.hang.shelf{
  --shelf: 420px;
  flex-wrap: nowrap;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding-bottom: 1rem;
  scrollbar-color: var(--surface-2) transparent;
}
.hang.shelf .hang-item{ flex-shrink: 0; scroll-snap-align: start; }
.hang.shelf .hang-item img{ background: oklch(0.215 0.02 65); }
.hang.shelf .plaque .t{ color: var(--ink); }
.hang.shelf .plaque .r{ color: var(--ink-muted); text-transform: none; }
.hang.shelf .plaque .yr{
  opacity: 1; color: var(--accent); font-variant-numeric: tabular-nums;
  margin-left: 0.4rem;
}
.hang.shelf:focus-visible{ outline: 2px solid var(--focus); outline-offset: 8px; }
@media (max-width: 899px){ .hang.shelf{ --shelf: 300px; } }
@media (max-width: 560px){ .hang.shelf{ --shelf: 240px; } }

/* ---- work detail page ---- */
.work-detail{ padding-top: 12.5rem; }
.crumb{ font-family:"Archivo",sans-serif; font-size:0.72rem; letter-spacing:0.14em;
  text-transform:uppercase; color:var(--ink-on-wall-muted); margin-bottom:clamp(1.5rem,3vw,2.5rem); }
.crumb a{ color:var(--accent-deep); }
.crumb a:hover{ text-decoration:underline; }
.work-lead{ display:grid; grid-template-columns:minmax(0,62fr) minmax(0,38fr);
  gap:clamp(2rem,4vw,3.5rem); align-items:end; }
.work-plate{ margin:0; }
.work-plate{ display:flex; justify-content:center; align-items:flex-end; }
.work-plate img{ display:block; width:auto; height:auto;
  max-width:100%; max-height:82vh;      /* size to the picture, never stretch the box */
  background:var(--wall-card); }
.work-record h1{ font-size:clamp(2rem,3.6vw,3.2rem); line-height:1.12; margin:0.4rem 0 0; text-wrap:balance; }
.work-record .flame-divider{ justify-content:flex-start; padding-block:0.9rem; }
/* Sponsors of a Lapham tree, listed on the tree's own page */
.sponsors { margin: 1.4rem 0 0.4rem; padding-top: 1rem; border-top: 1px solid var(--wall-line, rgba(0,0,0,.12)); }
.sponsors-h { font-family: "Archivo", sans-serif; font-size: 0.68rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-deep); margin: 0 0 0.5rem; }
.sponsors ul { list-style: none; padding: 0; margin: 0 0 0.7rem; display: grid; gap: 0.25rem; font-size: 0.92rem; }
.work-record .flame-divider::after{ display:none; }
.tombstone{ margin:0.5rem 0 1.75rem; display:grid; grid-template-columns:auto 1fr;
  gap:0.55rem 1.25rem; font-size:0.95rem; }
.tombstone dt{ font-family:"Archivo",sans-serif; font-weight:600; font-size:0.68rem;
  letter-spacing:0.13em; text-transform:uppercase; color:var(--ink-on-wall-muted);
  padding-top:0.2rem; white-space:nowrap; }
.tombstone dd{ margin:0; color:var(--ink-on-wall); }
.tombstone dd a{ color:var(--accent-deep); }
.tombstone dd a:hover{ text-decoration:underline; }
.work-text{ margin:0 0 1.75rem; max-width:62ch; }
.work-text p{ margin:0 0 0.85rem; line-height:1.65; color:var(--ink-on-wall); }
.work-text p:last-child{ margin-bottom:0; }
.work-cta{ margin:0 0 0.8rem; }
.work-detail .article-pn{ margin-top:clamp(2.5rem,5vw,4rem); align-items:center; }
@media (max-width: 899px){
  .work-detail{ padding-top:10rem; }
  .work-lead{ grid-template-columns:1fr; align-items:start; }
  .work-plate img{ max-height:70vh; }
}

/* ---- the viewer ---- */
#viewer{
  /* margin:auto is what centres a modal <dialog>. The global `* { margin: 0 }`
     reset near the top of this file wipes the UA default, which pinned the
     viewer to the top-left of the viewport — and pushed .v-close (top:-0.75rem)
     off-screen where it was clipped. Do not remove. */
  border:0; padding:0; margin:auto; max-width:min(94vw,1400px); max-height:94vh; width:auto;
  background:var(--bg); color:var(--ink); overflow:visible;
}
#viewer::backdrop{ background:oklch(0.12 0.015 65 / 0.94); overscroll-behavior:contain; }
html:has(#viewer[open]){ overflow:hidden; }
.v-frame{ display:grid; grid-template-rows:1fr auto; gap:1.25rem; padding:clamp(1rem,2.5vw,2rem); }
.v-stage{ display:flex; align-items:center; justify-content:center; min-height:0; }
.v-img{ display:block; width:auto; height:auto; max-width:100%; max-height:74vh; background:var(--surface); }
.v-bar{ display:flex; align-items:baseline; gap:1.25rem; flex-wrap:wrap;
  border-top:2px solid var(--accent); padding-top:0.7rem; font-family:"Archivo",sans-serif; }
.v-title{ font-weight:600; font-size:0.8rem; letter-spacing:0.14em; text-transform:uppercase; color:var(--ink); }
.v-spec{ font-size:0.78rem; letter-spacing:0.05em; color:var(--ink-muted); flex:1; }
.v-count{ font-size:0.72rem; letter-spacing:0.12em; color:var(--ink-muted); font-variant-numeric:tabular-nums; }
.v-link{ font-size:0.72rem; font-weight:600; letter-spacing:0.12em; text-transform:uppercase; color:var(--accent); }
.v-link:hover{ text-decoration:underline; }
.v-nav{ display:flex; gap:0.5rem; }
.v-nav button, .v-close{
  background:none; border:1px solid var(--surface-2); color:var(--ink); cursor:pointer;
  border-radius:4px; min-width:44px; min-height:44px; font-family:"Archivo",sans-serif;
  font-size:0.9rem; line-height:1; transition:border-color 200ms var(--ease), color 200ms var(--ease);
}
.v-nav button:hover, .v-close:hover{ border-color:var(--accent); color:var(--accent); }
.v-close{ position:absolute; top:-0.75rem; right:-0.75rem; background:var(--bg); z-index:2; }
.v-frame{ position:relative; }
@media (max-width:560px){ .v-img{ max-height:60vh; } .v-close{ top:0.25rem; right:0.25rem; } }
/* The work's own photos under the viewer image (site.js builds the row). Each
   thumbnail keeps its true proportions -- fixed height, width from the image --
   so nothing is cropped even at this size. Auto margins centre a short row
   without stranding the first thumbnails when a long row scrolls. The row's
   4px padding is room for the focus ring, which a scrolling box would clip, and
   its min-height holds its place while site.js waits for the next work's photos. */
.v-frame{ --vt:64px; }
.v-thumbs{ display:flex; gap:0.5rem; overflow-x:auto; padding:4px; min-height:calc(var(--vt) + 10px); scrollbar-width:thin; }
.v-thumb:first-child{ margin-left:auto; }
.v-thumb:last-child{ margin-right:auto; }
.v-thumb{ flex:0 0 auto; padding:0; border:1px solid transparent; border-radius:3px; background:var(--surface);
  opacity:0.62; transition:opacity .2s ease, border-color .2s ease; }
.v-thumb img{ display:block; height:var(--vt); width:auto; max-width:none; border-radius:2px; }
.v-thumb:hover{ opacity:1; }
.v-thumb[aria-pressed="true"]{ opacity:1; border-color:var(--accent); }
.v-thumb:focus-visible{ opacity:1; outline:2px solid var(--focus); outline-offset:1px; }
/* The image gives up exactly what the row adds, so the viewer is no taller with
   it: thumbnail + 2px border + 8px padding, the extra 1.25rem grid gap, and 10px
   for a scrollbar on systems that always show one. */
.v-frame.has-thumbs .v-img{ max-height:calc(74vh - var(--vt) - 20px - 1.25rem); }
@media (max-width:560px){
  .v-frame{ --vt:48px; }
  .v-frame.has-thumbs .v-img{ max-height:calc(60vh - var(--vt) - 20px - 1.25rem); }
}

/* ---- per-work enquiry reference ---- */
.work-ref{ border:1px solid var(--wall-line); border-left:3px solid var(--accent);
  background:var(--wall-card); border-radius:4px; padding:1.1rem 1.3rem; margin-bottom:1.75rem; }
.work-ref .kicker{ margin-bottom:0.35rem; }
.work-ref-title{ font-family:"Marcellus",serif; font-size:1.2rem; margin:0 0 0.2rem; }
.work-ref-spec{ font-size:0.9rem; color:var(--ink-on-wall-muted); margin:0 0 0.6rem; }

/* ---- catalogue controls: facets + view toggle ---- */
.index-controls{ display:flex; flex-wrap:wrap; gap:1rem 1.5rem; align-items:center;
  justify-content:space-between; margin-bottom:0.75rem; }
.facets{ display:flex; flex-wrap:wrap; gap:0.5rem; }
.facet, .vs{
  font-family:"Archivo",sans-serif; font-weight:600; font-size:0.72rem; letter-spacing:0.12em;
  text-transform:uppercase; color:var(--ink-on-wall-muted); background:none; cursor:pointer;
  border:1px solid var(--wall-line); border-radius:99px; padding:0.55rem 0.95rem;
  min-height:36px; transition:color 200ms var(--ease), border-color 200ms var(--ease);
}
.facet:hover, .vs:hover{ color:var(--ink-on-wall); border-color:var(--accent); }
.facet.is-on, .vs.is-on{ color:var(--bg); background:var(--accent); border-color:var(--accent); }
.facet .fc{ opacity:0.65; margin-left:0.35rem; font-variant-numeric:tabular-nums; }
.facet.is-on .fc{ opacity:0.8; }
.viewswitch{ display:flex; gap:0.4rem; }
.count-line{ font-size:0.72rem; letter-spacing:0.14em; text-transform:uppercase;
  color:var(--ink-on-wall-muted); margin:0 0 clamp(1.75rem,3vw,2.5rem); }
.facet:focus-visible, .vs:focus-visible{ outline:2px solid var(--focus); outline-offset:3px; }

/* ---- the index (tombstone list) view ---- */
.index-table{ width:100%; border-collapse:collapse; font-size:0.95rem; }
.index-table th{ text-align:left; font-family:"Archivo",sans-serif; font-weight:600;
  font-size:0.68rem; letter-spacing:0.13em; text-transform:uppercase;
  color:var(--ink-on-wall-muted); padding:0 1rem 0.6rem 0; border-bottom:2px solid var(--accent); }
.index-table td{ padding:0.85rem 1rem 0.85rem 0; border-bottom:1px solid var(--wall-line);
  vertical-align:baseline; }
.index-table td a{ color:var(--ink-on-wall); }
.index-table td a:hover{ color:var(--accent-deep); text-decoration:underline; }
.index-table tr td:nth-child(2){ font-variant-numeric:tabular-nums; white-space:nowrap; }
.index-table tr td:nth-child(3), .index-table tr td:nth-child(4){ color:var(--ink-on-wall-muted); font-size:0.9rem; }
.sr-only{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden;
  clip:rect(0 0 0 0); white-space:nowrap; border:0; }
/* The [hidden] attribute is how the JS hides things (view switch, facet filter,
   tree groups). The UA rule for it is only `display:none`, which ANY author
   display declaration outranks -- .hang sets display:flex, so switching to the
   Index view left the 100-tile grid on screen underneath the table, showing
   every work twice. Force it, so `hidden` always means hidden. */
[hidden] { display: none !important; }
@media (max-width:700px){ .index-table tr td:nth-child(4), .index-table thead th:nth-child(4){ display:none; } }

/* A hero for pages whose works are all portrait: show the piece whole on a mat
   rather than force it into the landscape band and cut it in half. */
.page-hero .hero-media--plate img{
  width:auto; height:auto; max-width:100%; max-height:min(58vh, 30rem);
  aspect-ratio:auto; object-fit:contain; margin-inline:auto;
  background:var(--wall-card);
}
.page-hero.light .hero-media--plate img{ background:var(--wall-card); }
.page-hero:not(.light) .hero-media--plate img{ background:var(--surface); }


/* ---- Further views: alternate photographs on a work page ---------------- */
.view-strip .views-row{
  display:flex; flex-wrap:wrap; gap:clamp(1.25rem,2.4vw,1.75rem);
  align-items:flex-start;
}
.view-card{
  margin:0; flex:1 1 calc(50% - 1rem); min-width:min(100%, 320px);
}
.view-card img{
  display:block; width:100%; height:auto; border-radius:4px;
  box-shadow:0 18px 50px var(--shadow);
}
@media (max-width:899px){ .view-card{ flex-basis:100%; } }


/* ---- Tree time: the silicone-mold clips --------------------------------- */
.process-video .clips-row{
  display:flex; flex-wrap:wrap; gap:clamp(1.25rem,2.4vw,1.75rem);
}
.process-clip{
  flex:1 1 calc(50% - 1rem); min-width:min(100%,320px);
  max-height:70vh; border-radius:4px; background:var(--surface);
  box-shadow:0 18px 50px var(--shadow);
}
@media (max-width:899px){ .process-clip{ flex-basis:100%; } }
/* Behind the Scenes: one labelled group of clips per piece */
.bts-item{ margin-bottom: 2.75rem; }
.bts-item h3{ font-size: var(--t-h4, 1.05rem); margin-bottom: 0.75rem; }
.bts-item h3 a{ color: var(--ink-on-wall, inherit); }
/* ---- YouTube facade ------------------------------------------------------
   A thumbnail and a play button; the real player is injected on click, from
   youtube-nocookie.com. Shorts sit in a 9:16 frame and are held narrower so a
   vertical film does not tower over the landscape ones beside it. */
.yt-row{ display:grid; grid-template-columns:repeat(auto-fill,minmax(18rem,1fr)); gap:clamp(1.25rem,2.4vw,1.75rem); align-items:start; }
.yt{ margin:0; }
.yt.is-short{ max-width:19rem; }
.yt-play{
  position:relative; display:block; width:100%; aspect-ratio:var(--yt-ar,16 / 9);
  padding:0; border:0; border-radius:4px; overflow:hidden; cursor:pointer;
  background:#000; box-shadow:0 18px 50px var(--shadow);
}
.yt-play img{ display:block; width:100%; height:100%; object-fit:cover; opacity:.9; transition:opacity 200ms var(--ease), transform 600ms var(--ease); }
.yt-play:hover img, .yt-play:focus-visible img{ opacity:1; transform:scale(1.02); }
.yt-play:focus-visible{ outline:2px solid var(--focus); outline-offset:3px; }
.yt-btn{
  position:absolute; inset:0; margin:auto; width:4rem; height:4rem; border-radius:999px;
  display:grid; place-items:center; padding-left:.25rem;
  background:var(--accent); color:oklch(0.16 0.02 65);
  box-shadow:0 8px 28px oklch(0 0 0 / .45);
  transition:transform 200ms var(--ease);
}
.yt-play:hover .yt-btn{ transform:scale(1.06); }
.yt iframe{ display:block; width:100%; aspect-ratio:var(--yt-ar,16 / 9); border:0; border-radius:4px; box-shadow:0 18px 50px var(--shadow); }
.yt .plaque{ margin-top:.7rem; }
.bts-item:last-child{ margin-bottom: 0; }


/* Any figure image in an editorial sidebar scales by width; without this, an
   <img> carrying its intrinsic width/height attributes renders the HEIGHT
   attribute literally while CSS shrinks the width — the MCAD exhibition card
   showed at 542x3794. The attributes stay (they feed aspect-ratio and prevent
   CLS); height:auto is what keeps them advisory. */
.side figure img { height: auto; }
