/* ===========================================================================
   Portfolio — dark cinematic
   Design tokens live in :root. Change --accent to re-skin the whole site.
   =========================================================================== */

/* ---------- 1. Tokens ---------- */
:root {
  /* Surfaces */
  --bg:         #09090a;
  --bg-2:       #0f0f11;
  --surface:    #141417;
  --line:       rgba(255, 255, 255, .09);
  --line-str:   rgba(255, 255, 255, .18);

  /* Ink */
  --ink:        #f4f3f1;
  --ink-2:      #a4a4aa;
  --ink-3:      #6b6b73;

  /* The single accent. One colour, used sparingly.
     Amber, picked over the usual portfolio orange because amber monochrome
     monitors were a real thing — it earns the CRT theme instead of decorating
     it. Alternatives that work on this background: #d4ff3f (acid),
     #00ff9f (phosphor green), #22d3ee (cyan). */
  --accent:     #ffb000;
  --accent-dim: rgba(255, 176, 0, .13);

  /* Amber is bright: text sitting ON the accent must be dark, not white. */
  --on-accent:  #0b0b0c;

  /* Type
     --font-display is the futuristic face, used only for the name, section
     titles and the brand mark. Swap that one line to re-face the whole site;
     "Bruno Ace", "Tektur" and "Orbitron" are drop-in alternatives (remember to
     change the Google Fonts <link> in index.html too). */
  --font-display: "Syncopate", "Inter Tight", system-ui, sans-serif;
  --font:  "Inter Tight", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --mono:  "Share Tech Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Fluid type scale — everything breathes with the viewport */
  --t-xs:   clamp(.66rem, .62rem + .18vw, .75rem);
  --t-sm:   clamp(.8rem,  .76rem + .2vw,  .9rem);
  --t-base: clamp(.95rem, .9rem  + .25vw, 1.06rem);
  --t-lg:   clamp(1.1rem, 1rem   + .5vw,  1.4rem);
  --t-xl:   clamp(1.6rem, 1.2rem + 2vw,   2.6rem);
  --t-2xl:  clamp(2.2rem, 1.4rem + 4vw,   4.2rem);
  /* Sized for Syncopate, which is far wider than a normal face — a smaller
     cap here keeps "A.BURAK KOÇ" on one line without overflowing. */
  --t-mega: clamp(1.5rem, .2rem + 6.2vw, 7rem);

  /* Rhythm */
  --gutter:  clamp(1.15rem, .6rem + 3vw, 4.5rem);
  --section: clamp(5rem, 3rem + 9vw, 12rem);
  --maxw:    1680px;

  /* Motion — one easing curve across the site keeps it coherent */
  --ease:     cubic-bezier(.16, 1, .3, 1);
  --ease-io:  cubic-bezier(.65, .05, .36, 1);
  --fast:     .28s;
  --slow:     .9s;

  --radius: 3px;
}

/* ---------- 1b. Hover signal ----------
   Nothing is laid over thumbnails or pills at rest — they are simply clean.
   On hover a single bright band sweeps through once, which reads as a signal
   catching rather than as a permanent screen texture. Fast and quiet: this
   is a flicker of acknowledgement, not an effect. */
.fx {
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    transparent 40%,
    rgba(255, 255, 255, .5) 49%,
    rgba(255, 255, 255, .5) 51%,
    transparent 60%
  );
}

@keyframes fx-sweep {
  0%   { opacity: 0;   transform: translateY(-62%); }
  18%  { opacity: .85; }
  80%  { opacity: .45; }
  100% { opacity: 0;   transform: translateY(62%); }
}

/* ---------- 2. Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; padding: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Stops the lightbox opening from shifting the page sideways */
  scrollbar-gutter: stable;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--t-base);
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: -.005em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

