/* ============================================================
   TOKENS
   ============================================================ */
:root {
  --bg: #f3f3f0;
  --fg: #111114;
  --fg-rgb: 17, 17, 20;
  --muted: #7a7a82;
  --line: rgba(17, 17, 20, .12);
  --accent: #2337ff;
  --accent-rgb: 35, 55, 255;
  --bar-bg: rgba(255, 255, 255, .72);
  --card: #ffffff;

  --font: 'Instrument Sans', system-ui, -apple-system, sans-serif;
  --mono: 'Space Grotesk', system-ui, sans-serif;   /* supporting text: labels, meta, bars */

  --ease: cubic-bezier(.22, 1, .36, 1);
  --ease-io: cubic-bezier(.65, 0, .35, 1);
  --t-hover: .25s;   /* hover / system responses */
  --t-press: .16s;   /* press feedback */
  --pad: clamp(16px, 3vw, 40px);
  --bar-h: 48px;
}

:root[data-theme="dark"] {
  --bg: #0a0a0c;
  --fg: #ececec;
  --fg-rgb: 236, 236, 236;
  --muted: #7c7c86;
  --line: rgba(255, 255, 255, .12);
  --accent: #3d5bff;
  --accent-rgb: 61, 91, 255;
  --bar-bg: rgba(20, 20, 24, .72);
  --card: #141418;
}

/* ============================================================
   BASE
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Hide native cursor once the custom one is active */
html.has-cursor, html.has-cursor * { cursor: none !important; }

a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; }
ul { list-style: none; margin: 0; padding: 0; }
figure { margin: 0; }

.mono {
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 0;
}

::selection { background: var(--accent); color: #fff; }

/* The label name is always bold, wherever it appears (see render() in js/i18n.js) */
.brand { font-weight: 700; }

/* ============================================================
   FLOATING BARS (top nav + bottom footer)
   ============================================================ */
.bar {
  position: fixed;
  left: 12px;
  right: 12px;
  z-index: 50;
  height: var(--bar-h);
  padding: 0 18px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bar-bg);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  font-family: var(--mono);
  font-size: 13px;
  transition: background .3s var(--ease), border-color .3s var(--ease);
}
.bar--top { top: 12px; }
.bar--bottom { bottom: 12px; }

.bar__brand { font-weight: 600; }

.bar__nav { display: flex; gap: 28px; }
.bar__nav a {
  position: relative;
  display: inline-block;
  padding: 6px 2px;
}
/* underline that grows from the left, shrinks to the right */
.bar__nav a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--t-hover) var(--ease);
}

.bar__clock { font-variant-numeric: tabular-nums; }

/* Right end of the top bar: language + theme */
.bar__end { display: flex; align-items: center; gap: 18px; }

/* Language switch — deliberately quiet: muted text, active one in --fg */
.lang { display: flex; align-items: center; gap: 6px; color: var(--muted); }
.lang button {
  padding: 6px 2px;
  color: var(--muted);
  transition: color var(--t-hover) var(--ease);
}
.lang button[aria-pressed="true"] { color: var(--fg); }

/* Theme toggle */
.theme-toggle {
  position: relative;
  width: 40px;
  height: 22px;
  border-radius: 999px;
  background: var(--fg);
  transition: background .3s var(--ease), transform var(--t-press) var(--ease);
}
.theme-toggle:active { transform: scale(.94); }
.theme-toggle__knob {
  position: absolute;
  top: 3px; left: 3px;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--bg);
  transition: transform .2s var(--ease), background .3s var(--ease);
}
:root[data-theme="dark"] .theme-toggle__knob { transform: translateX(18px); }

/* ============================================================
   CUSTOM CURSOR
   ============================================================ */
.cursor {
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  display: none;
}
html.has-cursor .cursor { display: block; }

.cursor__dot,
.cursor__ring {
  position: absolute;
  top: 0; left: 0;
  border-radius: 50%;
  will-change: transform;
}
.cursor__dot {
  width: 6px; height: 6px;
  margin: -3px 0 0 -3px;
  background: var(--fg);
  transition: opacity .2s, background .3s var(--ease);
}
.cursor__ring {
  width: 32px; height: 32px;
  margin: -16px 0 0 -16px;
  display: grid;
  place-items: center;
}
/* The visible disc. Only transform / opacity / colour animate — never size. */
.cursor__fill {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid var(--fg);
  transition: transform .25s var(--ease), background .25s var(--ease), border-color .25s var(--ease);
}
.cursor__label {
  position: relative;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .02em;
  color: var(--bg);
  opacity: 0;
  transform: scale(.8);
  transition: opacity .2s var(--ease), transform .25s var(--ease);
}

