/* P Display — layout concept: walls are cut to fit the work. Chrome stays plaster-neutral
   and quiet so the art supplies all the colour; one slanted wordmark carries the name. */
:root {
  --ground: #E8E9E6;
  --raise: #F3F3F1;
  --ink: #0D0E11;
  --mute: #494D56;
  --line: #C6C8C4;
  --accent: #2B3AF5;
  --tile: #D3D5D1;
  --scrim: rgba(232, 233, 230, 0.97);
  --on-art: #FFFFFF;
  --art-shade: rgba(6, 7, 9, 0.72);
  --f-display: 'Syne', 'Arial Black', 'Helvetica Neue', system-ui, sans-serif;
  --f-body: 'Hanken Grotesk', 'Helvetica Neue', system-ui, sans-serif;
  --f-mono: 'DM Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;
  --gutter: clamp(16px, 3vw, 40px);
  --gap: 14px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground: #0A0B0E; --raise: #14161B; --ink: #ECEDEF; --mute: #AAAEB8; --line: #2A2D34;
    --accent: #8F9BFF; --tile: #1A1C22; --scrim: rgba(8, 9, 11, 0.97); color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --ground: #0A0B0E; --raise: #14161B; --ink: #ECEDEF; --mute: #AAAEB8; --line: #2A2D34;
  --accent: #8F9BFF; --tile: #1A1C22; --scrim: rgba(8, 9, 11, 0.97); color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { scroll-behavior: auto; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; touch-action: manipulation; }
button, a { -webkit-tap-highlight-color: transparent; }
button { -webkit-appearance: none; appearance: none; touch-action: manipulation; }
a { touch-action: manipulation; }
body {
  background: var(--ground); color: var(--ink);
  font: 400 1rem/1.55 var(--f-body); -webkit-font-smoothing: antialiased;
  min-height: 100vh; min-height: 100dvh; overflow-x: clip;
  padding-left: env(safe-area-inset-left, 0px); padding-right: env(safe-area-inset-right, 0px);
}
button { font: inherit; color: inherit; cursor: pointer; }
a { color: inherit; text-decoration: none; }
img, canvas { max-width: 100%; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.mono { font: 500 0.72rem/1.4 var(--f-mono); letter-spacing: 0.04em; text-transform: uppercase; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ---------- bar ---------- */
.bar {
  position: sticky; top: env(safe-area-inset-top, 0px); z-index: 20;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 12px var(--gutter);
  background: var(--ground);
  border-bottom: 1px solid var(--line);
}
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .bar { background: color-mix(in srgb, var(--ground) 94%, transparent); }
}
.mark { display: inline-block; font: 800 1.2rem/1 var(--f-display); letter-spacing: 0.02em; text-transform: uppercase; transform: skewX(-12deg); transform-origin: left bottom; }
.mark em { font-style: normal; color: var(--accent); }
.bar-nav { display: flex; align-items: center; gap: 18px; }
.bar-nav a { font: 500 0.78rem/1 var(--f-mono); letter-spacing: 0.06em; text-transform: uppercase; padding: 8px 0; border-bottom: 1px solid transparent; }
.bar-nav a[aria-current] { border-bottom-color: var(--ink); }
.icon-btn { width: 38px; height: 38px; display: grid; place-items: center; border: 1px solid var(--line); border-radius: 50%; background: transparent; }
.icon-btn svg { width: 18px; height: 18px; }

/* view options */
.vwrap { position: relative; }
.view-btn { display: inline-flex; align-items: center; gap: 8px; height: 38px; padding: 0 14px 0 12px; border: 1px solid var(--line); border-radius: 99px; background: transparent; font: 500 0.78rem/1 var(--f-mono); letter-spacing: 0.06em; text-transform: uppercase; }
.view-btn[aria-expanded="true"] { border-color: var(--ink); }
.view-btn svg { width: 16px; height: 16px; }
.view-sum { color: var(--mute); }
.view-pop {
  position: absolute; right: 0; top: calc(100% + 12px); z-index: 30; width: min(360px, calc(100vw - 32px));
  display: grid; gap: 18px; padding: 18px; background: var(--raise); border: 1px solid var(--line); border-radius: 8px;
  max-height: calc(100vh - 110px); max-height: calc(100dvh - 110px); overflow-y: auto; overscroll-behavior: contain;
  box-shadow: 0 24px 60px -24px rgba(0, 0, 0, 0.5);
}
.opt { display: grid; gap: 8px; }
.opt-h { color: var(--mute); }
.seg { display: flex; border: 1px solid var(--line); border-radius: 99px; padding: 3px; gap: 2px; }
.seg button { flex: 1; min-width: 0; height: 32px; padding: 0 8px; border: 0; border-radius: 99px; background: transparent; font: 500 0.8rem/1 var(--f-mono); color: var(--mute); }
.seg button[aria-checked="true"] { background: var(--ink); color: var(--ground); }
.hint { margin: 0; color: var(--mute); font-size: 0.82rem; line-height: 1.4; }
.reset { justify-self: start; padding: 4px 0; border: 0; background: none; color: var(--mute); border-bottom: 1px solid var(--line); }
#view[data-caps="always"] .tile:not(.card) .cap { opacity: 1; transform: none; }
#view[data-caps="always"] .tile:not(.card) .no { opacity: 0.95; }
@media (max-width: 640px) {
  .view-sum { display: none; }
  .view-pop { position: fixed; left: 16px; right: 16px; width: auto; top: calc(env(safe-area-inset-top, 0px) + 66px); }
}

/* ---------- home hero ---------- */
main { display: block; padding-bottom: 40px; }
.view-in { animation: viewIn 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) both; }
@keyframes viewIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.hero { padding: clamp(28px, 5vw, 64px) var(--gutter) clamp(22px, 3vw, 36px); display: grid; gap: 22px; grid-template-columns: minmax(0, 1fr); }
.hero h1 {
  margin: 0; font: 800 clamp(2.6rem, 8.4vw, 7.8rem)/0.9 var(--f-display); letter-spacing: -0.04em;
  text-wrap: balance; max-width: 14ch;
}
.hero h1 .sl { display: inline-block; transform: skewX(-11deg); color: var(--accent); }
.hero-side { display: grid; gap: 14px; align-content: end; max-width: 46ch; }
.hero-side p { margin: 0; color: var(--mute); font-size: 1.05rem; }
.eyebrow { color: var(--mute); margin: 0; }
@media (min-width: 900px) {
  .hero { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); align-items: end; }
  .hero .eyebrow { grid-column: 1 / -1; }
}

