/* =========================================================
   YOUR NAME — portfolio
   Tokens → base → layout → components → motion → responsive
   One accent colour. Dark is primary; light is a full peer.
   ========================================================= */

/* ── Tokens ─────────────────────────────────────────────── */
:root {
  --font-display: "Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
  --font-body: "Inter Tight", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;

  --step--1: clamp(0.82rem, 0.79rem + 0.14vw, 0.9rem);
  --step-0:  clamp(1rem, 0.96rem + 0.2vw, 1.12rem);
  --step-1:  clamp(1.2rem, 1.1rem + 0.5vw, 1.5rem);
  --step-2:  clamp(1.6rem, 1.35rem + 1.2vw, 2.4rem);
  --step-3:  clamp(2.2rem, 1.6rem + 3vw, 4rem);
  --step-4:  clamp(3rem, 1.6rem + 7vw, 8.5rem);

  --gutter: clamp(1.25rem, 4vw, 3rem);
  --section-y: clamp(5rem, 12vh, 10rem);
  --maxw: 1200px;
  --radius: 14px;

  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --dur: 0.6s;
}

/* Cool neutrals, one electric blue. The greys carry a blue cast on purpose —
   a warm grey under a blue accent is what makes an accent look bolted on. */
:root[data-theme="dark"] {
  --bg: #07090a;
  --bg-elev: #0e1214;
  --bg-elev-2: #161d20;
  --text: #edf4f5;
  --muted: #93a3a7;
  --line: rgba(255, 255, 255, 0.11);
  --line-strong: rgba(255, 255, 255, 0.24);
  --accent: #3ad4de;
  --accent-ink: #04181b;
  --dot-rgb: 200, 240, 245;
  --accent-rgb: 58, 212, 222;
  --shadow: 0 30px 70px -34px rgba(0, 0, 0, 0.95);

  --glass-bg: rgba(255, 255, 255, 0.055);
  --glass-edge: rgba(255, 255, 255, 0.14);
  --glass-hi: rgba(255, 255, 255, 0.24);
  --glass-lo: rgba(0, 0, 0, 0.38);
  --glass-spec: rgba(255, 255, 255, 0.3);
}

:root[data-theme="light"] {
  --bg: #f2f6f7;
  --bg-elev: #ffffff;
  --bg-elev-2: #e4eef0;
  --text: #0b1113;
  --muted: #4e5c60;
  --line: rgba(11, 17, 19, 0.12);
  --line-strong: rgba(11, 17, 19, 0.26);
  --accent: #0a6875;
  --accent-ink: #ffffff;
  --dot-rgb: 15, 42, 48;
  --accent-rgb: 10, 104, 117;
  --shadow: 0 26px 54px -32px rgba(13, 30, 60, 0.32);

  --glass-bg: rgba(255, 255, 255, 0.5);
  --glass-edge: rgba(13, 17, 23, 0.1);
  --glass-hi: rgba(255, 255, 255, 0.95);
  --glass-lo: rgba(13, 30, 60, 0.09);
  --glass-spec: rgba(255, 255, 255, 0.75);
}

/* ── Base ───────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

/* Scroll padding keeps anchored targets — and anything the keyboard focuses —
   clear of the fixed bar at the top and, on phones, the nav pill at the
   bottom. Without the bottom value, tabbing near the end of a section lands
   focus underneath the pill. */
html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: 6.5rem;
  scroll-padding-bottom: 6rem;
}

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Theme crossfade — enabled only after first paint (see main.js) so the
   initial render never animates from the wrong colours. */
body.theme-ready,
body.theme-ready .card,
body.theme-ready .topbar,
body.theme-ready .btn {
  transition: background-color 0.45s var(--ease), color 0.45s var(--ease),
              border-color 0.45s var(--ease);
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0 0 1.1em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: inherit; }

img { max-width: 100%; display: block; }

ul { margin: 0; padding: 0; list-style: none; }

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

::selection { background: rgba(var(--accent-rgb), 0.28); }

.skip-link {
  position: fixed;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 200;
  padding: 0.6rem 1rem;
  background: var(--accent);
  color: var(--accent-ink);
  border-radius: 8px;
  font-weight: 600;
  transform: translateY(-160%);
  transition: transform 0.2s var(--ease);
}
.skip-link:focus-visible { transform: translateY(0); }

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

