/* ==========================================================================
   Denis Ogorodov — standalone site
   Style C: "Big Media Windows"
   ========================================================================== */

:root {
  --bg: #0B0B0A;
  --ink: #F4F1E8;
  --ink-dim: rgba(244, 241, 232, 0.5);
  --ink-dimmer: rgba(244, 241, 232, 0.35);
  --accent: #E0574F;
  --border: rgba(244, 241, 232, 0.15);
  --tile-bg: #17110F;

  /* Footage-tint gradients — see the "Adding real footage" section in
     README.md. Each tile's window is built from two stacked layers:
     .media-fill (the actual video/image once you have it) and
     .tint-overlay (this gradient). Right now there's no footage, so the
     overlay sits at full opacity/normal blend and IS the visible tile —
     that's the clean placeholder look. Once you drop a <video> or <img>
     into .media-fill, flip the tile to data-has-footage="true" and the
     same gradient automatically becomes a color-grade wash over the real
     clip instead of a flat fill, so every category still reads as one
     consistent palette no matter how different the source footage is. */
  --tint-a: linear-gradient(160deg, #3a2418, #7a4a26 45%, #c98a4b); /* Broadcast/Film/Doc */
  --tint-b: linear-gradient(160deg, #2a1030, #7a1f6b 45%, #e0497a); /* Vertical & Social */
  --tint-c: linear-gradient(160deg, #0a1f2e, #124a5c 45%, #3fb8c9); /* VR & Immersive */
  --tint-d: linear-gradient(160deg, #0f2a22, #1f5c48 45%, #4fd19a); /* Interactive/Press/Games */
  --tint-e: linear-gradient(160deg, #2a0f10, #7a1f22 45%, #e0574f); /* Live Events & Stages */

  /* The five category mask shapes, shared by the home tiles, the small
     icon badge on each category page, and the "jump to another category"
     icons at the bottom of a category page — one shape definition, three
     places it's used. See the "category mask shapes" rule block below for
     where each of these is applied. */
  --mask-tv: url('data:image/svg+xml,%3Csvg viewBox=%270 0 200 200%27 fill=%27black%27 xmlns=%27http://www.w3.org/2000/svg%27%3E%3Crect x=%2712%27 y=%2728%27 width=%27176%27 height=%27112%27 rx=%2720%27/%3E%3Crect x=%2788%27 y=%27140%27 width=%2724%27 height=%2718%27 rx=%275%27/%3E%3Crect x=%2755%27 y=%27158%27 width=%2790%27 height=%2710%27 rx=%275%27/%3E%3C/svg%3E');
  --mask-vert: url('data:image/svg+xml,%3Csvg viewBox=%270 0 140 240%27 fill=%27black%27 xmlns=%27http://www.w3.org/2000/svg%27%3E%3Crect x=%276%27 y=%276%27 width=%27128%27 height=%27228%27 rx=%2726%27/%3E%3C/svg%3E');
  --mask-vr: url('data:image/svg+xml,%3Csvg viewBox=%270 0 200 200%27 fill=%27black%27 xmlns=%27http://www.w3.org/2000/svg%27%3E%3Cg transform=%27translate(21,6) scale(0.56) rotate(-10 100 112)%27%3E%3Cpath fill-rule=%27evenodd%27 d=%27M52 66 h96 c26 0 42 22 38 52 l-6 34 c-3 16 -22 20 -30 6 l-14 -24 h-72 l-14 24 c-8 14 -27 10 -30 -6 l-6 -34 c-4 -30 12 -52 38 -52 Z M70 90 h10 v11 h11 v10 h-11 v11 h-10 v-11 h-11 v-10 h11 Z M147 98 A7 7 0 1 0 133 98 A7 7 0 1 0 147 98 Z M165 112 A7 7 0 1 0 151 112 A7 7 0 1 0 165 112 Z%27/%3E%3C/g%3E%3Cg transform=%27translate(34,45.3) scale(0.84)%27%3E%3Cpath fill-rule=%27evenodd%27 d=%27M41 58 H159 A33 33 0 0 1 159 124 H41 A33 33 0 0 1 41 58 Z M86 91 A16 16 0 1 0 54 91 A16 16 0 1 0 86 91 Z M146 91 A16 16 0 1 0 114 91 A16 16 0 1 0 146 91 Z%27/%3E%3C/g%3E%3C/svg%3E');
  --mask-interactive: url('data:image/svg+xml,%3Csvg viewBox=%270 0 200 200%27 fill=%27black%27 xmlns=%27http://www.w3.org/2000/svg%27%3E%3Cg transform=%27translate(8,16) scale(0.48)%27 stroke=%27black%27 stroke-width=%2714%27 stroke-linecap=%27round%27%3E%3Cpath d=%27M55 65 L148 52 M148 52 L105 148 M105 148 L55 65%27 fill=%27none%27/%3E%3Ccircle cx=%2755%27 cy=%2765%27 r=%2718%27/%3E%3Ccircle cx=%27148%27 cy=%2752%27 r=%2715%27/%3E%3Ccircle cx=%27105%27 cy=%27148%27 r=%2720%27/%3E%3C/g%3E%3Cg transform=%27translate(42,42) scale(0.74)%27%3E%3Cpath d=%27M68 64 L68 136 Q68 150 80 143 L138 107 Q150 100 138 93 L80 57 Q68 50 68 64 Z%27/%3E%3C/g%3E%3Cg transform=%27translate(1,120) scale(0.33)%27 fill=%27none%27 stroke=%27black%27 stroke-width=%2714%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpath d=%27M82 50 L35 100 L82 150%27/%3E%3Cpath d=%27M118 50 L165 100 L118 150%27/%3E%3C/g%3E%3C/svg%3E');
  --mask-live: url('data:image/svg+xml,%3Csvg viewBox=%270 0 200 200%27 fill=%27black%27 xmlns=%27http://www.w3.org/2000/svg%27%3E%3Crect x=%276%27 y=%2722%27 width=%2746%27 height=%2762%27 rx=%278%27 transform=%27rotate(-18 29 53)%27/%3E%3Crect x=%27148%27 y=%2722%27 width=%2746%27 height=%2762%27 rx=%278%27 transform=%27rotate(18 171 53)%27/%3E%3Crect x=%2762%27 y=%276%27 width=%2776%27 height=%2782%27 rx=%2710%27/%3E%3Crect x=%2790%27 y=%27118%27 width=%2720%27 height=%2738%27 rx=%2710%27/%3E%3Cpath d=%27M75 150 a25 25 0 0 0 50 0 h-7 a18 18 0 0 1 -36 0 z%27/%3E%3Crect x=%2797%27 y=%27175%27 width=%275%27 height=%2715%27 rx=%272%27/%3E%3Crect x=%2785%27 y=%27190%27 width=%2729%27 height=%276%27 rx=%273%27/%3E%3C/svg%3E');
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: 'Inter', sans-serif;
}

a { color: inherit; }

.mono { font-family: 'IBM Plex Mono', monospace; }

/* ---------- header ---------- */

.site-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 28px 64px;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  background: var(--bg);
  z-index: 20;
}

.wordmark {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 14px;
  letter-spacing: 0.08em;
  font-weight: 500;
  background: none;
  border: none;
  color: inherit;
  padding: 0;
  cursor: pointer;
}

.wordmark-icon {
  width: 34px;
  height: 34px;
  flex: none;
  display: block;
}

.nav-links {
  display: flex;
  gap: 40px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.1em;
}

.nav-links a {
  text-decoration: none;
  transition: color 0.15s ease;
}

.nav-links a:hover { color: var(--accent); }

.menu-btn {
  display: none;
  flex-direction: column;
  gap: 4px;
  width: 22px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
  margin: -8px;
}

.menu-btn span {
  display: block;
  height: 1.5px;
  background: var(--ink);
}

.mobile-menu {
  display: none;
  flex-direction: column;
  gap: 0;
  position: fixed;
  inset: 65px 0 auto 0;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  z-index: 19;
  transform: translateY(-8px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.mobile-menu.is-open {
  display: flex;
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.mobile-menu a {
  padding: 20px 24px;
  border-bottom: 1px solid var(--border);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.1em;
  text-decoration: none;
}

/* ---------- hero ---------- */

.hero { padding: 56px 64px 40px; }

.eyebrow {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.14em;
  color: var(--accent);
  margin-bottom: 22px;
}

.hero h1 {
  margin: 0;
  font-family: 'Bebas Neue', sans-serif;
  font-weight: 400;
  font-size: 92px;
  line-height: 0.94;
  letter-spacing: 0.01em;
}

.hero-sub {
  margin: 22px 0 0;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--ink-dim);
  max-width: 780px;
  line-height: 1.7;
}

/* ---------- bento grid ---------- */

.bento {
  padding: 0 64px 24px;
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  /* clamp(), not a fixed px, so these rows — and the icon masks inside
     them, which size themselves off the row's own height (see
     "auto 120%" etc. below) — grow with a wide browser window instead of
     staying frozen at one size. The 420px floor keeps every width at or
     below ~1750px (ordinary laptop/desktop windows) pixel-identical to
     the old fixed 420px, and the 520px ceiling stops it from ballooning
     on an ultrawide monitor. */
  grid-template-rows: repeat(3, clamp(420px, 24vw, 520px));
  gap: 40px;
  grid-template-areas:
    "tv   vert"
    "vr   vert"
    "interactive live";
}

.tile {
  position: relative;
  display: flex;
  flex-direction: column;
}

.tile-window {
  position: relative;
  flex: 1;
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  background: var(--tile-bg);
  cursor: pointer;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  overflow: hidden;
  outline: 3px solid transparent;
  outline-offset: 6px;
  transition: outline-color 0.15s ease;
}

.tile:hover .tile-window,
.tile-window:focus-visible,
.tile.is-active .tile-window {
  outline-color: var(--accent);
}

.tile.is-active .tile-label { color: var(--accent); }

.media-fill,
.tint-overlay {
  position: absolute;
  inset: 0;
}

.media-fill {
  /* Empty for now — this is where a <video> or <img> goes once you have
     real footage for a category. See README.md. */
  background: #000;
}

.tile-window[data-tint="a"] .tint-overlay { background: var(--tint-a); }
.tile-window[data-tint="b"] .tint-overlay { background: var(--tint-b); }
.tile-window[data-tint="c"] .tint-overlay { background: var(--tint-c); }
.tile-window[data-tint="d"] .tint-overlay { background: var(--tint-d); }
.tile-window[data-tint="e"] .tint-overlay { background: var(--tint-e); }

/* Per-tile icon size tweaks on the home grid, relative to each tile's
   default mask-size: contain. Every one of these tiles turns out to be
   height-constrained under contain (each box is proportionally wider than
   its own icon's aspect ratio, tv/vr/vert alike) — measured via each
   .tile-window's actual rendered box, not assumed from the grid track
   sizes, since the caption text eats into that box's effective height.
   So scaling the height is the right lever for all three. */
.tile--tv .tile-window,
.tile--vr .tile-window {
  -webkit-mask-size: auto 120%;
  mask-size: auto 120%;
}

.tile--vert .tile-window {
  -webkit-mask-size: auto 90%;
  mask-size: auto 90%;
}

/* Once a tile has real footage in .media-fill, add data-has-footage="true"
   to .tile-window (in the HTML) and this rule turns the same gradient into
   a color-grade wash over the clip instead of a flat placeholder fill. */
.tile-window[data-has-footage="true"] .tint-overlay {
  mix-blend-mode: color;
  opacity: 0.8;
}

.footage-tag {
  position: absolute;
  top: 14px;
  left: 14px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(244, 241, 232, 0.65);
  background: rgba(0, 0, 0, 0.35);
  padding: 5px 8px;
}

.tile-window[data-has-footage="true"] .footage-tag { display: none; }

/* Named so the browser can morph each tile into the full-screen category
   page when it opens (see openCategory() in script.js). Only meaningful
   while #mainHome is visible — a display:none element is dropped from the
   view-transition tree, so there's no naming conflict with the backdrop
   below when the category page is open instead. */
.tile--tv .tile-window { view-transition-name: vt-tv; }
.tile--vert .tile-window { view-transition-name: vt-vert; }
.tile--vr .tile-window { view-transition-name: vt-vr; }
.tile--interactive .tile-window { view-transition-name: vt-interactive; }
.tile--live .tile-window { view-transition-name: vt-live; }

/* category mask shapes — one definition per category (see --mask-* in
   :root), reused by the home tile window, the small icon badge on that
   category's page, and the "jump to another category" icon buttons at the
   bottom of a category page. */
.tile--tv .tile-window,
.category-icon-badge[data-cat="tv"],
.other-cat-icon-shape[data-cat="tv"] {
  -webkit-mask-image: var(--mask-tv);
  mask-image: var(--mask-tv);
}

.tile--vert .tile-window,
.category-icon-badge[data-cat="vert"],
.other-cat-icon-shape[data-cat="vert"] {
  -webkit-mask-image: var(--mask-vert);
  mask-image: var(--mask-vert);
}

.tile--vr .tile-window,
.category-icon-badge[data-cat="vr"],
.other-cat-icon-shape[data-cat="vr"] {
  -webkit-mask-image: var(--mask-vr);
  mask-image: var(--mask-vr);
}

.tile--interactive .tile-window,
.category-icon-badge[data-cat="interactive"],
.other-cat-icon-shape[data-cat="interactive"] {
  -webkit-mask-image: var(--mask-interactive);
  mask-image: var(--mask-interactive);
}

.tile--live .tile-window,
.category-icon-badge[data-cat="live"],
.other-cat-icon-shape[data-cat="live"] {
  -webkit-mask-image: var(--mask-live);
  mask-image: var(--mask-live);
}

.tile-caption {
  margin-top: 16px;
}

.tile-label {
  margin: 0;
  font-family: 'Bebas Neue', sans-serif;
  font-weight: 400;
  font-size: 26px;
  letter-spacing: 0.02em;
  color: var(--ink);
  transition: color 0.15s ease;
}

/* ---------- footer ---------- */

.site-footer {
  margin-top: 24px;
  padding: 34px 64px 46px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.talk {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 30px;
  color: var(--accent);
  text-decoration: none;
  letter-spacing: 0.02em;
}

.copyright {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  color: var(--ink-dimmer);
}

/* ==========================================================================
   Category page — full-screen subpage opened from a home tile
   ========================================================================== */

#mainHome.is-hidden { display: none; }

.category-page {
  position: relative;
  min-height: 100vh;
}

.category-page[hidden] { display: none; }

.category-hero-backdrop {
  position: relative;
  padding: 28px 64px 54px;
  min-height: 340px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background: var(--tile-bg);
  overflow: hidden;
}

/* the backdrop's own color comes from the same --tint-* used by the tile
   that opened it, assigned via data-tint in script.js's openCategory() */
.category-hero-backdrop[data-tint="a"] { background: var(--tint-a); }
.category-hero-backdrop[data-tint="b"] { background: var(--tint-b); }
.category-hero-backdrop[data-tint="c"] { background: var(--tint-c); }
.category-hero-backdrop[data-tint="d"] { background: var(--tint-d); }
.category-hero-backdrop[data-tint="e"] { background: var(--tint-e); }

/* Optional hero photo for a category's color band — set via `heroImage` on
   a category in script.js's CATEGORIES (so far just `tv`). When present,
   showCategory() adds data-has-image="true" and sets this element's
   background; the flat tint above is replaced by the photo, with the same
   tint gradient laid back over it as a color-grade wash (mix-blend-mode:
   color, same trick the home tiles use for real footage) so every category
   band still reads as one consistent palette. A bottom-up dark gradient on
   top keeps the title/description legible over a busy photo. See README.md
   "Hero image for a category page". */
.hero-media-fill {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
}

.hero-tint { display: none; }

.category-hero-backdrop[data-has-image="true"] {
  background: var(--tile-bg);
}

.category-hero-backdrop[data-has-image="true"] .hero-tint {
  display: block;
  position: absolute;
  inset: 0;
  mix-blend-mode: color;
  opacity: 0.85;
}

.category-hero-backdrop[data-has-image="true"][data-tint="a"] .hero-tint { background: var(--tint-a); }
.category-hero-backdrop[data-has-image="true"][data-tint="b"] .hero-tint { background: var(--tint-b); }
.category-hero-backdrop[data-has-image="true"][data-tint="c"] .hero-tint { background: var(--tint-c); }
.category-hero-backdrop[data-has-image="true"][data-tint="d"] .hero-tint { background: var(--tint-d); }
.category-hero-backdrop[data-has-image="true"][data-tint="e"] .hero-tint { background: var(--tint-e); }

/* A plain stacked element rather than a ::before — a pseudo-element
   generates as the FIRST child in paint order (so it would land behind
   hero-media-fill above, not in front of it), while a real element placed
   after hero-media-fill/hero-tint in the HTML paints on top of them, same
   as everything else on this stack (see the stacking-order note on
   .category-head below). */
.hero-scrim { display: none; }

.category-hero-backdrop[data-has-image="true"] .hero-scrim {
  display: block;
  position: absolute;
  inset: 0;
  background: linear-gradient(0deg, rgba(11, 11, 10, 0.92) 0%, rgba(11, 11, 10, 0.55) 50%, rgba(11, 11, 10, 0.05) 75%, rgba(11, 11, 10, 0.25) 100%);
}

/* Small watermark version of the category's own icon — same mask shape as
   the home tile, rendered as a dark solid cutout instead of the gradient
   fill, sitting in the corner of the color band as a quiet "you are here"
   marker. data-cat is set in script.js's showCategory(). */
.category-icon-badge {
  position: absolute;
  top: 28px;
  right: 64px;
  width: 130px;
  height: 130px;
  background: rgba(255, 255, 255, 0.85);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  pointer-events: none;
}

/* Positioned (not just in-flow) so it paints above the absolutely-
   positioned hero-media-fill/hero-tint layers above — without this,
   browsers stack any z-index:auto positioned element above plain in-flow
   content regardless of DOM order, so a hero photo would otherwise cover
   the title/description. */
.category-head {
  position: relative;
}

.category-title {
  margin: 0;
  font-family: 'Bebas Neue', sans-serif;
  font-weight: 400;
  font-size: 68px;
  line-height: 0.96;
  letter-spacing: 0.01em;
  color: var(--ink);
}

.category-desc {
  margin: 18px 0 0;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  color: rgba(244, 241, 232, 0.75);
  max-width: 640px;
  line-height: 1.6;
}

.work-grid {
  padding: 56px 64px 80px;
  display: flex;
  flex-direction: column;
  gap: 56px;
}

/* A "group" clusters a client/campaign's projects (e.g. three Espolón
   Tequila spots, four TeamUSA athlete films) under one shared heading,
   so they read as a set instead of as unrelated tiles — see the `group`
   field on a work item in script.js's CATEGORIES, and renderWorkGrid().
   A work item with no `group` just renders in its own unheaded section,
   same look as the old flat grid. */
.work-group-title {
  margin: 0 0 20px;
  font-family: 'Bebas Neue', sans-serif;
  font-weight: 400;
  font-size: 24px;
  letter-spacing: 0.02em;
  color: var(--ink-dim);
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}

.work-group-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
}

.work-card { display: flex; flex-direction: column; }

.work-thumb {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: none;
  background: var(--tile-bg);
  cursor: pointer;
  overflow: hidden;
}

.work-thumb .thumb-fill,
.work-thumb .thumb-tint,
.work-thumb .thumb-embed {
  position: absolute;
  inset: 0;
}

.work-thumb .thumb-fill { background: #000; }

.work-thumb .play-icon {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  color: var(--ink);
  background: rgba(0, 0, 0, 0.15);
  transition: background 0.15s ease;
}

.work-thumb:hover .play-icon { background: rgba(0, 0, 0, 0.05); }

.work-thumb.is-playing .play-icon,
.work-thumb.is-playing .thumb-tint { display: none; }

.thumb-embed { display: none; }
.work-thumb.is-playing .thumb-embed { display: block; }
.thumb-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: none; z-index: 1; }

/* The ✕ that backs out of a playing video — transparent, just the glyph,
   sitting above the iframe (which is appended after it, so it would
   otherwise stack on top without this) in the embed's top-right corner.
   See closeActivePlayer() in script.js. */
.thumb-close {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  padding: 0;
  color: #fff;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.85);
  opacity: 0.8;
  transition: opacity 0.15s ease;
}

.thumb-close:hover,
.thumb-close:focus-visible { opacity: 1; }

/* Custom Cloudflare Stream controls — the native control bar is turned off
   (controls=false, see buildEmbedUrl()/REEL_VIDEO_UID embed in script.js)
   because Cloudflare only lets you show/hide the whole bar, not individual
   buttons. This small replacement bar drops the settings/quality gear and
   picture-in-picture icons, and its right-most button fills the browser
   window in-page instead of the real Fullscreen API. See
   mountStreamControls() / setFillMode() in script.js. */
.cf-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0));
}

.cf-btn {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  padding: 2px;
  color: #fff;
  cursor: pointer;
  opacity: 0.9;
}

.cf-btn:hover,
.cf-btn:focus-visible { opacity: 1; }

.cf-btn svg { display: block; }

.cf-time {
  flex: 0 0 auto;
  color: #fff;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  white-space: nowrap;
}

.cf-progress {
  flex: 1 1 auto;
  min-width: 30px;
  -webkit-appearance: none;
  appearance: none;
  height: 3px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 2px;
  outline: none;
  cursor: pointer;
}

.cf-progress::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: #fff;
  cursor: pointer;
}

.cf-progress::-moz-range-thumb {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: #fff;
  border: none;
  cursor: pointer;
}

.cf-progress::-moz-range-track {
  height: 3px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 2px;
}

/* "Fill the window" — an in-page stand-in for real fullscreen, toggled by
   .cf-fill and exited the same way (press again), via Escape, or via the ✕
   close button. The holder just goes position:fixed over the viewport; no
   requestFullscreen() call, so there's no OS/browser fullscreen chrome.
   !important on position: on the Reel page, ".reel-player .thumb-embed"
   (further down, same specificity) also sets position:absolute, and being
   later in the file it would otherwise win the tie and strand this at the
   reel player's own location/size instead of covering the viewport —
   which also pushed the ✕ close button off-screen since it's positioned
   relative to this holder. !important makes this win regardless of where
   else "position" gets set on .thumb-embed. */
.thumb-embed.is-filled {
  position: fixed !important;
  inset: 0;
  width: 100vw;
  height: 100vh;
  z-index: 9999;
  background: #000;
}

.thumb-embed.is-filled .cf-bar {
  padding: 16px 22px;
  gap: 16px;
}

.thumb-embed.is-filled .cf-btn svg { width: 19px; height: 19px; }

.thumb-embed.is-filled .cf-time { font-size: 13px; }

body.has-filled-video { overflow: hidden; }

/* Every other thumbnail on the page dims and desaturates while one video
   plays — a focus cue that replaces the old grow/shrink-on-play behavior
   (see dimOthers() in script.js). Not used on the Vertical & Social page. */
.work-thumb.is-dimmed,
.work-thumb--cluster.is-dimmed {
  opacity: 0.5;
  filter: grayscale(100%);
}

.work-thumb,
.work-thumb--cluster {
  transition: opacity 0.2s ease, filter 0.2s ease;
}

.thumb-coming-soon {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(244, 241, 232, 0.5);
  text-align: center;
  padding: 20px;
}

.work-meta { margin-top: 14px; }

.work-title {
  margin: 0;
  font-family: 'Bebas Neue', sans-serif;
  font-weight: 400;
  font-size: 20px;
  letter-spacing: 0.02em;
}

.work-desc {
  margin: 6px 0 0;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10.5px;
  color: var(--ink-dimmer);
  line-height: 1.5;
}

/* ---------- cluster cards (a multi-video project collapsed into one
   thumbnail — see buildClusterCard() in script.js) ---------- */

/* Expanding a cluster makes its card span the full grid width so its
   sub-videos have room to lay out in their own row — but the collapsed
   thumbnail itself stays capped to its original card width instead of
   stretching to fill that whole row at 16:9. The cap is computed to match
   .work-group-grid's own math exactly (3 columns, 2 gaps of 40px) rather
   than a guessed fixed pixel value, so a cluster's "main" thumbnail is
   really the same size collapsed and expanded, at any viewport width —
   not just approximately. (Vertical & Social overrides this below with
   its own fixed 60px "button" size once expanded, at higher specificity.) */
.work-card--cluster.is-expanded {
  grid-column: 1 / -1;
}

.work-card--cluster.is-expanded .cluster-stack-wrap,
.work-card--cluster.is-expanded .work-meta {
  max-width: calc((100% - 2 * 40px) / 3);
}

/* On the portrait (9:16) Vertical & Social grid, a full-size collapsed
   thumbnail is still tall once expanded (220 wide x 391 tall) and pushes
   the sub-video row down. Once you've opened it, the big preview has
   served its purpose, so shrink it down to a small vertical "button" that
   sits beside the title instead of above it — a grid with named areas
   places the thumb/meta/sub-videos regardless of their order in the
   markup, so the sub-grid can sit right under that compact header row. */
.work-grid--vertical .work-card--cluster.is-expanded {
  display: grid;
  grid-template-columns: 60px 1fr;
  grid-template-areas:
    "thumb meta"
    "items items";
  column-gap: 14px;
  align-items: center;
}

.work-grid--vertical .work-card--cluster.is-expanded .cluster-stack-wrap {
  grid-area: thumb;
  max-width: 60px;
}

.work-grid--vertical .work-card--cluster.is-expanded .work-meta {
  grid-area: meta;
  max-width: none;
  margin-top: 0;
}

.work-grid--vertical .work-card--cluster.is-expanded .cluster-items {
  grid-area: items;
}

/* No room for the video-count badge at button size — the sub-videos are
   right there now, so the count would be redundant anyway. */
.work-grid--vertical .work-card--cluster.is-expanded .cluster-badge {
  display: none;
}

.work-grid--vertical .work-card--cluster.is-expanded .cluster-expand-icon {
  font-size: 18px;
}

.work-grid--vertical .work-card--cluster.is-expanded .cluster-stack-far {
  transform: translate(5px, 5px);
}

.work-grid--vertical .work-card--cluster.is-expanded .cluster-stack-near {
  transform: translate(2.5px, 2.5px);
}

/* Two offset rectangles peeking out behind the real thumbnail, suggesting
   "more than one" before you even read the count badge. */
.cluster-stack-wrap {
  position: relative;
}

.cluster-stack {
  position: absolute;
  inset: 0;
  background: var(--tile-bg);
  border: 1px solid var(--border);
}

.cluster-stack-far { transform: translate(14px, 14px); opacity: 0.45; }
.cluster-stack-near { transform: translate(7px, 7px); opacity: 0.7; }

.cluster-badge {
  position: absolute;
  bottom: 14px;
  left: 14px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(244, 241, 232, 0.65);
  background: rgba(0, 0, 0, 0.45);
  padding: 5px 8px;
}

.cluster-expand-icon {
  font-size: 30px;
  font-weight: 300;
  transition: transform 0.15s ease;
}

/* A "+" rotated 45° reads as "×" — same icon doubles as the collapse
   affordance once expanded. */
.work-card--cluster.is-expanded .cluster-expand-icon { transform: rotate(45deg); }

.cluster-items {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 24px;
  margin-top: 28px;
}

/* Outside the Vertical & Social page, a cluster's sub-video thumbnails
   use the exact same column count and gap as the page's own standalone/
   main-thumbnail grid (.work-group-grid above), so every thumbnail on the
   page — standalone, a cluster's own collapsed thumbnail, or one of its
   sub-videos — is always exactly the same size, no matter how many
   sub-videos a given cluster has. The Vertical & Social page keeps its
   original auto-fit sizing above (not covered by this rule). */
.work-grid:not(.work-grid--vertical) .cluster-items {
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
}

.cluster-items[hidden] { display: none; }

/* Sub-videos inside an expanded cluster read as secondary to the category's
   own project tiles — smaller title, no description clutter. */
.work-card--sub .work-title { font-size: 15px; }
.work-card--sub .work-meta { margin-top: 10px; }
.work-card--sub .work-desc { display: none; }

/* Vertical & Social's work-grid gets a portrait-shaped thumbnail instead of
   16:9, so the grid itself reads as "these are vertical videos" before you
   even press play. Narrower, non-stretching columns keep the tall thumbs
   from ballooning to an awkward height on wide screens. */
.work-grid--vertical .work-group-grid {
  grid-template-columns: repeat(auto-fill, 220px);
  justify-content: start;
}

.work-grid--vertical .work-thumb { aspect-ratio: 9 / 16; }

/* ---------- other categories (bottom of a category page) ---------- */

.other-categories {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: 48px;
  padding: 20px 64px 80px;
  border-top: 1px solid var(--border);
  margin: 0 64px;
}

.other-cat-icon {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  background: none;
  border: none;
  padding: 24px 8px 0;
  cursor: pointer;
  color: var(--ink-dim);
}

.other-cat-icon-shape {
  display: block;
  width: 56px;
  height: 56px;
  background: var(--ink-dimmer);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  transition: background 0.15s ease;
}

.other-cat-icon:hover .other-cat-icon-shape,
.other-cat-icon:focus-visible .other-cat-icon-shape {
  background: var(--accent);
}

/* On hover/focus, each icon fills with its own category's tint — the same
   gradient used on the home tile and that category's color band — instead
   of one shared accent color, so the icon itself hints at which format
   you're about to jump to. */
.other-cat-icon:hover .other-cat-icon-shape[data-cat="tv"],
.other-cat-icon:focus-visible .other-cat-icon-shape[data-cat="tv"] {
  background: var(--tint-a);
}

.other-cat-icon:hover .other-cat-icon-shape[data-cat="vert"],
.other-cat-icon:focus-visible .other-cat-icon-shape[data-cat="vert"] {
  background: var(--tint-b);
}

.other-cat-icon:hover .other-cat-icon-shape[data-cat="vr"],
.other-cat-icon:focus-visible .other-cat-icon-shape[data-cat="vr"] {
  background: var(--tint-c);
}

.other-cat-icon:hover .other-cat-icon-shape[data-cat="interactive"],
.other-cat-icon:focus-visible .other-cat-icon-shape[data-cat="interactive"] {
  background: var(--tint-d);
}

.other-cat-icon:hover .other-cat-icon-shape[data-cat="live"],
.other-cat-icon:focus-visible .other-cat-icon-shape[data-cat="live"] {
  background: var(--tint-e);
}

.other-cat-icon-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
  max-width: 120px;
  line-height: 1.5;
  transition: color 0.15s ease;
}

.other-cat-icon:hover .other-cat-icon-label,
.other-cat-icon:focus-visible .other-cat-icon-label {
  color: var(--ink);
}

/* ---------- floating back button ---------- */

/* One shared "back to work" button, fixed to the viewport, shown whenever
   a category page or the about page is open (see showCategory()/showAbout()/
   showHome() in script.js) — so you're never stuck scrolling back to the top
   just to leave a subpage, especially on mobile. This replaces the need for
   a second full-size back button at the bottom of every page. */
.floating-back-btn {
  position: fixed;
  left: 24px;
  bottom: 24px;
  z-index: 30;
  background: rgba(11, 11, 10, 0.85);
  backdrop-filter: blur(4px);
  border: 1px solid var(--border);
  color: var(--ink);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.08em;
  padding: 12px 18px;
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4);
  transition: background 0.15s ease, border-color 0.15s ease;
}