img, svg, iframe, video { display: block; max-width: 100%; }
img { height: auto; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

a { color: inherit; text-decoration: none; }

ul, ol { list-style: none; }

::selection { background: var(--accent); color: var(--on-accent); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ---------- 3. Utilities ---------- */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.vh {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Small uppercase mono label — the technical voice of the site */
.eyebrow {
  font-family: var(--mono);
  font-size: var(--t-xs);
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Skip link */
.skip {
  position: fixed;
  top: .6rem; left: .6rem;
  z-index: 200;
  padding: .7rem 1.1rem;
  background: var(--ink);
  color: var(--bg);
  font-size: var(--t-sm);
  font-weight: 600;
  border-radius: var(--radius);
  transform: translateY(-160%);
  transition: transform var(--fast) var(--ease);
}
.skip:focus { transform: translateY(0); }

/* ---------- 4. Atmosphere: grain, vignette, scroll bar ---------- */
/* Fixed overlays that sit above the page but never catch the pointer. */
.grain, .vignette {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 90;
}

.grain {
  opacity: .035;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: grain-shift 6s steps(5) infinite;
}

@keyframes grain-shift {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(-3%, 2%); }
  40%  { transform: translate(2%, -3%); }
  60%  { transform: translate(-2%, -2%); }
  80%  { transform: translate(3%, 1%); }
  100% { transform: translate(0, 0); }
}

.vignette {
  background: radial-gradient(130% 95% at 50% 42%, transparent 48%, rgba(0, 0, 0, .55) 100%);
}

.progress {
  position: fixed;
  top: 0; left: 0;
  z-index: 110;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: var(--accent);
  will-change: transform;
}

/* ---------- 5. Header ---------- */
.header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  border-bottom: 1px solid transparent;
  transition: background var(--slow) var(--ease),
              backdrop-filter var(--slow) var(--ease),
              border-color var(--slow) var(--ease),
              transform .5s var(--ease);
}

/* Frosts over once you leave the hero */
.header.is-stuck {
  background: rgba(9, 9, 10, .72);
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  border-bottom-color: var(--line);
}

/* Hides on scroll-down, returns on scroll-up */
.header.is-hidden { transform: translateY(-100%); }

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  height: clamp(60px, 8vh, 84px);
}

.brand {
  font-family: var(--font-display);
  font-size: clamp(.66rem, .58rem + .3vw, .8rem);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: opacity var(--fast) var(--ease);
}
.brand:hover { opacity: .6; }

/* The readout standing in for the name in the header. */
.brand--readout {
  font-family: var(--mono);
  font-size: var(--t-xs);
  font-weight: 400;
  letter-spacing: .13em;
  color: var(--ink-2);
  overflow: hidden;
}

/* Keep only the location once the header gets tight. */
@media (max-width: 760px) {
  .brand--readout .readout__i:nth-of-type(n + 2) { display: none; }
}

.nav {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 2.4rem);
}

.nav__link {
  position: relative;
  font-size: var(--t-sm);
  color: var(--ink-2);
  white-space: nowrap;
  transition: color var(--fast) var(--ease);
}
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; bottom: -4px;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform .45s var(--ease);
}
.nav__link:hover { color: var(--ink); }
.nav__link:hover::after { transform: scaleX(1); }

.nav__cta {
  padding: .5rem 1.1rem;
  border: 1px solid var(--line-str);
  border-radius: 100px;
  color: var(--ink);
  font-size: var(--t-sm);
  transition: background var(--fast) var(--ease),
              border-color var(--fast) var(--ease),
              color var(--fast) var(--ease);
}
.nav__cta:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
}

@media (max-width: 720px) {
  .nav__link[data-hide-sm] { display: none; }
}

/* ---------- 6. Hero ---------- */
.hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 100svh;
  padding-block: calc(clamp(60px, 8vh, 84px) + 4rem) clamp(2rem, 5vh, 4.5rem);
  overflow: hidden;
}

/* Slow drifting glow, so the empty space is never dead.
   Suppressed when the reel is playing behind — the video is the backdrop. */
.hero::before {
  content: "";
  position: absolute;
  top: -30%; left: 50%;
  width: min(140vw, 1500px);
  aspect-ratio: 1;
  background: radial-gradient(circle, var(--accent-dim) 0%, transparent 62%);
  pointer-events: none;
  animation: drift 22s var(--ease-io) infinite alternate;
}
.has-hero-video .hero::before { opacity: .35; }

@keyframes drift {
  from { transform: translate(-56%, -3%) scale(1); }
  to   { transform: translate(-44%, 4%) scale(1.12); }
}

/* ---- Hero background video ---- */
/* The still frame from the reel is set as this element's background image, so
   the hero always shows imagery even if the video never autoplays. */
.hero__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background-color: #000;
  background-size: cover;
  background-position: center;
  filter: saturate(.72) contrast(1.06);
}

/* The iframe is deliberately larger than the viewport and scaled up, which
   pushes YouTube's title bar and watermark outside the visible area. */
.hero__bg-frame {
  position: absolute;
  top: 50%; left: 50%;
  width: 100vw;
  height: 56.25vw;             /* 16:9 against width  */
  min-height: 100%;
  min-width: 177.78vh;         /* 16:9 against height */
  transform: translate(-50%, -50%) scale(1.32);
  pointer-events: none;
  /* Held hidden until the player reports it is genuinely playing, so a
     blocked autoplay never exposes YouTube's play button. */
  opacity: 0;
  transition: opacity 1.4s var(--ease);
}
.hero__bg.is-playing .hero__bg-frame { opacity: 1; }