section[tabindex="-1"]:focus { outline: none; }

/* ── Ambient background canvas ──────────────────────────── */
#bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

/* ── Custom cursor ──────────────────────────────────────── */
.cursor,
.cursor-dot { display: none; }

body.has-custom-cursor,
body.has-custom-cursor a,
body.has-custom-cursor button { cursor: none; }

body.has-custom-cursor .cursor,
body.has-custom-cursor .cursor-dot {
  display: block;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 150;
  pointer-events: none;
  will-change: transform;
}

body.has-custom-cursor .cursor {
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  transition: width 0.25s var(--ease), height 0.25s var(--ease),
              margin 0.25s var(--ease), border-color 0.25s var(--ease),
              background-color 0.25s var(--ease), opacity 0.25s var(--ease);
}

body.has-custom-cursor .cursor-dot {
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  background: var(--accent);
  border-radius: 50%;
}

body.has-custom-cursor.cursor-active .cursor {
  width: 58px;
  height: 58px;
  margin: -29px 0 0 -29px;
  border-color: rgba(var(--accent-rgb), 0.55);
  background: rgba(var(--accent-rgb), 0.09);
}

/* ── Top bar / nav ──────────────────────────────────────── */
.topbar {
  position: fixed;
  inset: 0.9rem var(--gutter) auto;
  z-index: 100;
  max-width: calc(var(--maxw) - 2rem);
  margin-inline: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.55rem 0.6rem 0.55rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
}

@supports not (backdrop-filter: blur(4px)) {
  .topbar { background: var(--bg-elev); }
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  text-decoration: none;
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.02em;
  font-size: var(--step--1);
}
.brand-mark { color: var(--accent); font-size: 0.7em; }

.nav-list {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.15rem;
}

/* One indicator that slides between links rather than five that blink. */
.nav-pill {
  position: absolute;
  top: 0;
  left: 0;
  border-radius: 999px;
  background: var(--bg-elev-2);
  opacity: 0;
  pointer-events: none;
  transition: transform 0.5s var(--ease), width 0.5s var(--ease),
              height 0.3s var(--ease), opacity 0.3s var(--ease);
}

.nav-list li { position: relative; }

.nav-list a {
  display: inline-block;
  padding: 0.45rem 0.85rem;
  border-radius: 999px;
  font-size: var(--step--1);
  color: var(--muted);
  text-decoration: none;
  transition: color 0.25s var(--ease);
}
.nav-list a:hover { color: var(--text); }
.nav-list a[aria-current="true"] { color: var(--text); }

.theme-toggle {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex: none;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--text);
  cursor: pointer;
}
.theme-toggle:hover { border-color: var(--line-strong); }

/* One disc, two faces. The flip IS the state change. */
.toggle-faces {
  position: relative;
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  transform-style: preserve-3d;
  transition: transform 0.65s var(--ease);
}
.toggle-faces svg {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
}
.icon-moon { transform: rotateY(180deg); }
:root[data-theme="light"] .toggle-faces { transform: rotateY(180deg); }

/* ── Scroll progress ────────────────────────────────────── */
.scroll-progress {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 120;
  height: 2px;
  pointer-events: none;
}
.scroll-progress span {
  display: block;
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, transparent, var(--accent));
  transform: scaleX(0);
  transform-origin: 0 50%;
}

/* ── Hero ───────────────────────────────────────────────── */
.hero {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  padding-block: 8rem 4rem;
}

.hero-title .accent { color: var(--accent); }

.hero-title {
  font-size: var(--step-4);
  font-weight: 700;
  letter-spacing: -0.045em;
  line-height: 0.92;
  margin-bottom: 1.4rem;
}

.hero-sub {
  font-size: var(--step-1);
  color: var(--muted);
  max-width: 34ch;
  margin-bottom: 2.4rem;
}

.hero-cta { display: flex; flex-wrap: wrap; gap: 0.75rem; }

