/* ================================================================== *
   Xposure — Selected Work
   Daylight Studio system: a paper-light gallery that dims into a
   screening room the moment you open a project.
   Tokens are lifted 1:1 from xposure-vp-3/src/app/globals.css so this
   page can be dropped into that site later without a repaint.
 * ================================================================== */

:root {
  --bg: #f3f1ec;
  --ink: #101114;
  --muted: #75726a;
  --line: rgba(16, 17, 20, 0.14);
  --blue: #1f3aff;
  --card: #e9e6df;

  /* --muted lands at 4.2:1 on --bg — fine for a soft line of body copy, under
     the 4.5:1 floor for the small uppercase labels. Those use this instead. */
  --muted-strong: #5c5950;

  --gut: 4vw;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --spring: cubic-bezier(0.34, 1.42, 0.5, 1);

  /* the light↔dark drift and the view swap land together, fast */
  --theme-ms: 420ms;
  --theme-ease: cubic-bezier(0.4, 0, 0.2, 1);
  --view-ms: 280ms;
  --view-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --head-h: 65px;

  /* How tall a 9:16 cut is allowed to stand. Tuned so it lands within a few
     pixels of the height a 16:9 cut reaches across the same column — the two
     orientations read as one stage instead of one dwarfing the other. */
  --stage-h: min(78vh, 780px);
}

.dark {
  --bg: #0a0b0d;
  --ink: #f0eee8;
  --muted: #8b8a84;
  --line: rgba(240, 238, 232, 0.14);
  --blue: #5b74ff;
  --card: #131417;
  --muted-strong: #9d9c95;
}

* { box-sizing: border-box; }

/* grids and flex boxes below would otherwise out-specify the attribute */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: "Schibsted Grotesk", sans-serif;
  font-size: 16px;
  line-height: 1.5;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

/* ── view swap ──────────────────────────────────────────────────
   The two views never overlap. The outgoing one is cut instantly, so
   nothing cross-dissolves; only the incoming view animates, lifting off
   the solid page background on a fast decelerating curve. Reads as an
   instant cut that still has weight.                                 */

#view-grid,
#view-project { background: var(--bg); }

.view-entering {
  will-change: opacity, transform;
  animation: view-in var(--view-ms) var(--view-ease) both;
}
@keyframes view-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

.theme-shift,
.theme-shift * {
  transition-property: background-color, color, border-color, outline-color,
    fill, stroke, box-shadow;
  transition-duration: var(--theme-ms);
  transition-timing-function: var(--theme-ease);
}
.theme-shift a,
.theme-shift button { transition-duration: 250ms; }

/* while the room is changing, links and buttons drift with everything else
   instead of snapping ahead on their fast hover timing */
body.theming a,
body.theming button {
  transition-duration: var(--theme-ms);
  transition-timing-function: var(--theme-ease);
}

.serif-i {
  font-family: Fraunces, serif;
  font-style: italic;
  font-weight: 480;
  letter-spacing: -0.01em;
}

/* Small uppercase mono is the page's label voice. It was set at 11px / 0.14em,
   which reads as texture rather than words — at that size the wide tracking
   pulls the letters apart faster than the eye groups them. Bigger, heavier and
   tighter keeps the same editorial feel and is actually legible. */
.mono {
  font-family: "Geist Mono", monospace;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

::selection { background: var(--blue); color: #f3f1ec; }

/* film grain over everything, very quiet */
.grain::after {
  content: "";
  position: fixed;
  inset: -50%;
  z-index: 70;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: grain 9s steps(6) infinite;
}
@keyframes grain {
  0%, 100% { transform: translate(0, 0); }
  20% { transform: translate(-4%, 3%); }
  40% { transform: translate(3%, -5%); }
  60% { transform: translate(-3%, -2%); }
  80% { transform: translate(4%, 4%); }
}

.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.9s var(--ease), transform 0.9s var(--ease);
}
.reveal.on { opacity: 1; transform: none; }

:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ── header ─────────────────────────────────────────────────────── */

.site-head {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px var(--gut);
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}

.mark {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--ink);
  text-decoration: none;
}
.mark-dot { color: var(--blue); }

