/* ============================================================
   site.css — reset, layout, components
   ============================================================ */

/* ---- Reset ------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}

body {
  hyphens: none;                 /* break to a new line, never hyphenate */
  font-family: var(--font-sans);
  font-size: var(--t-label);
  line-height: 1.5;
  color: var(--ink-2);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, picture, svg, video { display: block; max-width: 100%; }
img { height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: none; padding: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; padding: 0; }
h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: inherit; line-height: 1.1; }

::selection { background: var(--sel-bg); color: var(--sel-ink); }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

/* ---- Utility ----------------------------------------------- */
.u-visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; top: 0; left: 50%; translate: -50% -120%;
  z-index: 200; padding: 0.75rem 1.25rem;
  background: var(--ink); color: var(--bg); font-size: var(--t-meta);
  transition: translate var(--dur-fast) var(--ease-out);
}
.skip-link:focus { translate: -50% 0; }

.shell {
  width: 100%;
  max-width: calc(var(--container) + var(--gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.meta {
  font-size: var(--t-meta);
  letter-spacing: var(--t-meta-ls);
  text-transform: uppercase;
}

.serif { font-family: var(--font-display); font-weight: 400; }

/* ============================================================
   Custom cursor — pointer devices only
   ============================================================ */

.cursor, .cursor-ring { display: none; }

@media (hover: hover) and (pointer: fine) {
  body.has-cursor,
  body.has-cursor a,
  body.has-cursor button { cursor: none; }

  .cursor, .cursor-ring {
    display: grid; place-items: center;
    position: fixed; top: 0; left: 0; z-index: 150;
    pointer-events: none; will-change: transform;
  }
  /* A modal <dialog> paints in the top layer, which sits above every
     z-index. The cursor nodes are therefore re-parented into the open
     dialog by JS; this keeps them pinned to the viewport once there. */
  dialog .cursor, dialog .cursor-ring { position: fixed; }
  .cursor {
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--ink);
    transition: scale var(--dur-fast) var(--ease-out), opacity var(--dur-fast);
  }
  .cursor-ring {
    width: 36px; height: 36px; border-radius: 50%;
    border: 1px solid var(--ink-faint);
    transition: width var(--dur) var(--ease-out),
                height var(--dur) var(--ease-out),
                background var(--dur) var(--ease-out),
                border-color var(--dur) var(--ease-out),
                opacity var(--dur-fast);
  }
  .cursor-ring .label {
    font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
    color: var(--bg); opacity: 0;
    transition: opacity var(--dur-fast) var(--ease-out);
  }
  body[data-cursor="link"] .cursor { scale: 0; }
  body[data-cursor="link"] .cursor-ring { width: 54px; height: 54px; border-color: var(--ink); }
  body[data-cursor="view"] .cursor { scale: 0; }
  body[data-cursor="view"] .cursor-ring {
    width: 88px; height: 88px; background: var(--ink); border-color: transparent;
  }
  body[data-cursor="view"] .cursor-ring .label { opacity: 1; }
  body[data-cursor="hidden"] .cursor,
  body[data-cursor="hidden"] .cursor-ring { opacity: 0; }
}

/* ============================================================
   Masthead
   현 <-> HYUN and KYU <-> 규 swap together on header hover.
   Each glyph rolls vertically behind a mask, staggered per
   character. The bilingual switch is the brand idea, so it is
   built from real text — selectable, translatable, readable by
   a screen reader in one language only.
   ============================================================ */

.masthead {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  border-bottom: var(--rule) solid transparent;
  transition: border-color var(--dur) var(--ease-out);
}
.masthead[data-stuck="true"] { border-bottom-color: var(--line); }

.masthead__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--col-gap);
  padding-block: clamp(0.9rem, 0.6rem + 0.9vw, 1.5rem);
}

/* Desktop: 현 left, pronunciation dead centre, KYU right. */
.masthead__mark-left { justify-self: start; }
.masthead__phon { justify-self: center; }
.masthead__mark-right { justify-self: end; }

/* The Menu trigger is a word, set like the hero nav links. */
.menu-btn {
  display: none;
  font-size: var(--t-meta);
  letter-spacing: var(--t-meta-ls);
  text-transform: uppercase;
  color: var(--ink-2);
}