.hero__bg iframe,
.hero__bg-frame > div {
  width: 100%; height: 100%;
  border: 0;
  display: block;
  pointer-events: none;
}

/* Knocks the footage back so type stays readable on top.
   One gradient only — the global .vignette and .grain layers stack on top of
   this, so anything heavier here turns the video completely black. Light at
   the top where the footage shows, dense at the bottom behind the type. */
.hero__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(9, 9, 10, .58) 0%,
    rgba(9, 9, 10, .62) 30%,
    rgba(9, 9, 10, .82) 60%,
    rgba(9, 9, 10, .96) 85%,
    var(--bg) 100%
  );
}

/* ---- CRT scanlines ---- */
.hero__scan {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: .55;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 0 2px,
    rgba(0, 0, 0, .34) 2px 3px
  );
}

/* A soft band drifting down the screen, like a refresh roll. */
.hero__scan::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  height: 16%;
  background: linear-gradient(to bottom, transparent, rgba(185, 225, 255, .055), transparent);
  animation: crt-roll 7.5s linear infinite;
}

@keyframes crt-roll {
  from { transform: translateY(-130%); }
  to   { transform: translateY(730%); }
}

/* ---- Viewfinder corner marks ---- */
.hero__hud {
  position: absolute;
  inset: clamp(12px, 2.2vw, 30px);
  z-index: 3;
  pointer-events: none;
}
.hero__hud span {
  position: absolute;
  width: 15px; height: 15px;
  border: 1px solid rgba(255, 255, 255, .22);
}
.hero__hud span:nth-child(1) { top: 0;    left: 0;    border-right: 0; border-bottom: 0; }
.hero__hud span:nth-child(2) { top: 0;    right: 0;   border-left: 0;  border-bottom: 0; }
.hero__hud span:nth-child(3) { bottom: 0; left: 0;    border-right: 0; border-top: 0; }
.hero__hud span:nth-child(4) { bottom: 0; right: 0;   border-left: 0;  border-top: 0; }

.hero__inner {
  position: relative;
  z-index: 4;
  display: grid;
  gap: clamp(1.4rem, 3.5vh, 2.6rem);
}

/* ---- Terminal readout strip ---- */
.readout {
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
}
.readout__i i { font-style: normal; opacity: .5; }

/* Drop the year-span segment before the strip gets wide enough to clip. */
@media (max-width: 620px) {
  .readout__i:last-of-type { display: none; }
}

.hero__title {
  position: relative;
  font-family: var(--font-display);
  font-size: var(--t-mega);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -.01em;
  text-transform: uppercase;
  animation: crt-flicker 6.5s steps(1) infinite;
}

/* Keeps each word intact so the name wraps between words, never mid-word. */
.hero__title .word {
  display: inline-block;
  white-space: nowrap;
}

@keyframes crt-flicker {
  0%, 96%, 100% { opacity: 1; }
  97%           { opacity: .86; }
  98%           { opacity: 1; }
  99%           { opacity: .92; }
}

/* ---- Rack-focus reveal ----
   Letters fade up out of defocus, left to right. The faint scale-down as each
   one sharpens is what sells it as a lens pulling focus rather than a plain
   fade — without it the blur just looks like a slow render. */
.hero__title .ch {
  display: inline-block;
  opacity: 0;
  filter: blur(14px);
}

.hero__title.is-revealed .ch {
  animation: ch-focus 1.15s cubic-bezier(.22, 1, .36, 1) forwards;
  animation-delay: calc(var(--d, 0) * 58ms + 120ms);
}

@keyframes ch-focus {
  0% {
    opacity: 0;
    filter: blur(15px);
    transform: scale(1.045);
  }
  60% { opacity: 1; }
  100% {
    opacity: 1;
    filter: blur(0);
    transform: none;
  }
}

.hero__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(1.5rem, 4vw, 4rem);
}

/* Statement band — deliberately below the fold, so the first screen is only
   the name over the reel. */
.statement {
  padding-block: clamp(3.5rem, 2rem + 7vw, 9rem);
}

.statement__inner {
  display: grid;
  gap: clamp(2.5rem, 5vw, 5rem);
}

/* The statement never filled the full width, so the spare column now carries
   the profile links instead of sitting empty. */
@media (min-width: 900px) {
  .statement__inner {
    grid-template-columns: minmax(0, 1.5fr) minmax(220px, .7fr);
    align-items: start;
  }
}

.statement__text {
  max-width: 34ch;
  font-size: clamp(1.15rem, .75rem + 1.7vw, 2.25rem);
  font-weight: 200;
  line-height: 1.38;
  letter-spacing: -.022em;
  color: var(--ink);
  text-wrap: pretty;
}