/* The nav used to run three type voices side by side — mono uppercase for the
   links, sentence-case grotesk in the CTA, and the wordmark. The links now
   speak the CTA's voice at one step down, so the header reads as one row and
   the filled pill is the only thing shouting. */
.head-nav {
  display: flex;
  align-items: center;
  gap: 18px;
}
.head-link,
.head-nav button {
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1;
  color: var(--muted-strong);
  text-decoration: none;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.head-link {
  position: relative;
  padding-bottom: 3px;
}
/* rule grows from the left rather than fading in — the hover reads as a
   movement, not a state change */
.head-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 280ms var(--ease);
}
.head-link:hover::after { transform: scaleX(1); }
.head-link:hover,
.head-nav button:hover { color: var(--ink); }

/* ── theme toggle ─────────────────────────────────────────────────
   Icon only. A 38px disc, borderless at rest so the CTA keeps the only
   outline in the header, with the disc filling in on hover to give the
   glyph a hit target you can see. The label is in the accessible name. */

#theme-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  margin-right: -4px;          /* optical: the disc reads wider than its ink */
  border-radius: 999px;
  transition: color 220ms var(--ease), background-color 220ms var(--ease);
}
#theme-btn:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }

/* 19px, not 18 — a hairline stroke reads lighter than a 14px letterform, so
   the glyph needs the extra pixel to sit at the same weight as "Work" */
.theme-glyphs {
  position: relative;
  display: block;
  width: 19px;
  height: 19px;
}
.theme-icon {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transition: opacity 260ms var(--ease), transform 420ms var(--spring);
}
/* light = offer the moon (dim), dark = offer the sun (lights up); the pair
   rotates through each other so the swap has direction */
.icon-sun  { opacity: 0; transform: rotate(-70deg) scale(0.6); }
.icon-moon { opacity: 1; transform: none; }
.dark .icon-sun  { opacity: 1; transform: none; }
.dark .icon-moon { opacity: 0; transform: rotate(70deg) scale(0.6); }

/* the toggle's only visible label, so it has to survive for screen readers */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── arrow-fill CTA ───────────────────────────────────────────────
   Ported from the React/Tailwind reference component; this page has no
   build step, so it is plain CSS. Three stacked layers inside one pill:
   the label, a circle that grows to fill the whole pill on hover, and a
   copy of the label clipped to that circle so the words change colour
   exactly as the fill sweeps over them. The reference's vw-based sizing
   is a hero scale — in a header it is fixed px instead.              */

.arrow-btn {
  --btn-bg: var(--ink);
  --btn-text: var(--bg);
  --btn-fill-bg: var(--blue);
  --btn-fill-text: var(--bg);
  --icon-circle: 30px;
  --icon-right: 4px;
  --circle-inset-y: calc((100% - var(--icon-circle)) / 2);
  --pad-l: 20px;
  --pad-r: calc(var(--icon-circle) + var(--icon-right) + 14px);
  --arrow-ease: cubic-bezier(0.785, 0.135, 0.15, 0.86);
  --arrow-ms: 450ms;

  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 38px;
  padding: 0 var(--pad-r) 0 var(--pad-l);
  border: 1px solid var(--btn-bg);
  border-radius: 999px;
  background: var(--btn-bg);
  color: var(--btn-text);
  overflow: hidden;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  -webkit-text-rendering: geometricPrecision;
  text-rendering: geometricPrecision;
}

.arrow-btn-label {
  position: relative;
  z-index: 1;
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1;
}

/* the growing circle */
.arrow-btn-fill {
  position: absolute;
  z-index: 2;
  inset: var(--circle-inset-y) var(--icon-right) var(--circle-inset-y)
         calc(100% - var(--icon-right) - var(--icon-circle));
  border-radius: 999px;
  background: var(--btn-fill-bg);
  pointer-events: none;
  transition: inset var(--arrow-ms) var(--arrow-ease);
}