/* ---------- mosaic + tiles ---------- */
.wall { padding: 0 var(--gutter); }
.wall-home { padding-top: 66px; } /* clears the floating buttons; the covers start right under them */
.mosaic { position: relative; width: 100%; }
.tile {
  position: absolute; display: block; margin: 0; padding: 0; border: 0; overflow: hidden; text-align: left;
  border-radius: 3px; background: var(--ph, var(--tile)); color: var(--on-art);
  contain: layout paint; -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
}
.tile .im, .tile .an { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.tile .im { opacity: 0; transition: opacity 0.6s ease, transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1); }
.tile.ready .im { opacity: 1; }
.tile .an { opacity: 0; transition: opacity 0.4s ease; }
.tile.live .an { opacity: 1; }
.tile:focus-visible .im, .tile:focus-visible .ss { transform: scale(1.035); }
.tile .ss { transition: opacity 0.6s ease, transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1); }
.tile:focus-visible { outline-offset: -3px; outline-color: var(--on-art); box-shadow: 0 0 0 3px var(--accent); }
.tile .cap {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 34px 12px 11px;
  background: linear-gradient(to top, var(--art-shade), transparent);
  display: grid; gap: 1px; opacity: 0; transform: translateY(6px);
  transition: opacity 0.3s ease, transform 0.3s ease; pointer-events: none;
}
.tile:focus-visible .cap { opacity: 1; transform: none; }
.cap-t { font: 600 clamp(0.86rem, 1.1vw, 1rem)/1.2 var(--f-display); letter-spacing: -0.01em; }
.cap-m { font: 400 0.68rem/1.35 var(--f-mono); letter-spacing: 0.03em; opacity: 0.85; }
.tile .no { position: absolute; top: 9px; left: 10px; font: 500 0.68rem/1 var(--f-mono); letter-spacing: 0.06em; text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55); opacity: 0; transition: opacity 0.3s ease; }
.tile:focus-visible .no { opacity: 0.95; }
.badge {
  position: absolute; top: 8px; right: 8px; display: inline-flex; align-items: center; gap: 6px;
  font: 500 0.68rem/1 var(--f-mono); letter-spacing: 0.04em; padding: 5px 8px 5px 7px; border-radius: 99px;
  background: rgba(8, 9, 11, 0.62); color: var(--on-art);
}
.badge svg { width: 11px; height: 11px; fill: currentColor; }
.prog, .segs { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; }
.prog::before { content: ''; display: block; height: 100%; width: calc(var(--p, 0) * 100%); background: var(--on-art); opacity: 0.85; }
.segs { display: flex; gap: 2px; padding: 0 8px 6px; height: 8px; opacity: 0; transition: opacity 0.3s ease; }
.tile:focus-visible .segs { opacity: 1; }
.segs i { flex: 1; height: 2px; background: rgba(255, 255, 255, 0.35); align-self: flex-end; }
.segs i.on { background: var(--on-art); }
.tile .ss { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 0.6s ease; }
.tile .ss.on { opacity: 1; }

/* artist cards */
.card { container-type: size; }
/* sizes first in vw for browsers without container query units (older iOS), then in cqw */
.card .cap { opacity: 1; transform: none; padding: 60px 16px 16px; padding: 60px 4cqw 4cqw; gap: 6px; background: linear-gradient(to top, var(--art-shade), rgba(6, 7, 9, 0.28) 60%, transparent); }
.card .cap-t { font: 800 clamp(1.1rem, 4.6vw, 2.2rem)/0.95 var(--f-display); font-size: clamp(1.15rem, 8.2cqw, 2.7rem); letter-spacing: -0.03em; }
.card .cap-m { font-size: 0.68rem; font-size: clamp(0.62rem, 2.6cqw, 0.74rem); text-transform: uppercase; letter-spacing: 0.07em; }
.card .go { position: absolute; top: 12px; right: 12px; top: 3.5cqw; right: 3.5cqw; width: 34px; height: 34px; width: clamp(30px, 8cqw, 42px); height: clamp(30px, 8cqw, 42px); border-radius: 50%; background: var(--on-art); color: #0D0E11; display: grid; place-items: center; opacity: 0; transform: translate(-6px, 6px); transition: opacity 0.3s ease, transform 0.3s ease; }
.card:focus-visible .go { opacity: 1; transform: none; }
.card .go svg { width: 45%; height: 45%; }
.card .n { position: absolute; top: 14px; left: 14px; top: 3.5cqw; left: 4cqw; font: 500 0.7rem/1 var(--f-mono); letter-spacing: 0.06em; text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55); }

/* ---------- artist page ---------- */
.crumbs { padding: 18px var(--gutter) 14px; display: flex; gap: 10px; align-items: center; color: var(--mute); }
.stage {
  position: relative; margin: 0 var(--gutter); height: clamp(340px, 44vw, 560px);
  border-radius: 4px; overflow: hidden; background: #0b0b0e; color: var(--on-art);
  display: flex; flex-direction: column; justify-content: flex-end;
}
.stage canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.stage::after { content: ''; position: absolute; inset: 0; background: linear-gradient(to top, rgba(6, 7, 9, 0.82) 0%, rgba(6, 7, 9, 0.35) 45%, rgba(6, 7, 9, 0) 75%); pointer-events: none; }
.stage-in { position: relative; z-index: 1; padding: clamp(18px, 3vw, 40px); display: grid; gap: 14px; grid-template-columns: minmax(0, 1fr); }
.stage h1 { margin: 0; font: 800 clamp(2.5rem, 9vw, 8rem)/0.88 var(--f-display); letter-spacing: -0.04em; text-wrap: balance; }
.stage .lede { margin: 0; max-width: 52ch; font-size: clamp(1rem, 1.5vw, 1.15rem); line-height: 1.5; opacity: 0.92; }
.stage .disc { margin: 0; opacity: 0.85; }
@media (min-width: 900px) {
  .stage-in { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); align-items: end; column-gap: 40px; }
  .stage-in .disc, .stage-in h1 { grid-column: 1 / -1; }
}
.facts { display: flex; flex-wrap: wrap; gap: 6px 22px; padding: 16px var(--gutter) 0; color: var(--mute); align-items: center; }
.facts b { color: var(--ink); font-weight: 500; }
.dots { display: inline-flex; gap: 5px; align-items: center; }
.dots i { width: 14px; height: 14px; border-radius: 50%; border: 1px solid var(--line); display: block; }

.sect { padding: 0 var(--gutter); margin-top: clamp(36px, 5vw, 72px); scroll-margin-top: 70px; }
.sect-head { display: flex; align-items: flex-end; justify-content: space-between; flex-wrap: wrap; gap: 12px 24px; margin-bottom: 16px; }
.sect-head h2 { margin: 0; font: 800 clamp(1.7rem, 3.4vw, 3rem)/0.95 var(--f-display); letter-spacing: -0.035em; }
.sect-head p { margin: 6px 0 0; color: var(--mute); }
.sect-head .grp { min-width: 0; }

.pager { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.pg { min-width: 38px; height: 38px; padding: 0 12px; display: inline-grid; place-items: center; border: 1px solid var(--line); border-radius: 99px; font: 500 0.8rem/1 var(--f-mono); background: transparent; transition: border-color 0.2s, background 0.2s; }
.pg.on { background: var(--ink); color: var(--ground); border-color: var(--ink); }
.pg.off { opacity: 0.35; pointer-events: none; }
.pager-end { margin: clamp(40px, 6vw, 80px) var(--gutter) 0; padding-top: 22px; border-top: 1px solid var(--line); display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap; }
.pager-end p { margin: 0; color: var(--mute); }
.pager-end.single { display: none; }
/* Invisible sentinel just above the end pager — IntersectionObserver trips it to append the next page. */
.wall-sent { height: 1px; width: 100%; margin: 0; padding: 0; pointer-events: none; visibility: hidden; }

.nextart { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 20px; margin: clamp(28px, 5vw, 56px) var(--gutter) 0; padding: clamp(18px, 3vw, 32px); border-radius: 4px; background: var(--raise); border: 1px solid var(--line); transition: border-color 0.2s; }
.nextart .nm { display: block; margin-top: 8px; font: 800 clamp(1.8rem, 5.5vw, 4.6rem)/0.92 var(--f-display); letter-spacing: -0.04em; overflow-wrap: anywhere; }
.nextart .th { width: clamp(84px, 16vw, 200px); aspect-ratio: var(--ar, 1); border-radius: 3px; overflow: hidden; background: var(--ph, var(--tile)); }
.nextart .th img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; transition: opacity 0.5s; }
.nextart .th img.ready { opacity: 1; }

.foot { padding: 34px var(--gutter) calc(34px + env(safe-area-inset-bottom, 0px)); color: var(--mute); display: flex; flex-wrap: wrap; gap: 10px 32px; justify-content: space-between; border-top: 1px solid var(--line); margin-top: 24px; }
.foot p { margin: 0; max-width: 62ch; font-size: 0.9rem; }