.floating-back-btn[hidden] { display: none; }

.floating-back-btn:hover {
  background: rgba(11, 11, 10, 0.97);
  border-color: var(--accent);
}

/* ==========================================================================
   About page — bio + contact form, opened from "CONTACT" nav or "Let's talk"
   ========================================================================== */

.about-page[hidden] { display: none; }

.about-page {
  position: relative;
  min-height: 100vh;
  padding: 72px 64px 90px;
}

.about-wrap {
  display: grid;
  grid-template-columns: 340px 1fr;
  gap: 72px;
  align-items: start;
}

/* Wraps the photo + social icons as their own column so the icons sit
   snugly below the photo, independent of how tall the bio/contact-form
   column on the right ends up being (CSS Grid auto-placement would
   otherwise push a 3rd grid child below the entire tall row instead). */
.about-left {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.about-photo {
  position: relative;
  aspect-ratio: 4 / 5;
  background: var(--tile-bg);
  overflow: hidden;
}

.about-social {
  display: flex;
  gap: 22px;
}

.about-social-link {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-dim);
  transition: color 0.2s ease;
}

.about-social-link svg {
  width: 26px;
  height: 26px;
}

.about-social-link:hover {
  color: var(--accent);
}

.about-photo img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.about-photo-placeholder {
  display: none;
  position: absolute;
  inset: 0;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 24px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  line-height: 1.7;
  letter-spacing: 0.04em;
  color: var(--ink-dimmer);
  border: 1px dashed var(--border);
}