/* the same label, clipped to the circle, in the fill's text colour */
.arrow-btn-clip {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  padding: 0 var(--pad-r) 0 var(--pad-l);
  color: var(--btn-fill-text);
  pointer-events: none;
  clip-path: inset(var(--circle-inset-y) var(--icon-right) var(--circle-inset-y)
                   calc(100% - var(--icon-right) - var(--icon-circle)));
  transition: clip-path var(--arrow-ms) var(--arrow-ease);
}

.arrow-btn-icon {
  position: absolute;
  right: var(--icon-right);
  top: 50%;
  z-index: 3;
  translate: 0 -50%;
  width: var(--icon-circle);
  height: var(--icon-circle);
  border-radius: 999px;
  background: var(--btn-fill-bg);
  color: var(--btn-fill-text);
  overflow: hidden;
  pointer-events: none;
}

.arrow-btn-arrow {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 15px;
  transform-origin: center;
  transition: transform var(--arrow-ms) var(--arrow-ease);
}
.arrow-btn-arrow.arrow-out { transform: translate(-50%, -50%); }
.arrow-btn-arrow.arrow-in { transform: translate(-170%, -50%) scale(0); }

.arrow-btn:hover .arrow-btn-fill,
.arrow-btn:focus-visible .arrow-btn-fill { inset: 0; }

.arrow-btn:hover .arrow-btn-clip,
.arrow-btn:focus-visible .arrow-btn-clip { clip-path: inset(0 0 0 0); }

.arrow-btn:hover .arrow-btn-arrow.arrow-out,
.arrow-btn:focus-visible .arrow-btn-arrow.arrow-out {
  transform: translate(70%, -50%) scale(0);
}
.arrow-btn:hover .arrow-btn-arrow.arrow-in,
.arrow-btn:focus-visible .arrow-btn-arrow.arrow-in {
  transform: translate(-50%, -50%) scale(1);
}

/* ── hero ───────────────────────────────────────────────────────── */

.hero {
  padding: clamp(70px, 13vh, 150px) var(--gut) clamp(50px, 8vh, 90px);
  max-width: 1500px;
  margin-inline: auto;
}

.hero-eyebrow { color: var(--muted-strong); margin: 0 0 30px; }

.hero-title {
  margin: 0;
  font-size: clamp(42px, 8.2vw, 118px);
  line-height: 0.94;
  letter-spacing: -0.045em;
  font-weight: 500;
  max-width: 15ch;
}
.hero-title .serif-i { letter-spacing: -0.03em; }

/* rights disclaimer — quiet, but plainly legible */
.hero-note {
  margin: 38px 0 0;
  max-width: 62ch;
  padding-left: 18px;
  border-left: 1px solid var(--line);
  color: var(--muted);
  font-size: 13.5px;
  line-height: 1.7;
}

/* ── project grid ───────────────────────────────────────────────── */

.grid-wrap {
  max-width: 1500px;
  margin-inline: auto;
  padding: 46px var(--gut) clamp(80px, 12vh, 150px);
  scroll-margin-top: 90px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 46px 30px;
}