/* ---------- lightbox ---------- */
.lb { position: fixed; inset: 0; z-index: 50; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; background: var(--scrim); overscroll-behavior: contain;
  padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px); animation: lbIn 0.25s ease both; }
@keyframes lbIn { from { opacity: 0; } to { opacity: 1; } }
.lb-top { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 8px var(--gutter); }
.lb-who { display: flex; gap: 12px; align-items: baseline; min-width: 0; flex-wrap: wrap; }
.lb-who b { font: 800 1.05rem/1 var(--f-display); letter-spacing: -0.01em; }
.lb-who span { color: var(--mute); }
.lb-stage { position: relative; min-height: 0; display: grid; place-items: center; padding: 0 clamp(8px, 3.5vw, 56px); touch-action: pan-y; }
.lb-media { position: relative; background: var(--ph, var(--tile)); border-radius: 2px; box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.55); overflow: hidden; }
.lb-media img, .lb-media canvas, .lb-media video { display: block; width: 100%; height: 100%; }
.lb-media img { opacity: 0; transition: opacity 0.35s ease; object-fit: contain; }
.lb-media video { object-fit: contain; }
.stage .stage-media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: var(--bpos, center 30%); display: block; }
.empty { padding: 48px var(--gutter); color: var(--mute); }
.lb-media img.ready { opacity: 1; }
.lb-nav { position: absolute; top: 50%; translate: 0 -50%; width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center; border: 1px solid var(--line); background: var(--ground); z-index: 2; }
.lb-nav svg { width: 18px; height: 18px; }
.lb-nav.prev { left: clamp(8px, 1.6vw, 24px); } .lb-nav.next { right: clamp(8px, 1.6vw, 24px); }
.lb-bot { display: grid; gap: 12px 32px; grid-template-columns: minmax(0, 1fr); padding: 8px var(--gutter) 12px; }
.lb-cap h3 { margin: 0; font: 800 clamp(1.1rem, 2vw, 1.5rem)/1 var(--f-display); letter-spacing: -0.03em; }
.lb-cap p { margin: 5px 0 0; color: var(--mute); font: 400 0.78rem/1.5 var(--f-mono); letter-spacing: 0.02em; }
.lb-ctl { display: flex; align-items: center; gap: 14px; min-width: 0; }
.lb-dots { display: flex; align-items: center; }
.lb-dots i { position: relative; width: 26px; height: 26px; cursor: pointer; }
.lb-dots i::before { content: ''; position: absolute; inset: 9px; border-radius: 50%; background: var(--line); }
.lb-dots i.on::before { background: var(--ink); }
.lb-play { width: 42px; height: 42px; border-radius: 50%; border: 1px solid var(--ink); display: grid; place-items: center; background: var(--ink); color: var(--ground); flex: none; }
.lb-play svg { width: 16px; height: 16px; fill: currentColor; }
.lb-time { color: var(--mute); white-space: nowrap; font-variant-numeric: tabular-nums; }
.lb-range { flex: 1; min-width: 80px; -webkit-appearance: none; appearance: none; height: 22px; background: transparent; }
.lb-range::-webkit-slider-runnable-track { height: 3px; border-radius: 2px; background: linear-gradient(to right, var(--accent) var(--fill, 0%), var(--line) var(--fill, 0%)); }
.lb-range::-moz-range-track { height: 3px; border-radius: 2px; background: var(--line); }
.lb-range::-moz-range-progress { height: 3px; background: var(--accent); }
.lb-range::-webkit-slider-thumb { -webkit-appearance: none; width: 14px; height: 14px; border-radius: 50%; background: var(--ink); border: 0; margin-top: -5.5px; }
.lb-range::-moz-range-thumb { width: 14px; height: 14px; border-radius: 50%; background: var(--ink); border: 0; }
@media (min-width: 900px) { .lb-bot { grid-template-columns: minmax(0, 1fr) minmax(280px, 42%); align-items: end; } }
@media (max-width: 640px) { .lb-nav { top: auto; bottom: 8px; translate: 0 0; } .lb-nav.prev { left: 8px; } .lb-nav.next { right: 8px; } .lb-stage { padding-bottom: 56px; } }