/* Tablet and phone: 현 hard left, KYU dead centre, Menu hard right.
   Deliberately NOT space-between: each mark reserves the width of its
   wider language so the header can't reflow mid-swap, which means the
   left box is ~70px wider than the 현 glyph inside it. Distributing the
   boxes evenly therefore pushes the middle mark off-centre. Keeping the
   grid and centring the middle column fixes that — the reserved width
   sits inside a 1fr column where it costs nothing. */
@media (max-width: 1023px) {
  .masthead__phon { display: none; }
  .menu-btn { display: inline-block; justify-self: end; }
  .masthead__mark-right { justify-self: center; }
}

.masthead__phon {
  justify-self: center;
  font-size: var(--t-phon);
  letter-spacing: var(--t-phon-ls);
  text-transform: uppercase;
  color: var(--ink-mute);
  white-space: nowrap;
}

/* --- the swapping mark ------------------------------------- */

.mark {
  font-family: var(--font-display);
  font-size: var(--t-mark);
  line-height: 1.15;
  display: inline-grid;              /* both faces stack in one cell */
  align-items: center;
}
.mark--left { justify-items: start; }
.mark--right { justify-items: end; }

/* On tablet and phone the right mark is centred on the page. 규 is narrower
   than KYU, so both faces are centred inside the reserved box — otherwise
   the mark jumps off-centre on the swap. This has to sit after the base
   rule above to win the cascade. */
@media (max-width: 1023px) {
  .mark--right { justify-items: center; }
}

.mark__face {
  grid-area: 1 / 1;                  /* superimposed, so no layout shift */
  display: flex;
  overflow: hidden;                  /* the mask the glyphs roll behind */
  padding-block: 0.08em;             /* room for descenders while masked */
}
.mark--left .mark__face[data-lang="ko"] { letter-spacing: 0.02em; }
.mark--left .mark__face[data-lang="en"] { letter-spacing: 0.12em; }
.mark--right .mark__face[data-lang="en"] { letter-spacing: 0.12em; }
.mark--right .mark__face[data-lang="ko"] { letter-spacing: 0.02em; }

.mark__ch {
  display: block;
  transition: translate var(--dur) var(--ease-out),
              opacity var(--dur) var(--ease-out);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}

/* resting state: the first face is up, the second is held below */
.mark__face[data-role="out"] .mark__ch { translate: 0 0; opacity: 1; }
.mark__face[data-role="in"]  .mark__ch { translate: 0 110%; opacity: 0; }

/* hover anywhere in the header rolls both marks at once */
.masthead:hover .mark__face[data-role="out"] .mark__ch,
.masthead:focus-within .mark__face[data-role="out"] .mark__ch,
.masthead[data-swapped="true"] .mark__face[data-role="out"] .mark__ch {
  translate: 0 -110%; opacity: 0;
}
.masthead:hover .mark__face[data-role="in"] .mark__ch,
.masthead:focus-within .mark__face[data-role="in"] .mark__ch,
.masthead[data-swapped="true"] .mark__face[data-role="in"] .mark__ch {
  translate: 0 0; opacity: 1;
}

/* On touch there is no hover, so the swap is driven by JS: a 4s loop plus
   tap-to-flip. Hover is disabled there so the two can't fight. */
@media (hover: none) {
  .masthead:hover .mark__face[data-role="out"] .mark__ch { translate: 0 0; opacity: 1; }
  .masthead:hover .mark__face[data-role="in"] .mark__ch { translate: 0 110%; opacity: 0; }
  .masthead[data-swapped="true"] .mark__face[data-role="out"] .mark__ch { translate: 0 -110%; opacity: 0; }
  .masthead[data-swapped="true"] .mark__face[data-role="in"] .mark__ch { translate: 0 0; opacity: 1; }
}

/* The "in" face must not claim layout width — the cell is sized
   by whichever face is wider, so nothing reflows mid-roll. */
.mark__face[data-role="in"] { pointer-events: none; }

/* ============================================================
   Hero
   ============================================================ */

.hero { padding-block: var(--sp-hero-top) var(--sp-hero-bottom); }