/* States are set by js/cursor.js */
.cursor.is-link .cursor__fill {
  transform: scale(1.5);
  background: rgba(var(--accent-rgb), .12);
  border-color: transparent;
}
.cursor.is-label .cursor__dot { opacity: 0; }
.cursor.is-label .cursor__fill {
  transform: scale(2.25);
  background: var(--fg);
  border-color: transparent;
}
.cursor.is-label .cursor__label { opacity: 1; transform: scale(1); }
.cursor.is-hidden { opacity: 0; }

/* ============================================================
   LAYOUT HELPERS
   ============================================================ */
section {
  position: relative;
  padding: calc(var(--bar-h) + 40px) var(--pad);
}

.section-head {
  display: flex;
  justify-content: space-between;
  color: var(--muted);
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 40px;
}

/* Split-line reveal: each .line clips its inner span */
[data-reveal] .line {
  display: block;
  overflow: hidden;
  /* Tight line-height would clip descenders (the g in "Designer"): give the
     clip box room below and pull the next line back up by the same amount. */
  padding-bottom: .14em;
  margin-bottom: -.14em;
}
[data-reveal] .line > span {
  display: block;
  transform: translateY(110%);
  transition: transform .75s var(--ease);
}
[data-reveal].in .line > span { transform: translateY(0); }
[data-reveal].in .line:nth-child(2) > span { transition-delay: .08s; }
[data-reveal].in .line:nth-child(3) > span { transition-delay: .16s; }
[data-reveal].in .line:nth-child(4) > span { transition-delay: .24s; }
[data-reveal].in .line:nth-child(5) > span { transition-delay: .32s; }
[data-reveal].in .line:nth-child(6) > span { transition-delay: .40s; }

/* Scroll reveal for blocks (js/reveal.js adds .in once, on first entry).
   Hidden state is scoped to html.js so nothing disappears without JS.
   - [data-reveal-up]       the element itself rises 14px + fades in
   - [data-reveal-stagger]  each direct child does the same, 50ms apart   */