.card {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 0;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

/* one poster per project — the film count carries the "it's a set" cue */
.card-well {
  display: block;
  position: relative;
}

.card-poster {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: 10px;
  overflow: hidden;
  background: var(--card);
  border: 1px solid var(--line);
  display: grid;
  place-items: center;
  transition: transform 0.55s var(--spring), border-color 0.3s var(--ease);
}
.card:hover .card-poster,
.card:focus-visible .card-poster {
  transform: translateY(-5px);
  border-color: var(--ink);
}
/* ── hover tiles ────────────────────────────────────────────────
   Still and loop are stacked and framed identically, so the swap reads
   as the frame coming alive rather than a second image appearing.   */

.tile-img,
.tile-loop {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.tile-loop {
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s var(--ease);
}
.loop-on .tile-loop { opacity: 1; }

/* the still drifts up a touch under the loop — tiny, but it sells the swap */
.tile-img { transition: transform 0.6s var(--ease); }
.loop-on .tile-img { transform: scale(1.03); }

/* On a touch screen there is no pointer to answer, so the card that is
   playing takes the state hover would have given it: lifted, outlined and
   wearing the play badge. It is the one card in motion, and it should look
   picked rather than merely animated. */
@media (hover: none), (max-width: 680px) {
  .card.loop-on .card-poster {
    transform: translateY(-5px);
    border-color: var(--ink);
  }
  .card.loop-on .card-play { opacity: 1; transform: scale(1); }
}

/* placeholder texture: quiet diagonal rule + centred glyph */
.ph {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background-image: repeating-linear-gradient(
    -45deg,
    var(--line) 0 1px,
    transparent 1px 13px
  );
  opacity: 0.55;
}
.ph-glyph {
  font-family: Fraunces, serif;
  font-style: italic;
  font-size: clamp(30px, 4vw, 52px);
  color: var(--muted);
  opacity: 0.6;
  letter-spacing: -0.03em;
}

.card-play {
  position: absolute;
  right: 12px;
  bottom: 12px;
  z-index: 2;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: var(--blue);
  display: grid;
  place-items: center;
  opacity: 0;
  transform: scale(0.7);
  transition: opacity 0.35s var(--ease), transform 0.45s var(--spring);
}
.card:hover .card-play,
.card:focus-visible .card-play { opacity: 1; transform: scale(1); }
.card-play::after {
  content: "";
  border-left: 9px solid #f3f1ec;
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  margin-left: 3px;
}

.card-meta {
  display: block;
  margin-top: 18px;
}
.card-name {
  margin: 0;
  font-size: 20px;
  font-weight: 500;
  letter-spacing: -0.025em;
}

/* ── footer ─────────────────────────────────────────────────────── */

.site-foot { padding: 0 var(--gut) 40px; max-width: 1500px; margin-inline: auto; }
.foot-line { height: 1px; background: var(--line); }
.foot-inner {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  padding-top: 18px;
  color: var(--muted-strong);
}

/* ── contact ──────────────────────────────────────────────────────
   The only call to action on the page, so it gets its own band above
   the colophon instead of being folded into that line.             */

.foot-contact {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 24px 40px;
  padding: 52px 0 46px;
  border-bottom: 1px solid var(--line);
}
/* The one line on the page asking for a reply. It was a 13px mono label
   stranded at the far left of a row of 15px links, so it read as a caption
   for them rather than the invitation. Set as a heading it holds that end of
   the band and gives the actions something to answer to. */
.foot-contact-label {
  margin: 0;
  color: var(--ink);
  font-size: clamp(26px, 3.4vw, 38px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.035em;
}

.contact-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 28px;
}

.contact-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--ink);
  text-decoration: none;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
  transition: color 220ms var(--ease), border-color 220ms var(--ease);
}
.contact-link:hover { color: var(--blue); border-bottom-color: var(--blue); }
.contact-link svg { width: 17px; height: 17px; flex: none; }

/* the footer runs the same CTA as the header, one size up — the page should
   not present one action in two different button languages */
.arrow-btn-lg {
  height: 46px;
  --icon-circle: 36px;
  --icon-right: 5px;
  --pad-l: 24px;
  --pad-r: calc(var(--icon-circle) + var(--icon-right) + 16px);
}
.arrow-btn-lg .arrow-btn-label { font-size: 15px; }
.arrow-btn-lg .arrow-btn-arrow { width: 17px; height: 17px; }

/* ================================================================== *
   Project view — the screening room
 * ================================================================== */

.project {
  min-height: 100vh;
  padding: 0 var(--gut) clamp(70px, 10vh, 120px);
}
.project:focus { outline: none; }