@media (max-height: 620px) {
  .lb-top { padding-block: 6px; } .lb-bot { padding-block: 6px 10px; gap: 6px 24px; } .lb-cap p { display: none; }
  .lb-cap h3 { font-size: 1.05rem; } .lb-play { width: 34px; height: 34px; } .lb-stage { padding-bottom: 0; }
  .lb-nav { top: 50%; translate: 0 -50%; bottom: auto; width: 38px; height: 38px; }
}
@media (max-width: 640px) { :root { --gap: 6px; } .bar-nav { gap: 12px; } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---------- pointer-specific behaviour ----------
   Hover rules only apply where there is a real hover (mouse, trackpad). On a phone a tap would
   otherwise leave an element stuck in its hover state, and iOS may swallow the first tap. */
@media (hover: hover) and (pointer: fine) {
  .bar-nav a:hover { border-bottom-color: var(--ink); }
  .icon-btn:hover, .lb-nav:hover, a.pg:hover, .nextart:hover { border-color: var(--ink); }
  .view-btn:hover { border-color: var(--ink); }
  .seg button:hover { color: var(--ink); }
  .seg button[aria-checked="true"]:hover { color: var(--ground); }
  .reset:hover { color: var(--ink); border-bottom-color: var(--ink); }
  .crumbs a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
}
/* Touch: what hover would reveal is shown, or replaced by motion and a pressed state. */
@media (hover: none) {
  .card .go { opacity: 1; transform: none; }
  .segs { opacity: 1; }
  .tile { transition: transform 0.18s ease; }
  .tile:active { transform: scale(0.985); }
  .tile:active .im, .tile:active .ss { transform: scale(1.02); }
  .icon-btn:active, .view-btn:active, a.pg:active, .lb-nav:active { border-color: var(--ink); }
}
@media (pointer: coarse) {
  .icon-btn { width: 44px; height: 44px; }
  .view-btn { height: 44px; }
  .pg { min-width: 44px; height: 44px; }
  .seg button { height: 40px; }
  .lb-nav { width: 48px; height: 48px; }
  .lb-play { width: 48px; height: 48px; }
  .lb-range { height: 40px; }
  .lb-range::-webkit-slider-thumb { width: 26px; height: 26px; margin-top: -11.5px; }
  .lb-range::-moz-range-thumb { width: 26px; height: 26px; }
  .bar-nav a { padding: 14px 0; }
  .mono { font-size: 0.76rem; }
}

/* Viewer open: freeze the page where it is (iOS Safari ignores overflow:hidden on the document). */
html.lb-open body { position: fixed; top: calc(var(--lb-y, 0px) * -1); left: 0; right: 0; }

/* Narrow phones: the wordmark already links home, so the top bar keeps only View and theme. */
.bar-nav { min-width: 0; }
@media (max-width: 480px) { #nav-artists { display: none; } }
@media (max-width: 350px) { .view-btn > span { display: none; } .view-btn { padding: 0 12px; } }

/* ================= visual effects =================
   Everything here moves transform or opacity only. html[data-fx] is set by fx.js:
   high = all effects, mid = no pointer effects, low = plain fades. */

/* tiles arrive as a ripple: the picture settles from slightly zoomed-in */
.tile .im { transform: scale(1.14); transition: opacity 0.7s ease calc(var(--i, 0) * 50ms), transform 1.3s cubic-bezier(0.2, 0.7, 0.2, 1) calc(var(--i, 0) * 50ms); }
.tile.ready .im { opacity: 1; transform: none; }
.tile.settled .im, .tile.settled .ss { transition-delay: 0s; transition-duration: 0.6s, 0.9s; }
html[data-fx="low"] .tile .im { transform: none; transition: opacity 0.25s ease; }

/* headline words rise out of a mask (the end state is the normal state) */
.w { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: 0.16em; margin-bottom: -0.16em; padding-right: 0.06em; margin-right: -0.06em; }
.wi { display: inline-block; animation: wordUp 0.9s cubic-bezier(0.2, 0.8, 0.2, 1) backwards; animation-delay: calc(var(--k, 0) * 70ms + 80ms); }
@keyframes wordUp { from { transform: translateY(108%); } }
html[data-fx="low"] .wi { animation: none; }

/* scroll progress under the bar */
.sp { position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; background: var(--accent); transform: scaleX(0); transform-origin: 0 50%; pointer-events: none; }

/* banner parallax: the picture is oversized so it never shows an edge while it drifts */
.stage canvas, .stage .stage-media { will-change: transform; }
.stage-in { will-change: transform, opacity; }
html[data-fx="low"] .stage canvas, html[data-fx="low"] .stage .stage-media, html[data-fx="low"] .stage-in { will-change: auto; }

/* cursor label (mouse only, high tier) */
.cur { position: fixed; left: 0; top: 0; z-index: 60; width: 56px; height: 56px; margin: -28px 0 0 -28px; border-radius: 50%; pointer-events: none; opacity: 0; display: none;
  place-items: center; text-align: center; background: var(--ink); color: var(--ground); font: 500 0.58rem/1.15 var(--f-mono); letter-spacing: 0.06em; text-transform: uppercase; }

/* (the moving glare on tilting cards is gone; hovered works get the still gloss defined near the end of this file) */

@media (hover: hover) and (pointer: fine) {
  html[data-fx="high"] .cur { display: grid; }
  html[data-fx="high"] .tile { cursor: none; }
  /* the rest of the wall steps back while one card is in focus */
}

/* the viewer glows with the colour of what it shows */
.lb-stage::before { content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(52% 48% at 50% 50%, color-mix(in srgb, var(--ph, transparent) 42%, transparent), transparent 74%); }
.lb-media { will-change: transform; }

/* moving between artists: the card and the banner are the same object */
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.32s; animation-timing-function: cubic-bezier(0.3, 0.7, 0.2, 1); }
.bar { view-transition-name: bar; } /* the top bar stays put while the page beneath it changes */
::view-transition-group(bar) { animation-duration: 0s; }
@media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; } }
::view-transition-group(hero) { animation-duration: 0.52s; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
::view-transition-old(hero), ::view-transition-new(hero) { width: 100%; height: 100%; object-fit: cover; mix-blend-mode: normal; animation-duration: 0.4s; animation-timing-function: ease-out; }
/* the other cards are pushed away from the tapped one (offsets and delays are written per card by vtCards in app.js) */
@keyframes pdc-out { to { opacity: 0; transform: translate(var(--tx, 0), var(--ty, 0)) scale(0.9); } }
@keyframes pdc-in { from { opacity: 0; transform: translate(var(--tx, 0), var(--ty, 0)) scale(0.92); } }
/* the tapped card travels as a bare picture; its caption is left behind and the banner's title rises in instead */
.card.vt-src .cap, .card.vt-src .n, .card.vt-src .go, .card.vt-src::after { opacity: 0 !important; transition: none !important; }
.card.instant .im, .card.instant .an { transition: none !important; transform: none !important; }
/* the banner starts as the cover you tapped, then the live art fades in over it */
.stage.covered { background-size: cover; background-position: var(--bpos, center 30%); }
.stage canvas, .stage .stage-media { opacity: 0; transition: opacity 0.9s ease; }
.stage.live canvas, .stage.live .stage-media { opacity: 1; }
html[data-fx="low"] .stage canvas, html[data-fx="low"] .stage .stage-media { transition: none; }
/* while the morph plays only the banner exists; the sections then rise in together */
#view .sect, #view .pager-end, #view .nextart, #view .facts { transition: opacity 0.4s ease, transform 0.55s cubic-bezier(0.2, 0.8, 0.2, 1); }
#view.vt-wait .sect, #view.vt-wait .pager-end, #view.vt-wait .nextart { opacity: 0; transform: translateY(14px); }
#view.vt-wait .stage .wi { animation-delay: calc(var(--k, 0) * 55ms + 160ms); animation-duration: 0.7s; }

@media (prefers-reduced-motion: reduce) { .cur { display: none !important; } }

/* specificity fixes: pointer and focus zoom must beat the reveal state */
.tile.ready:focus-visible .im, .tile.ready:focus-visible .ss { transform: scale(1.035); }
@media (hover: none) { .tile.ready:active .im, .tile.ready:active .ss { transform: scale(1.02); } }
.w:has(.sl) { padding-right: 0.28em; margin-right: -0.28em; }

/* ================= stacks =================
   At rest a stack is a pile: the top image sits low-left at 91.5% and up to three more show as edges up and to the right,
   all inside the tile, so no space is wasted. Fanned, every image spreads across the tile and the one under the
   pointer comes forward. Transform and opacity only — will-change while fanned; scrubbing drops transitions so
   pointermove does not restart 0.55s animations on every card. Shadows stay light (one layer) to avoid paint thrash. */
.t-stack .cards { position: absolute; inset: 0; }
.t-stack .sc { position: absolute; inset: 0; opacity: 0; z-index: calc(20 - var(--k)); background: var(--ph, var(--tile)); border-radius: 2px;
  transform: translate(calc(-4.25% + var(--k) * 2.8%), calc(4.25% - var(--k) * 2.8%)) scale(0.915);
  transition: transform 0.55s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.5s ease calc(var(--i, 0) * 50ms + var(--k) * 60ms); }
.t-stack .sc img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 2px; box-shadow: 0 6px 14px -8px rgba(0, 0, 0, 0.55); }
.t-stack .sc::after { content: ''; position: absolute; inset: 0; border-radius: 2px; pointer-events: none; background: rgba(0, 0, 0, calc(var(--k) * 0.14)); transition: opacity 0.4s ease; }
.t-stack .sc:nth-child(n+5) { opacity: 0 !important; }
.t-stack.ready .sc { opacity: 1; }
.t-stack.fan .sc { transform: translate(calc(var(--fx) * 1%), calc(var(--fy) * 1%)) rotate(calc(var(--r) * 1deg)) scale(0.66);
  transition: transform 0.22s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.2s ease; will-change: transform; }
.t-stack.fan .sc:nth-child(n+5) { opacity: 1 !important; }
.t-stack.fan .sc::after { opacity: 0; }
.t-stack.fan .sc.on { z-index: 40; transform: translate(0, 0) rotate(0deg) scale(0.9); }
.t-stack.fan.scrub .sc { transition: none; }
.t-stack.fan .cap, .t-stack.fan .no { z-index: 50; }
html[data-fx="low"] .t-stack .sc { transition: opacity 0.25s ease; will-change: auto; }
.t-stack .badge, .t-stack .no, .t-stack .cap { z-index: 50; }

/* ================= viewer: scrim, hero, deck, flight =================
   The page dims through its own scrim layer so it can fade separately from the picture and the controls. */
.lb { background: none; animation: none; }
.lb-scrim { position: absolute; inset: 0; background: var(--ground); z-index: 0; }
.lb-top, .lb-stage, .lb-bot { position: relative; z-index: 1; }
.lb-stage { touch-action: none; }
.lb-hero { position: relative; width: 100%; height: 100%; display: grid; place-items: center; }
.lb-media { will-change: auto; }
.lb-media img { opacity: 1; transition: none; object-fit: cover; }
.lb-media img.hi, .lb-card img.hi { position: absolute; inset: 0; opacity: 0; transition: opacity 0.24s ease; }
.lb-media img.hi.on, .lb-card img.hi.on { opacity: 1; }

