/* ---------- tokens ---------- */
:root{
  --ink:#0b0b0c;
  --paper:#f3f1ea;
  --paper-dim:#e7e4d9;
  --accent:#2f6bff;
  --accent-2:#8a3ffc;
  --line:rgba(11,11,12,0.12);
  --ff-display:'Archivo', system-ui, sans-serif;
  --ff-body:'Space Grotesk', system-ui, sans-serif;
  --container:1280px;
  --pad:clamp(20px, 5vw, 64px);
}

*,*::before,*::after{box-sizing:border-box}
body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--ff-body);
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
  cursor:default;
}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
h1,h2,h3{font-family:var(--ff-display);margin:0;letter-spacing:-0.02em}
p{margin:0}

::selection{background:var(--ink);color:var(--accent)}

/* ---------- grain overlay ---------- */
.grain{
  position:fixed;inset:0;pointer-events:none;z-index:9998;opacity:.05;mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- marquee (below hero) ---------- */
.marquee-top{
  background:transparent;color:rgba(11,11,12,.4);
  font-family:var(--ff-display);font-weight:700;font-size:12px;letter-spacing:.14em;
  overflow:hidden;white-space:nowrap;padding:14px 0;
  border-bottom:1px solid var(--line);
}
.marquee-top__track{display:inline-flex;animation:scrollLeft 26s linear infinite}
.marquee-top__track span{padding-right:0}
@keyframes scrollLeft{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* ---------- nav ---------- */
.nav{
  position:sticky;top:0;z-index:500;
  display:flex;align-items:center;justify-content:space-between;
  padding:18px var(--pad);
  background:rgba(243,241,234,.78);backdrop-filter:blur(10px);
  border-bottom:1px solid var(--line);
}
.nav__logo{font-family:var(--ff-display);font-weight:800;font-size:20px}
.nav__logo .dot{color:var(--accent-2)}
.nav__links{display:flex;gap:32px;font-size:14px;font-weight:500}
.nav__links a{position:relative;padding:4px 0}
.nav__links a::after{content:'';position:absolute;left:0;bottom:0;width:0;height:1px;background:var(--ink);transition:width .25s}
.nav__links a:hover::after{width:100%}
.nav__cta{
  font-size:13px;font-weight:700;background:var(--ink);color:var(--paper);
  padding:10px 20px;border-radius:100px;
}
.nav__burger{display:none;background:none;border:0;width:30px;height:20px;position:relative;cursor:pointer}
.nav__burger span{position:absolute;left:0;width:100%;height:2px;background:var(--ink);transition:.3s}
.nav__burger span:first-child{top:0}
.nav__burger span:last-child{bottom:0}
.nav__burger.is-open span:first-child{transform:translateY(9px) rotate(45deg)}
.nav__burger.is-open span:last-child{transform:translateY(-9px) rotate(-45deg)}

.mobile-menu{
  display:none;position:fixed;inset:0;top:0;background:var(--ink);color:var(--paper);
  z-index:400;flex-direction:column;align-items:flex-start;justify-content:center;gap:22px;
  padding:0 var(--pad);
  transform:translateY(-100%);transition:transform .45s cubic-bezier(.77,0,.18,1);
}
.mobile-menu.is-open{transform:translateY(0)}
.mobile-menu a{font-family:var(--ff-display);font-size:38px;font-weight:700}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;gap:10px;
  font-family:var(--ff-display);font-weight:700;font-size:15px;
  padding:15px 26px;border-radius:100px;border:1px solid var(--ink);
  transition:transform .3s cubic-bezier(.2,.9,.3,1.2), background .3s, color .3s;
}
.btn-primary{background:var(--ink);color:var(--paper)}
.btn-primary:hover{background:var(--accent);color:#fff;border-color:var(--ink)}
.btn-ghost{background:transparent;color:var(--ink)}
.btn-ghost:hover{background:var(--ink);color:var(--paper)}
.btn-arrow{transition:transform .3s}
.btn:hover .btn-arrow{transform:translateX(4px)}

/* ---------- hero ---------- */
.hero{
  position:relative;min-height:92svh;display:flex;flex-direction:column;justify-content:center;
  padding:80px var(--pad) 60px;overflow:hidden;
}
.hero__bg{position:absolute;inset:0;z-index:0;overflow:hidden}
.hero__video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.16;filter:grayscale(.4)}
/* cursor-follow glow (js/hero-invert-cursor.js) — a soft accent-tinted
   light that brightens the video near the cursor. mix-blend-mode:screen
   adds light rather than inverting, so unlike the two earlier attempts
   (mix-blend-mode:difference had barely any color to blend against since
   the video below is only 16% opaque; backdrop-filter:invert produced a
   flat dark disc with a hard edge) this needs no real color underneath to
   work with, and the radial-gradient's own soft falloff means there's no
   circular edge at all — just an ambient pool of light. */
.hero__glow-cursor{
  position:absolute;top:0;left:0;width:440px;height:440px;border-radius:50%;
  background:radial-gradient(circle, rgba(47,107,255,.6) 0%, rgba(47,107,255,.25) 40%, transparent 72%);
  mix-blend-mode:screen;
  pointer-events:none;
  opacity:0;transition:opacity .5s ease;
  will-change:transform;
}
.hero__glow-cursor.is-active{opacity:1}
.blob{position:absolute;border-radius:50%;filter:blur(70px);opacity:.55}
.blob--1{width:520px;height:520px;background:var(--accent);top:-160px;right:-120px;animation:float1 14s ease-in-out infinite}
.blob--2{width:420px;height:420px;background:var(--accent-2);opacity:.35;bottom:-140px;left:-100px;animation:float2 16s ease-in-out infinite}
@keyframes float1{0%,100%{transform:translate(0,0)}50%{transform:translate(-40px,40px)}}
@keyframes float2{0%,100%{transform:translate(0,0)}50%{transform:translate(30px,-30px)}}
.hero__pixels{position:absolute;inset:0;z-index:1;width:100%;height:100%;pointer-events:none}

.hero__inner{position:relative;z-index:2;max-width:var(--container);margin:0 auto;width:100%}
.hero__eyebrow{
  display:inline-block;font-size:13px;font-weight:600;letter-spacing:.04em;
  padding:8px 16px;border:1px solid var(--line);border-radius:100px;margin-bottom:28px;
  background:rgba(255,255,255,.5)
}
.hero__title{font-size:clamp(52px, 9vw, 128px);line-height:.98;font-weight:800;margin-bottom:32px}
.hero__title .line{display:block;overflow:hidden}
.hero__title em{font-style:italic;font-weight:400;font-family:var(--ff-body)}
.accent-dot{color:var(--accent-2)}
.hero__lead{display:block;max-width:560px;font-size:clamp(16px,2vw,20px);line-height:1.5;color:rgba(11,11,12,.75);margin-bottom:40px}
.hero__actions{display:flex;gap:16px;flex-wrap:wrap}

.scroll-cue{
  position:absolute;bottom:28px;left:50%;transform:translateX(-50%);z-index:2;
  display:flex;flex-direction:column;align-items:center;gap:10px;
  font-size:11px;letter-spacing:.14em;font-weight:700;text-transform:uppercase;color:rgba(11,11,12,.55);
}
.scroll-cue span{width:1px;height:36px;background:var(--ink);position:relative;overflow:hidden}
.scroll-cue span::after{content:'';position:absolute;top:-100%;left:0;width:100%;height:100%;background:var(--accent-2);animation:cueDrop 1.8s ease-in-out infinite}
@keyframes cueDrop{0%{top:-100%}60%{top:100%}100%{top:100%}}

/* ---------- sections ---------- */
.section{padding:120px var(--pad);max-width:var(--container);margin:0 auto}
.section__head{margin-bottom:64px}
.section__tag{display:inline-block;font-size:13px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--accent-2);margin-bottom:16px}
.section__title{font-size:clamp(32px,6.5vw,84px);font-weight:800;line-height:1.05}
.section__sub{font-size:16px;line-height:1.6;color:rgba(11,11,12,.65);max-width:560px;margin-top:20px}