.close-btn {
  position: sticky;
  top: var(--head-h);   /* sits under the site header, which stays put now */
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 0 calc(var(--gut) * -1);
  padding: 22px var(--gut);
  width: calc(100% + var(--gut) * 2);
  font: inherit;
  font-family: "Geist Mono", monospace;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted-strong);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(14px);
  border: 0;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}
.close-btn:hover { color: var(--ink); }
.close-x {
  width: 16px;
  height: 1px;
  background: currentColor;
  position: relative;
}
.close-x::before,
.close-x::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 6px;
  height: 1px;
  background: currentColor;
  transform-origin: 0 50%;
}
.close-x::before { transform: rotate(-45deg); }
.close-x::after { transform: rotate(45deg); }

/* The title carries the head on its own now — the rule under it keeps the
   step down into the stage that the meta row used to provide. */
.project-head {
  max-width: 1400px;
  margin: clamp(30px, 5vh, 58px) auto clamp(26px, 3.6vh, 42px);
  padding-bottom: clamp(20px, 2.8vh, 32px);
  border-bottom: 1px solid var(--line);
}
.project-title {
  margin: 0;
  font-size: clamp(38px, 7vw, 96px);
  line-height: 0.95;
  letter-spacing: -0.045em;
  font-weight: 500;
}
.project-sub {
  margin: 14px 0 0;
  font-size: clamp(19px, 2.3vw, 30px);
  color: var(--muted);
}

/* main stage */
.stage-wrap { max-width: 1400px; margin-inline: auto; }

/* --ar / --ar-num come from the cut being played. A widescreen cut still
   fills the column exactly as it always did; only a vertical one is held
   back, by height × its own ratio, so it can't run off the screen. Either
   way the title bar sits on the player's real edges. */
.stage-frame {
  width: 100%;
  margin-inline: auto;
}
.stage-frame.is-vertical {
  max-width: calc(var(--stage-h) * var(--ar-num, 0.5625));
}
.stage {
  position: relative;
  aspect-ratio: var(--ar, 16 / 9);
  width: 100%;
  border-radius: 12px;
  overflow: hidden;
  background: var(--card);
  border: 1px solid var(--line);
}
.stage video,
.stage iframe {
  width: 100%;
  height: 100%;
  display: block;
  border: 0;
  object-fit: contain;   /* the frame already matches — this is just a backstop */
  background: #000;
}
.stage .ph { background-size: 18px 18px; }

.stage-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  text-align: center;
  padding: 24px;
}
.stage-empty .ph-glyph { font-size: clamp(34px, 5vw, 68px); }
.stage-empty code {
  font-family: "Geist Mono", monospace;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 6px 10px;
}

.stage-bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  padding: 16px 2px 0;
}
.stage-title {
  margin: 0;
  font-size: 17px;
  font-weight: 500;
  letter-spacing: -0.02em;
}
.stage-pos { color: var(--muted-strong); flex: none; }

/* ── credits ────────────────────────────────────────────────────── */

/* Credits close the project out, below the full set of videos, so they get
   the same column and rhythm as the grid above them rather than the tighter
   spacing they had when they sat directly under the player. */
.credits {
  max-width: 1400px;
  margin: clamp(52px, 8vh, 92px) auto 0;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}
.credits-label { color: var(--muted-strong); margin: 0 0 14px; }

/* One grid for the whole block, with the rows dissolved into it, so the label
   column is sized once by the longest role — "Cinematography/Post Production"
   — and every value starts on the same line. A per-row flex box cannot do
   that: each row would measure its own label and the values would stagger. */
.credits-body {
  margin: 0;
  display: grid;
  grid-template-columns: minmax(0, max-content) 1fr;
  align-items: baseline;
  gap: 14px 28px;
}
.credit-row { display: contents; }