@media (min-width: 900px) {
  .statement__text { font-size: clamp(1.5rem, .9rem + 1.7vw, 2.4rem); }
}

/* Word-by-word resolve, same defocus treatment as the name so the two read
   as one idea. Runs off the scroll observer, not a timer. */
.reveal-words .w {
  display: inline-block;
  opacity: 0;
  filter: blur(9px);
  transform: translateY(.32em);
}

.reveal-words.is-in .w {
  animation: word-focus .85s cubic-bezier(.22, 1, .36, 1) forwards;
  animation-delay: calc(var(--w, 0) * 26ms);
}

@keyframes word-focus {
  to { opacity: 1; filter: blur(0); transform: none; }
}

/* ---- Elsewhere list ---- */
.elsewhere__label {
  display: block;
  margin-bottom: 1.1rem;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .6s var(--ease) 700ms, transform .6s var(--ease) 700ms;
}
.elsewhere.is-in .elsewhere__label { opacity: 1; transform: none; }

.elsewhere ul { display: grid; }

/* Held back behind the statement on purpose. The 38-word statement takes
   roughly a second to resolve, so these start after it and arrive as the
   reader reaches the end of the sentence rather than competing with it. */
.elsewhere li {
  opacity: 0;
  transform: translateX(14px);
  transition: opacity .65s var(--ease), transform .65s var(--ease);
  transition-delay: calc(var(--li, 0) * 90ms + 850ms);
}
.elsewhere.is-in li { opacity: 1; transform: none; }

.elsewhere__link {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: .8rem;
  padding-block: .72rem;
  border-top: 1px solid var(--line);
  color: var(--ink-2);
  transition: color .35s var(--ease), padding-left .35s var(--ease);
}
.elsewhere li:last-child .elsewhere__link { border-bottom: 1px solid var(--line); }

/* Amber rule that wipes in from the left, echoing the filter pills. */
.elsewhere__link::before {
  content: "";
  position: absolute;
  left: 0; top: -1px;
  height: 1px; width: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform .5s var(--ease);
}

.elsewhere__n {
  font-family: var(--mono);
  font-size: var(--t-xs);
  color: var(--ink-3);
  transition: color .35s var(--ease);
}

.elsewhere__name {
  flex: 1;
  font-size: var(--t-lg);
  font-weight: 300;
  letter-spacing: -.01em;
}

.elsewhere__arrow {
  font-size: var(--t-base);
  opacity: 0;
  transform: translate(-6px, 4px);
  transition: opacity .35s var(--ease), transform .35s var(--ease);
}

/* Hovering the list focuses one row and recedes the others. */
.elsewhere:hover .elsewhere__link { opacity: .45; }

.elsewhere__link:hover,
.elsewhere__link:focus-visible {
  opacity: 1;
  color: var(--accent);
  padding-left: .55rem;
}
.elsewhere__link:hover::before,
.elsewhere__link:focus-visible::before { transform: scaleX(1); }
.elsewhere__link:hover .elsewhere__n,
.elsewhere__link:focus-visible .elsewhere__n { color: var(--accent); }
.elsewhere__link:hover .elsewhere__arrow,
.elsewhere__link:focus-visible .elsewhere__arrow { opacity: 1; transform: none; }

.hero__role {
  display: block;
  margin-bottom: .9rem;
}

.hero__links {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem .5rem;
}

.pill {
  padding: .42rem .95rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  font-size: var(--t-sm);
  color: var(--ink-2);
  white-space: nowrap;
  transition: border-color var(--fast) var(--ease),
              color var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
.pill:hover {
  border-color: var(--line-str);
  color: var(--ink);
  transform: translateY(-2px);
}

/* Blinking terminal caret after the role line */
.caret {
  display: inline-block;
  width: .5em;
  height: .95em;
  margin-left: .45em;
  vertical-align: -.1em;
  background: var(--accent);
  animation: blink 1.15s steps(1) infinite;
}

@keyframes blink {
  0%, 49%   { opacity: 1; }
  50%, 100% { opacity: 0; }
}

.hero__actions { margin-top: 1.4rem; }

.pill--accent {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  border-color: var(--line-str);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--t-sm);
  letter-spacing: .1em;
  text-transform: uppercase;
}
.pill--accent svg { width: .85em; fill: var(--accent); transition: fill var(--fast) var(--ease); }
.pill--accent:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}
.pill--accent:hover svg { fill: var(--on-accent); }