/* a stack's other pictures wait behind the front one */
.lb-deck { position: absolute; inset: 0; pointer-events: none; }
.lb-card { position: absolute; left: 50%; top: 50%; opacity: var(--o, 1); cursor: pointer; pointer-events: auto;
  transform: translate3d(var(--x, 0), var(--y, 0), 0) rotate(var(--r, 0deg)) scale(var(--s, 1));
  transition: transform 0.7s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.5s ease; }
.lb-card .in { position: relative; width: 100%; height: 100%; overflow: hidden; border-radius: 2px; background: var(--ph, var(--tile)); box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.55); }
.lb-card img { display: block; width: 100%; height: 100%; object-fit: cover; }
.lb-card::after { content: ''; position: absolute; inset: 0; border-radius: 2px; background: rgba(0, 0, 0, 0.3); transition: opacity 0.4s ease; pointer-events: none; }
.lb-card.front { cursor: default; }
.lb-card.front::after { opacity: 0; }

/* the copy of the picture that travels between the wall and the viewer */
.lb-fly { position: fixed; z-index: 70; overflow: hidden; border-radius: 2px; pointer-events: none; transform-origin: 0 0; will-change: transform, opacity;
  box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.55); }
.lb-fly img { display: block; width: 100%; height: 100%; object-fit: cover; }

@media (hover: hover) and (pointer: fine) { .lb-card:not(.front):hover::after { opacity: 0.08; } }
html[data-fx="low"] .lb-card { transition: opacity 0.25s ease; }
.lb-card.front { cursor: grab; }

/* ================= viewer controls: arrows live in the bottom bar =================
   The previous and next arrows sit beside the play button and progress bar, so the picture no longer gives up
   space at its sides and can grow to nearly the full width. */
.lb-stage { padding: 0 clamp(10px, 2vw, 28px); padding-bottom: 0; }
.lb-row { display: flex; align-items: center; gap: 14px; min-width: 0; }
.lb-arrows { display: flex; gap: 8px; flex: none; }
.lb-row .lb-nav { position: static; translate: none; top: auto; bottom: auto; left: auto; right: auto; width: 44px; height: 44px; flex: none; }
.lb-row .lb-nav svg { width: 18px; height: 18px; }
.lb-row .lb-ctl { flex: 1; min-width: 0; }
.lb-row .lb-dots { margin-left: 4px; }
@media (min-width: 900px) { .lb-bot { grid-template-columns: minmax(0, 1fr) minmax(320px, 46%); } }
@media (max-width: 640px) { .lb-stage { padding-bottom: 0; } .lb-row .lb-nav { width: 46px; height: 46px; } }
@media (max-height: 620px) { .lb-row .lb-nav { width: 40px; height: 40px; } }
@media (hover: hover) and (pointer: fine) { .lb-row .lb-nav:hover { border-color: var(--ink); } }
@media (min-width: 900px) and (min-height: 621px) {
  .lb-bot { padding-block: 8px 12px; }
  .lb-row .lb-nav, .lb-row .lb-play { width: 40px; height: 40px; }
}

/* ================= View panel: frosted glass =================
   Semi-transparent so the page shows softly through it. Solid where colour mixing is unsupported, and no blur in the low tier. */
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .view-pop {
    background: color-mix(in srgb, var(--raise) 70%, transparent);
    border-color: color-mix(in srgb, var(--ink) 16%, transparent);
    -webkit-backdrop-filter: blur(20px) saturate(1.5); backdrop-filter: blur(20px) saturate(1.5);
    box-shadow: 0 24px 60px -24px rgba(0, 0, 0, 0.55), inset 0 1px 0 color-mix(in srgb, var(--ink) 8%, transparent);
  }
  .view-pop .seg { border-color: color-mix(in srgb, var(--ink) 18%, transparent); background: color-mix(in srgb, var(--ground) 30%, transparent); }
  html[data-fx="low"] .view-pop { background: color-mix(in srgb, var(--raise) 90%, transparent); -webkit-backdrop-filter: none; backdrop-filter: none; }
}

/* ================= compact artist banner =================
   The banner is a strip, not a poster: the works start higher on the page. Its height follows its text, with a modest minimum. */
.stage { height: auto; min-height: clamp(210px, 22vw, 300px); }
.stage-in { padding: clamp(14px, 2.2vw, 26px); gap: 8px; }
.stage h1 { font-size: clamp(2rem, 4.8vw, 4.2rem); line-height: 0.92; }
.stage .lede { font-size: clamp(0.9rem, 1.15vw, 1rem); line-height: 1.45; max-width: 58ch; }
@media (max-width: 640px) { .stage h1 { font-size: 2rem; } .stage .lede { font-size: 0.88rem; } }
.crumbs { padding-block: 12px 10px; }

/* ================= soft gradient background =================
   Three colour glows on a fixed layer behind the page. The layer never repaints (it only drifts, using transform), so it costs
   almost nothing. The colours are registered properties, so they cross-fade when the page changes; artist pages set them
   from that artist's palette. Older browsers fall back to the fixed default colours. */