.js [data-reveal-up],
.js [data-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.js [data-reveal-stagger] > * { transition-delay: calc(var(--i, 0) * 50ms); }
.js [data-reveal-up].in,
.js [data-reveal-stagger].in > * { opacity: 1; transform: none; }

/* ============================================================
   HERO
   ============================================================ */
.hero {
  min-height: 100svh;
  padding: 0;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}
.hero__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
.hero__copy {
  position: relative;
  z-index: 1;
  padding: 0 var(--pad) calc(var(--bar-h) + 28px);
  pointer-events: none;
}
.hero__title {
  margin: 0 0 20px;
  font-size: clamp(40px, 7vw, 112px);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -.035em;
}
.hero__hint {
  color: var(--muted);
  margin: 0;
}
.hero__hint #heroMode { color: var(--fg); }

/* ============================================================
   WORK LIST
   ============================================================ */
.work__list { border-top: 1px solid var(--line); }

.work__item a {
  display: grid;
  grid-template-columns: 60px 1fr auto 80px;
  align-items: baseline;
  gap: 24px;
  padding: 26px 0;
  border-bottom: 1px solid var(--line);
  transition: opacity var(--t-hover) var(--ease);
}

.work__idx { color: var(--muted); transition: color var(--t-hover); }

.work__name {
  font-size: clamp(24px, 4vw, 56px);
  font-weight: 500;
  letter-spacing: -.03em;
  line-height: 1;
  display: inline-block;
  transition: transform .28s var(--ease);
}

.work__meta { color: var(--muted); text-align: right; }
.work__year { color: var(--muted); text-align: right; }

/* Floating preview */
.preview {
  position: fixed;
  top: 0; left: 0;
  z-index: 40;
  width: 300px;
  aspect-ratio: 4 / 3;
  pointer-events: none;
  will-change: transform;
  opacity: 0;
  transition: opacity .25s var(--ease);
}
.preview.is-on { opacity: 1; }

.preview__stack {
  position: absolute;
  inset: 0;
  border-radius: 14px;
  overflow: hidden;
  transform: scale(.85) rotate(-4deg);
  transition: transform .35s var(--ease);
  box-shadow: 0 30px 60px -20px rgba(0, 0, 0, .35);
}
.preview.is-on .preview__stack { transform: scale(1) rotate(0deg); }

.preview__card {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #fff;
  clip-path: inset(0 0 100% 0);
  transition: clip-path .4s var(--ease);
}
.preview__card.is-active { clip-path: inset(0 0 0 0); z-index: 1; }
.preview__card.was-active { clip-path: inset(0 0 0 0); z-index: 0; }
.preview__card span { font-size: 64px; letter-spacing: -.04em; mix-blend-mode: overlay; }
.preview__card img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Placeholder "skins" — swap for <img> when you have real project shots */
.preview__card[data-skin="a"] { background: linear-gradient(135deg, #2337ff, #7fb0ff); }
.preview__card[data-skin="b"] { background: repeating-linear-gradient(0deg, #111 0 6px, #333 6px 12px); }
.preview__card[data-skin="c"] { background: radial-gradient(circle at 30% 30%, #ffb347, #ff5e62 70%); }
.preview__card[data-skin="d"] { background: conic-gradient(from 90deg, #0f0, #0aa, #05f, #0f0); }
.preview__card[data-skin="e"] { background: linear-gradient(160deg, #e9e4d9, #b8ada0); color: #111; }

/* ============================================================
   ABOUT (sticker trail zone)
   ============================================================ */
.about__text {
  margin: 0;
  max-width: 40ch;
  font-size: clamp(24px, 3.6vw, 56px);
  font-weight: 500;
  letter-spacing: -.03em;
  line-height: 1.15;
  position: relative;
  z-index: 1;
}
/* Sticker spawned by js/trail.js */
.sticker {
  position: fixed;
  z-index: 30;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -50%) scale(.6) rotate(var(--rot, 0deg));
  animation: sticker-in .3s var(--ease) forwards, sticker-out .4s var(--ease) forwards 1.1s;
}
/* The logo, tinted: a coloured box masked by the logo shape (see js/trail.js) */
.sticker--logo {
  background: var(--c, var(--accent));
  -webkit-mask: var(--trail-logo) center / contain no-repeat;
  mask: var(--trail-logo) center / contain no-repeat;
}
@keyframes sticker-in  { to { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(var(--rot, 0deg)); } }
@keyframes sticker-out { to { transform: translate(-50%, -50%) scale(.4) rotate(calc(var(--rot, 0deg) + 20deg)); opacity: 0; } }

/* ============================================================
   CONTACT
   ============================================================ */
.contact { padding-bottom: calc(var(--bar-h) + 80px); }

.contact__email {
  position: relative;
  display: block;
  margin: 0 0 56px;
  font-size: clamp(28px, 6.5vw, 104px);
  font-weight: 500;
  letter-spacing: -.04em;
  line-height: 1;
  text-align: left;
  transition: transform var(--t-press) var(--ease);
}
.contact__email:active { transform: scale(.985); }
.contact__email-text {
  display: block;
  transition: transform .22s var(--ease), opacity .2s var(--ease);
}
.contact__email-feedback {
  position: absolute;
  left: 0; top: 50%;
  transform: translateY(-50%) translateY(12px);
  color: var(--accent);
  opacity: 0;
  transition: transform .22s var(--ease), opacity .2s var(--ease);
}
.contact__email.is-copied .contact__email-text { transform: translateY(-14px); opacity: .25; }
.contact__email.is-copied .contact__email-feedback { transform: translateY(-50%); opacity: 1; }

.contact__links { display: flex; flex-wrap: wrap; gap: 8px 32px; margin-bottom: 96px; }
.contact__links a { display: inline-block; padding: 6px 0; font-size: 14px; }

/* Marquee */
.marquee {
  overflow: hidden;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 14px 0;
  font-size: clamp(18px, 3vw, 40px);
  letter-spacing: -.02em;
  white-space: nowrap;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track {
  display: inline-flex;
  animation: marquee 22s linear infinite;
}
@keyframes marquee { to { transform: translateX(-50%); } }

/* ============================================================
   PROJECT PAGE
   ============================================================ */
.page-project main { animation: page-in .45s var(--ease) both; }
@keyframes page-in { from { opacity: 0; transform: translateY(12px); } }

.project-head { padding-bottom: 0; }

.project-title {
  margin: 0 0 48px;
  font-size: clamp(64px, 14vw, 220px);
  font-weight: 500;
  line-height: .98;
  letter-spacing: -.045em;
}

.project-meta {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}
.project-meta__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px 24px;
  margin: 0;
}
.project-meta__grid dt { color: var(--muted); margin-bottom: 4px; }
.project-meta__grid dd { margin: 0; }
.project-meta__text {
  margin: 0;
  max-width: 44ch;
  font-size: clamp(16px, 1.6vw, 22px);
  line-height: 1.35;
  letter-spacing: -.01em;
}

/* Gallery layout */
.gallery { display: flex; flex-direction: column; gap: clamp(24px, 6vw, 96px); }

.frame-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(16px, 3vw, 40px);
  align-items: start;
}
.frame-row--reverse .frame:first-child { order: 2; }
.frame--offset { margin-top: clamp(40px, 10vw, 160px); }
.frame--wide { width: min(100%, 720px); margin-inline: auto; }
.frame--center { width: min(100%, 560px); margin-inline: auto; }

/* A single photo */
.frame {
  position: relative;
  /* clip, not hidden: overflow:hidden makes the figure a scroll container and
     the view() timeline below would measure against it instead of the viewport */
  overflow: clip;
  border-radius: 6px;
  background: var(--card);
}

.frame img {
  display: block;
  width: 100%;
  height: auto;
}

/* Card entrance, tied to the scroll position.
   As a frame comes up from the bottom of the viewport it grows from 80% to
   its real size and fades in. Scrolling back shrinks it again. Runs on the
   compositor via a view() timeline; no JS involved. */
@supports (animation-timeline: view()) {
  .frame {
    animation: frame-in linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 100%;
  }
}
@keyframes frame-in {
  from { transform: scale(.8); opacity: 0; }
  35%  { opacity: 1; }
  to   { transform: scale(1); opacity: 1; }
}

/* Fallback (no scroll-driven animations): one-shot grow when the frame
   enters, driven by the .in class from js/gallery.js. */
@supports not (animation-timeline: view()) {
  .frame {
    transform: scale(.9);
    opacity: 0;
    transition: transform .9s var(--ease), opacity .6s var(--ease);
  }
  .frame.in { transform: scale(1); opacity: 1; }
}

/* Film-edge caption slides up on hover */
.frame figcaption {
  position: absolute;
  left: 14px; bottom: 12px;
  padding: 5px 9px;
  border-radius: 999px;
  background: var(--fg);
  color: var(--bg);
  transform: translateY(140%);
  transition: transform var(--t-hover) var(--ease);
}

/* Project film (opens the page). Muted autoplay + a pill to turn sound on. */
.project-film { padding-bottom: 0; }
.film {
  position: relative;
  border-radius: 8px;
  overflow: clip;
  background: #000;
}
.film__video { display: block; width: 100%; height: auto; }
.film__controls {
  position: absolute;
  right: 14px; bottom: 12px;
  display: flex;
  gap: 8px;
}
.film__btn {
  padding: 7px 12px;
  border-radius: 999px;
  background: rgba(10, 10, 12, .72);
  color: #fff;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: transform var(--t-press) var(--ease), background var(--t-hover) var(--ease);
}
.film__btn:active { transform: scale(.96); }
/* In fullscreen the figure fills the screen; keep the video centred and letterboxed */
.film:fullscreen { border-radius: 0; display: grid; place-items: center; }
/* The custom cursor lives outside the fullscreen subtree: bring the native one back */
.film:fullscreen, .film:fullscreen * { cursor: auto !important; }
.film:fullscreen .film__btn { cursor: pointer !important; }
.film:fullscreen .film__video { width: 100%; height: 100%; object-fit: contain; }
.film__sound-on { display: none; }
.film.is-sound .film__sound-off { display: none; }
.film.is-sound .film__sound-on { display: inline; }

/* Scene loops inside gallery cards */
.frame--video video { display: block; width: 100%; height: auto; background: #000; }

/* Long titles: the reveal clips each line, so a line that wraps gets cut in
   half. Keep every line on one row and size the type so the longest one fits.
   The longest line here needs 8.1x the font size in width, so 10.5vw leaves
   room for the page padding at any viewport. */
.project-title--long { font-size: clamp(26px, 10.5vw, 150px); }
.project-title--long .line > span { white-space: nowrap; }

/* Carousel: images that form one continuous strip, slid sideways.
   No gap between them on purpose, so the picture reads as a single one. */
.carousel {
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
  overscroll-behavior-x: contain;
  border-radius: 8px;
  background: var(--card);
}
.carousel::-webkit-scrollbar { display: none; }
.carousel:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.carousel.is-dragging { cursor: grabbing; }

.carousel__track {
  display: flex;
  height: min(72vh, 760px);
  width: max-content;
}
.carousel__track img {
  flex: none;
  height: 100%;
  width: auto;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
}

/* Thin bar showing how far along the strip you are */
.carousel__progress {
  height: 2px;
  margin-top: 12px;
  background: var(--line);
  border-radius: 2px;
  overflow: hidden;
}
.carousel__progress span {
  display: block;
  height: 100%;
  background: var(--fg);
  transform-origin: left;
  transform: scaleX(.04);
}

@media (max-width: 720px) {
  .carousel__track { height: min(60vh, 520px); }
}

/* Next project */
.project-next {
  padding-top: clamp(64px, 12vw, 160px);
  padding-bottom: calc(var(--bar-h) + 80px);
  border-top: 1px solid var(--line);
  margin-top: clamp(48px, 8vw, 120px);
}
.project-next > .mono { color: var(--muted); display: block; margin-bottom: 16px; }
.project-next__link {
  display: inline-flex;
  align-items: baseline;
  gap: .3em;
  font-size: clamp(40px, 8vw, 120px);
  font-weight: 500;
  letter-spacing: -.04em;
  line-height: 1;
}
.project-next__arrow {
  display: inline-block;
  transition: transform var(--t-hover) var(--ease);
}

/* Lightbox */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: 6vh 6vw;
  background: rgba(10, 10, 12, .94);
  opacity: 0;
  pointer-events: none;
  transition: opacity .35s var(--ease);
}
.lightbox.is-open { opacity: 1; pointer-events: auto; }
.lightbox__img {
  max-width: 100%;
  max-height: 88vh;
  border-radius: 4px;
  /* --tx/--ty are written by gallery.js on mousemove; the transition smooths them */
  transform: scale(.97) translate(var(--tx, 0px), var(--ty, 0px));
  transition: opacity .15s var(--ease), transform .3s var(--ease);
  will-change: transform;
}
.lightbox.is-open .lightbox__img { transform: scale(1) translate(var(--tx, 0px), var(--ty, 0px)); }
.lightbox__counter {
  position: absolute;
  left: 50%; bottom: 24px;
  transform: translateX(-50%);
  color: #fff;
  opacity: .7;
}

@media (max-width: 720px) {
  .project-meta { grid-template-columns: 1fr; gap: 24px; }
  .frame-row { grid-template-columns: 1fr; }
  .frame-row--reverse .frame:first-child { order: 0; }
  .frame--offset { margin-top: 0; }
  .lightbox { padding: 4vh 4vw; }
}

/* ============================================================
   THEME SWAP (View Transitions circular reveal)
   ============================================================ */
::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}
::view-transition-new(root) { z-index: 1; }
::view-transition-old(root) { z-index: 0; }

/* Copy that depends on the input device */
.only-coarse { display: none; }
@media (hover: none) {
  .only-fine { display: none; }
  .only-coarse { display: inline; }
}

/* ============================================================
   HOVER MOTION — real pointers only (touch fires a sticky :hover on tap)
   ============================================================ */
@media (hover: hover) and (pointer: fine) {
  .bar__nav a:hover::after { transform: scaleX(1); transform-origin: left; }
  .work__list:hover .work__item:not(:hover) a { opacity: .3; }
  .work__item:hover .work__idx { color: var(--accent); }
  .work__item:hover .work__name { transform: translateX(14px); }
  .frame:hover figcaption { transform: translateY(0); }
  .project-next__link:hover .project-next__arrow { transform: translateX(.25em); }
  .marquee:hover .marquee__track { animation-play-state: paused; }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
/* Desktop hero: title on one line, smaller, so the logo canvas above it gets
   most of the viewport height (ascii.js fits the logo into the free band). */
@media (min-width: 1024px) {
  .hero__title { font-size: clamp(40px, 4.6vw, 72px); }
  .hero__title .line { display: inline-block; }
}

@media (max-width: 720px) {
  .bar { padding: 0 14px; font-size: 12px; }
  .bar__nav { gap: 16px; }
  .bar__brand { display: none; }

  .work__item a {
    grid-template-columns: 40px 1fr;
    grid-template-rows: auto auto;
    gap: 6px 16px;
    padding: 20px 0;
  }
  .work__meta, .work__year { grid-column: 2; text-align: left; }
  .preview { display: none; }

}

/* ============================================================
   REDUCED MOTION
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  html { scroll-behavior: auto; }

  /* Drop movement, keep short opacity fades so state changes still register. */
  [data-reveal] .line > span { transform: none; }
  .js [data-reveal-up], .js [data-reveal-stagger] > * {
    transform: none;
    transition-duration: .2s !important;
    transition-delay: 0s !important;
  }
  .frame { animation: none !important; transform: none !important; opacity: 1 !important; transition: none !important; }
  .preview, .lightbox { transition-duration: .2s !important; }
  .preview__stack, .lightbox__img { transform: none !important; }
  .preview__card { transition: opacity .2s !important; clip-path: none; opacity: 0; }
  .preview__card.is-active { opacity: 1; }
  .contact__email-text, .contact__email-feedback { transition-duration: .2s !important; transform: none; }
}