/* Scroll hint */
.scroll-hint {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin-top: clamp(1.5rem, 4vh, 3rem);
  color: var(--ink-3);
}
.scroll-hint__line {
  position: relative;
  width: 54px; height: 1px;
  background: var(--line-str);
  overflow: hidden;
}
.scroll-hint__line::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--accent);
  animation: sweep 2.6s var(--ease-io) infinite;
}
@keyframes sweep {
  0%        { transform: translateX(-100%); }
  55%, 100% { transform: translateX(100%); }
}

/* ---------- 7. Sections ---------- */
.section { padding-block: var(--section); }

.section__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 2rem;
  padding-bottom: clamp(1.5rem, 3vw, 2.5rem);
  border-bottom: 1px solid var(--line);
  margin-bottom: clamp(2rem, 4vw, 3.5rem);
}

.section__title {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, .7rem + 2vw, 2.4rem);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -.01em;
  text-transform: uppercase;
}

.section__count {
  font-family: var(--mono);
  font-size: var(--t-sm);
  color: var(--ink-3);
}

/* ---------- 8. Filter bar ---------- */
.filters {
  position: sticky;
  top: clamp(60px, 8vh, 84px);
  z-index: 50;
  display: flex;
  gap: .4rem;
  padding-block: .9rem;
  background: linear-gradient(to bottom, var(--bg) 62%, transparent);
  overflow-x: auto;
  scrollbar-width: none;
  /* Let the pills bleed to the screen edge when scrolled on mobile */
  margin-inline: calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
}
.filters::-webkit-scrollbar { display: none; }

.filter {
  position: relative;
  isolation: isolate;        /* so the wipe can sit behind the label */
  overflow: hidden;
  flex: 0 0 auto;
  padding: .55rem 1.15rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  font-size: var(--t-sm);
  color: var(--ink-2);
  white-space: nowrap;
  transition: color var(--fast) var(--ease),
              border-color var(--fast) var(--ease),
              opacity .35s var(--ease),
              transform .35s var(--ease);
}

.filter__t { display: inline-block; }

/* Same gesture as the thumbnails: scale up, one bright sweep through. */
.filter:hover {
  color: var(--ink);
  border-color: var(--line-str);
  transform: scale(1.06);
}

.filter:hover .fx,
.filter:focus-visible .fx { animation: fx-sweep .45s var(--ease-io) 1; }

/* Hovering anywhere in the bar focuses the one under the cursor. Scoped to
   :hover so these never apply at rest — otherwise the active pill would be
   pinned visible and skip the entrance below. */
.filters:hover .filter { opacity: .5; }
.filters:hover .filter:hover,
.filters:hover .filter[aria-pressed="true"] { opacity: 1; }

.filter[aria-pressed="true"] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
  font-weight: 500;
}
/* The active pill is already the loud one. */
.filter[aria-pressed="true"] .fx { display: none; }

/* One-time entrance when the work section scrolls in. Runs once on arrival,
   not on every hover.

   The fill mode is `backwards`, and the keyframes have no `to` block: the
   animation ends at the element's own styles and then releases them. With
   `forwards` the end state would stay pinned and beat the plain-declaration
   hover dim above, which is exactly the bug this shape avoids. */
.filters:not(.is-in) .filter {
  opacity: 0;
  transform: translate3d(-10px, 0, 0);
}

.filters.is-in .filter {
  animation: pill-arrive .6s var(--ease) backwards;
  animation-delay: calc(var(--fi, 0) * 60ms);
}

@keyframes pill-arrive {
  from { opacity: 0; transform: translate3d(-10px, 0, 0); }
}

.filter__n {
  margin-left: .5rem;
  font-family: var(--mono);
  font-size: .78em;
  opacity: .5;
}

/* Blurb that swaps as you change filter */
.filters-blurb {
  min-height: 1.6em;
  margin-block: clamp(1rem, 2vw, 1.6rem) clamp(1.8rem, 3.5vw, 2.8rem);
  max-width: 58ch;
  font-size: var(--t-base);
  color: var(--ink-3);
  transition: opacity .3s var(--ease);
}
.filters-blurb.is-swapping { opacity: 0; }

/* ---------- 9. Work grid ---------- */
.grid {
  /* Gaps are named so the registration marks can sit exactly halfway into
     them rather than guessing at an offset. */
  --gx: clamp(1rem, 1.8vw, 2rem);
  --gy: clamp(1.5rem, 2.6vw, 3.2rem);

  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 330px), 1fr));
  gap: var(--gy) var(--gx);
}

/* Registration marks in the dead space between cards. Each sits on the grid
   line at a card's top-left corner, so they line up into a regular lattice
   and read as deliberate rather than scattered. Crossing to an × on hover is
   the only movement they ever make. */