@property --g1 { syntax: '<color>'; inherits: true; initial-value: #6d7bff; }
@property --g2 { syntax: '<color>'; inherits: true; initial-value: #d65cc8; }
@property --g3 { syntax: '<color>'; inherits: true; initial-value: #2bc4b0; }
:root { --ga: 36%; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --ga: 32%; } }
:root[data-theme="dark"] { --ga: 32%; }
html { transition: --g1 1.4s ease, --g2 1.4s ease, --g3 1.4s ease; }
html[data-fx="low"] { transition: none; }
body::before {
  content: ''; position: fixed; inset: -18%; z-index: -1; pointer-events: none;
  background:
    radial-gradient(46% 40% at 14% 10%, rgba(109, 123, 255, 0.2), transparent 70%),
    radial-gradient(40% 38% at 88% 24%, rgba(214, 92, 200, 0.16), transparent 70%),
    radial-gradient(52% 46% at 68% 94%, rgba(43, 196, 176, 0.16), transparent 70%);
  animation: glowDrift 80s ease-in-out infinite alternate; will-change: transform;
}
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  body::before {
    background:
      radial-gradient(70% 46% at 50% -10%, color-mix(in srgb, var(--g1) calc(var(--ga) * 1.25), transparent), transparent 72%),
      radial-gradient(38% 42% at 96% 62%, color-mix(in srgb, var(--g2) var(--ga), transparent), transparent 70%),
      radial-gradient(46% 44% at 4% 92%, color-mix(in srgb, var(--g3) var(--ga), transparent), transparent 70%),
      radial-gradient(30% 26% at 60% 108%, color-mix(in srgb, var(--g2) calc(var(--ga) * 0.6), transparent), transparent 70%);
  }
}
@keyframes glowDrift { from { transform: translate3d(0, 0, 0) scale(1); } to { transform: translate3d(-3%, 2.5%, 0) scale(1.08); } }
html[data-fx="low"] body::before { animation: none; will-change: auto; }
@media (prefers-reduced-motion: reduce) { body::before { animation: none; } }
.lb-out { will-change: transform, opacity; }
.lb-out .lb-card, .lb-out .lb-media { transition: none; }

/* ================= floating controls instead of a top bar =================
   No bar, no line: the wordmark, View and theme buttons float over the page as small translucent pills, so the content
   starts at the top of the screen. The bar element is zero height and only carries the pills. */
.bar { height: 0; padding: 0 var(--gutter); overflow: visible; background: none; border: 0; pointer-events: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
.bar > * { pointer-events: auto; }
.mark, .bar-nav { position: absolute; top: 12px; }
.mark { left: max(var(--gutter), env(safe-area-inset-left, 0px)); transform-origin: left center; padding: 10px 16px 9px; }
.bar-nav { right: max(var(--gutter), env(safe-area-inset-right, 0px)); gap: 8px; }
.sp { top: 0; bottom: auto; }
.mark, .view-btn, .icon-btn {
  background: color-mix(in srgb, var(--ground) 52%, transparent);
  border: 1px solid color-mix(in srgb, var(--ink) 14%, transparent); border-radius: 99px;
  -webkit-backdrop-filter: blur(12px) saturate(1.4); backdrop-filter: blur(12px) saturate(1.4);
}
html[data-fx="low"] .mark, html[data-fx="low"] .view-btn, html[data-fx="low"] .icon-btn { -webkit-backdrop-filter: none; backdrop-filter: none; background: color-mix(in srgb, var(--ground) 82%, transparent); }
@media (hover: hover) and (pointer: fine) { .mark:hover { border-color: var(--ink); } }

/* ================= compact home hero =================
   One short headline, small enough to sit on a single line on a wide screen, so the covers start high on the page. */
.hero { padding: 66px var(--gutter) 16px; gap: 8px 32px; }
.hero h1 { font-size: clamp(1.9rem, 4.4vw, 3.9rem); line-height: 0.98; letter-spacing: -0.035em; max-width: none; }
.hero-side { max-width: 40ch; gap: 0; }
.hero-side p { font-size: 0.95rem; line-height: 1.45; }
.hero .eyebrow { font-size: 0.7rem; }
@media (min-width: 900px) { .hero { grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr); } }
.crumbs { padding-top: 62px; }
.hero h1 { font-size: clamp(1.65rem, 3.3vw, 3.1rem); }
.crumbs { padding-top: 68px; }

/* ================= richer background, still cheap =================
   Everything below is a static picture that only moves by transform, so nothing is ever repainted: a second layer of soft
   colour ribbons drifting against the first, a light that trails the pointer, and a fine grain on the page itself.
   Ribbons and light take the artist's colours; both step away in the mid and low effect tiers. */
.bg { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; }
.bg > i { position: absolute; display: block; }
/* Topographic contour lines: a picture drawn once in app.js is used as a mask over a gradient of the artist's three colours,
   so the lines take the palette (and the theme) and drift very slowly. Only shown once the mask exists and is supported. */
.bg .bg-b, .bg .bg-c {
  display: none; left: 0; top: -8%; bottom: -8%; width: 200%; opacity: 0.34; will-change: transform;
  /* the gradient repeats every half width, exactly as the picture does, so the slide has no seam */
  background: linear-gradient(90deg, var(--g1) 0%, var(--g2) 16.66%, var(--g3) 33.33%, var(--g1) 50%, var(--g2) 66.66%, var(--g3) 83.33%, var(--g1) 100%);
  -webkit-mask-size: 50% 100%; mask-size: 50% 100%; -webkit-mask-repeat: repeat-x; mask-repeat: repeat-x; -webkit-mask-position: 0 0; mask-position: 0 0;
}
.bg .bg-b.on, .bg .bg-c.on { display: block; }
.bg-b { animation: flowLeft 120s linear infinite; }
.bg .bg-c { opacity: 0.2; animation: flowRight 190s linear infinite; }
@keyframes flowLeft { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(-50%, 0, 0); } }
@keyframes flowRight { from { transform: translate3d(-50%, 0, 0); } to { transform: translate3d(0, 0, 0); } }
/* a second set of colour glows drifting on its own path against the first, so the colour itself seems to flow */
.bg::before {
  content: ''; position: absolute; inset: -25%; pointer-events: none; will-change: transform;
  background:
    radial-gradient(36% 34% at 28% 34%, rgba(214, 92, 200, 0.14), transparent 70%),
    radial-gradient(34% 32% at 74% 66%, rgba(43, 196, 176, 0.13), transparent 70%),
    radial-gradient(28% 28% at 52% 96%, rgba(109, 123, 255, 0.13), transparent 70%);
  animation: blobFlow 56s ease-in-out infinite alternate;
}
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .bg::before {
    background:
      radial-gradient(36% 34% at 28% 34%, color-mix(in srgb, var(--g2) calc(var(--ga) * 0.8), transparent), transparent 70%),
      radial-gradient(34% 32% at 74% 66%, color-mix(in srgb, var(--g3) calc(var(--ga) * 0.75), transparent), transparent 70%),
      radial-gradient(28% 28% at 52% 96%, color-mix(in srgb, var(--g1) calc(var(--ga) * 0.75), transparent), transparent 70%);
  }
}
@keyframes blobFlow {
  0% { transform: translate3d(-7%, 5%, 0) scale(1) rotate(0deg); }
  50% { transform: translate3d(6%, -4%, 0) scale(1.14) rotate(7deg); }
  100% { transform: translate3d(-3%, -7%, 0) scale(1.06) rotate(-5deg); }
}
html[data-fx="low"] .bg::before { animation: none; will-change: auto; }
@media (prefers-reduced-motion: reduce) { .bg::before, .bg-b, .bg-c { animation: none; } }
/* a broad band of light that crosses the page now and then */
.bg::after {
  content: ''; position: absolute; inset: -30% -70%; pointer-events: none; opacity: 0; will-change: transform, opacity;
  background: linear-gradient(104deg, transparent 43%, rgba(150, 160, 255, 0.1) 50%, transparent 57%);
  animation: lightSweep 34s ease-in-out 4s infinite;
}
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .bg::after { background: linear-gradient(104deg, transparent 43%, color-mix(in srgb, var(--g1) 20%, transparent) 50%, transparent 57%); }
}
@keyframes lightSweep {
  0% { transform: translate3d(-32%, 0, 0); opacity: 0; }
  14% { opacity: 1; }
  46% { opacity: 0; }
  100% { transform: translate3d(32%, 0, 0); opacity: 0; }
}
html[data-fx="low"] .bg::after { display: none; }
@media (prefers-reduced-motion: reduce) { .bg::after { display: none; } }
/* effect tiers: mid keeps the main silk layer (slower), low keeps only the still colour */
html[data-fx="low"] .bg .bg-b, html[data-fx="low"] .bg .bg-c, html[data-fx="mid"] .bg .bg-c { display: none !important; }
html[data-fx="mid"] .bg-b { animation-duration: 180s; }
html { transition: --g1 0.7s ease, --g2 0.7s ease, --g3 0.7s ease; }

/* ================= privacy blackout =================
   A solid black sheet over the whole viewport (above the viewer and the top bar too). Nothing shows through; the pointer stays visible. */
.veil { position: fixed; inset: 0; z-index: 120; opacity: 0; visibility: hidden; background: #000;
  transition: opacity 0.1s ease, visibility 0s 0.1s; }