/* ── Buttons ────────────────────────────────────────────── */
/* ── Liquid glass (approximation) ────────────────────────
   Apple documents Liquid Glass for Apple platforms only — there is no
   official web implementation and this is not one. It is an approximation
   built from four honest layers:
     1. a translucent fill over a blurred, saturated backdrop
     2. a hairline outer edge
     3. an inner top highlight + inner bottom shade (the refracting rim)
     4. a specular hotspot that tracks the pointer (see .glass::after)
   Falls back to a solid fill wherever backdrop-filter is unsupported or the
   user has asked for reduced transparency.                                  */
.glass,
.btn-ghost,
.card-link,
.theme-toggle {
  position: relative;
  isolation: isolate;
  background: var(--glass-bg);
  backdrop-filter: blur(16px) saturate(1.7);
  -webkit-backdrop-filter: blur(16px) saturate(1.7);
  border: 1px solid var(--glass-edge);
  box-shadow:
    inset 0 1px 0 var(--glass-hi),
    inset 0 -1px 0 var(--glass-lo),
    0 8px 22px -14px rgba(0, 0, 0, 0.7);
}

/* The rim brightens on the side the pointer is on, so the edge reads as
   curved glass catching light rather than a flat translucent panel. */
.glass::before,
.btn-ghost::before,
.card-link::before,
.theme-toggle::before,
.btn-primary::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(100deg,
              transparent 0%,
              var(--glass-spec) calc(var(--mx, 50%) - 22%),
              transparent calc(var(--mx, 50%) + 8%));
  opacity: 0;
  mix-blend-mode: overlay;
  transition: opacity 0.35s var(--ease);
  pointer-events: none;
}
.glass:hover::before,
.glass:focus-visible::before,
.btn-ghost:hover::before,
.btn-ghost:focus-visible::before,
.card-link:hover::before,
.card-link:focus-visible::before,
.theme-toggle:hover::before,
.theme-toggle:focus-visible::before,
.btn-primary:hover::before,
.btn-primary:focus-visible::before { opacity: 0.55; }

@supports not ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))) {
  .glass,
  .btn-ghost,
  .card-link,
  .theme-toggle { background: var(--bg-elev); }
}

@media (prefers-reduced-transparency: reduce) {
  .glass,
  .btn-ghost,
  .card-link,
  .theme-toggle,
  .topbar,
  .nav-list {
    background: var(--bg-elev) !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
  .glass::before,
  .btn-ghost::before,
  .card-link::before,
  .theme-toggle::before,
  .btn-primary::before { display: none; }
}

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 1.5rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
  overflow: hidden;
  isolation: isolate;
  will-change: transform;
}

/* Sheen: a highlight that tracks the pointer, so the surface reads as lit. */
.btn::after,
.card-link::after,
.theme-toggle::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(80px circle at var(--mx, 50%) var(--my, 50%),
              rgba(255, 255, 255, 0.22), transparent 70%);
  opacity: 0;
  transition: opacity 0.3s var(--ease);
  pointer-events: none;
}
.btn:hover::after,
.card-link:hover::after,
.theme-toggle:hover::after { opacity: 1; }

/* Press pushes the button away from you rather than just shrinking it. */
.btn:active,
.card-link:active,
.theme-toggle:active { transform: perspective(600px) translateZ(-10px); }

/* The primary CTA keeps an opaque fill — glass over a moving background makes
   its contrast unpredictable, and this is the one control that must stay
   legible everywhere. It gets the glass rim and specular, not the tint. */
.btn-primary {
  background: var(--accent);
  color: var(--accent-ink);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.38),
    inset 0 -1px 0 rgba(0, 0, 0, 0.22),
    0 10px 22px -16px rgba(var(--accent-rgb), 0.5);   /* contact shadow, not a glow */
}
.btn-primary:hover { filter: brightness(1.08); }

.btn-ghost { border-color: var(--glass-edge); color: var(--text); }
.btn-ghost:hover { background: color-mix(in srgb, var(--glass-bg) 100%, var(--text) 6%); }
.btn-ghost::after {
  background: radial-gradient(90px circle at var(--mx, 50%) var(--my, 50%),
              rgba(var(--accent-rgb), 0.22), transparent 70%);
}

.card-link,
.theme-toggle { position: relative; overflow: hidden; isolation: isolate; }
.card-link::after,
.theme-toggle::after {
  background: radial-gradient(70px circle at var(--mx, 50%) var(--my, 50%),
              rgba(var(--accent-rgb), 0.25), transparent 70%);
}