.hero__title {
  font-family: var(--font-display);
  font-size: var(--t-hero);
  line-height: var(--t-hero-lh);
  letter-spacing: var(--t-hero-ls);
  color: var(--ink);
  max-width: 22ch;
  /* Flex, so the negative margins on .line below do not collapse into
     each other. Two adjacent -0.12em margins would collapse to a single
     -0.12em, leaving half the mask padding as extra space between the
     phrase groups — which is what made the leading look uneven. */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Each phrase is its own masked block so it can roll in. The mask needs
   vertical padding or descenders get clipped — but that padding also added
   space between the three groups that does not exist between lines wrapping
   inside one group, so the leading read as uneven on mobile. The negative
   margin cancels the layout effect while keeping the taller mask box. */
.line {
  display: block;
  overflow: hidden;
  padding-block: 0.12em;
  margin-block: -0.12em;
}
.line > span {
  display: block;
  translate: 0 110%;
  animation: line-in 1s var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 90ms + 100ms);
}
@keyframes line-in { to { translate: 0 0; } }

.hero__nav {
  display: flex; gap: clamp(2rem, 1rem + 3vw, 5.25rem);
  margin-top: clamp(2rem, 1.2rem + 2.6vw, 3.5rem);
  opacity: 0; animation: fade-in 0.8s var(--ease-out) 560ms forwards;
}
@keyframes fade-in { to { opacity: 1; } }

/* underline-on-hover link */
.link {
  display: inline-block;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px;
  background-repeat: no-repeat;
  background-position: 0 100%;
  transition: background-size var(--dur) var(--ease-out);
  padding-bottom: 2px;
}
.link:hover, .link:focus-visible { background-size: 100% 1px; }
.link--on { background-size: 100% 1px; }
.link--on:hover { background-size: 0% 1px; background-position: 100% 100%; }

/* ============================================================
   Sections + the 4-column grid
   ============================================================ */

.section { padding-bottom: var(--sp-block); }

.section__title {
  font-family: var(--font-display);
  font-size: var(--t-head);
  color: var(--ink);
  margin-bottom: var(--sp-section);
}

/* Explicit steps only — no auto-fill, which picks intermediate counts
   (3 + 1) that break the rhythm. Phone: a single stack. Tablet: 2 x 2.
   Desktop: four across. */
.grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-row) var(--col-gap);
}
@media (min-width: 600px) {
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
  .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Highlights are secondary work — smaller thumbnails, four across at every
   width, scaling down rather than reflowing. */
/* Thumbnails stay four across at every width — declared after the .grid
   rules above so it wins the cascade without extra specificity. */
.grid--thumbs { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* The grey band that separates Other Highlights from the case studies. */
.band {
  background: var(--bg-band);
  padding: clamp(2rem, 1.2rem + 2.6vw, 3.5rem);
  margin-bottom: var(--sp-band-end);
}
.band .section { padding-bottom: 0; }
.band .card__frame { background: var(--bg-panel); }

/* thumbnails carry less weight than the case study cards */
.grid--thumbs .card__kicker,
.grid--thumbs .card__title {
  font-size: clamp(0.625rem, 0.44rem + 0.55vw, 0.875rem);
  letter-spacing: 0.04em;
  /* Wrap to a new line rather than hyphenate. break-word only splits a
     word that cannot fit on a line by itself, so ordinary two-word labels
     break at the space. */
  overflow-wrap: break-word;
  hyphens: none;
}
.grid--thumbs .card__title { margin-top: 5px; }
.grid--thumbs .card__labels { margin-bottom: clamp(0.75rem, 0.4rem + 1.1vw, 1.5rem); }
@media (max-width: 560px) {
  .grid--thumbs { gap: var(--sp-row) 8px; }
  .band { padding-inline: clamp(0.75rem, 0.2rem + 2.4vw, 1.5rem); }
  .grid--thumbs .card__kicker,
  .grid--thumbs .card__title { font-size: 9px; line-height: 1.35; }
  .grid--thumbs .card { padding-top: 10px; }
}

/* ---- Card: hairline, kicker, title, then the image frame ---- */

/* Cards stretch to the tallest in their row, and the label block absorbs
   the slack — so a title that wraps to two lines never pushes its panel
   out of line with the panels beside it. */
.card {
  display: flex;
  flex-direction: column;
  padding-top: 16px;
  border-top: var(--rule) solid var(--line);
  -webkit-touch-callout: none;
}

/* Press feedback — on touch there is no hover, so without this there is no
   signal that a tap registered. Scoped to `.grid .card` so it outranks the
   [data-reveal] transition, which every card also carries; otherwise the
   reveal's opacity/translate declaration wins and the press snaps. */
.grid .card {
  transition: opacity 800ms var(--ease-out),
              translate 800ms var(--ease-out),
              scale 240ms var(--ease-out);
}
.grid .card:active {
  scale: 0.978;
  opacity: 0.7;
  transition-duration: 90ms;
}
.grid .card:active .card__frame { background: var(--bg-inset); }

.card__labels {
  flex: 1 0 auto;
  margin-bottom: var(--card-frame-gap);
}

/* Stepped well below the section heading above them, and separated from
   each other by weight and colour rather than size alone. */
.card__kicker,
.card__title {
  display: block;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.3;
}
.card__kicker {
  font-size: clamp(0.6875rem, 0.64rem + 0.19vw, 0.75rem);
  font-weight: 400;
  color: var(--ink-mute);
}
.card__title {
  font-size: clamp(0.8125rem, 0.74rem + 0.31vw, 0.9375rem);
  font-weight: 500;
  color: var(--ink);
  margin-top: 6px;
}

/* The grey panel spans the full column; the artwork is inset inside it
   (31px each side, 31px top, flush to the bottom) and centre-cropped.
   Absolute positioning rather than grid centring, because a percentage
   height on a centred grid item does not resolve. */
.card__frame {
  position: relative;
  display: block;
  aspect-ratio: var(--frame-ratio);
  overflow: hidden;
  background: var(--bg-frame);
}
/* An <img> is a replaced element: with auto width it takes its intrinsic
   size rather than stretching between insets, so size it explicitly. */
.card__frame img {
  position: absolute;
  left: var(--frame-pad-x);
  top: var(--frame-pad-t);
  width: calc(100% - var(--frame-pad-x) * 2);
  height: calc(100% - var(--frame-pad-t));
  object-fit: cover;
  transition: scale var(--dur-slow) var(--ease-out);
}
.card:hover .card__frame img,
.card--tap:hover .card__frame img { scale: 1.04; }

/* A white logo laid over the artwork behind it. */
.card__frame img.card__overlay {
  inset: 0;
  margin: auto;
  width: auto; height: auto;
  max-width: 44%; max-height: 18%;
  object-fit: contain;
  transition: none;
}
.card:hover .card__frame img.card__overlay,
.card--tap:hover .card__frame img.card__overlay { scale: 1; }

/* the highlight tiles are buttons, not links */
.card--tap { width: 100%; text-align: left; cursor: zoom-in; }

/* ============================================================
   Case study page
   ============================================================ */

.cs-cover { margin-bottom: clamp(2.5rem, 1.4rem + 3.2vw, 4.75rem); }
.cs-cover img { width: 100%; background: var(--bg-frame); }

.cs-title {
  font-family: var(--font-display);
  font-size: var(--t-head);
  color: var(--ink);
  margin-bottom: var(--sp-section);
}

.cs-back { display: inline-block; margin-bottom: clamp(1.5rem, 1rem + 1.6vw, 2.5rem); color: var(--ink-mute); }

/* role + tags sit in the left half, matching the original */
.cs-meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: var(--sp-row) var(--col-gap);
  margin-bottom: var(--sp-block);
}
.cs-meta__label { display: block; color: var(--ink-mute); margin-bottom: 6px; }
.cs-meta__tags { color: var(--ink-mute); line-height: 1.7; }

/* label left / body right, stacked — the original spec list */
.spec { display: grid; gap: clamp(1.25rem, 0.9rem + 1vw, 2rem); margin-bottom: var(--sp-block); }
.spec__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr);
  gap: var(--col-gap);
  align-items: start;
}
.spec__label { color: var(--ink-2); text-align: right; }
.spec__body { color: var(--ink-2); text-wrap: pretty; }
@media (max-width: 720px) {
  .spec__row { grid-template-columns: 1fr; gap: 6px; }
  .spec__label { text-align: left; color: var(--ink-mute); }
}

/* image collage — images keep their own aspect and share a row */
.plates {
  display: flex; flex-wrap: wrap; align-items: flex-start;
  gap: clamp(1.25rem, 0.9rem + 1.4vw, 2.25rem);
  margin-bottom: var(--sp-block);
}
.plate { flex: 1 1 var(--basis, 20rem); min-width: min(100%, 16rem); }
.plate img { width: 100%; background: var(--bg-frame); cursor: zoom-in; }
.plate figcaption { margin-top: 10px; font-size: var(--t-meta); color: var(--ink-mute); }

.cs-body { max-width: 576px; color: var(--ink-2); text-wrap: pretty; }
.cs-body p + p { margin-top: 1em; }

