/* Dhruv Moghe — shared engine styles. Each edition (assets/ed/*.css) sets the tokens and the look;
   this file only holds mechanics: reset, reveals, transitions, cursor, loader shell, menus, toasts. */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; scroll-behavior: auto; }
body { margin: 0; min-height: 100vh; background: var(--bg, #0a0a0a); color: var(--ink, #eee); font-family: var(--f-body, system-ui, sans-serif); line-height: 1.55; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; overflow-x: hidden; overflow-x: clip; }
html { overflow-x: clip; }
img, svg, canvas, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button, input, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }
h1, h2, h3, h4, p, figure, blockquote, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
::selection { background: var(--acc, #c00); color: var(--acc-ink, #fff); }
:focus-visible { outline: 2px solid var(--acc, #c00); outline-offset: 3px; }

.sr { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.skip { position: fixed; left: 12px; top: -60px; z-index: 10001; padding: 10px 14px; background: var(--ink); color: var(--bg); font: 600 12px/1 var(--f-mono, monospace); transition: top .2s; }
.skip:focus { top: 12px; }
.wrap { width: min(100% - 2 * var(--gut, 32px), var(--max, 1320px)); margin-inline: auto; }
@media (max-width: 640px) { .wrap { width: calc(100% - 32px); } }

/* One motion vocabulary for the whole site (matched to the reference): hr-out for arrivals, hr-inout for page moves. */
:root { --hr-out: cubic-bezier(.16, 1, .3, 1); --hr-inout: cubic-bezier(.76, 0, .24, 1); }

/* Reveal on scroll: rise 22px over 1s; blocks entering together cascade 70ms apart (--bd).
   Editions can vary the motion with [data-rv="left|right|scale|fade|wipe"]. */
html.js [data-rv] { opacity: 0; transform: translate3d(0, 22px, 0); transition: opacity 1s var(--hr-out), transform 1s var(--hr-out), clip-path 1.1s var(--hr-out); transition-delay: calc(var(--d, 0) * 1ms + var(--bd, 0) * 1ms); }
html.js [data-rv="left"] { transform: translate3d(-34px, 0, 0); }
html.js [data-rv="right"] { transform: translate3d(34px, 0, 0); }
html.js [data-rv="scale"] { transform: scale(.94); }
html.js [data-rv="fade"] { transform: none; }
html.js [data-rv="wipe"] { opacity: 1; transform: none; clip-path: inset(0 0 100% 0); }
html.js [data-rv].in { opacity: 1; transform: none; clip-path: inset(0 0 0 0); }

/* Split headings: masked lines rise in, characters track in from tighter spacing. */
.split .ln { display: block; overflow: clip; padding: .12em .1em .16em; margin: -.12em -.1em -.16em; }
.split-inl .ln { display: inline-block; vertical-align: top; }
.split .ln-in, .split .w, .split .ch { display: inline-block; }
.split .w { white-space: nowrap; }
html.js .split .ln-in { transform: translate3d(0, 128%, 0); transition: transform 1.25s var(--hr-out) calc(var(--d, 0) * 1ms + var(--l, 0) * 80ms); }
html.js .split .ch { transform: translate3d(var(--x, 0), 0, 0); transition: transform 1.4s var(--hr-out) calc(var(--d, 0) * 1ms + 60ms + var(--l, 0) * 80ms + var(--c, 0) * 8ms); }
html.js .split.in .ln-in, html.js .split.in .ch { transform: none; }
.split-mask { display: inline-block; overflow: clip; vertical-align: bottom; padding-bottom: .04em; }

/* Smooth scroll owns the wheel; native behaviour stays for touch, keys and the scrollbar. */
html.smooth { scroll-behavior: auto !important; }

/* Looping decorations pause while their section is off screen (saves frames while scrolling). */
.is-off, .is-off * { animation-play-state: paused !important; }

/* Nav tucks away while reading down and returns on the way up. */
.nav.tucked { transform: translate3d(0, -101%, 0); }

/* Horizontal pinned deck: a tall runway; the sticky panel slides its track sideways. */
.hp-count, .hp-bar { display: none; }
.hp-run.hp-on .hp-stick { position: sticky; top: 0; height: 100vh; display: flex; flex-direction: column; justify-content: center; overflow: clip; padding-top: var(--nav-h, 64px); }
.hp-run.hp-on .hp-head { display: flex; justify-content: space-between; align-items: baseline; gap: 20px; }
.hp-run.hp-on .hp-head > * { margin-top: 0; margin-bottom: 22px; }
.hp-run.hp-on .hp-count { display: block; font: 500 11px/1 var(--f-mono, monospace); letter-spacing: .22em; color: var(--muted); }
.hp-run.hp-on .hp-track { display: flex; align-items: stretch; gap: var(--hp-gap, 22px); border-top: 0; will-change: translate; }
.hp-run.hp-on .hp-track > * { flex: 0 0 var(--hp-w, min(500px, 70vw)); margin: 0; }
.hp-lbl { font: 500 11px/1.4 var(--f-mono, monospace); letter-spacing: .22em; text-transform: uppercase; color: var(--acc); }
.hp-run:not(.hp-on) .hp-lbl { display: none; }
.cs-deck.hp-on .hp-track > * { display: grid; grid-template-columns: 1fr; align-content: start; gap: 16px; padding: 30px 28px; border: 1px solid var(--line); background: var(--bg2, var(--bg)); }

/* Stacking cards: each card pins under the nav and the next one slides over it, pushing it back. */
[data-stack].stack-on > * { position: sticky; top: calc(var(--nav-h, 64px) + 18px + var(--si, 0) * 14px); transform-origin: 50% 0; }
[data-stack].stack-on > *::after { content: ''; position: absolute; inset: 0; background: #000; opacity: calc(var(--stk, 0) * .5); pointer-events: none; }
.hp-run.hp-on .hp-bar { display: block; height: 2px; margin-top: 30px; background: var(--line); position: relative; overflow: hidden; }
.hp-run.hp-on .hp-bar i { position: absolute; inset: 0; background: var(--acc); transform-origin: left; transform: scaleX(var(--hp, 0)); }

/* Roll links: two copies of the label; the second slides up on hover. */
.roll { position: relative; display: inline-flex; overflow: hidden; vertical-align: middle; }
.roll > span { display: block; transition: transform .5s var(--ease, cubic-bezier(.16,1,.3,1)); }
.roll > span + span { position: absolute; left: 0; top: 0; transform: translateY(110%); }
.roll:hover > span:first-child, a:hover > .roll > span:first-child, button:hover > .roll > span:first-child { transform: translateY(-110%); }
.roll:hover > span + span, a:hover > .roll > span + span, button:hover > .roll > span + span { transform: translateY(0); }

/* Page curtain (between pages). */
#dm-curtain { position: fixed; inset: 0; z-index: 9500; pointer-events: none; background: var(--curtain, var(--acc, #111)); transform: translate3d(0, 101%, 0); }
#dm-curtain.cover { transform: none; transition: transform .72s var(--hr-inout); pointer-events: auto; }
html.curtained #dm-curtain { transform: none; }
html.curtained #dm-curtain.lift { transform: translate3d(0, -101%, 0); transition: transform .9s var(--hr-inout) .05s; }
#dm-curtain i { transition: opacity .4s; }
#dm-curtain.lift i { opacity: 0; }
#dm-curtain i { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); font: 600 11px/1 var(--f-mono, monospace); letter-spacing: .3em; text-transform: uppercase; color: var(--curtain-ink, var(--acc-ink, #fff)); opacity: .8; font-style: normal; }

/* Edition loader shell. Each edition fills .dm-loader with its own scene. */
.dm-loader { position: fixed; inset: 0; z-index: 9000; display: grid; place-items: center; background: var(--loader-bg, var(--bg)); color: var(--ink); clip-path: inset(0 0 0 0); transition: clip-path .95s var(--hr-inout) .08s, visibility 0s 1.05s; }
.dm-loader > * { transition: transform .9s var(--hr-inout), opacity .55s ease; }
.dm-loader.out { clip-path: inset(0 0 100% 0); visibility: hidden; }
.dm-loader.out > * { transform: translate3d(0, -7vh, 0); opacity: 0; }
.dm-loader .ld-skip { position: absolute; right: 18px; bottom: 18px; font: 500 10px/1 var(--f-mono, monospace); letter-spacing: .25em; text-transform: uppercase; opacity: .55; padding: 10px; color: inherit; }
html.loading body { overflow: hidden; }

/* Custom cursor (fine pointers only). */
.dm-cur { position: fixed; left: 0; top: 0; z-index: 9800; pointer-events: none; display: none; }
@media (hover: hover) and (pointer: fine) { html.has-cur .dm-cur { display: block; } html.has-cur, html.has-cur a, html.has-cur button, html.has-cur [data-cursor] { cursor: none; } html.has-cur input, html.has-cur textarea { cursor: text; } }
.dm-cur-dot, .dm-cur-ring { position: fixed; left: 0; top: 0; border-radius: 50%; transform: translate3d(-100px, -100px, 0); will-change: transform; }
.dm-cur-dot { width: 6px; height: 6px; margin: -3px 0 0 -3px; background: var(--cur, var(--acc)); }
.dm-cur-ring { width: 34px; height: 34px; margin: -17px 0 0 -17px; border: 1px solid var(--cur-ring, var(--ink)); opacity: .55; transition: width .35s var(--ease), height .35s var(--ease), margin .35s var(--ease), opacity .3s, background .3s, border-color .3s, border-radius .35s; display: grid; place-items: center; }
.dm-cur.hot .dm-cur-ring { width: 64px; height: 64px; margin: -32px 0 0 -32px; opacity: 1; background: color-mix(in srgb, var(--acc) 14%, transparent); border-color: var(--acc); }
.dm-cur-label { font: 600 9px/1 var(--f-mono, monospace); letter-spacing: .18em; text-transform: uppercase; color: var(--ink); opacity: 0; transition: opacity .2s; white-space: nowrap; }
.dm-cur.hot .dm-cur-label { opacity: 1; }

/* Floating controls: edition switch + sound. */
.dm-fab { position: fixed; left: 18px; bottom: 18px; z-index: 900; display: flex; gap: 8px; align-items: center; }
.dm-fab button { width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center; background: var(--fab-bg, color-mix(in srgb, var(--bg) 80%, var(--ink))); color: var(--fab-ink, var(--ink)); border: 1px solid var(--line, rgba(255,255,255,.15)); box-shadow: 0 8px 24px rgba(0,0,0,.25); transition: transform .3s var(--ease), background .3s; }
.dm-fab button:hover { transform: scale(1.08); }
.dm-fab .fab-ed { background: var(--acc); color: var(--acc-ink); border-color: transparent; }
.dm-fab svg { width: 16px; height: 16px; }
.dm-fab .fab-tip { font: 600 10px/1 var(--f-mono, monospace); letter-spacing: .2em; text-transform: uppercase; color: var(--ink); opacity: 0; transform: translateX(-6px); transition: .3s; pointer-events: none; background: var(--bg); padding: 6px 8px; }
.dm-fab:hover .fab-tip { opacity: .9; transform: none; }
.fab-snd .bars { display: flex; gap: 2px; align-items: flex-end; height: 12px; }
.fab-snd .bars i { width: 2px; height: 4px; background: currentColor; }
.fab-snd.on .bars i { animation: dmEq .9s ease-in-out infinite alternate; }
.fab-snd.on .bars i:nth-child(2) { animation-delay: -.3s; } .fab-snd.on .bars i:nth-child(3) { animation-delay: -.6s; }
@keyframes dmEq { from { height: 3px; } to { height: 12px; } }

/* Edition picker sheet. */
.dm-picker { position: fixed; inset: 0; z-index: 9400; display: grid; place-items: center; background: rgba(0,0,0,.72); backdrop-filter: blur(6px); opacity: 0; visibility: hidden; transition: opacity .35s, visibility 0s .35s; }
.dm-picker.open { opacity: 1; visibility: visible; transition: opacity .35s; }
.dm-picker-in { width: min(560px, calc(100% - 32px)); background: #0d0c0b; color: #efe9e1; border: 1px solid rgba(255,255,255,.12); padding: 22px; font-family: 'JetBrains Mono', 'IBM Plex Mono', ui-monospace, monospace; transform: translateY(14px); transition: transform .45s var(--ease, ease); }
.dm-picker.open .dm-picker-in { transform: none; }
.dm-picker-in h2 { font-size: 11px; letter-spacing: .3em; text-transform: uppercase; opacity: .6; font-weight: 500; margin-bottom: 12px; display: flex; justify-content: space-between; }
.dm-picker a { display: grid; grid-template-columns: 34px 1fr auto; gap: 10px; align-items: baseline; padding: 12px 6px; border-top: 1px solid rgba(255,255,255,.08); font-size: 13px; letter-spacing: .08em; text-transform: uppercase; transition: background .2s, padding .3s; }
.dm-picker a:hover, .dm-picker a:focus-visible { background: rgba(255,255,255,.05); padding-left: 12px; }
.dm-picker a small { opacity: .5; font-size: 10px; }
.dm-picker a b { font-weight: 500; }
.dm-picker a[aria-current] b::after { content: ' ●'; color: #e2483d; }
.dm-picker .pk-foot { display: flex; justify-content: space-between; gap: 10px; margin-top: 12px; font-size: 10px; letter-spacing: .2em; text-transform: uppercase; opacity: .6; }
.dm-picker .pk-foot a { display: inline; padding: 0; border: 0; font-size: inherit; }

/* Toasts. */
.dm-toasts { position: fixed; right: 18px; bottom: 18px; z-index: 950; display: grid; gap: 10px; pointer-events: none; }
.dm-toast { pointer-events: auto; min-width: 240px; max-width: 340px; padding: 12px 14px; background: var(--toast-bg, var(--bg)); color: var(--ink); border: 1px solid var(--acc); box-shadow: 0 14px 40px rgba(0,0,0,.35); font: 500 12px/1.4 var(--f-mono, monospace); animation: dmToastIn .5s var(--ease) both; }
.dm-toast.bye { animation: dmToastOut .4s ease both; }
.dm-toast b { display: block; font-size: 10px; letter-spacing: .22em; text-transform: uppercase; color: var(--acc); margin-bottom: 4px; }
@keyframes dmToastIn { from { opacity: 0; transform: translateY(16px) scale(.97); } }
@keyframes dmToastOut { to { opacity: 0; transform: translateX(30px); } }

/* Marquee. */
.mq { overflow: hidden; white-space: nowrap; }
.mq-track { display: inline-flex; animation: dmMq var(--mq, 50s) linear infinite; }
.mq-track > * { flex: none; }
.mq.rev .mq-track { animation-direction: reverse; }
@keyframes dmMq { to { transform: translateX(-50%); } }

/* Full-screen menu shell. */
.dm-menu { position: fixed; inset: 0; z-index: 9300; visibility: hidden; pointer-events: none; }
.dm-menu.open { visibility: visible; pointer-events: auto; }
body.menu-open { overflow: hidden; }

/* Continue-to-next-page block: a tall runway with a sticky panel and a progress bar. */
.dm-continue { position: relative; height: 190vh; }
.dm-continue > .cont-pin { position: sticky; top: 0; height: 100vh; display: grid; place-items: center; text-align: center; padding: 0 20px; }
.cont-bar { width: min(320px, 70vw); height: 2px; background: var(--line); margin: 22px auto 10px; position: relative; overflow: hidden; }
.cont-bar i { position: absolute; inset: 0; background: var(--acc); transform-origin: left; transform: scaleX(var(--p, 0)); }

/* Exhibit charts (shared by every edition; colours come from tokens). */
.ex { color: var(--ink); }
.ex svg { width: 100%; height: auto; overflow: visible; }
.ex .ex-axis { stroke: currentColor; stroke-opacity: .25; stroke-width: 1; fill: none; }
.ex .ex-grid { stroke: currentColor; stroke-opacity: .1; stroke-dasharray: 2 4; }
.ex .ex-a { fill: var(--ex-a, var(--acc)); }
.ex .ex-b { fill: var(--ex-b, currentColor); fill-opacity: .55; }
.ex .ex-line { fill: none; stroke: var(--ex-a, var(--acc)); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.ex .ex-line2 { fill: none; stroke: currentColor; stroke-opacity: .5; stroke-width: 1.5; stroke-dasharray: 4 5; }
.ex text { fill: currentColor; font: 500 10px var(--f-mono, monospace); letter-spacing: .06em; }
.ex .ex-big { font: 700 15px var(--f-mono, monospace); }
.ex .ex-node { fill: var(--bg); stroke: currentColor; stroke-opacity: .5; }
.ex .ex-node.hot { stroke: var(--ex-a, var(--acc)); stroke-opacity: 1; }
.ex .ex-tile { fill: color-mix(in srgb, currentColor 7%, transparent); stroke: currentColor; stroke-opacity: .2; }
html.js .ex [data-grow] { transform-box: fill-box; transform-origin: bottom; transform: scaleY(0); transition: transform 1.2s var(--ease) calc(var(--d, 0) * 1ms); }
html.js .ex.in [data-grow] { transform: none; }
html.js .ex [data-draw] { stroke-dasharray: var(--len, 1200); stroke-dashoffset: var(--len, 1200); transition: stroke-dashoffset 1.8s var(--ease) calc(var(--d, 0) * 1ms); }
html.js .ex.in [data-draw] { stroke-dashoffset: 0; }
html.js .ex [data-pop] { opacity: 0; transition: opacity .6s calc(var(--d, 0) * 1ms); }
html.js .ex.in [data-pop] { opacity: 1; }

/* Monogram portrait (used until a photo is added). */
.mono-portrait { position: relative; aspect-ratio: 4 / 5; display: grid; place-items: center; overflow: hidden; background: var(--mono-bg, color-mix(in srgb, var(--ink) 8%, var(--bg))); color: var(--mono-ink, var(--ink)); }
.mono-portrait svg { width: 62%; height: auto; }

/* Odometer drum digits. */
.drum { display: inline-flex; overflow: hidden; height: 1em; line-height: 1; vertical-align: baseline; }
.drum .dcol { display: flex; flex-direction: column; transition: transform 1.6s cubic-bezier(.2,.9,.1,1); transition-delay: calc(var(--i, 0) * 90ms); }
.drum .dcol span { height: 1em; display: block; }

html.static *, html.static *::before, html.static *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; transition-delay: 0s !important; }
html.static [data-rv], html.static .split .ch, html.static .split .ln-in, html.static .ex [data-grow], html.static .ex [data-pop] { opacity: 1 !important; transform: none !important; clip-path: none !important; }
html.static .ex [data-draw] { stroke-dashoffset: 0 !important; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
  html.js [data-rv], html.js .split .ch, html.js .split .ln-in { opacity: 1; transform: none; clip-path: none; }
}

/* Phones and tablets: live blurs, blend modes and a clip-path wipe repaint the whole screen on every
   frame, which is what dropped frames while scrolling and opening the menu. Solid fills and a
   transform slide look the same and stay on the GPU. */
@media (hover: none), (pointer: coarse) {
  .nav, .nav.scrolled, .nav-in, .dm-picker { -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }
  .nav.scrolled { background: var(--bg); }
  .dm-picker { background: rgba(0, 0, 0, .88); }
  .mn-panel { clip-path: none !important; transform: translate3d(0, -100%, 0); transition: transform .7s cubic-bezier(.7, 0, .2, 1) !important; will-change: transform; }
  .dm-menu.open .mn-panel { transform: none; }
  .lg-gloss { mix-blend-mode: normal; opacity: .3; }
  /* sound bars: same 3px-12px bounce, drawn by scaling from the bottom so it never re-lays out the page */
  .fab-snd .bars i { height: 12px; transform: scaleY(.333); transform-origin: 50% 100%; }
  .fab-snd.on .bars i { animation-name: dmEqT; }
}
@keyframes dmEqT { from { transform: scaleY(.25); } to { transform: none; } }