/* ---------- category grid (homepage work nav) ---------- */
.category-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
.category-tile{
  display:block;padding:36px;border-radius:20px;border:1px solid var(--line);
  background:var(--paper-dim);transition:transform .35s cubic-bezier(.2,.9,.3,1.2),box-shadow .35s,border-color .35s;
  position:relative;overflow:hidden;
}
/* ambient brand-colored glow, opposite corner from the big numeral so hover
   reads as a diagonal light sweep across the card rather than piling both
   accents into one corner */
.category-tile::before{
  content:'';position:absolute;bottom:-35%;right:-20%;width:280px;height:280px;border-radius:50%;
  background:var(--tile-color,var(--accent-2));opacity:0;filter:blur(60px);transition:opacity .4s;
}
/* same glow used on project-card media elsewhere on the site (identical
   color/timing/pulse), just rendered inset instead of bleeding outward —
   the card's own overflow:hidden (needed to clip the blob above) would
   otherwise cut an outward glow off entirely */
.category-tile::after{
  content:"";position:absolute;inset:0;border-radius:20px;pointer-events:none;z-index:1;
  opacity:0;box-shadow:inset 0 0 22px 2px rgba(47,107,255,.42);
  transition:opacity .4s cubic-bezier(.22,.68,.36,1);
}
.category-tile:hover{transform:translateY(-6px);box-shadow:0 24px 50px -28px rgba(11,11,12,.35);border-color:var(--ink)}
.category-tile:hover::before{opacity:.25}
.category-tile:hover::after{opacity:1;animation:cardGlowPulseInset 2.6s ease-in-out infinite}
@keyframes cardGlowPulseInset{
  0%,100%{box-shadow:inset 0 0 20px 2px rgba(47,107,255,.35)}
  50%{box-shadow:inset 0 0 32px 4px rgba(47,107,255,.55)}
}

/* big, light-weight ghost numeral — a corner accent rather than a label,
   tinted with the card's own brand color so it still ties to --tile-color */