/* Impact figures */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: var(--sp-row) var(--col-gap);
  margin-bottom: var(--sp-block);
}
.stat__num {
  display: block;
  font-family: var(--font-display);
  font-size: var(--t-head);
  color: var(--ink);
  margin-bottom: 10px;
}
.stat__label { color: var(--ink-mute); line-height: 1.5; }

.pager {
  display: flex; justify-content: space-between; gap: var(--col-gap);
  padding-top: clamp(2rem, 1.4rem + 1.8vw, 3rem);
  border-top: var(--rule) solid var(--line);
  margin-bottom: var(--sp-block);
}
.pager__link { display: grid; gap: 8px; }
.pager__link--next { text-align: right; justify-items: end; }
.pager__title { font-family: var(--font-display); font-size: var(--t-head); color: var(--ink); }

/* ============================================================
   Footer
   ============================================================ */

.colophon {
  display: flex; flex-wrap: wrap; gap: clamp(1.5rem, 1rem + 2vw, 3.5rem);
  justify-content: space-between; align-items: baseline;
  padding-block: clamp(2rem, 1.4rem + 2vw, 3.5rem);
  border-top: var(--rule) solid var(--line);
}
.colophon__links { display: flex; flex-wrap: wrap; gap: clamp(1.5rem, 1rem + 2.4vw, 4.25rem); }
.colophon__links a { font-family: var(--font-display); font-size: var(--t-head); color: var(--ink); }
.colophon__meta { display: flex; flex-wrap: wrap; gap: clamp(1rem, 0.7rem + 1.4vw, 2.5rem); color: var(--ink-mute); }

/* Where the grey band already separates the footer, the rule is redundant.
   Must come after .colophon above to win the cascade. */
.colophon--bare { border-top: none; }

/* On phones the three links stack, and the three meta items sit in a single
   horizontal row beneath them. */
@media (max-width: 640px) {
  .colophon {
    flex-direction: column;
    align-items: stretch;
    gap: clamp(1.5rem, 1rem + 3vw, 2.5rem);
  }
  .colophon__links {
    flex-direction: column;
    gap: clamp(0.5rem, 0.3rem + 1vw, 1rem);
  }
  .colophon__meta {
    flex-wrap: nowrap;
    justify-content: space-between;
    gap: 0.75rem;
    font-size: 0.625rem;   /* 10px — so all three fit on one line */
  }
  .colophon__meta span { white-space: nowrap; }
}

/* ============================================================
   Lightbox
   ============================================================ */