.card::before {
  content: "+";
  position: absolute;
  left: calc(var(--gx) / -2);
  top: calc(var(--gy) / -2);
  z-index: 3;
  font-family: var(--mono);
  font-size: .78rem;
  line-height: 1;
  color: var(--ink-3);
  opacity: .62;
  pointer-events: none;
  transform: translate(-50%, -50%);
  transition: color .5s var(--ease),
              opacity .5s var(--ease),
              transform .5s var(--ease);
}

.card:hover::before,
.card:focus-within::before {
  color: var(--accent);
  opacity: 1;
  transform: translate(-50%, -50%) rotate(45deg);
}

/* On phones the single column makes a vertical dotted rail rather than a
   lattice, which looks like a mistake. Hide them. */
@media (max-width: 700px) {
  .card::before { display: none; }
}

@media (min-width: 900px) {
  .card.is-featured { grid-column: span 2; }
}

/* Cards animate in, and re-animate on every filter change.
   --i is the index within the current result set, set by JS. */
.card {
  position: relative;
  opacity: 0;
  transform: translateY(26px) scale(.98);
  transition: opacity .6s var(--ease), transform .6s var(--ease);
  transition-delay: calc(var(--i, 0) * 45ms);
}
.card.is-in { opacity: 1; transform: none; }

/* Once the entrance stagger has finished, swap to a transition with no delay
   so the magnetic hover responds immediately instead of inheriting the
   per-card entrance offset. */
.card.is-settled {
  transition: transform .5s cubic-bezier(.22, 1, .36, 1),
              opacity .4s var(--ease);
  transition-delay: 0ms;
}

/* The hovered card scales up, so it has to sit above its neighbours. */
.card.is-hot { z-index: 5; }

/* Stretched link: a transparent button covering the card. Keeps the markup
   valid while making the entire card clickable and keyboard-reachable. */
.card__link {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  border-radius: var(--radius);
}

.card__media {
  display: block;
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  background-color: var(--surface);
  /* Fallback shown when a YouTube thumbnail is missing */
  background-image:
    radial-gradient(90% 120% at 15% 0%, rgba(255, 255, 255, .07), transparent 60%),
    linear-gradient(135deg, #17171b, #0d0d0f);
}

.card__media::after {
  /* Darkening wash that lifts on hover */
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, .5), transparent 55%);
  transition: opacity var(--slow) var(--ease);
}

/* Thumbnails sit clean at rest — a gentle lift in contrast is the only thing
   hover changes, besides the one-shot sweep. */
.card__img {
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(1.012);
  filter: saturate(.94);
  transition: transform 1.1s var(--ease),
              opacity .5s var(--ease),
              filter .6s cubic-bezier(.22, 1, .36, 1);
}

.card:hover .card__img,
.card:focus-within .card__img { filter: saturate(1.04) brightness(1.03); }

.card:hover .fx,
.card:focus-within .fx { animation: fx-sweep .52s var(--ease-io) 1; }

/* The badge and the play affordance must stay above the sweep. */
.card__type, .card__play { z-index: 2; }
.card__img[hidden] { display: none; }

.card:hover .card__img,
.card:focus-within .card__img { transform: scale(1.055); }

.card:hover .card__media::after,
.card:focus-within .card__media::after { opacity: .45; }

/* Play affordance */
.card__play {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
}
.card__play span {
  display: grid;
  place-items: center;
  width: clamp(44px, 4vw, 58px);
  aspect-ratio: 1;
  border: 1px solid rgba(255, 255, 255, .4);
  border-radius: 50%;
  background: rgba(10, 10, 12, .3);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  transform: scale(.75);
  transition: opacity .45s var(--ease), transform .45s var(--ease),
              background .45s var(--ease), border-color .45s var(--ease);
}
.card:hover .card__play span,
.card:focus-within .card__play span {
  opacity: 1;
  transform: scale(1);
  background: var(--accent);
  border-color: var(--accent);
}
.card__play svg { width: 36%; translate: 8% 0; fill: #fff; transition: fill .45s var(--ease); }
.card:hover .card__play svg,
.card:focus-within .card__play svg { fill: var(--on-accent); }

/* Deliverable badge, top-left of the frame */
.card__type {
  position: absolute;
  top: .7rem; left: .7rem;
  padding: .3rem .6rem;
  border-radius: 2px;
  background: rgba(9, 9, 10, .66);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink);
}

.card__body {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-top: .95rem;
}

.card__title {
  font-size: var(--t-lg);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -.02em;
  text-wrap: balance;
  transition: color var(--fast) var(--ease);
}
.card:hover .card__title,
.card:focus-within .card__title { color: var(--accent); }

.card__sub {
  margin-top: .25rem;
  font-size: var(--t-sm);
  color: var(--ink-3);
}