.category-tile__num{
  position:absolute;top:20px;right:24px;font-family:var(--ff-display);font-size:clamp(52px,6vw,76px);
  font-weight:400;line-height:1;color:var(--tile-color,var(--accent-2));opacity:.16;
  pointer-events:none;
}
.category-tile h3{font-size:clamp(22px,2.6vw,28px);font-weight:800;margin:14px 0 10px;position:relative;max-width:80%}
.category-tile p{font-size:15px;line-height:1.6;color:rgba(11,11,12,.7);max-width:420px;margin-bottom:22px;position:relative}
.category-tile__chips{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:26px;position:relative}
.category-tile__chips span{font-size:12px;font-weight:600;padding:6px 12px;border-radius:100px;background:rgba(255,255,255,.6);border:1px solid var(--line);color:rgba(11,11,12,.65)}
.category-tile__link{
  display:inline-flex;align-items:center;gap:8px;font-family:var(--ff-display);font-weight:700;font-size:14px;
  position:relative;
}
.category-tile__link .btn-arrow{transition:transform .3s}
.category-tile:hover .category-tile__link .btn-arrow{transform:translateX(4px)}
@media (prefers-reduced-motion:reduce){
  .category-tile:hover::after{animation:none;box-shadow:inset 0 0 22px 2px rgba(47,107,255,.42)}
}

/* ---------- category / work pages ---------- */
.page-header{padding:160px var(--pad) 40px;max-width:var(--container);margin:0 auto}
.breadcrumb{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:600;color:rgba(11,11,12,.5);margin-bottom:24px}
.breadcrumb a{color:rgba(11,11,12,.5);transition:color .2s}
.breadcrumb a:hover{color:var(--ink)}
.page-header h1{font-size:clamp(36px,7.5vw,100px);font-weight:800;line-height:1;white-space:nowrap;margin-bottom:20px}
.page-header__lead{font-size:18px;line-height:1.6;color:rgba(11,11,12,.7);max-width:640px}
.page-header__chips{display:flex;flex-wrap:wrap;gap:10px;margin-top:28px}
.page-header__chips span{font-size:13px;font-weight:600;padding:8px 16px;border-radius:100px;background:var(--paper-dim);border:1px solid var(--line);color:rgba(11,11,12,.65)}

.subcat{padding:0 var(--pad) 72px;max-width:var(--container);margin:0 auto}
.subcat__head{margin-bottom:28px}
.subcat__head h2{font-size:clamp(22px,4.2vw,44px);font-weight:800}
.subcat__head p{font-size:14px;color:rgba(11,11,12,.6);margin-top:8px;max-width:480px}
.subcat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}

.reel-card.is-placeholder .reel-card__ph{
  aspect-ratio:1/1;border-radius:14px;border:1.5px dashed var(--line);
  display:flex;align-items:center;justify-content:center;text-align:center;
  color:rgba(11,11,12,.32);font-size:13px;font-weight:600;padding:20px;
}
.reel-card.is-placeholder figcaption{opacity:.6}

/* ---------- reel ---------- */
.section--reel{padding-top:60px}

.reel-main{margin-top:56px}
.reel-main video{
  width:100%;aspect-ratio:16/9;border-radius:20px;border:1px solid var(--line);
  background:#000;box-shadow:0 24px 50px -24px rgba(11,11,12,.4);display:block;
}
.reel-main__cap{display:flex;justify-content:space-between;align-items:center;margin-top:14px;font-size:13px;color:rgba(11,11,12,.55)}
.reel-main__cap a{font-weight:700;color:var(--accent-2)}
.reel-main__cap a:hover{text-decoration:underline}

.reel-filters{display:flex;flex-wrap:wrap;gap:10px}
.reel-filter{
  font-family:var(--ff-display);font-weight:700;font-size:13px;
  padding:9px 18px;border-radius:100px;border:1px solid var(--line);
  background:transparent;color:rgba(11,11,12,.6);cursor:pointer;transition:background .25s,color .25s,border-color .25s;
}
.reel-filter:hover{border-color:var(--ink);color:var(--ink)}
.reel-filter.is-active{background:var(--ink);color:var(--paper);border-color:var(--ink)}

.reel-grid{
  margin-top:28px;display:grid;grid-template-columns:repeat(4,1fr);gap:20px;
}
.reel-card{margin:0;transition:opacity .3s,transform .3s}
.reel-card.is-hidden{display:none}
.reel-card__btn{
  all:unset;position:relative;display:block;width:100%;cursor:pointer;
  border-radius:14px;transform:scale(1);
  transition:transform .35s cubic-bezier(.22,.68,.36,1);
}
.reel-card__btn:hover{transform:scale(1.025)}
/* soft neon glow, layered on a ::after so its pulse animation never fights
   the border's box-shadow transition on the button itself — a slow breathe,
   not a bloom or a flash. This rule covers every card NOT sitting inside a
   clipped carousel viewport (Merge's grid, VersusTrade's split). Cards
   inside .pcard__media (the sliding carousel, which must clip its track) get
   the equivalent glow one level up, on .pcard__media itself — see below —
   since a box-shadow on this ::after would otherwise be cut off by the
   carousel's own overflow:hidden. */