.veil.on { opacity: 1; visibility: visible; transition: opacity 0.1s ease; }
html.blurred { background: #000; }

@media (prefers-reduced-motion: reduce) { .veil, .veil.on { transition: none; } }

/* wordmark: set as typed, no capitals or dot */
.mark { text-transform: none; letter-spacing: -0.01em; font-size: 1.12rem; }

/* ================= artist strip =================
   The banner is now one low band, so the works start right under it. It still carries the live art and everything the old
   banner and facts row held: number, discipline and city over the name; the statement and one line of facts beside it. */
.stage { height: auto; min-height: clamp(240px, 34vh, 420px); border-radius: 6px; }
.stage::after { background: linear-gradient(to top, rgba(6, 7, 9, 0.88) 0%, rgba(6, 7, 9, 0.5) 38%, rgba(6, 7, 9, 0.1) 72%, rgba(6, 7, 9, 0) 100%); }
.stage .stage-in { flex: 1; display: grid; grid-template-columns: minmax(0, 1fr); align-items: end; gap: 10px 32px; padding: clamp(14px, 1.8vw, 22px) clamp(14px, 2.2vw, 26px); }
.st-l { min-width: 0; display: grid; gap: 6px; }
.st-kick { margin: 0; opacity: 0.82; font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; }
.stage h1 { font-size: clamp(2.2rem, 5vw, 4.4rem); line-height: 0.92; }
.st-r { min-width: 0; display: grid; gap: 8px; }
.stage .lede { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden; max-width: 50ch; margin: 0; font-size: clamp(0.86rem, 1vw, 0.95rem); line-height: 1.4; }
.st-meta { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px; font-size: 0.68rem; letter-spacing: 0.06em; text-transform: uppercase; opacity: 0.92; }
.st-meta b { font-weight: 500; }
.st-meta .dots i { border-color: rgba(255, 255, 255, 0.4); }
@media (min-width: 820px) { .stage .stage-in { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); } }
@media (max-width: 899px) { .st-x { display: none; } }
@media (max-width: 639px) { .stage .lede { display: none; } }
.stage + .sect { margin-top: clamp(22px, 3vw, 40px); }

/* ================= hover: the print lifts =================
   Mouse only: nothing here runs on a phone, where a tap keeps its pressed state. The work you point at lifts a little off the
   wall and its picture begins a slow drift; a caption bar slides up from its bottom edge. Transform/opacity only — no
   animated box-shadow (overflow:hidden clips it anyway and the paint cost was the hover lag). will-change promotes the
   hovered tile; stacks that are fanning skip the lift so parent+child transforms do not fight. */