.card__year {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: var(--t-sm);
  color: var(--ink-3);
}

/* Empty state */
.empty {
  padding-block: clamp(3rem, 8vw, 6rem);
  text-align: center;
  color: var(--ink-3);
}

/* ---------- 10. About ---------- */
.about {
  display: grid;
  gap: clamp(2rem, 5vw, 5rem);
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  .about { grid-template-columns: 1.25fr 1fr; }
}

/* ---- Portrait ----
   Deliberately small. Same scanline + veil treatment as the hero video so it
   reads as another feed on the same screen rather than a stock headshot. */
.portrait {
  position: relative;
  width: clamp(116px, 14vw, 168px);
  aspect-ratio: 1;
  margin-bottom: clamp(1.5rem, 3vw, 2.2rem);
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);

  opacity: 0;
  transform: translateY(20px) scale(.94);
  transition: opacity .9s var(--ease) .15s, transform .9s var(--ease) .15s;
}
.about.is-in .portrait { opacity: 1; transform: none; }

.portrait img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.08) brightness(.95);
  transition: filter .7s var(--ease), transform 1.1s var(--ease);
}
.portrait:hover img { filter: grayscale(.25) contrast(1.02); transform: scale(1.04); }

.portrait__scan {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .5;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 0 2px,
    rgba(0, 0, 0, .34) 2px 3px
  );
}

.portrait__veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(110% 90% at 50% 40%, transparent 45%, rgba(9, 9, 10, .55) 100%),
    linear-gradient(to bottom, rgba(9, 9, 10, .12), rgba(9, 9, 10, .34));
}

/* The same drifting refresh band as the hero. */
.portrait__scan::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  height: 22%;
  background: linear-gradient(to bottom, transparent, rgba(185, 225, 255, .085), transparent);
  animation: crt-roll 6s linear infinite;
}

.about__lead {
  font-size: var(--t-xl);
  font-weight: 200;
  line-height: 1.3;
  letter-spacing: -.025em;
  text-wrap: pretty;
}

.about__body {
  margin-top: 1.5rem;
  max-width: 56ch;
  color: var(--ink-2);
}
.about__body p + p { margin-top: 1rem; }

.services {
  display: grid;
  gap: 0;
  counter-reset: svc;
}

.services li {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-block: .85rem;
  border-top: 1px solid var(--line);
  font-size: var(--t-base);
  color: var(--ink-2);
  transition: color var(--fast) var(--ease), padding-left var(--fast) var(--ease);
}
.services li:last-child { border-bottom: 1px solid var(--line); }
.services li:hover { color: var(--ink); padding-left: .4rem; }

.services li::before {
  content: counter(svc, decimal-leading-zero);
  counter-increment: svc;
  font-family: var(--mono);
  font-size: var(--t-xs);
  color: var(--ink-3);
}

/* ---------- 11. Contact / footer ---------- */
.contact { border-top: 1px solid var(--line); }

/* ---- Contact ----
   One sentence, one link. The address lives inside the line rather than
   sitting under it as a bare mailto, which is what made it feel like a
   footer afterthought. */
.contact__cta {
  display: block;
  margin-block: clamp(1.2rem, 2.5vw, 2rem) clamp(2rem, 4vw, 3rem);
  font-size: clamp(1.35rem, .6rem + 3.1vw, 3.2rem);
  font-weight: 200;
  line-height: 1.12;
  letter-spacing: -.03em;
  color: var(--ink-2);
  transition: color .4s var(--ease);
}
.contact__cta:hover { color: var(--ink); }

.contact__line { display: block; }

.contact__mail {
  position: relative;
  color: var(--ink);
  word-break: break-word;
  transition: color .4s var(--ease);
}

/* Rule that wipes in under the address on hover. */
.contact__mail::after {
  content: "";
  position: absolute;
  left: 0; bottom: -.06em;
  width: 100%; height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform .55s var(--ease);
}
.contact__cta:hover .contact__mail { color: var(--accent); }
.contact__cta:hover .contact__mail::after { transform: scaleX(1); }

.contact__arrow {
  display: inline-block;
  width: .72em;
  margin-left: .3em;
  vertical-align: baseline;
  color: var(--accent);
  opacity: 0;
  transform: translateX(-.35em);
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.contact__arrow svg { width: 100%; height: auto; }

.contact__cta:hover .contact__arrow,
.contact__cta:focus-visible .contact__arrow {
  opacity: 1;
  transform: translateX(.1em);
}

.footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  padding-block: 2rem;
  border-top: 1px solid var(--line);
}