.reel-card__btn::after{
  content:"";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;
  opacity:0;box-shadow:0 0 22px 2px rgba(47,107,255,.42);
  transition:opacity .4s cubic-bezier(.22,.68,.36,1);
}
.reel-card__btn:hover::after{opacity:1;animation:cardGlowPulse 2.6s ease-in-out infinite}
@keyframes cardGlowPulse{
  0%,100%{box-shadow:0 0 20px 2px rgba(47,107,255,.35)}
  50%{box-shadow:0 0 32px 4px rgba(47,107,255,.55)}
}
@media (prefers-reduced-motion:reduce){
  .reel-card__btn:hover{transform:none}
  .reel-card__btn:hover::after{animation:none;box-shadow:0 0 22px 2px rgba(47,107,255,.42)}
  .pcard__media:hover::after{animation:none;box-shadow:0 0 22px 2px rgba(47,107,255,.42)}
}
.reel-card video{
  width:100%;aspect-ratio:var(--ar, 16/9);object-fit:cover;border-radius:14px;border:1px solid var(--line);
  background:#000;display:block;transition:border-color .35s cubic-bezier(.22,.68,.36,1);
}
.reel-play{
  position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:52px;height:52px;border-radius:50%;background:rgba(11,11,12,.55);
  color:var(--paper);display:flex;align-items:center;justify-content:center;
  font-size:16px;padding-left:3px;backdrop-filter:blur(4px);
  opacity:1;transition:opacity .2s;pointer-events:none;
}
.reel-card__btn:hover .reel-play{opacity:0}
.reel-expand{
  position:absolute;bottom:10px;right:10px;width:24px;height:24px;border-radius:7px;
  background:rgba(11,11,12,.6);color:var(--paper);display:flex;align-items:center;justify-content:center;
  backdrop-filter:blur(4px);opacity:0;transition:opacity .2s,background .2s;pointer-events:none;
}
.reel-expand svg{width:13px;height:13px}
.reel-card__btn:hover .reel-expand{opacity:1}
.reel-expand:hover{background:rgba(11,11,12,.85)}
@media (hover:none),(pointer:coarse){
  .reel-play{display:none}
  .reel-expand{opacity:.75;pointer-events:auto}
}
.reel-card figcaption{margin-top:10px;font-size:13px;line-height:1.5;color:rgba(11,11,12,.65)}
.reel-tag{
  display:inline-block;font-family:var(--ff-display);font-weight:700;font-size:11px;
  letter-spacing:.04em;text-transform:uppercase;color:var(--accent-2);margin-bottom:4px;
}

/* ---------- UI & Product Motion: project blocks ---------- */
.project-block{padding:40px 0 44px;border-top:1px solid var(--line)}
.project-block:first-child{border-top:none;padding-top:0}
.project-block__header{display:flex;align-items:center;gap:18px;flex-wrap:wrap;margin-bottom:18px}
.project-block__logo{height:30px;width:auto;max-width:150px;object-fit:contain;object-position:left center;border-radius:10%}
.project-block__logo--icon{height:40px;width:40px;max-width:40px;border-radius:9px}
.project-block__logo--recolor{filter:brightness(0) saturate(100%)}
/* the project name — always a separate text node next to the logo, never
   baked into the logo graphic itself. Same .project-name class everywhere
   (project blocks and pcards) so every header reads consistently; only the
   size differs by context. */
.project-name{font-weight:800;color:var(--ink)}
.project-block__header .project-name{font-size:19px;margin-right:auto}
.project-block__visit{padding:9px 18px;font-size:13px;font-weight:700;white-space:nowrap}
.project-block__desc{font-size:14px;line-height:1.65;color:rgba(11,11,12,.68);max-width:none;margin-bottom:22px}
.project-block__note{font-size:13px;font-style:italic;color:rgba(11,11,12,.45);margin:-14px 0 22px}
.project-block__grid{display:grid;gap:20px}
.project-block__grid.project-grid--many{grid-template-columns:repeat(4,1fr)}
@media (max-width:900px){
  .project-block__grid.project-grid--many{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:560px){
  .project-block__grid.project-grid--many{grid-template-columns:1fr}
}
/* a single fixed aspect-ratio (rather than each clip's own --ar) keeps every
   cell in a row the same height regardless of the source video's real shape —
   cropped via object-fit:cover so the grid reads as tidy and aligned instead
   of uneven/misaligned when clips of different ratios sit side by side */
.project-block__grid .reel-card video,
.project-block__grid.project-grid--many .reel-card video{
  aspect-ratio:3/2;object-fit:cover;
}

/* content-type pills (Video / Lottie / Rive) shown under a block's header */
.project-tags{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 18px}
.tag-pill{
  display:inline-flex;align-items:center;font-family:var(--ff-display);
  font-size:11px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;
  padding:5px 12px;border-radius:100px;border:1px solid var(--line);
  color:rgba(11,11,12,.6);background:var(--paper-dim);
}

/* split layout — all four clips the same size, in one 2x2 grid, filling one
   unified block edge-to-edge (VersusTrade). A fixed height on the grid
   (rather than each clip's own aspect-ratio) is what makes the four cells
   equal and butt up against each other with no gaps or overflow, cropped to
   fit via object-fit:cover. */
.project-split{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;gap:14px;height:440px}
.project-split .reel-card{height:100%;margin:0;min-width:0;min-height:0}
.project-split .reel-card__btn{display:block;width:100%;height:100%}
/* aspect-ratio:auto is load-bearing here, not decoration — the generic
   .reel-card video rule sets aspect-ratio:var(--ar) at equal specificity, and
   inside a CSS Grid 1fr row a percentage height isn't treated as "definite"
   during the aspect-ratio sizing pass, so that rule was winning: each video
   sized itself from its own native ratio at its column width instead of
   filling the row, overflowing past the split's fixed 440px box (confirmed
   via computed style: aspect-ratio was resolving to the clip's real ratio,
   e.g. 1280/520, not "auto"). Cancelling it here is what makes height:100%
   actually apply. */
.project-split video{width:100%;height:100%;aspect-ratio:auto;object-fit:cover;border-radius:14px;border:1px solid var(--line);display:block;transition:border-color .35s cubic-bezier(.22,.68,.36,1)}
@media (max-width:900px){
  .project-split{grid-template-columns:1fr;grid-template-rows:none;height:auto}
  .project-split .reel-card{height:auto}
  .project-split .reel-card__btn{height:auto}
  .project-split video{height:auto;aspect-ratio:var(--ar,16/9)}
}

/* subtle hover-only shimmer sweep — Versus Partners' Visit Site button
   specifically, opted into via this class rather than
   applied to .btn-ghost/.project-block__visit sitewide */
.btn-shimmer{position:relative;overflow:hidden}
.btn-shimmer::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(115deg, transparent 40%, rgba(255,255,255,.55) 50%, transparent 60%);
  background-size:250% 100%;background-position:150% 0;opacity:0;
}
.btn-shimmer:hover::after{opacity:1;animation:btnShimmerSweep 1.2s linear infinite}
@keyframes btnShimmerSweep{
  from{background-position:150% 0}
  to{background-position:-150% 0}
}
@media (prefers-reduced-motion:reduce){
  .btn-shimmer:hover::after{animation:none;opacity:0}
}