.about-photo-placeholder code {
  color: var(--ink-dim);
}

.about-photo.is-placeholder img { display: none; }
.about-photo.is-placeholder .about-photo-placeholder { display: flex; }

.about-content { max-width: 640px; }

.about-bio .eyebrow { margin-bottom: 18px; }

.about-title {
  margin: 0 0 22px;
  font-family: 'Bebas Neue', sans-serif;
  font-weight: 400;
  font-size: 56px;
  line-height: 0.96;
  letter-spacing: 0.01em;
}

.about-bio p {
  margin: 0 0 16px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  line-height: 1.75;
  color: rgba(244, 241, 232, 0.8);
  max-width: 620px;
}

.about-contact {
  margin-top: 56px;
  padding-top: 40px;
  border-top: 1px solid var(--border);
}

.contact-heading {
  margin: 0 0 10px;
  font-family: 'Bebas Neue', sans-serif;
  font-weight: 400;
  font-size: 34px;
  color: var(--accent);
  letter-spacing: 0.02em;
}

.contact-sub {
  margin: 0 0 28px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12.5px;
  color: var(--ink-dim);
  line-height: 1.6;
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
  max-width: 480px;
}

.hp-field {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.field span {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.field input,
.field textarea {
  background: var(--tile-bg);
  border: 1px solid var(--border);
  color: var(--ink);
  font-family: 'Inter', sans-serif;
  font-size: 14px;
  padding: 12px 14px;
  resize: vertical;
}

.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--accent);
}