/* ---------- 12. Lightbox ---------- */
.lb {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: grid;
  place-items: center;
  padding: clamp(.75rem, 3vw, 3rem);
  opacity: 0;
  transition: opacity .4s var(--ease);
}
.lb.is-open { opacity: 1; }
.lb[hidden] { display: none; }

.lb__scrim {
  position: absolute;
  inset: 0;
  background: rgba(4, 4, 5, .86);
  backdrop-filter: blur(22px) saturate(120%);
  -webkit-backdrop-filter: blur(22px) saturate(120%);
}

.lb__panel {
  position: relative;
  width: min(100%, 1180px);
  max-height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  transform: scale(.94) translateY(22px);
  opacity: 0;
  transition: transform .55s var(--ease), opacity .4s var(--ease);
}
.lb.is-open .lb__panel { transform: none; opacity: 1; }

.lb__stage {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #000;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.lb__stage iframe {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  border: 0;
}

/* Shown when the video ID is still a placeholder */
.lb__missing {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: .6rem;
  padding: 2rem;
  text-align: center;
  color: var(--ink-3);
  background: linear-gradient(135deg, #16161a, #0b0b0d);
}

.lb__info {
  display: grid;
  gap: 1.1rem clamp(1.5rem, 4vw, 3.5rem);
  padding-top: clamp(1.1rem, 2.5vw, 1.8rem);
}
@media (min-width: 820px) {
  .lb__info { grid-template-columns: 1.4fr 1fr; align-items: start; }
}

.lb__title {
  font-size: var(--t-xl);
  font-weight: 300;
  line-height: 1.12;
  letter-spacing: -.03em;
  text-wrap: balance;
}

.lb__blurb {
  margin-top: .7rem;
  max-width: 60ch;
  color: var(--ink-2);
}

.lb__facts {
  display: grid;
  gap: 0;
  font-size: var(--t-sm);
}
.lb__facts > div {
  display: flex;
  gap: 1rem;
  justify-content: space-between;
  padding-block: .55rem;
  border-top: 1px solid var(--line);
}
.lb__facts dt { color: var(--ink-3); white-space: nowrap; }
.lb__facts dd { text-align: right; }

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  margin-top: 1rem;
}
.chip {
  padding: .3rem .65rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  font-family: var(--mono);
  font-size: var(--t-xs);
  color: var(--ink-2);
}

/* Lightbox controls */
.lb__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.3rem .4rem;
  margin-top: 1.4rem;
  border-top: 1px solid var(--line);
}

.lb__nav { display: flex; gap: .5rem; }

.lb__btn {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem 1rem;
  border: 1px solid var(--line-str);
  border-radius: 100px;
  font-size: var(--t-sm);
  color: var(--ink-2);
  transition: background var(--fast) var(--ease),
              color var(--fast) var(--ease),
              border-color var(--fast) var(--ease);
}
.lb__btn:hover:not(:disabled) {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
}
.lb__btn:disabled { opacity: .3; cursor: not-allowed; }

.lb__close {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-left: auto;
  margin-bottom: .7rem;
  padding: .5rem .9rem;
  border: 1px solid var(--line-str);
  border-radius: 100px;
  background: rgba(9, 9, 10, .7);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-2);
  transition: background var(--fast) var(--ease),
              color var(--fast) var(--ease),
              border-color var(--fast) var(--ease);
}
.lb__close:hover { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }

/* ---------- 13. Scroll reveals ---------- */
.reveal {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity .85s var(--ease), transform .85s var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }

/* ---------- 14. Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    transition-delay: 0ms !important;
  }

  /* Anything that animates in should simply be visible — including the two
     defocus reveals, whose resting state is blurred, not just transparent. */
  .reveal, .card, .lb__panel, .elsewhere li { opacity: 1; transform: none; }
  .hero__title .ch,
  .reveal-words .w {
    opacity: 1;
    transform: none;
    filter: none;
    animation: none;
  }
  .filter__t { filter: none; animation: none; }

  /* The pills are hidden until their entrance animation runs; with motion off
     that animation is instant, but make the resting state visible regardless
     so a missed observer can never leave the bar blank. */
  .filters:not(.is-in) .filter { opacity: 1; transform: none; }
  .elsewhere__label { opacity: 1; transform: none; }

  /* Keep the screen texture — it is a look, not a movement — but drop the
     ripple so it simply disappears on hover. */
  .fx { animation: none; opacity: 0; }
  .card__img { filter: none; }
  .portrait { opacity: 1; transform: none; }
  .portrait__scan::after { display: none; }
  .grain { display: none; }

  /* CRT motion is decorative — drop the moving parts, keep the static
     texture. JS also skips building the background video entirely. */
  .hero__scan::after { display: none; }
  .caret { opacity: 1; }
  .hero__title { animation: none; }
}