/* ---------- pcard: ONE fixed-slot component for every 1-2 clip project ---------- */
/* Every project below (all but Merge and VersusTrade, which stay as their
   own larger showcase blocks) renders through this exact same component:
   hero -> header -> tags -> thumbnail strip -> description -> divider, each
   slot a fixed height/width. Nothing here is sized from a project's own
   content, so a row of cards lines up regardless of how many clips or how
   much description text any one of them has. Do not add per-project
   overrides to this block — a clip that needs special framing gets an
   object-position via CLIP_OBJECT_POSITION in the generator, not new CSS. */
.pgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:0 28px;margin-top:8px}
.pcard{
  display:flex;flex-direction:column;min-width:0;
  border-top:1px solid var(--line);padding:32px 0;
}

/* slot 1: media carousel — fixed square viewport; every clip a project has
   is a full-size slide (a poster is mandatory for every clip at generation
   time, so this is never blank). Arrows page between slides one at a time;
   a single-clip project still gets the same viewport, just with no arrows
   (nothing to page to). */
/* .pcard__media itself is NOT overflow:hidden — the hover glow lives on its
   own ::after and needs to bleed outside this box. Clipping the sliding
   track (so only one slide shows at a time) happens one level down, on
   .pcard__media-clip, so it never clips the glow layer above it. */
.pcard__media{position:relative;margin-bottom:16px;border-radius:14px}
/* the unclipped equivalent of .reel-card__btn's glow (see above) — same
   values, scoped to the whole carousel viewport instead of the individual
   slide button, since that's the level not clipped by the carousel's own
   overflow:hidden */
.pcard__media::after{
  content:"";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:2;
  opacity:0;box-shadow:0 0 22px 2px rgba(47,107,255,.42);
  transition:opacity .4s cubic-bezier(.22,.68,.36,1);
}
.pcard__media:hover::after{opacity:1;animation:cardGlowPulse 2.6s ease-in-out infinite}
.pcard__media-clip{position:relative;overflow:hidden;border-radius:14px}
.pcard__media-track{display:flex;transition:transform .3s cubic-bezier(.2,.8,.2,1)}
.pcard__media-track .reel-card{flex:0 0 100%;width:100%;margin:0}
.pcard__media-track .reel-card video{
  width:100%;aspect-ratio:1/1;object-fit:cover;
  border-radius:14px;border:1px solid var(--line);display:block;
  transition:border-color .35s cubic-bezier(.22,.68,.36,1);
}
/* the static 1px border fades out on hover everywhere — one rule for all
   three video contexts (Merge's grid, VersusTrade's split, the pcard
   carousel) since they all share the same .reel-card__btn > video
   structure. Placed after each context's own border declaration so it
   wins the specificity tie via source order. */
.reel-card__btn:hover video{border-color:transparent}
.pcard__media .reel-card figcaption{display:none}
/* solid filled circle, centered chevron, no border/gradient/shadow — shared
   by section 01's per-project pcard carousel and section 02's reel stage
   (which reuses this exact class, not a lookalike copy) */
.pcard__media-arrow{
  position:absolute;top:50%;transform:translateY(-50%);width:38px;height:38px;border-radius:50%;
  background:var(--ink);color:var(--paper);border:none;display:flex;align-items:center;
  justify-content:center;cursor:pointer;padding:0;z-index:2;
  opacity:0;transition:opacity .2s,background .2s;
}
.pcard__media-arrow svg{width:16px;height:16px;display:block}
.pcard__media-arrow--prev svg{transform:scaleX(-1)}
.pcard__media:hover .pcard__media-arrow{opacity:1}
.pcard__media-arrow:hover{background:rgba(11,11,12,.8)}
.pcard__media-arrow--prev{left:10px}
.pcard__media-arrow--next{right:10px}
@media (hover:none),(pointer:coarse){
  .pcard__media-arrow{opacity:.85}
}