/* ── Sections ───────────────────────────────────────────── */
.section { padding-block: var(--section-y); }

.section-grid {
  display: grid;
  gap: clamp(1.5rem, 4vw, 4rem);
  grid-template-columns: 1fr;
}

.section-title {
  font-size: var(--step--1);
  font-family: var(--font-body);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.section-note {
  color: var(--muted);
  font-size: var(--step--1);
  margin-top: 0.75rem;
  margin-bottom: 2.5rem;
}

.section-body { max-width: 62ch; }
.lead { font-size: var(--step-2); letter-spacing: -0.02em; line-height: 1.25; font-family: var(--font-display); }
.section-body p + p { color: var(--muted); }

.facts {
  margin: 2.5rem 0 0;
  display: grid;
  gap: 1rem;
  border-top: 1px solid var(--line);
  padding-top: 1.5rem;
}
.facts div { display: flex; gap: 1rem; justify-content: space-between; align-items: baseline; }
.facts dt { color: var(--muted); font-size: var(--step--1); }
.facts dd { margin: 0; text-align: right; }

/* ── Project grid ───────────────────────────────────────── */
.grid {
  display: grid;
  gap: clamp(1rem, 2.5vw, 1.75rem);
  grid-template-columns: 1fr;
}

/* The shell owns scroll-driven rotation; the card owns pointer tilt. Keeping
   them on separate elements is what lets both run at once. */
.card-shell {
  display: flex;
  transform-style: preserve-3d;
  will-change: transform, opacity;
}
.card-shell > .card { flex: 1; }

/* NOTE: the card must NOT set `overflow: hidden` — a non-visible overflow
   flattens the 3D context and kills every child's translateZ. The media
   element clips its own corners instead. */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-elev);
  transform-style: preserve-3d;
  will-change: transform;
  transition: border-color 0.3s var(--ease), box-shadow 0.4s var(--ease);
}
.card:hover,
.card:focus-within {
  border-color: var(--line-strong);
  box-shadow: var(--shadow);
}

/* Pointer-tracked sheen, as if a light sat where the cursor is. */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(340px circle at var(--mx, 50%) var(--my, 50%),
              rgba(var(--accent-rgb), 0.1), transparent 62%);
  opacity: 0;
  transition: opacity 0.4s var(--ease);
  pointer-events: none;
}
.card:hover::after { opacity: 1; }

.card-media {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: calc(var(--radius) - 1px) calc(var(--radius) - 1px) 0 0;
  background:
    radial-gradient(120% 120% at 20% 0%, rgba(var(--accent-rgb), 0.16), transparent 60%),
    var(--bg-elev-2);
  overflow: hidden;
}

/* Scaled up so the scroll parallax has room to travel without exposing an
   edge. The transform is written per frame by initScrollMotion. */
.card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.12);
  transition: opacity 0.4s var(--ease);
}