.lightbox {
  border: none; padding: 0; background: transparent;
  max-width: 100vw; max-height: 100vh; width: 100%; height: 100%;
  overflow: hidden;
}
.lightbox::backdrop {
  background: rgb(252 252 251 / 0.985);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

/* A gallery, not a single frame: the neighbours stay on screen, smaller and
   faded, so it reads as something you can keep moving through. */
.gallery {
  position: absolute; inset: 0;
  display: flex; align-items: center;
  overflow: hidden;
}
.gallery__track {
  display: flex; align-items: center;
  gap: var(--slide-gap);
  will-change: transform;
  transition: transform 620ms var(--ease-out);
}
.gallery__slide {
  flex: 0 0 auto;
  width: var(--slide-w);
  display: grid; justify-items: center; gap: 14px;
  opacity: var(--slide-opacity-off);
  scale: var(--slide-scale-off);
  cursor: pointer;
  transition: opacity 620ms var(--ease-out), scale 620ms var(--ease-out);
}
.gallery__slide.is-active { opacity: 1; scale: 1; cursor: default; }
.gallery__slide img {
  max-width: 100%; max-height: 52vh;
  object-fit: contain;
  background: var(--bg-frame);
}
.gallery__slide figcaption {
  text-align: center; font-size: var(--t-meta);
  letter-spacing: var(--t-meta-ls); text-transform: uppercase;
  color: var(--ink-mute);
  opacity: 0; transition: opacity 400ms var(--ease-out) 120ms;
}
.gallery__slide.is-active figcaption { opacity: 1; }

.lightbox__count {
  position: fixed; bottom: var(--gutter); left: 50%; translate: -50% 0;
  font-size: var(--t-meta); letter-spacing: var(--t-meta-ls);
  color: var(--ink-faint);
}
.lightbox__close {
  position: fixed; top: var(--gutter); right: var(--gutter); z-index: 2;
  font-size: var(--t-meta); letter-spacing: var(--t-meta-ls); text-transform: uppercase; color: var(--ink-mute);
}
.lightbox__close:hover { color: var(--ink); }
.lightbox__nav {
  position: fixed; top: 50%; translate: 0 -50%; z-index: 2;
  width: 44px; height: 44px; display: grid; place-items: center;
  color: var(--ink-mute);
}
.lightbox__nav:hover { color: var(--ink); }
.lightbox__nav--prev { left: var(--gutter); }
.lightbox__nav--next { right: var(--gutter); }

/* ============================================================
   Reveal on scroll
   ============================================================ */

[data-reveal] {
  opacity: 0; translate: 0 18px;
  transition: opacity 800ms var(--ease-out), translate 800ms var(--ease-out);
  transition-delay: var(--d, 0ms);
}
[data-reveal].is-in { opacity: 1; translate: 0 0; }

/* ============================================================
   Reduced motion & print
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  [data-reveal] { opacity: 1; translate: none; }
  .line > span { translate: none; }
  .gallery__track { transition: none; }
  .hero__nav { opacity: 1; }
  body.has-cursor { cursor: auto; }
  .cursor, .cursor-ring { display: none !important; }
}

@media print {
  .masthead, .cursor, .cursor-ring, .lightbox { display: none !important; }
  body { color: #000; background: #fff; }
}

/* ============================================================
   Mobile menu
   A panel inset from the edges — page still visible at the
   margins — sliding in from the right over a dimmed page.
   ============================================================ */

.menu {
  border: none; padding: 0; background: transparent;
  max-width: 100vw; max-height: 100vh; width: 100%; height: 100%;
  overflow: hidden;
}
.menu::backdrop { background: rgb(20 24 26 / 0.28); }

.menu__panel {
  position: fixed;
  top: var(--menu-inset);
  right: var(--menu-inset);
  bottom: var(--menu-inset);
  left: var(--menu-inset-left);
  background: var(--bg-band);
  padding: var(--menu-pad);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
  translate: 110% 0;
  transition: translate 520ms var(--ease-out);
}
.menu[open] .menu__panel { translate: 0 0; }

.menu__head {
  display: flex; align-items: center; justify-content: flex-end;
  margin-bottom: clamp(2rem, 1.4rem + 3vw, 3.5rem);
}
.menu__close {
  font-size: var(--t-meta);
  letter-spacing: var(--t-meta-ls);
  text-transform: uppercase;
  color: var(--ink-2);
}

.menu__list { display: grid; gap: clamp(1rem, 0.7rem + 1.4vw, 1.5rem); }
.menu__link {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.2rem + 1.6vw, 2rem);
  line-height: 1.15;
  color: var(--ink);
}

/* Case Studies is a disclosure, not a link — the sub-list slides open.
   Animating grid-template-rows from 0fr to 1fr gives a real auto-height
   transition without measuring anything in JS. */
.menu__toggle {
  display: flex; align-items: center; gap: 0.4em;
  width: 100%; text-align: left;
}
.menu__chev {
  display: inline-flex;
  transition: rotate var(--dur) var(--ease-out);
  color: var(--ink-mute);
}
.menu__toggle[aria-expanded="true"] .menu__chev { rotate: 180deg; }

.menu__drawer {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 420ms var(--ease-out);
}
.menu__drawer-inner { overflow: hidden; min-height: 0; }
.menu__group[data-open="true"] .menu__drawer { grid-template-rows: 1fr; }

/* the case studies sit under their heading as a sub-list */
.menu__sub {
  display: grid;
  gap: clamp(0.5rem, 0.35rem + 0.6vw, 0.75rem);
  padding-top: clamp(0.75rem, 0.5rem + 1vw, 1rem);
  padding-left: clamp(0.75rem, 0.5rem + 1.2vw, 1.25rem);
  border-left: var(--rule) solid var(--line);
}
.menu__sub a {
  font-size: var(--t-meta);
  letter-spacing: var(--t-meta-ls);
  text-transform: uppercase;
  color: var(--ink-mute);
  line-height: 1.4;
}
.menu__sub a:hover, .menu__sub a:focus-visible { color: var(--ink); }

.menu__cta {
  display: block;
  width: 100%;
  margin-top: clamp(2rem, 1.4rem + 3vw, 3rem);
  padding: clamp(0.9rem, 0.7rem + 1vw, 1.15rem);
  background: var(--ink);
  color: #fff;
  text-align: center;
  font-size: var(--t-meta);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

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