/* slot 2: logo + label row — fixed height regardless of logo type or
   whether a name is shown next to it */
.pcard__header{display:flex;align-items:center;justify-content:space-between;gap:14px;height:40px;margin-bottom:12px}
.pcard__brand{display:flex;align-items:center;gap:10px;min-width:0;height:100%}
.pcard__brand .project-name{font-size:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pcard__visit{font-size:12px;padding:7px 14px;white-space:nowrap}

/* slot 3: type-tags row — fixed min-height so it takes the same vertical
   space whether a project carries one tag or three (.project-tags/.tag-pill
   are the shared pill styles also used on the Merge/VersusTrade blocks) */
.pcard .project-tags{min-height:26px;margin:0 0 14px}

/* slot 4: description — bounded to the card's own column width, always
   wraps, never overflows into the next column */
.pcard__desc{
  font-size:14px;line-height:1.65;color:rgba(11,11,12,.68);
  max-width:100%;overflow-wrap:break-word;min-height:calc(1.65em * 2);
}

@media (max-width:900px){
  .pgrid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:560px){
  .pgrid{grid-template-columns:1fr}
  .pcard__header{flex-wrap:wrap;height:auto}
}

/* ---------- AI-Generated Content: reel stage ----------
   Same background/section treatment as everywhere else on the site (no
   unique dark band) — a plain two-column layout: descriptive text on the
   left, one prominent vertical (9:16) reel at a time on the right, with the
   next/prev few reels peeking in depth behind it, coverflow-style. Every
   reel stays in the DOM at all times; switching the active one or the
   filter just recomputes each item's --tx/--scale/--op/--blur custom
   properties and lets them transition, rather than sliding a scrolling
   track (see .reels__track below for why: a scrolling container can't also
   let the glow bleed past its own box). */
.reels-layout{display:grid;grid-template-columns:320px 1fr;gap:56px;align-items:center}
.reels-layout__text h2{font-size:clamp(24px,2.6vw,32px);font-weight:800;margin-bottom:14px}
.reels-layout__text p{font-size:15px;line-height:1.65;color:rgba(11,11,12,.68);margin-bottom:28px}

/* ---------- stage ---------- */
/* Height is derived directly from .reels__item's own width formula (same
   9:16), not an independent clamp() — an independent formula drifts out of
   sync with the item's actual height at plenty of real viewport widths
   (e.g. 432px stage vs. a 498px-tall item at 1440px wide), and .reels__clip
   below silently crops whatever doesn't fit, top and bottom. Tying both to
   one formula makes that impossible. */
.reels__stage{
  position:relative;height:calc(min(280px,30vw) * 16 / 9);
  display:flex;align-items:center;justify-content:center;
}
/* The glow must render outside whatever clips the peeking side-reels. Full
   ancestor chain checked: .reels-layout/.reels__stage set no transform, no
   overflow, no contain — .reels__stage is the only positioned one (for the
   absolute children below), so it's the safe, unclipped anchor. Only
   .reels__clip (sized to the stage, wrapping .reels__track alone) gets
   overflow:hidden, purely to stop far off-stage reels from widening the
   page horizontally. .reels__glow is a DIRECT sibling of .reels__clip, at
   the same level, never a descendant of it — so it always renders in full,
   regardless of viewport width or how far the side reels sit. */
.reels__glow{
  position:absolute;top:50%;left:50%;z-index:0;pointer-events:none;
  width:min(280px,30vw);aspect-ratio:9/16;
  transform:translate(-50%,-50%);border-radius:28px;
  box-shadow:0 0 90px 12px rgba(47,107,255,.4);
  opacity:.85;animation:reelsGlowPulse 3.4s ease-in-out infinite;
  transition:opacity .25s cubic-bezier(.2,.8,.2,1);
}
/* the glow is a fixed, content-less rounded rect always centered on the
   stage — while a reel switch is mid-flight it would otherwise just sit
   there alone for a moment as the real content slides past it, reading as
   an empty placeholder frame. Hidden for the length of the transition (see
   hideGlowDuringTransition in main.js) so only real, moving content is ever
   on screen. */
.reels__stage.is-transitioning .reels__glow{opacity:0;animation:none}
@keyframes reelsGlowPulse{
  0%,100%{box-shadow:0 0 70px 8px rgba(47,107,255,.32)}
  50%{box-shadow:0 0 110px 18px rgba(47,107,255,.5)}
}
.reels__clip{position:absolute;inset:0;overflow:hidden}
.reels__track{position:absolute;inset:0}
.reels__item{
  position:absolute;top:50%;left:50%;z-index:1;
  width:min(280px,30vw);aspect-ratio:9/16;margin:0;
  --tx:0px;--scale:1;--op:1;--blur:0px;
  transform:translate(-50%,-50%) translateX(var(--tx)) scale(var(--scale));
  opacity:var(--op);filter:blur(var(--blur));
  /* 500ms, real ease-out (fast start, gentle settle) — the earlier .8s
     .16,1,.3,1 curve read as sluggish/stiff at this scale */
  transition:transform .5s cubic-bezier(.22,1,.36,1), opacity .5s cubic-bezier(.22,1,.36,1), filter .5s cubic-bezier(.22,1,.36,1);
}
/* no hover scale here — only the ambient glow (.reels__glow, always behind
   the active reel) responds to hover; the reel itself never resizes */
/* the video fills its button by absolute position instead of computing its
   own aspect-ratio — two independent aspect-ratio calcs (this box and the
   video's own) can drift apart by a few pixels in some engines, showing as
   a sliver of the card's own background peeking around the video; an
   absolute fill makes that impossible since there's only one size to
   compute, and object-fit:cover (inherited from .reel-card video) still
   crops the source to match exactly. */
.reels__item .reel-card__btn{border-radius:22px;height:100%}
.reels__item video{position:absolute;inset:0;width:100%;height:100%;border-radius:22px}
.reels__item .reel-card__btn::after{display:none} /* the shared per-card hover glow is replaced by .reels__glow */
/* the shared .reel-card__btn:hover scale(1.025) is also switched off here —
   .reels__stage clips tightly to the card's own size, so any scale-up
   pushes the video past that boundary and gets cropped top/bottom */
.reels__item .reel-card__btn:hover{transform:none}
.reels__item figcaption{display:none}
/* the active reel plays continuously (no hover needed — see main.js), so
   its play icon would be misleading; non-active reels aren't playing, so
   theirs still reads correctly as "click to feature this one" */
.reels__item.is-active .reel-play{opacity:0}

/* same arrow used for section 01's per-card carousel (.pcard__media-arrow)
   — reused directly rather than restyled, so this is pixel-identical, not
   a lookalike copy. Only the show/hide trigger differs (that component
   shows on hovering one card; this one shows on hovering the whole stage). */
.reels__stage:hover .pcard__media-arrow{opacity:1}

/* a small numbered index rather than generic dots — matches the site's
   existing "01 — Work" / .category-tile__num convention elsewhere */
.reels__count{
  margin-top:24px;font-family:var(--ff-display);font-size:13px;font-weight:700;
  letter-spacing:.1em;color:rgba(11,11,12,.4);font-variant-numeric:tabular-nums;
}
.reels__count b{color:var(--ink);font-weight:700}

@media (max-width:900px){
  .reels-layout{grid-template-columns:1fr;gap:24px}
  .reels__stage{height:calc(min(240px,54vw) * 16 / 9)}
  .reels__item{width:min(240px,54vw)}
  .reels__glow{width:min(240px,54vw)}
}

/* ---------- lightbox ---------- */
.lightbox{
  position:fixed;inset:0;z-index:1000;background:rgba(11,11,12,.92);
  display:flex;align-items:center;justify-content:center;padding:40px;
  opacity:0;pointer-events:none;transition:opacity .3s;
}
.lightbox.is-open{opacity:1;pointer-events:auto}
.lightbox__inner{max-width:min(1100px,90vw)}
.lightbox__video{width:100%;max-height:80vh;border-radius:12px;background:#000;display:block}
.lightbox__cap{margin-top:14px;font-size:14px;color:rgba(243,241,234,.65);text-align:center}
.lightbox__close{
  position:absolute;top:24px;right:28px;width:44px;height:44px;border-radius:50%;
  border:1px solid rgba(243,241,234,.3);background:transparent;color:var(--paper);
  font-size:18px;cursor:pointer;transition:background .2s;
}
.lightbox__close:hover{background:rgba(243,241,234,.12)}

/* ---------- about ---------- */
.section--about{padding-top:60px}
.about-grid{display:grid;grid-template-columns:.85fr 1.15fr;gap:72px;align-items:start}
.about-media{position:relative}
.about-media img{
  border-radius:24px;width:100%;aspect-ratio:4/5;object-fit:cover;
  border:1px solid var(--line);filter:grayscale(1) contrast(1.05);
}
.about-media__badge{
  position:absolute;bottom:-24px;left:-24px;background:var(--ink);color:var(--paper);
  padding:18px 22px;border-radius:16px;font-size:13px;line-height:1.4;max-width:200px;
  box-shadow:0 20px 40px -18px rgba(11,11,12,.5);
}
.about-media__badge span{display:block;color:rgba(243,241,234,.6);margin-bottom:4px}
.about-media__badge strong{font-family:var(--ff-display);font-size:15px}
.about-copy h2{font-size:clamp(30px,4.8vw,60px);font-weight:800;line-height:1.1;margin-bottom:28px}
.about-copy p{font-size:16px;line-height:1.7;color:rgba(11,11,12,.75);margin-bottom:18px;max-width:560px}
.facts{display:grid;grid-template-columns:1fr 1fr;gap:28px;margin-top:36px;padding-top:36px;border-top:1px solid var(--line)}
.fact{display:flex;flex-direction:column;gap:6px}
.fact--wide{grid-column:1 / -1}
.fact__label{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--accent-2)}
.fact__value{font-size:15px;font-weight:600;line-height:1.4}
.fact__value small{font-weight:400;color:rgba(11,11,12,.55)}

.exp{margin-top:44px;padding-top:36px;border-top:1px solid var(--line)}
.exp > .fact__label{display:block;margin-bottom:20px}
.exp-list{display:flex;flex-direction:column;gap:24px}
.exp-item{padding-bottom:24px;border-bottom:1px solid var(--line)}
.exp-item:last-child{padding-bottom:0;border-bottom:none}
.exp-item__head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;flex-wrap:wrap}
.exp-item__head h4{font-family:var(--ff-display);font-size:20px;font-weight:800}
.exp-item__dates{font-size:13px;font-weight:600;color:rgba(11,11,12,.55);white-space:nowrap}
.exp-item__role{font-size:14px;font-weight:600;color:var(--accent-2);margin-top:2px}
.exp-item__note{font-weight:400;color:rgba(11,11,12,.5);font-size:13px}
.exp-item__loc{font-size:13px;color:rgba(11,11,12,.55);margin-top:2px}
.exp-item__desc{font-size:14px;line-height:1.6;color:rgba(11,11,12,.72);margin-top:10px;max-width:480px}