.submit-btn {
  align-self: flex-start;
  margin-top: 6px;
  background: var(--accent);
  color: var(--bg);
  border: none;
  font-family: 'Bebas Neue', sans-serif;
  font-size: 20px;
  letter-spacing: 0.02em;
  padding: 12px 26px;
  cursor: pointer;
  transition: opacity 0.15s ease;
}

.submit-btn:hover { opacity: 0.85; }
.submit-btn:disabled { opacity: 0.5; cursor: default; }

.form-status {
  margin: 4px 0 0;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  color: var(--ink-dim);
  min-height: 1.4em;
}

.form-status.is-error { color: var(--accent); }
.form-status.is-success { color: #4fd19a; }

/* ==========================================================================
   Reel page — the motion graphics/color showreel, opened from "REELS" nav
   ========================================================================== */

.reel-page[hidden] { display: none; }

.reel-page {
  position: relative;
  min-height: 100vh;
  padding: 72px 64px 90px;
  display: flex;
  justify-content: center;
}

.reel-wrap {
  width: 100%;
  max-width: 1100px;
}

.reel-wrap .eyebrow { margin-bottom: 18px; }

.reel-title {
  margin: 0 0 14px;
  font-family: 'Bebas Neue', sans-serif;
  font-weight: 400;
  font-size: 56px;
  line-height: 0.96;
  letter-spacing: 0.01em;
}

.reel-sub {
  margin: 0 0 32px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  color: var(--ink-dim);
  line-height: 1.6;
}

.reel-player {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: none;
  background: var(--tile-bg);
  cursor: pointer;
  overflow: hidden;
}

.reel-player .thumb-fill,
.reel-player .thumb-embed {
  position: absolute;
  inset: 0;
}

.reel-player .thumb-fill { background: #000; }

.reel-player .play-icon {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
  color: var(--ink);
  background: rgba(0, 0, 0, 0.15);
  transition: background 0.15s ease;
}

.reel-player:hover .play-icon { background: rgba(0, 0, 0, 0.05); }

.reel-player.is-playing .play-icon { display: none; }

.reel-player .thumb-embed { display: none; }
.reel-player.is-playing .thumb-embed { display: block; }
.reel-player .thumb-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: none; z-index: 1; }

/* ==========================================================================
   Mobile (< 900px) — single-column stack, same windows, full width
   ========================================================================== */

@media (max-width: 900px) {

  .site-header { padding: 20px 22px; }
  .nav-links { display: none; }
  .menu-btn { display: flex; }
  .wordmark { gap: 9px; }
  .wordmark-icon { width: 28px; height: 28px; }

  .hero { padding: 36px 22px 30px; }
  .hero h1 { font-size: 52px; line-height: 0.96; }
  .hero-sub { font-size: 12px; }

  .bento {
    display: block;
    padding: 0 22px 10px;
  }

  .tile {
    margin-bottom: 52px;
  }

  .tile-window {
    flex: none;
    height: 380px;
    -webkit-mask-size: 74%;
    mask-size: 74%;
  }

  /* Same relative +20%/+20%/-10% icon-size adjustment as the desktop
     overrides above, scaled off the mobile baseline — all bumped up
     another 20% on top of that (62%/74%/56% → 74%/89%/67%) per request. */
  .tile--tv .tile-window,
  .tile--vr .tile-window {
    -webkit-mask-size: 89%;
    mask-size: 89%;
  }

  .tile--vert .tile-window {
    -webkit-mask-size: 67%;
    mask-size: 67%;
  }

  .tile--vert .tile-window { height: 460px; }

  .tile-label { font-size: 22px; }

  .site-footer { padding: 30px 22px 40px; }
  .talk { font-size: 26px; }

  .category-hero-backdrop { padding: 20px 22px 36px; min-height: 260px; }
  .category-title { font-size: 40px; }
  .category-desc { font-size: 12px; }
  .work-grid { padding: 36px 22px 60px; gap: 44px; }
  .work-group-title { font-size: 20px; margin-bottom: 16px; padding-bottom: 10px; }
  .work-group-grid { grid-template-columns: 1fr; gap: 36px; }

  .work-grid:not(.work-grid--vertical) .cluster-items {
    grid-template-columns: 1fr;
    gap: 36px;
  }

  /* .work-group-grid is a single column at this width, so a cluster's own
     collapsed thumbnail is already full-width — match that once expanded
     too instead of still capping to the (now irrelevant) desktop 3-column
     math above. */
  .work-grid:not(.work-grid--vertical) .work-card--cluster.is-expanded .cluster-stack-wrap,
  .work-grid:not(.work-grid--vertical) .work-card--cluster.is-expanded .work-meta {
    max-width: none;
  }

  .work-grid--vertical .work-group-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
  }

  .category-icon-badge { top: 16px; right: 22px; width: 70px; height: 70px; }

  .other-categories { gap: 28px; padding: 16px 22px 60px; margin: 0 22px; }
  .other-cat-icon-shape { width: 44px; height: 44px; }
  .other-cat-icon-label { font-size: 9px; max-width: 88px; }

  .floating-back-btn { left: 16px; bottom: 16px; padding: 10px 16px; font-size: 11px; }

  .reel-page { padding: 52px 22px 60px; }
  .reel-title { font-size: 40px; }
  .reel-sub { font-size: 12px; }

  .about-page { padding: 52px 22px 60px; }
  .about-wrap { grid-template-columns: 1fr; gap: 32px; }
  .about-photo { max-width: 260px; aspect-ratio: 4 / 5; }
  .about-social { max-width: 260px; }
  .about-title { font-size: 40px; }
  .contact-heading { font-size: 28px; }
  .about-contact { margin-top: 40px; padding-top: 28px; }
}