/* Fallback shown when no poster file exists yet. */
.card-index {
  position: absolute;
  inset: auto auto 0.5rem 1rem;
  font-family: var(--font-display);
  font-size: clamp(4rem, 12vw, 7rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.05em;
  color: rgba(var(--dot-rgb), 0.09);
  pointer-events: none;
}
.card.has-poster .card-index { display: none; }

/* Video thumbnail: a real frame, fading in over the gradient once it decodes
   so there is no flash of an empty black box. Sits under the numeral and the
   play marker, above the gradient. */
.card-thumb {
  position: absolute;
  inset: 0;
  z-index: 0;                 /* under the numeral and the play marker */
  width: 100%;
  height: 100%;
  object-fit: cover;          /* vertical teasers crop to the card's 16:10 */
  opacity: 0;
  transition: opacity 0.6s var(--ease), transform 0.8s var(--ease);
  pointer-events: none;
}
.card-thumb.is-ready { opacity: 1; }
.card:hover .card-thumb.is-ready { transform: scale(1.03); }

.card-index,
.card-play { z-index: 1; }

/* The numeral is a stand-in for missing artwork; once a real frame is up it
   just sits on top of the picture. */
.card.has-thumb .card-index { display: none; }

/* A real poster file wins over the video frame — it is far cheaper. */
.card.has-poster .card-thumb { display: none; }

/* Medium marker: these are films. A CSS triangle, not a hand-rolled icon. */
.card-play {
  position: absolute;
  top: 1rem;
  right: 1rem;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  /* Fixed dark scrim rather than theme tokens: this sits over film frames,
     which can be anything from a black night shot to a white title card. */
  background: rgba(6, 10, 12, 0.55);
  backdrop-filter: blur(10px) saturate(1.5);
  -webkit-backdrop-filter: blur(10px) saturate(1.5);
  border: 1px solid rgba(255, 255, 255, 0.35);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 2px 10px rgba(0, 0, 0, 0.35);
  transition: transform 0.4s var(--ease), background-color 0.3s var(--ease);
}
.card-play::after {
  content: "";
  width: 0;
  height: 0;
  margin-left: 3px;
  border-left: 9px solid #fff;
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
}
.card:hover .card-play {
  transform: scale(1.12) translateZ(30px);
  background: var(--accent);
  border-color: var(--accent);
}
.card:hover .card-play::after { border-left-color: var(--accent-ink); }
.card-media.is-clickable { cursor: pointer; }

.card-body {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  padding: 1.25rem 1.25rem 1.35rem;
  transform-style: preserve-3d;
}

/* Depth planes: as the card turns, these separate instead of moving as one
   flat face. Only on fine pointers with motion allowed. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .card-head,
  .tags,
  .card-desc {
    transition: transform 0.5s var(--ease);
  }
  .card:hover .card-head { transform: translateZ(42px); }
  .card:hover .tags { transform: translateZ(26px); }
  .card:hover .card-desc { transform: translateZ(16px); }
}

.card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.card-title { font-size: var(--step-1); letter-spacing: -0.025em; }
.card-cat { font-size: var(--step--1); color: var(--muted); white-space: nowrap; }

.card-desc { color: var(--muted); font-size: var(--step--1); margin: 0; }

.tags { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.tag {
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.28rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
}

.card-links { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.15rem; }

.card-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 44px;          /* WCAG target size */
  padding: 0 1rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  font-size: var(--step--1);
  font-weight: 500;
  text-decoration: none;
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease);
}
.card-link:hover { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.card-link .ext { font-size: 0.85em; }

/* The actions are always visible — hiding them until hover made them
   undiscoverable for anyone scanning with their eyes rather than the mouse,
   which is the "reliance on hover only" anti-pattern. Hover now lifts them
   onto their own depth plane instead of revealing them. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .card-links { transition: transform 0.35s var(--ease); }
  .card:hover .card-links { transform: translateZ(34px); }
}

.card-time {
  margin-left: 0.45rem;
  font-variant-numeric: tabular-nums;
  font-size: 0.78em;
  color: var(--muted);
}
.card-link:hover .card-time { color: inherit; }

/* ── Player ─────────────────────────────────────────────── */
.lightbox {
  width: min(1100px, 94vw);
  max-width: none;
  padding: 0;
  border: 1px solid var(--glass-edge);
  border-radius: var(--radius);
  background: var(--bg-elev);
  color: var(--text);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.lightbox::backdrop {
  background: rgba(3, 5, 10, 0.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.lightbox-panel { display: flex; flex-direction: column; }

.lightbox.is-portrait { width: auto; }
.lightbox.is-portrait video {
  width: auto;
  height: min(74vh, 780px);
  max-width: 94vw;
}

/* Portrait teasers and 4K landscape films share this box: fit inside it,
   letterboxed, never cropped and never taller than the viewport. */
.lightbox video {
  display: block;
  width: 100%;
  max-width: 100%;
  max-height: min(74vh, 780px);
  margin-inline: auto;
  background: #000;
  object-fit: contain;
}

.lightbox-error {
  margin: 0;
  padding: 3rem 1.5rem;
  text-align: center;
  color: var(--muted);
}
.lightbox-error a { color: var(--accent); }

.lightbox-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 0.85rem 1rem;
  border-top: 1px solid var(--line);
}
.lightbox-title {
  margin: 0;
  font-size: var(--step--1);
  font-weight: 500;
}
.lightbox-actions { display: flex; gap: 0.5rem; }

/* The custom cursor hides the native one; inside the player you need it back
   to work the video controls. */
body.is-modal { overflow: hidden; }
body.is-modal.has-custom-cursor,
body.is-modal.has-custom-cursor a,
body.is-modal.has-custom-cursor button { cursor: auto; }
body.is-modal .cursor,
body.is-modal .cursor-dot { display: none; }

/* ── Skills ─────────────────────────────────────────────── */
.skills {
  display: grid;
  gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.skill-group h3 {
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.9rem;
}
.skill-group li {
  padding: 0.4rem 0;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
}
.skill-group li:last-child { border-bottom: 0; }

/* ── Contact ────────────────────────────────────────────── */
.section-contact { padding-bottom: clamp(4rem, 10vh, 8rem); }
.contact-title { font-size: var(--step-3); margin-bottom: 2rem; }

.contact-mail {
  display: inline-block;
  font-family: var(--font-display);
  font-size: var(--step-2);
  letter-spacing: -0.02em;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid rgba(var(--accent-rgb), 0.4);
  padding-bottom: 0.15rem;
  will-change: transform;
}
.contact-mail:hover { border-bottom-color: var(--accent); }

.socials {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
  margin-top: 3rem;
}
.socials a {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 44px;
  color: var(--muted);
  text-decoration: none;
  transition: color 0.25s var(--ease);
}
.socials a:hover { color: var(--text); }
.socials .ext { font-size: 0.8em; }

/* ── Footer ─────────────────────────────────────────────── */
.footer {
  border-top: 1px solid var(--line);
  padding-block: 1.5rem;
  font-size: var(--step--1);
  color: var(--muted);
}
.footer-inner { display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.footer a { text-decoration: none; }
.footer a:hover { color: var(--text); }

/* ── Scroll reveal ──────────────────────────────────────── */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
  transition-delay: calc(var(--reveal-delay, 0) * 90ms);
}
.reveal.is-visible { opacity: 1; transform: none; }

/* ── Responsive ─────────────────────────────────────────── */
@media (min-width: 700px) {
  .grid { grid-template-columns: repeat(2, 1fr); }
  .facts { gap: 0.75rem; }
}

@media (min-width: 900px) {
  .section-grid { grid-template-columns: 200px 1fr; }
  .section-title { padding-top: 0.6rem; }
}

/* Mobile: the nav becomes a thumb-reachable floating pill at the bottom. */
@media (max-width: 719px) {
  .brand-name { display: none; }

  /* The pill chrome moves onto the two floating controls. The topbar itself
     must drop its backdrop-filter: a filtered ancestor becomes the containing
     block for fixed children, which would trap the nav at the top. */
  .topbar {
    padding: 0;
    border-color: transparent;
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  .brand,
  .theme-toggle {
    border: 1px solid var(--line);
    border-radius: 999px;
    background: color-mix(in srgb, var(--bg) 80%, transparent);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
  }
  .brand { padding: 0.55rem 0.7rem; line-height: 1; }

  /* Both floating controls get a full 44px touch target on phones. */
  .brand,
  .theme-toggle { min-width: 44px; min-height: 44px; }
  .theme-toggle { width: 44px; height: 44px; }

  .nav {
    position: fixed;
    inset: auto 0 calc(0.9rem + env(safe-area-inset-bottom)) 0;
    display: flex;
    justify-content: center;
    pointer-events: none;
  }
  .nav-list {
    pointer-events: auto;
    gap: 0.1rem;
    padding: 0.3rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: color-mix(in srgb, var(--bg) 80%, transparent);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow: var(--shadow);
  }
  /* 44px minimum on the thumb nav, per WCAG target size. */
  .nav-list a {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0 0.7rem;
    font-size: 0.8rem;
  }
  .footer { padding-bottom: 6.5rem; }
}

/* ── Increased contrast ─────────────────────────────────── */
@media (prefers-contrast: more) {
  :root {
    --line: var(--line-strong);
    --glass-edge: var(--line-strong);
  }
  .btn-ghost,
  .card-link,
  .theme-toggle,
  .card { border-width: 2px; }
  .card-desc,
  .hero-sub,
  .footer,
  .nav-list a,
  .socials a { color: var(--text); }
}

/* ── Reduced motion ─────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
  .card-media img { transform: none !important; }
}