/* ---------- skills cloud ---------- */
.skills-cloud{display:flex;flex-wrap:wrap;gap:14px}
.skills-cloud span{
  font-family:var(--ff-display);font-weight:600;font-size:16px;
  padding:12px 20px;border:1px solid var(--line);border-radius:100px;
  background:var(--paper-dim);transition:transform .3s, background .3s, color .3s;
}
.skills-cloud span.lg{font-size:22px;font-weight:700;background:transparent}
.skills-cloud span:hover{background:var(--ink);color:var(--accent);transform:translateY(-4px) rotate(-1deg)}

/* ---------- cta band ---------- */
.cta-band{background:var(--ink);color:var(--paper);padding:140px var(--pad);position:relative;overflow:hidden}
.cta-band::before{
  content:'';position:absolute;width:640px;height:640px;border-radius:50%;
  background:radial-gradient(circle,var(--accent-2) 0%,transparent 70%);opacity:.35;
  top:-260px;right:-160px;
}
.cta-band__inner{max-width:var(--container);margin:0 auto;position:relative;z-index:1}
.cta-band h2{font-size:clamp(34px,7vw,96px);font-weight:800;line-height:1.05;margin-bottom:24px}
.cta-band h2 em{color:var(--accent);font-style:normal}
.cta-band p{font-size:18px;color:rgba(243,241,234,.7);max-width:480px}
.cta-band .cta-note{font-size:14px;color:rgba(243,241,234,.5);margin-top:8px;margin-bottom:40px}
.cta-band .btn-primary{background:var(--accent);color:#fff;border-color:var(--accent)}
.cta-band .btn-primary:hover{background:var(--paper);border-color:var(--paper);color:var(--ink)}
.cta-band .btn-ghost{color:var(--paper);border-color:rgba(243,241,234,.3)}
.cta-band .btn-ghost:hover{background:var(--paper);color:var(--ink);border-color:var(--paper)}

/* ---------- footer ---------- */
.footer{padding:32px var(--pad);border-top:1px solid var(--line)}
.footer__top{display:flex;justify-content:space-between;align-items:center;font-family:var(--ff-display);font-weight:700;font-size:15px;padding-bottom:20px;margin-bottom:20px;border-bottom:1px solid var(--line)}
.footer__back{font-weight:600;color:rgba(11,11,12,.6);transition:color .2s}
.footer__back:hover{color:var(--ink)}
.footer__bottom{display:flex;justify-content:space-between;font-size:13px;color:rgba(11,11,12,.55)}
.footer__bottom a:hover{color:var(--ink)}

/* ---------- reveal animations ---------- */
.reveal{opacity:0;transform:translateY(28px);transition:opacity .8s cubic-bezier(.2,.8,.2,1), transform .8s cubic-bezier(.2,.8,.2,1)}
.reveal.is-visible{opacity:1;transform:translateY(0)}
/* full-width stacked sections (each project block/card) fade in place with
   no Y-offset — IntersectionObserver fires independently per element, so on
   a fast scroll two adjacent sections' 800ms transitions can overlap in
   time; with a translateY that lets one section's still-animating transform
   visually intrude into the section above/below it even though the final
   layout position is correct. A plain opacity fade can never do that. */
.project-block.reveal,.pcard.reveal{transform:none !important}
.reveal-word{opacity:0;transform:translateY(100%)}
.reveal-word.is-visible{animation:wordUp .8s cubic-bezier(.2,.8,.2,1) forwards}
@keyframes wordUp{to{opacity:1;transform:translateY(0)}}

/* stagger children inside skills/facts already fine without per-item delay */

/* ---------- responsive ---------- */
@media (max-width:900px){
  .nav__links,.nav__cta{display:none}
  .nav__burger{display:block}
  .mobile-menu{display:flex}
  .category-grid{grid-template-columns:1fr}
  .about-grid{grid-template-columns:1fr;gap:56px}
  .about-media{max-width:340px}
  .facts{grid-template-columns:1fr}
  .reel-grid{grid-template-columns:repeat(2,1fr)}
  .subcat-grid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:560px){
  .cta-band__actions .btn{width:100%;justify-content:center}
  .reel-grid{grid-template-columns:1fr}
  .subcat-grid{grid-template-columns:1fr}
  .page-header h1{font-size:clamp(30px,9vw,52px)}
}