.tile:not(.card) .cap {
  left: 0; right: 0; bottom: 0; padding: 10px 12px 11px; gap: 2px; background: rgba(10, 11, 14, 0.8); border-radius: 0;
  opacity: 1; transform: translateY(100%); transition: transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.tile:not(.card) .cap-t, .tile:not(.card) .cap-m { opacity: 1; transform: none; transition: none; }
.tile:not(.card):focus-visible .cap, #view[data-caps="always"] .tile:not(.card) .cap { transform: none; }
.tile::before, .tile::after { display: none; }
@media (hover: hover) and (pointer: fine) {
  .tile { transition: transform 0.5s cubic-bezier(0.2, 0.8, 0.2, 1); }
  .tile:hover { transform: translateY(-4px) scale(1.012); z-index: 5; will-change: transform; }
  .tile.t-stack.fan:hover { transform: none; } /* fan children own the motion */
  .tile.ready:hover .im, .tile.ready:hover .ss { transform: scale(1.09) translate(-1.2%, -0.8%); transition: opacity 0.6s ease, transform 12s linear; will-change: transform; }
  .tile:not(.card):hover .cap { transform: none; }
  .tile:hover .no { opacity: 0.95; }
  .tile:hover .segs { opacity: 1; }
  .card:hover .go { opacity: 1; transform: translate(2px, -2px); background: var(--accent); color: #fff; }
}
/* narrow phones: the View button keeps only its icon, so the wordmark and three buttons fit on one line */
@media (max-width: 480px) { .view-btn > span { display: none; } .view-btn { padding: 0 11px; } }.tile .cap, .tile .no, .tile .badge, .tile .segs, .card .go, .card .n { z-index: 3; }
/* ================= viewer: open and dismiss =================
   The picture lifts off the wall before it travels, so it carries a shadow from the first frame; the scrim darkens towards the
   edges so the picture sits in a pool of light; the controls slide in from above and below (see uiIn / uiOut in app.js). */
.lb-fly { box-shadow: 0 34px 80px -26px rgba(0, 0, 0, 0.62); }
.lb-scrim { background: radial-gradient(120% 100% at 50% 42%, var(--ground) 0%, var(--ground) 100%); }
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .lb-scrim { background: radial-gradient(120% 100% at 50% 42%, var(--ground) 0%, color-mix(in srgb, var(--ground) 80%, #000) 100%); }
}
.lb-ui { will-change: transform, opacity; }
/* pager: the fold between distant pages */
.pg.gap { border: 0; min-width: 22px; padding: 0; color: var(--mute); pointer-events: none; }


/* ================= series / manga strip (kind=set) =================
   Wall: cover thumbnail uses first-page AR (normal tile). Badge shows page count.
   Lightbox: PDF/webtoon vertical scroll through every page (`.lb-strip`). Stacks stay as fan. */
.tile.t-set .im { object-position: center top; }

.lb.lb-reading .lb-stage {
  touch-action: pan-y;
  align-items: stretch;
  justify-items: center;
  place-items: stretch center;
  min-height: 0;
}
.lb.lb-reading .lb-hero {
  align-items: stretch;
  width: 100%;
  height: 100%;
  min-height: 0;
  max-height: 100%;
}
.lb.lb-reading .lb-scrim { background: #000; }
.lb.lb-reading .lb-stage::before { opacity: 0; }
/* Desktop / fine pointer: comfortable centered reader — chrome stays, modest gutters */
.lb-media.lb-strip {
  align-self: stretch;
  width: min(760px, 100%);
  height: 100%;
  max-height: 100%;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  background: #000;
  box-shadow: none;
  border-radius: 0;
  touch-action: pan-y;
}
.lb-media.lb-strip img {
  width: 100%; height: auto !important;
  max-width: 100%;
  opacity: 1; display: block;
  margin: 0;
  object-fit: contain;
  background: #000;
  border-radius: 0;
  pointer-events: none; /* chrome toggle hits stage; long-press hit-tests imgs in JS (pointer-events none) */
}
html[data-fx="low"] .lb-media.lb-strip img { transition: none; }

/* Phone / touch / narrow: full-bleed immersive strip (pages use the whole device) */
.lb.lb-reading.lb-immerse {
  padding: 0;
  background: #000;
  /* top/bot are position:absolute — collapse their grid rows so stage gets the full viewport */
  grid-template-rows: 0 minmax(0, 1fr) 0;
}
.lb.lb-reading.lb-immerse .lb-top,
.lb.lb-reading.lb-immerse .lb-bot {
  position: absolute;
  left: 0; right: 0;
  z-index: 4;
  margin: 0;
  transition: opacity 0.28s ease, transform 0.28s ease;
  pointer-events: none;
}
.lb.lb-reading.lb-immerse .lb-top {
  top: 0;
  padding-top: max(10px, env(safe-area-inset-top, 0px));
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.72) 0%, rgba(0, 0, 0, 0.28) 70%, transparent 100%);
}
.lb.lb-reading.lb-immerse .lb-bot {
  bottom: 0;
  padding-bottom: max(12px, env(safe-area-inset-bottom, 0px));
  background: linear-gradient(0deg, rgba(0, 0, 0, 0.78) 0%, rgba(0, 0, 0, 0.32) 70%, transparent 100%);
}
.lb.lb-reading.lb-immerse .lb-top > *,
.lb.lb-reading.lb-immerse .lb-bot > *,
.lb.lb-reading.lb-immerse .lb-top button,
.lb.lb-reading.lb-immerse .lb-bot button,
.lb.lb-reading.lb-immerse .lb-dots i { pointer-events: auto; }
.lb.lb-reading.lb-immerse:not(.lb-chrome-on) .lb-top,
.lb.lb-reading.lb-immerse:not(.lb-chrome-on) .lb-bot {
  opacity: 0;
  transform: translateY(0);
  pointer-events: none;
}
.lb.lb-reading.lb-immerse:not(.lb-chrome-on) .lb-top { transform: translateY(-8px); }
.lb.lb-reading.lb-immerse:not(.lb-chrome-on) .lb-bot { transform: translateY(8px); }
.lb.lb-reading.lb-immerse.lb-chrome-on .lb-top,
.lb.lb-reading.lb-immerse.lb-chrome-on .lb-bot { opacity: 1; transform: none; }
.lb.lb-reading.lb-immerse .lb-stage {
  padding: 0;
  touch-action: pan-y;
  align-items: stretch;
  justify-items: stretch;
  place-items: stretch;
  min-height: 0;
  height: 100%;
  align-self: stretch;
}
.lb.lb-reading.lb-immerse .lb-hero {
  width: 100%;
  height: 100%;
  min-height: 0;
  max-height: none;
  display: grid;
  place-items: stretch;
  align-self: stretch;
}
/* Immersive: CSS height:100% fills the stage. JS sets width only (no tiny px height from collapsed avail). */
.lb.lb-reading.lb-immerse .lb-media.lb-strip {
  display: block;
  width: 100%;
  max-width: 100%;
  height: 100%;
  max-height: none;
  min-height: 0;
  align-self: stretch;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
  background: #000;
}
.lb.lb-reading.lb-immerse .lb-media.lb-strip img {
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto !important;
  margin: 0;
  border-radius: 0;
  object-fit: contain;
  background: #000;
}
.lb.lb-reading.lb-immerse .lb-who b,
.lb.lb-reading.lb-immerse .lb-who span,
.lb.lb-reading.lb-immerse .lb-cap h3,
.lb.lb-reading.lb-immerse .lb-cap p { color: #f2f2f2; text-shadow: 0 1px 8px rgba(0, 0, 0, 0.55); }
.lb.lb-reading.lb-immerse .lb-who span,
.lb.lb-reading.lb-immerse .lb-cap p { color: rgba(242, 242, 242, 0.72); }
.lb.lb-reading.lb-immerse .icon-btn,
.lb.lb-reading.lb-immerse .lb-nav {
  background: rgba(0, 0, 0, 0.45);
  border-color: rgba(255, 255, 255, 0.18);
  color: #fff;
}
.lb.lb-reading.lb-immerse .lb-dots i::before { background: rgba(255, 255, 255, 0.35); }
.lb.lb-reading.lb-immerse .lb-dots i.on::before { background: #fff; }
html[data-fx="low"] .lb.lb-reading.lb-immerse .lb-top,
html[data-fx="low"] .lb.lb-reading.lb-immerse .lb-bot { transition: none; }


/* ================= lightbox page zoom ================= */
.lb-zchip {
  position: absolute;
  right: max(12px, env(safe-area-inset-right, 0px));
  bottom: max(12px, env(safe-area-inset-bottom, 0px));
  z-index: 5;
  height: 28px;
  padding: 0 10px;
  border-radius: 99px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(0, 0, 0, 0.55);
  color: #f2f2f2;
  font: 500 0.72rem/1 var(--f-mono);
  letter-spacing: 0.04em;
  cursor: pointer;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.lb.lb-reading.lb-immerse .lb-zchip { bottom: max(16px, env(safe-area-inset-bottom, 0px)); }
.lb-zinner {
  position: relative;
  width: 100%;
  height: 100%;
}
.lb-zinner img,
.lb-zinner canvas,
.lb-zinner video {
  display: block; width: 100%; height: 100%; object-fit: cover;
}
.lb-media.lb-zooming,
.lb-card .in.lb-zooming,
.lb-zinner.lb-zooming,
.lb-media.lb-strip img.lb-zooming {
  transform-origin: 0 0;
  will-change: transform;
}
.lb.lb-zoomed .lb-stage { cursor: grab; }
.lb.lb-zoomed .lb-card.front { cursor: grab; }
.lb.lb-zoomed .lb-media.lb-strip { overscroll-behavior: none; }

/* Phone lightbox zoom only (coarse pointer / no hover / narrow). Desktop wheel path unchanged. */
@media (hover: none), (pointer: coarse), (max-width: 720px) {
  .lb.lb-zoomed .lb-stage,
  .lb.lb-zoomed .lb-media.lb-strip,
  .lb.lb-zoomed .lb-zinner {
    touch-action: none;
    overscroll-behavior: none;
  }
  .lb-zinner.lb-zooming,
  .lb-media.lb-strip img.lb-zooming {
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
  }
}


/* ================= media save / copy sheet (long-press) ================= */
.media-sheet {
  position: fixed; inset: 0; z-index: 85; display: grid; align-items: end; justify-items: center;
  padding: 16px 16px max(16px, env(safe-area-inset-bottom, 0px));
  pointer-events: auto;
  -webkit-user-select: none; user-select: none;
}
.media-sheet[hidden] { display: none !important; }
.media-sheet-scrim { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.45); }
.media-sheet-panel {
  position: relative; z-index: 1; width: min(360px, 100%);
  display: grid; gap: 6px; padding: 14px 14px 12px;
  background: var(--raise); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.55);
  animation: mediaSheetIn 0.22s cubic-bezier(.2,.9,.3,1) both;
}
@keyframes mediaSheetIn {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to { opacity: 1; transform: none; }
}
.media-sheet-name {
  margin: 0 4px 6px; color: var(--mute); font-size: 0.72rem; letter-spacing: 0.04em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.media-sheet-panel button {
  height: 46px; border-radius: 10px; border: 1px solid var(--line);
  background: color-mix(in srgb, var(--ground) 55%, transparent);
  font: 600 0.95rem/1 var(--f-body); color: var(--ink);
  cursor: pointer;
}
.media-sheet-panel button:active { transform: scale(0.985); }
.media-sheet-panel button.primary {
  background: var(--ink); color: var(--ground); border-color: var(--ink);
}
.media-sheet-panel button.ghost {
  border-color: transparent; background: transparent; color: var(--mute); height: 40px; font-weight: 500;
}
.media-sheet-panel button[disabled] { opacity: 0.55; pointer-events: none; }
.lb-media img, .lb-deck img, .lb-card img, .tile img {
  -webkit-touch-callout: none;
}
html:not(.started) .foot { visibility: hidden; } /* the footer waits for the wall, so it never flashes alone at the top */

/* Zoomed single picture grows past its frame to the edges of the screen; the captions step aside, the close button stays */
.lb-media.lb-zfree { overflow: visible; }
.lb-top, .lb-bot { transition: opacity 0.25s ease; }
.lb.lb-zoomed .lb-top { z-index: 3; }
.lb.lb-zoomed .lb-who, .lb.lb-zoomed .lb-bot { opacity: 0; pointer-events: none; }

/* Thin name bar: sits under the top bar once the tall banner has scrolled away. Takes no space in the page. */
.mini { position: sticky; top: var(--barh, 58px); height: 0; z-index: 15; pointer-events: none; }
.mini-in { position: absolute; left: 0; right: 0; top: 0; height: 36px; display: flex; align-items: center; gap: 14px; padding: 0 var(--gutter);
  background: var(--ground); border-bottom: 1px solid var(--line); opacity: 0; transform: translateY(-10px); visibility: hidden;
  transition: opacity 0.2s ease, transform 0.28s cubic-bezier(0.2, 0.8, 0.2, 1), visibility 0s 0.28s; }
@supports (background: color-mix(in srgb, red 50%, transparent)) { .mini-in { background: color-mix(in srgb, var(--ground) 94%, transparent); } }
.mini.on .mini-in { opacity: 1; transform: none; visibility: visible; transition: opacity 0.2s ease, transform 0.28s cubic-bezier(0.2, 0.8, 0.2, 1); }
.mini-n { font: 800 0.95rem/1 var(--f-display); letter-spacing: -0.01em; }
.mini-m { color: var(--mute); }
@media (prefers-reduced-motion: reduce) { .mini-in { transition: none; } }