.credit-row dt {
  color: var(--muted-strong);
  font-family: "Geist Mono", monospace;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.credit-row dd { margin: 0; color: var(--ink); font-size: 15px; }

/* a line with no role — a campaign name — spans both columns */
.credit-row dd:first-child { grid-column: 1 / -1; }

.credits-empty {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
  font-style: italic;
  opacity: 0.75;
}

/* all cuts */
.cuts {
  max-width: 1400px;
  margin: clamp(52px, 8vh, 92px) auto 0;
}
.cuts-label {
  color: var(--muted);
  margin: 0 0 20px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
}
/* Widescreen and vertical cuts get a block each, so every row inside a
   block is the same height. Verticals run narrower and denser — six-ish
   columns of 9:16 land at roughly the height of a 16:9 row, which is what
   stops a mixed project from reading as two unrelated grids. */
.cut-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 30px 24px;
  align-items: start;
}
.cut-grid-v { grid-template-columns: repeat(5, 1fr); }

.cut-split {
  height: 1px;
  background: var(--line);
  margin: clamp(38px, 5vh, 58px) 0;
}

/* a 9:16 card is too narrow to sit a title and a duration side by side */
.cut-grid-v .cut-body {
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
}

.cut {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.cut-thumb {
  display: block;
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: 9px;
  overflow: hidden;
  background: var(--card);
  border: 1px solid var(--line);
  transition: border-color 0.3s var(--ease), transform 0.5s var(--spring);
}
.cut:hover .cut-thumb { transform: translateY(-4px); border-color: var(--ink); }
.cut[aria-current="true"] .cut-thumb { border-color: var(--blue); }
.cut-thumb img,
.cut-thumb video { width: 100%; height: 100%; object-fit: cover; display: block; }

.cut-num {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  font-family: "Geist Mono", monospace;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.07em;
  color: var(--muted-strong);
}
.cut[aria-current="true"] .cut-num { color: var(--blue); }

.cut-body {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  margin-top: 12px;
}
.cut-name { margin: 0; font-size: 15px; font-weight: 500; letter-spacing: -0.015em; }
.cut-dur { color: var(--muted-strong); flex: none; }

/* prev / next */
.project-nav {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  max-width: 1400px;
  margin: clamp(60px, 9vh, 110px) auto 0;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}
.project-nav button {
  font: inherit;
  color: var(--muted-strong);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  gap: 10px;
}
.project-nav button:hover { color: var(--ink); }

/* ── responsive ─────────────────────────────────────────────────── */

@media (max-width: 1100px) {
  .grid { grid-template-columns: repeat(2, 1fr); gap: 40px 24px; }
  .cut-grid { grid-template-columns: repeat(2, 1fr); }
  .cut-grid-v { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 680px) {
  :root { --gut: 22px; }
  .grid { grid-template-columns: 1fr; gap: 34px; }
  .cut-grid { grid-template-columns: 1fr; }
  .cut-grid-v { grid-template-columns: repeat(2, 1fr); }
  .head-nav { gap: 14px; }
  .foot-inner { flex-direction: column; gap: 6px; }
  .foot-contact { flex-direction: column; align-items: flex-start; gap: 18px; }
  .contact-actions { flex-direction: column; align-items: flex-start; gap: 16px; }

  /* the wordmark already goes home, so the "Work" link is the one that
     gives way when the CTA and the theme toggle need the room */
  .head-link { display: none; }
  .head-nav { gap: 8px; }
  #theme-btn { width: 34px; height: 34px; }
  .foot-contact { padding: 40px 0 34px; }
  /* the label column would eat the width on a phone — stack the rows */
  .credits-body { grid-template-columns: 1fr; gap: 4px 0; }
  .credit-row dt { padding-top: 12px; }
  .arrow-btn {
    height: 34px;
    --icon-circle: 27px;
    --pad-l: 16px;
    --pad-r: calc(var(--icon-circle) + var(--icon-right) + 11px);
  }
  .arrow-btn-label { font-size: 12.5px; }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::after,
  *::before {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .reveal { opacity: 1; transform: none; }
}
