/* ============================================================
   TKM — Tyler Kosec Media
   Design System + Global Styles
   ============================================================ */

/* Fonts load from a <link> in each page head, not an @import. An @import
   inside a stylesheet serialises the requests: the browser must fetch and
   parse main.css before it even learns the fonts exist. */

/* ── Custom Properties ────────────────────────────────────── */
:root {
  /* ── Oxblood ──────────────────────────────────────────────────────
     Chosen 2026-09-29. The old palette was #080808 with a bright accent,
     which is on the frontend-design skill's list of AI-design tells by name.
     It was also not TKM: it was the palette any dark agency site arrives at.

     This one is the logo's red taken seriously - not a red accent on black,
     but red as the whole field, the way a shop wall or a race livery is red.
     The accent is hi-vis orange because that is the actual material Tyler
     works around: cones, vests, equipment. His words: "I love high viz orange
     in real life."

     Contrast, measured not guessed:
       bone on oxblood    8.42:1  passes for body text
       dew  on oxblood    6.71:1  passes for body text
       dew  on ink       13.20:1
       stone on bone      4.94:1  passes for body text
     Every colour here can carry reading text, which the orange could not.

     The accent used to be hi-vis orange, on Tyler's note that he likes it in
     real life. It was wrong for a reason worth writing down: orange sits
     about 20 degrees from this red on the colour wheel, so the field and the
     accent were two hot saturated hues with nothing between them, and the
     page read muddy. Tyler: "the colors are kind of weird." That was hue
     distance, not brightness, so reaching for a different bright colour
     would not have fixed it.

     Dew is cold, desaturated and roughly complementary: it separates instead
     of vibrating, and it is turf, which is where half the work gets shot.
     Desaturated far enough that red and green never land as Christmas.

     The field also went deeper, #8E1B14 to #7C1F18, so it stops competing
     with the footage sitting on top of it. */
  --oxblood:     #7C1F18;
  --bone:        #EFE9DF;
  --dew:         #C9D6C0;
  --dew-hot:     #E2EADB;
  --ink:         #1A1512;
  --rust:        #5C1009;
  --stone:       #6B625B;

  /* Legacy names. Roughly 2,600 lines already reference these; renaming every
     call site is churn with no payoff, so the names stay and the values move.
     --red resolves to orange now, and that is correct: on an oxblood field,
     orange is what pops. Red on red would not. */
  --bg:          var(--ink);
  --bg-mid:      #241C18;
  --bg-card:     #2A211C;
  --red:         var(--dew);
  --red-hot:     var(--dew-hot);
  --red-dim:     var(--rust);
  --red-bright:  var(--dew);
  /* Brass is retired. Red plus orange plus gold was three hot hues competing
     for the same job. Proof now reads in bone, quietly, which is what proof
     should do. Chanel's rule: take one thing off before you leave. */
  --brass:       var(--bone);
  --white:       var(--bone);
  --white-dim:   #C6B8AC;
  --border:      rgba(255, 106, 19, 0.28);
  --border-dim:  rgba(239, 233, 223, 0.14);

  --font-block:  'Archivo', system-ui, sans-serif;
  --fs-lead:     clamp(1.0625rem, 1.4vw, 1.1875rem);  /* 17-19px  leads */
  --fs-body:     clamp(1rem, 1.2vw, 1.0625rem);       /* 16-17px  read */
  --fs-cap:      0.8125rem;                           /* 13px     captions */
  --font-text:   'Literata', Georgia, serif;
  --font-cond:   var(--font-text);   /* prose; 26 rules already use it */
  --font-script: 'Satisfy', cursive;
  --font-ui:     'Archivo', system-ui, sans-serif;
  --font-voice:  var(--font-text);   /* Tyler's voice = text face, italic */

  /* Archivo carries a width axis. Display is Expanded; body sits at normal.
     One family, two genuinely different voices. */
  --wide:        125;
  --normal:      100;

  --header-h:    72px;
  --max-w:       1440px;

  --ease-crash:  cubic-bezier(0.22, 1, 0.36, 1);
  --ease-snap:   cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out:    cubic-bezier(0.33, 1, 0.68, 1);
}

/* ── Reset ────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
  font-size: 16px;
  scroll-behavior: smooth;
  -webkit-font-smoothing: antialiased;
}

body {
  background: var(--bg);
  color: var(--white);
  font-family: var(--font-cond);
  font-weight: 400;
  line-height: 1.5;
  min-height: 100vh;
  overflow-x: hidden;
  position: relative;
}

img, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { cursor: pointer; font-family: inherit; }
ul { list-style: none; }

/* ── Grain Overlay ────────────────────────────────────────── */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)' opacity='1'/%3E%3C/svg%3E");
  background-size: 300px 300px;
  opacity: 0.045;
  pointer-events: none;
  z-index: 9999;
}

/* ── Typography Scale ─────────────────────────────────────── */
.t-display {
  font-family: var(--font-block);
  font-size: clamp(4rem, 10vw, 10rem);
  line-height: 0.92;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.t-hero {
  font-family: var(--font-block);
  font-size: clamp(3rem, 7vw, 7.5rem);
  line-height: 0.9;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.t-section {
  font-family: var(--font-block);
  font-size: clamp(2rem, 4vw, 4rem);
  line-height: 1;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.t-label {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--red-bright);
}
.t-script {
  font-family: var(--font-script);
  font-size: clamp(1.5rem, 3vw, 2.5rem);
  color: var(--white-dim);
}
.t-body {
  font-family: var(--font-cond);
  font-size: var(--fs-lead);
  font-weight: 400;
  line-height: 1.7;
  color: var(--white-dim);
}

/* ── Red Accent Highlight ─────────────────────────────────── */
.accent { color: var(--red); }
.accent-stroke { -webkit-text-stroke: 2px var(--red); color: transparent; }

/* ── Layout ───────────────────────────────────────────────── */
.container {
  width: 100%;
  max-width: var(--max-w);
  margin: 0 auto;
  padding: 0 clamp(1.5rem, 4vw, 5rem);
}
.container--narrow {
  max-width: 900px;
}

/* ── Header ───────────────────────────────────────────────── */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 clamp(1.5rem, 4vw, 5rem);
  background: linear-gradient(to bottom, rgba(8,8,8,0.98) 0%, rgba(8,8,8,0.92) 80%, transparent 100%);
  border-bottom: 1px solid var(--border-dim);
  transition: border-color 0.3s ease;
}
.site-header.scrolled {
  background: rgba(8,8,8,0.98);
  border-bottom-color: var(--border);
}

.header-logo {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  text-decoration: none;
}
.header-logo svg {
  height: 44px;
  width: auto;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 1rem;
}

/* ── Buttons ──────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-block);
  font-size: var(--fs-body);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.75rem 2rem;
  border: 2px solid currentColor;
  background: transparent;
  color: var(--white);
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
  position: relative;
}
.btn:hover {
  background: var(--white);
  color: var(--bg);
  transform: translateY(-1px);
}
.btn--red {
  background: var(--red);
  color: var(--white);
  border-color: var(--red);
}
.btn--red:hover {
  background: var(--red-hot);
  color: var(--white);
  border-color: var(--red-hot);
}
.btn--red-outline {
  border-color: var(--red);
  color: var(--red);
}
.btn--red-outline:hover {
  background: var(--red);
  color: var(--white);
}
.btn--contact {
  font-family: var(--font-block);
  font-size: var(--fs-body);
  letter-spacing: 0.14em;
  padding: 0.6rem 1.5rem;
  background: var(--red);
  color: var(--white);
  border: 2px solid var(--red);
  text-transform: uppercase;
}
.btn--contact:hover {
  background: var(--red-hot);
  border-color: var(--red-hot);
  color: var(--white);
  transform: none;
}
.btn--lg {
  font-size: 1.3rem;
  padding: 1.1rem 3rem;
}

/* ── Entry Rows (Homepage) ────────────────────────────────────
   Rebuilt 2026-09-01. Was four centred outline pills, which read as a
   template. Now full-bleed numbered slabs: a red wipe takes the whole row
   on hover and the title slides into it. Reads like a title card, which is
   the business Tyler is actually in.
   ─────────────────────────────────────────────────────────── */
.entry-list {
  border-top: 1px solid var(--border-dim);
}
.entry-row {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: clamp(1rem, 3vw, 3rem);
  padding: clamp(1.6rem, 3.4vw, 2.9rem) clamp(1.25rem, 5vw, 4.5rem);
  border-bottom: 1px solid var(--border-dim);
  overflow: hidden;
  isolation: isolate;
  transition: color 0.3s var(--ease-out);
}
/* Skewed red wipe. Inset is negative so the skew never exposes a corner. */
.entry-row::before {
  content: '';
  position: absolute;
  inset: 0 -8%;
  background: var(--red);
  transform: skewX(-9deg) scaleX(0);
  transform-origin: left center;
  transition: transform 0.42s var(--ease-snap);
  z-index: -1;
}
.entry-row:hover::before,
.entry-row:focus-visible::before { transform: skewX(-9deg) scaleX(1); }
.entry-row:focus-visible { outline: none; }

.entry-row__num {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.22em;
  color: var(--red-bright);
  transition: color 0.3s var(--ease-out);
}
.entry-row__title {
  display: block;
  font-family: var(--font-block);
  font-size: clamp(2.1rem, 5.6vw, 4.6rem);
  line-height: 0.95;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  transition: transform 0.42s var(--ease-snap);
}
.entry-row__sub {
  display: block;
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--white-dim);
  margin-top: 0.4rem;
  max-width: 52ch;
  transition: transform 0.42s var(--ease-snap), color 0.3s var(--ease-out);
}
/* Each row previews its own medium: a reel for the reel row, a captured
   website for the website row. Fills the dead space on the right and puts
   real work at the exact moment someone is choosing. */
.entry-row__peek {
  width: clamp(96px, 11vw, 150px);
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border: 1px solid rgba(240,237,232,0.16);
  opacity: 0.5;
  filter: grayscale(1) contrast(1.1) brightness(0.8);
  transform: rotate(2.5deg) scale(0.94);
  transition: opacity 0.42s var(--ease-snap), transform 0.42s var(--ease-snap),
              filter 0.42s var(--ease-snap);
}
.entry-row__peek--site { object-position: top center; }
.entry-row:hover .entry-row__peek {
  opacity: 1;
  filter: grayscale(0) contrast(1) brightness(1);
  transform: rotate(-2.5deg) scale(1.04);
}
@media (max-width: 900px) {
  /* Arrow goes, preview stays: on a touch screen the image is the thing that
     carries the row, and there is no hover to reveal it later. */
  .entry-row { grid-template-columns: auto 1fr auto; }
  .entry-row__arrow { display: none; }
  .entry-row__peek { width: 84px; opacity: 0.75; filter: none; }
}

.entry-row__arrow {
  font-family: var(--font-block);
  font-size: clamp(1.6rem, 3vw, 2.6rem);
  color: var(--white-dim);
  transition: transform 0.42s var(--ease-snap), color 0.3s var(--ease-out);
}
.entry-row:hover .entry-row__num,
.entry-row:hover .entry-row__sub,
.entry-row:hover .entry-row__arrow { color: var(--white); }
.entry-row:hover .entry-row__title,
.entry-row:hover .entry-row__sub { transform: translateX(clamp(0.5rem, 1.6vw, 1.6rem)); }
.entry-row:hover .entry-row__arrow { transform: translateX(0.75rem); }

@media (prefers-reduced-motion: reduce) {
  .entry-row::before { transition: none; }
  .entry-row:hover .entry-row__title,
  .entry-row:hover .entry-row__sub,
  .entry-row:hover .entry-row__arrow { transform: none; }
}

/* ── Section Headers ──────────────────────────────────────── */
.section-header {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 3rem;
}
.section-header--center {
  align-items: center;
  text-align: center;
}

/* ── Hero ─────────────────────────────────────────────────── */
.hero {
  position: relative;
  width: 100%;
  height: 100vh;
  min-height: 600px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  /* Deliberately tied with .mosaic at 0. The mosaic comes later in the DOM
     so it paints ON TOP of the reel at 0.72 opacity - the reel shows through
     the wall of real client work. Tyler's call, and it is the look. */
  z-index: 0;
}

/* ── Slot-machine loop seam ──────────────────────────────────────────
   The mosaic is HIDDEN while the reel plays and appears only across the
   loop point, covering the hard jump from last frame back to first.

   .is-live is added by js/hero-transition.js ONLY once the reel is actually
   playing, so a missing or blocked video still gets the fallback wall.

   WHY THIS IS ONE ANIMATION AND NOT A SPEED CHANGE
   The first version sped the base drift up and then slowed it down by
   swapping animation-duration. That reads as a clunk, because changing the
   duration of a running animation makes the browser recompute where it
   should be from elapsed time - so the columns physically jump.

   Instead the seam runs its OWN one-shot animation with the deceleration
   baked into a single cubic-bezier. Nothing switches mid-flight, so there is
   nothing to jump. It is still gliding when it fades out, which is what
   makes it feel like a dismount rather than a stop.

   When the classes come off, the base drift resumes - invisibly, because
   opacity is already 0 by then. */
.hero .mosaic {
  transition: opacity 280ms cubic-bezier(0.33, 1, 0.68, 1);
}
.hero .mosaic.is-live { opacity: 0; }

.hero .mosaic.is-live.is-spinning {
  opacity: 0.95;
  transition: opacity 190ms cubic-bezier(0.55, 0, 1, 0.45);   /* in, accelerating */
}
.hero .mosaic.is-live.is-settling {
  opacity: 0;
  transition: opacity 620ms cubic-bezier(0.16, 1, 0.3, 1);    /* out, gliding */
}

/* One shot, expo-out. Applied across BOTH phases so it never restarts. */
@keyframes slotSpin    { from { transform: translateY(0); }  to { transform: translateY(-230%); } }
@keyframes slotSpinRev { from { transform: translateY(0); }  to { transform: translateY(230%);  } }

.hero .mosaic.is-spinning .mosaic__col,
.hero .mosaic.is-settling .mosaic__col {
  animation: slotSpin 2.4s cubic-bezier(0.16, 1, 0.3, 1) forwards !important;
}
.hero .mosaic.is-spinning .mosaic__col:nth-child(even),
.hero .mosaic.is-settling .mosaic__col:nth-child(even) {
  animation: slotSpinRev 2.7s cubic-bezier(0.16, 1, 0.3, 1) forwards !important;
}
.hero .mosaic.is-spinning .mosaic__col:nth-child(3),
.hero .mosaic.is-settling .mosaic__col:nth-child(3) {
  animation: slotSpin 2.1s cubic-bezier(0.16, 1, 0.3, 1) forwards !important;
}
.hero__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    rgba(8,8,8,0.3) 0%,
    rgba(8,8,8,0.15) 40%,
    rgba(8,8,8,0.5) 75%,
    rgba(8,8,8,1) 100%
  );
  z-index: 1;
}
.hero__content {
  position: relative;
  z-index: 2;
  text-align: center;
  padding: 0 1.5rem;
}
.hero__placeholder {
  position: absolute;
  inset: 0;
  background: var(--bg-mid);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  z-index: 0;
}
.hero__placeholder::after {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    45deg,
    transparent,
    transparent 40px,
    rgba(204,0,0,0.03) 40px,
    rgba(204,0,0,0.03) 41px
  );
}

/* ── Service Hero (sub-pages) ─────────────────────────────── */
.service-hero {
  position: relative;
  width: 100%;
  height: 60vh;
  min-height: 400px;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  padding-bottom: 4rem;
}
.service-hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}
.service-hero__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, transparent 0%, rgba(8,8,8,0.6) 60%, rgba(8,8,8,1) 100%);
  z-index: 1;
}
.service-hero__placeholder {
  position: absolute;
  inset: 0;
  background: var(--bg-mid);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 0;
}
.service-hero__placeholder::after {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    -45deg,
    transparent,
    transparent 40px,
    rgba(204,0,0,0.04) 40px,
    rgba(204,0,0,0.04) 41px
  );
}
.service-hero__content {
  position: relative;
  z-index: 2;
  padding: 0 clamp(1.5rem, 4vw, 5rem);
}

/* ── Video Placeholder (inline) ───────────────────────────── */
.video-placeholder {
  width: 100%;
  background: var(--bg-card);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  border: 1px solid var(--border-dim);
  position: relative;
  overflow: hidden;
}
.video-placeholder::before {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    45deg,
    transparent,
    transparent 30px,
    rgba(204,0,0,0.03) 30px,
    rgba(204,0,0,0.03) 31px
  );
}
.video-placeholder__icon {
  width: 60px;
  height: 60px;
  border: 2px solid var(--red);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  z-index: 1;
}
.video-placeholder__icon::after {
  content: '';
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 10px 0 10px 18px;
  border-color: transparent transparent transparent var(--red);
  margin-left: 4px;
}
.video-placeholder__label {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--white-dim);
  position: relative;
  z-index: 1;
}

/* ── Client Bar ───────────────────────────────────────────── */
.client-section {
  padding: 6rem 0;
  border-top: 1px solid var(--border-dim);
}
.client-section:first-of-type { border-top: none; }

.client-bar {
  display: grid;
  grid-template-columns: 1fr 300px;
  min-height: 420px;
  overflow: hidden;
  border: 1px solid var(--border-dim);
  position: relative;
  transition: border-color 0.3s ease;
}
.client-bar:hover { border-color: rgba(204,0,0,0.35); }

.client-bar__video-wrap {
  position: relative;
  overflow: hidden;
  background: var(--bg-mid);
}
.client-bar__video-wrap video,
.client-bar__video-wrap .video-placeholder {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.client-bar__video-wrap .video-placeholder {
  min-height: 420px;
}

.client-bar__info {
  background: var(--bg-card);
  padding: 2.5rem 2rem;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  border-left: 1px solid var(--border-dim);
}
.client-bar__name {
  font-family: var(--font-block);
  font-size: 2.2rem;
  line-height: 1;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  margin-bottom: 1.5rem;
}
.client-bar__work-list {
  flex: 1;
}
.client-bar__work-list li {
  font-family: var(--font-cond);
  font-size: var(--fs-body);
  font-weight: 400;
  color: var(--white-dim);
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border-dim);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.client-bar__work-list li::before {
  content: '—';
  color: var(--red);
  font-size: var(--fs-cap);
}

/* ── Category Tags ────────────────────────────────────────── */
.cat-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 1.5rem;
}
.cat-tag {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--red-dim);
  color: var(--red);
  background: rgba(204,0,0,0.07);
  transition: background 0.2s ease, color 0.2s ease;
}
.cat-tag:hover {
  background: var(--red);
  color: var(--white);
}

/* ── Band Group (band page) ───────────────────────────────── */
.band-group {
  padding: 5rem 0;
  border-top: 1px solid var(--border-dim);
}
.band-group__header {
  display: flex;
  align-items: baseline;
  gap: 1.5rem;
  margin-bottom: 3rem;
}
.band-group__name {
  font-family: var(--font-block);
  font-size: clamp(2.5rem, 5vw, 5rem);
  text-transform: uppercase;
  line-height: 1;
}
.band-group__name .the { font-family: var(--font-script); font-size: 0.45em; color: var(--white-dim); text-transform: none; }

.band-pieces {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

/* ── Featured Video ───────────────────────────────────────── */
.featured-video-section {
  padding: 5rem 0;
}
.featured-video-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 1px;
  background: var(--border-dim);
}
.featured-video-main {
  position: relative;
}
.featured-video-main .video-placeholder { min-height: 480px; }
.featured-video-side {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.featured-video-side .video-placeholder { min-height: 238px; }

/* ── Testimonials ─────────────────────────────────────────── */
.testimonials {
  padding: 6rem 0;
  overflow: hidden;
  position: relative;
}
.testimonials::before {
  content: '"';
  font-family: var(--font-block);
  font-size: 40vw;
  color: rgba(204,0,0,0.04);
  position: absolute;
  top: -5rem;
  left: -2rem;
  line-height: 1;
  pointer-events: none;
  z-index: 0;
}
.testimonials__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  position: relative;
  z-index: 1;
}
.testimonial-card {
  background: var(--bg-card);
  padding: 2.5rem 2rem;
  border: 1px solid var(--border-dim);
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}
.testimonial-card__quote {
  font-family: var(--font-cond);
  font-size: var(--fs-lead);
  font-weight: 400;
  line-height: 1.6;
  color: var(--white);
}
.testimonial-card__quote::before { content: '"'; color: var(--red); }
.testimonial-card__quote::after  { content: '"'; color: var(--red); }
.testimonial-card__author {
  margin-top: auto;
  border-top: 1px solid var(--border-dim);
  padding-top: 1rem;
}
.testimonial-card__name {
  font-family: var(--font-block);
  font-size: var(--fs-lead);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.testimonial-card__role {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--red);
  margin-top: 0.2rem;
}

/* ── Cross-links ──────────────────────────────────────────── */
.cross-links {
  padding: 5rem 0;
  background: var(--bg-mid);
  border-top: 1px solid var(--border-dim);
  border-bottom: 1px solid var(--border-dim);
}
.cross-links__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--border-dim);
}
.cross-link-card {
  background: var(--bg-card);
  padding: 2.5rem 2rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  position: relative;
  overflow: hidden;
  transition: background 0.3s ease;
}
.cross-link-card::after {
  content: '→';
  position: absolute;
  right: 1.5rem;
  bottom: 1.5rem;
  font-family: var(--font-block);
  font-size: 2rem;
  color: var(--red);
  transition: transform 0.25s var(--ease-snap);
}
.cross-link-card:hover { background: #1a1a1a; }
.cross-link-card:hover::after { transform: translateX(4px); }
.cross-link-card__label { color: var(--red-bright); }
.cross-link-card__title {
  font-family: var(--font-block);
  font-size: 1.8rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1;
}
.cross-link-card__desc {
  font-size: var(--fs-body);
  color: var(--white-dim);
  font-weight: 400;
}

/* ── Bundles ──────────────────────────────────────────────── */
.bundles-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 2px;
  background: var(--border-dim);
  padding: 5rem 0;
}
.bundle-card {
  background: var(--bg-card);
  padding: 3rem 2.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  border: 1px solid transparent;
  transition: border-color 0.3s ease;
}
.bundle-card:hover { border-color: var(--red); }
.bundle-card--featured {
  background: rgba(204,0,0,0.08);
  border-color: var(--border);
}
.bundle-card__badge {
  display: inline-block;
  /* The card is a flex column, so a bare inline-block still stretches the full
     width and reads as a bar rather than a badge. */
  align-self: flex-start;
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 0.25rem 0.6rem;
  background: var(--red);
  color: var(--white);
}
.bundle-card__name {
  font-family: var(--font-block);
  font-size: clamp(2rem, 3.5vw, 3.5rem);
  text-transform: uppercase;
  line-height: 1;
}
.bundle-card__price {
  font-family: var(--font-block);
  font-size: 2.5rem;
  color: var(--red);
  line-height: 1;
}
.bundle-card__price span { font-size: var(--fs-body); color: var(--white-dim); font-family: var(--font-ui); font-weight: 400; vertical-align: top; margin-top: 0.3rem; display: inline-block; }
.bundle-card__includes {
  flex: 1;
}
.bundle-card__includes li {
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border-dim);
  color: var(--white-dim);
  font-size: var(--fs-body);
  font-weight: 400;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.bundle-card__includes li::before { content: '✓'; color: var(--red); font-weight: 700; font-size: var(--fs-cap); }

/* ── Band Intake Form ─────────────────────────────────────── */
.intake-section {
  padding: 6rem 0;
  background: var(--bg-mid);
  border-top: 1px solid var(--border-dim);
}
.intake-form {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}
.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
.form-group {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.form-label {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--red);
}
.form-input,
.form-textarea {
  background: var(--bg-card);
  border: 1px solid var(--border-dim);
  color: var(--white);
  font-family: var(--font-cond);
  font-size: var(--fs-body);
  font-weight: 400;
  padding: 0.85rem 1rem;
  width: 100%;
  transition: border-color 0.2s ease;
  outline: none;
  appearance: none;
}
.form-input:focus,
.form-textarea:focus { border-color: var(--red); }
.form-textarea { resize: vertical; min-height: 140px; }

.form-services {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.form-services__label {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--red);
  margin-bottom: 0.5rem;
}
.service-checkboxes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.service-checkbox {
  display: none;
}
.service-checkbox + label {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.5rem 1rem;
  border: 1px solid var(--border-dim);
  color: var(--white-dim);
  cursor: pointer;
  transition: all 0.2s ease;
}
.service-checkbox:checked + label {
  background: var(--red);
  border-color: var(--red);
  color: var(--white);
}
.service-checkbox + label:hover {
  border-color: var(--red);
  color: var(--red);
}

/* ── Footer ───────────────────────────────────────────────── */
.site-footer {
  background: var(--bg);
  border-top: 1px solid rgba(204,0,0,0.4);
  padding: 5rem 0 3rem;
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 1fr;
  gap: 3rem;
  margin-bottom: 4rem;
}
.footer-brand__logo { margin-bottom: 1.5rem; }
.footer-brand__tagline {
  font-family: var(--font-script);
  font-size: var(--fs-lead);
  color: var(--white-dim);
  margin-bottom: 1rem;
}
.footer-brand__desc {
  font-size: var(--fs-body);
  font-weight: 400;
  color: var(--white-dim);
  line-height: 1.7;
}
.footer-col__title {
  font-family: var(--font-block);
  font-size: var(--fs-lead);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 1.5rem;
  color: var(--white);
}
.footer-col ul { display: flex; flex-direction: column; gap: 0.6rem; }
.footer-col ul li a {
  font-size: var(--fs-body);
  font-weight: 400;
  color: var(--white-dim);
  letter-spacing: 0.04em;
  transition: color 0.2s ease;
}
.footer-col ul li a:hover { color: var(--red); }
.footer-contact-item {
  font-size: var(--fs-body);
  font-weight: 400;
  color: var(--white-dim);
  margin-bottom: 0.5rem;
}
.footer-contact-item a { color: var(--white-dim); transition: color 0.2s ease; }
.footer-contact-item a:hover { color: var(--red); }
.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-top: 1px solid var(--border-dim);
  padding-top: 2rem;
}
.footer-bottom p {
  font-size: var(--fs-cap);
  color: var(--white-dim);
  letter-spacing: 0.06em;
}
.footer-social {
  display: flex;
  gap: 1rem;
}
.footer-social a {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--white-dim);
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--border-dim);
  transition: all 0.2s ease;
}
.footer-social a:hover {
  border-color: var(--red);
  color: var(--red);
}

/* ── Red Divider Line ─────────────────────────────────────── */
.red-rule {
  height: 2px;
  background: linear-gradient(to right, transparent, var(--red), transparent);
  margin: 0;
  border: none;
}

/* ── CTA Strip ────────────────────────────────────────────── */
.cta-strip {
  background: var(--red);
  padding: 4rem 0;
  text-align: center;
}
.cta-strip__title {
  font-family: var(--font-block);
  font-size: clamp(2.5rem, 5vw, 5rem);
  color: var(--white);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1;
  margin-bottom: 1.5rem;
}
.cta-strip .btn {
  color: var(--white);
  border-color: var(--white);
}
.cta-strip .btn:hover {
  background: var(--white);
  color: var(--red);
}

/* ── Scroll Reveal ────────────────────────────────────────── */
.reveal {
  opacity: 0;
  transform: translateY(50px);
  transition: opacity 0.55s ease, transform 0.55s var(--ease-crash);
}
.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}
.reveal-crash {
  opacity: 0;
  transform: translateY(90px) scaleY(0.94);
  transition: opacity 0.4s ease, transform 0.65s var(--ease-crash);
}
.reveal-crash.visible {
  opacity: 1;
  transform: translateY(0) scaleY(1);
}
.reveal-left {
  opacity: 0;
  transform: translateX(-60px);
  transition: opacity 0.5s ease, transform 0.6s var(--ease-crash);
}
.reveal-left.visible { opacity: 1; transform: translateX(0); }
.reveal-right {
  opacity: 0;
  transform: translateX(60px);
  transition: opacity 0.5s ease, transform 0.6s var(--ease-crash);
}
.reveal-right.visible { opacity: 1; transform: translateX(0); }

/* Stagger delays */
.delay-1 { transition-delay: 0.1s; }
.delay-2 { transition-delay: 0.2s; }
.delay-3 { transition-delay: 0.3s; }
.delay-4 { transition-delay: 0.4s; }

/* ── Page Spacing ─────────────────────────────────────────── */
.page-content { padding-top: var(--header-h); }
.section { padding: 5rem 0; }
.section--lg { padding: 8rem 0; }

/* ── Horizontal Rule ──────────────────────────────────────── */
hr.dark { border: none; border-top: 1px solid var(--border-dim); }

/* ── Responsive ───────────────────────────────────────────── */
@media (max-width: 1100px) {
  .footer-grid { grid-template-columns: 1fr 1fr; gap: 2rem; }
  .testimonials__grid { grid-template-columns: 1fr 1fr; }
  .cross-links__grid { grid-template-columns: 1fr 1fr; }
  .featured-video-grid { grid-template-columns: 1fr; }
  .featured-video-side { flex-direction: row; }
  .featured-video-side .video-placeholder { min-height: 200px; }
}
@media (max-width: 860px) {
  .client-bar { grid-template-columns: 1fr; }
  .client-bar__info { border-left: none; border-top: 1px solid var(--border-dim); }
  .bundles-grid { grid-template-columns: 1fr; }
  .form-row { grid-template-columns: 1fr; }
  .cross-links__grid { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .testimonials__grid { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr; }
  .footer-social { flex-wrap: wrap; }
  .featured-video-side { flex-direction: column; }
}

/* ═══════════════ SITE SHOWCASE ═════════════════════════════
   A tilted 3D browser panel that steps through a site section by section,
   naming each one as it lands. Not a continuous scroll - it holds on each
   part long enough to actually read it.

   The full site width is always visible. Zooming in past full width is what
   makes these look broken, so the only movement is vertical panning between
   real sections plus a slight lift on the shorter ones.
   ───────────────────────────────────────────────────────────── */

.showcase-stage {
  perspective: 1800px;
  perspective-origin: 50% 40%;
  padding: 2.5rem 1rem 3rem;
}

.showcase {
  position: relative;
  transform-style: preserve-3d;
  transform: rotateY(-13deg) rotateX(5deg) translateZ(0);
  transition: transform 0.9s cubic-bezier(0.22, 1, 0.36, 1),
              box-shadow 0.9s cubic-bezier(0.22, 1, 0.36, 1);
  box-shadow: 28px 34px 70px rgba(0, 0, 0, 0.65),
              0 0 0 1px var(--border-dim, #2a2a2a);
  background: var(--bg-card, #111);
}

/* Straighten out when someone actually wants to look at it. */
.showcase:hover,
.showcase.is-playing {
  transform: rotateY(-3deg) rotateX(1.5deg) translateZ(30px);
  box-shadow: 16px 22px 60px rgba(0, 0, 0, 0.7),
              0 0 0 1px var(--red, #CC0000);
}

@media (prefers-reduced-motion: reduce) {
  .showcase, .showcase:hover, .showcase.is-playing { transform: none; }
}

.showcase__chrome {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.9rem;
  background: #1a1a1a;
  border-bottom: 1px solid var(--border-dim, #2a2a2a);
}

.showcase__dot { width: 10px; height: 10px; border-radius: 50%; background: #3a3a3a; flex: 0 0 auto; }
.showcase__dot--live { background: var(--red, #CC0000); }

.showcase__url {
  margin-left: 0.5rem;
  padding: 0.2rem 0.8rem;
  flex: 1;
  background: #0d0d0d;
  border-radius: 100px;
  font-family: var(--font-ui, sans-serif);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--white-dim, #888);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.showcase__viewport {
  position: relative;
  width: 100%;
  padding-bottom: 72%;
  overflow: hidden;
  background: var(--bg-mid, #151515);
}

.showcase__page {
  position: absolute;
  top: 0; left: 0;
  width: 1280px;
  /* max-width:none is load-bearing. The global `img { max-width: 100% }` near the
     top of this file caps the page to the card width BEFORE the transform below
     shrinks it again, which rendered the site at ~58% of 58%. */
  max-width: none;
  border: none;
  display: block;
  transform-origin: top left;
  /* --s fits the 1280px design width to the card. --fy pans to a section. */
  transform: scale(var(--s, 1)) translateY(var(--fy, 0px));
  transition: transform 1.5s cubic-bezier(0.65, 0, 0.35, 1);
  will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
  .showcase__page { transition: none; }
}

/* Section name, bottom left. Swaps as the panel lands on each part. */
.showcase__caption {
  position: absolute;
  left: 0; bottom: 0;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 1rem;
  background: linear-gradient(to right, rgba(0,0,0,0.92) 60%, rgba(0,0,0,0));
  font-family: var(--font-ui, sans-serif);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #fff;
  pointer-events: none;
  max-width: 100%;
}

.showcase__caption-text {
  opacity: 1;
  transition: opacity 0.35s ease;
}
.showcase__caption-text.is-swapping { opacity: 0; }

.showcase__caption::before {
  content: "";
  width: 18px; height: 2px;
  background: var(--red, #CC0000);
  flex: 0 0 auto;
}

/* Progress ticks - one per section, filling as it advances. */
.showcase__ticks {
  position: absolute;
  right: 0.9rem; bottom: 0.8rem;
  display: flex;
  gap: 4px;
  pointer-events: none;
}
.showcase__tick {
  width: 16px; height: 2px;
  background: rgba(255,255,255,0.22);
  transition: background 0.3s ease;
}
.showcase__tick.is-active { background: var(--red, #CC0000); }

/* ═══════════════════════════════════════════════════════════════════
   HOMEPAGE HERO — rebuilt 2026-09-01
   ═══════════════════════════════════════════════════════════════════
   The hero used to be the logo on a black rectangle, because it points at
   assets/video/sizzle-reel.mp4 and that file has never existed. So the site
   opened on nothing.

   Until the sizzle reel is cut, the fallback is a drifting mosaic of the
   REAL work: YouTube "oar"/hq thumbnails from the reels already embedded on
   content.html. It fills the screen with actual client footage across five
   verticals on first paint, and it costs about 130KB because hqdefault is
   8KB a piece. The <video> sits above it and simply covers it once the file
   is dropped in, so nothing here needs undoing later.

   Why hqdefault and not maxres: for a vertical Short, YouTube's 480x360
   hqdefault puts the true 9:16 frame dead centre with a blurred zoom behind
   it. object-fit:cover on a 9:16 tile crops to exactly that centre strip.
   ─────────────────────────────────────────────────────────────────── */

/* Generalised 2026-09-01: the same wall now backs every hero whose .mp4 does
   not exist yet. Column count and tile aspect come from js/mosaic.js as
   custom properties, so one rule set serves vertical reels and landscape
   films alike. */
.mosaic {
  position: absolute;
  inset: -14%;
  z-index: 0;
  display: grid;
  grid-template-columns: repeat(var(--mosaic-cols, 6), 1fr);
  gap: 8px;
  transform: rotate(-5deg) scale(1.16);
  opacity: 0.72;
  filter: grayscale(0.18) contrast(1.05) brightness(1);
  pointer-events: none;
}
.mosaic__col {
  display: grid;
  grid-auto-rows: 1fr;
  gap: 8px;
  animation: mosaicDrift 64s linear infinite;
  will-change: transform;
}
/* Alternate direction + speed so the wall never reads as one sliding sheet */
.mosaic__col:nth-child(even) { animation-direction: reverse; animation-duration: 78s; }
.mosaic__col:nth-child(3)    { animation-duration: 92s; }
.mosaic__col img {
  width: 100%;
  aspect-ratio: var(--mosaic-aspect, 9 / 16);
  object-fit: cover;
  display: block;
}
/* Each column holds its tiles twice, so -50% lands exactly on a seam */
@keyframes mosaicDrift {
  from { transform: translateY(0); }
  to   { transform: translateY(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .mosaic__col { animation: none; }
}

/* Heavier overlay than the video version needs: thumbnails are busier than
   a graded sizzle reel, and the headline has to stay readable over them. */
.service-hero .mosaic { inset: -20%; transform: rotate(-4deg) scale(1.2); opacity: 0.6; }
/* The stripe placeholder was the whole background of four sub-page heroes.
   Where a mosaic is present it sits behind it and is no longer needed. */
.service-hero__placeholder:has(+ .mosaic) { background: var(--bg); }
.service-hero__placeholder:has(+ .mosaic)::after { display: none; }
.service-hero__overlay--mosaic {
  background:
    radial-gradient(ellipse 90% 80% at 50% 40%, rgba(8,8,8,0.35) 0%, rgba(8,8,8,0.75) 60%, rgba(8,8,8,0.95) 100%),
    linear-gradient(to bottom, rgba(8,8,8,0.55) 0%, rgba(8,8,8,0.35) 35%, rgba(8,8,8,0.85) 80%, var(--bg) 100%);
}
/* Lightened 2026-09-17. These values were tuned when the hero was a wall of
   busy thumbnails that needed knocking back. It is a graded reel now, so the
   same scrim was burying the footage. Kept enough at the top and bottom to
   hold the nav and the headline, and opened up the middle where the picture
   actually is. */
.hero__overlay--mosaic {
  background:
    radial-gradient(ellipse 86% 66% at 50% 46%, rgba(8,8,8,0.16) 0%, rgba(8,8,8,0.48) 62%, rgba(8,8,8,0.8) 100%),
    linear-gradient(to bottom, rgba(8,8,8,0.62) 0%, rgba(8,8,8,0.10) 34%, rgba(8,8,8,0.42) 78%, var(--bg) 100%);
}

.hero__content { max-width: 1100px; }
.hero__mark { width: clamp(120px, 14vw, 190px); height: auto; margin: 0 auto 1.75rem; }
.hero__kicker {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--white-dim);
  margin-bottom: 1.1rem;
}
.hero__kicker b { color: var(--red); font-weight: 600; }
.hero__title {
  font-family: var(--font-block);
  font-size: clamp(2.9rem, 8.2vw, 8rem);
  line-height: 0.88;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.hero__title .accent { display: block; }
.hero__sub {
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: clamp(1.05rem, 1.5vw, 1.35rem);
  line-height: 1.6;
  color: var(--white);
  max-width: 60ch;
  margin: 1.6rem auto 0;
}
.hero__sub b { color: var(--white); font-weight: 600; }
.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: center;
  margin-top: 2.4rem;
}
.hero__ghost {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--white);
  padding: 1.1rem 2.2rem;
  border: 1px solid rgba(240,237,232,0.28);
  transition: border-color 0.25s ease, background 0.25s ease;
}
.hero__ghost:hover { border-color: var(--white); background: rgba(240,237,232,0.07); }

/* ── Pull quote (real testimonial) ───────────────────────────────────
   One real quote, given the whole width. A three-card grid was what made
   the fabricated version possible in the first place: it created two holes
   that had to be filled with something.
   ─────────────────────────────────────────────────────────────────── */
.pullquote {
  position: relative;
  padding: clamp(4.5rem, 9vw, 8rem) 1.5rem;
  text-align: center;
  overflow: hidden;
}
.pullquote::before {
  content: '\201C';
  position: absolute;
  top: -0.18em;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-script);
  font-size: clamp(14rem, 26vw, 26rem);
  line-height: 1;
  color: var(--red);
  opacity: 0.09;
  pointer-events: none;
}
.pullquote__text {
  position: relative;
  font-family: var(--font-cond);
  font-weight: 400;
  font-style: italic;
  font-size: clamp(1.6rem, 4vw, 3.4rem);
  line-height: 1.22;
  letter-spacing: 0.01em;
  max-width: 22ch;
  margin: 0 auto;
}
.pullquote__text em { font-style: italic; color: var(--red); }
.pullquote__who {
  margin-top: 2.4rem;
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.pullquote__where {
  margin-top: 0.4rem;
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: var(--fs-body);
  letter-spacing: 0.06em;
  color: var(--white-dim);
}

@media (max-width: 720px) {
  .mosaic { grid-template-columns: repeat(3, 1fr); transform: rotate(-6deg) scale(1.35); }
  .entry-row { grid-template-columns: 1fr auto; }
  .entry-row__num { grid-column: 1 / -1; margin-bottom: 0.35rem; }
}

/* ── Mobile navigation ───────────────────────────────────────────────
   Added 2026-09-01 with js/nav.js. The nav used to overflow the right edge
   of a phone and get clipped by body{overflow-x:hidden}, which quietly hid
   Bundles, Bands and Contact on every phone.

   The !important flags are not laziness: every .nav-link in this project
   carries its 0.75rem font-size as an inline style, and inline beats a
   stylesheet rule at any specificity.
   ─────────────────────────────────────────────────────────────────── */
.nav-toggle { display: none; }

@media (max-width: 900px) {
  .nav-toggle {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 44px;
    height: 44px;
    padding: 0 8px;
    background: none;
    border: none;
    position: relative;
    z-index: 1002;
  }
  .nav-toggle span {
    display: block;
    height: 2px;
    width: 100%;
    background: var(--white);
    transition: transform 0.3s var(--ease-snap), opacity 0.2s ease;
  }
  body.nav-open .nav-toggle span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  body.nav-open .nav-toggle span:nth-child(2) { opacity: 0; }
  body.nav-open .nav-toggle span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  .header-actions {
    position: fixed;
    top: var(--header-h);
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1001;
    flex-direction: column;
    justify-content: center;
    gap: 0.25rem;
    background: var(--bg);
    /* The panel starts at top:var(--header-h), so -102% of its OWN height
       left the last ~65px of the closed menu on screen at every width below
       900px: "Pricing" sat where the logo belongs and the Contact button
       floated over the hero. It has to travel its own height PLUS that top
       offset to clear. visibility is the backstop, delayed on close so the
       slide still animates. */
    transform: translateY(calc(-100% - var(--header-h)));
    visibility: hidden;
    transition: transform 0.4s var(--ease-snap), visibility 0s linear 0.4s;
    overscroll-behavior: contain;
  }
  body.nav-open { overflow: hidden; }
  body.nav-open .header-actions {
    transform: translateY(0);
    visibility: visible;
    transition: transform 0.4s var(--ease-snap), visibility 0s;
  }

  .header-actions .nav-link {
    font-family: var(--font-block) !important;
    font-size: clamp(1.9rem, 8vw, 2.6rem) !important;
    letter-spacing: 0.05em !important;
    color: var(--white) !important;
    padding: 0.5rem 1rem !important;
  }
  .header-actions .btn--contact { margin-top: 1.5rem; font-size: var(--fs-lead); padding: 0.9rem 2.5rem; }
}
@media (prefers-reduced-motion: reduce) {
  .header-actions { transition: none; }
  .nav-toggle span { transition: none; }
}

/* ── Credential belt ─────────────────────────────────────────────────
   Added 2026-09-01 at Tyler's request: proof of the calibre of the places
   the work has been, sitting directly under the hook.

   This is deliberately NOT the logo wall he hates ("the logo wall goes up
   when the work can't speak for itself"). A logo wall says "these people
   paid me." This says "the course I shot is the number one course in Texas,"
   which is a different and much harder claim to fake.

   Every claim carries the publication that made it. Anything unattributed
   would be the fabricated-testimonial mistake again in a new costume.

   Slots not yet earned carry data-pending and are hidden by CSS rather than
   filled with something invented. Same pattern as the showcase cards, which
   hide themselves when their screenshot is missing.
   ─────────────────────────────────────────────────────────────────── */
.belt {
  border-top: 1px solid rgba(201, 162, 39, 0.3);
  border-bottom: 1px solid rgba(201, 162, 39, 0.3);
  background: linear-gradient(to bottom, rgba(201, 162, 39, 0.06), transparent 60%);
  padding: clamp(2.5rem, 5vw, 4rem) clamp(1.25rem, 5vw, 4rem);
}
.belt__label {
  color: var(--brass);
  text-align: center;
  margin-bottom: clamp(1.75rem, 3vw, 2.5rem);
}
.belt__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: stretch;
  gap: clamp(1.5rem, 4vw, 4rem);
}
.belt__item[data-pending] { display: none; }
/* Four venues rather than one hero credential, so the items are narrower
   and the claims block is unused. 2026-09-06. */
/* All four have to land on one row at desktop. At the shared gap they were
   268px wide and wrapped 3+1, which read as a mistake. */
.belt__row--courses { gap: clamp(1rem, 2.4vw, 2.5rem); }
.belt__row--courses .belt__item { flex: 0 1 clamp(150px, 17.5vw, 225px); }
.belt__row--courses .belt__name { font-size: clamp(1.15rem, 1.7vw, 1.45rem); }
.belt__soon {
  display: inline-block;
  margin-top: 0.6rem;
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brass);
  border: 1px solid rgba(201, 162, 39, 0.4);
  padding: 0.2rem 0.5rem;
}
.belt__item {
  flex: 0 1 clamp(260px, 29vw, 380px);
  text-align: center;
  padding: 0 clamp(0.5rem, 2vw, 1.5rem);
  border-left: 1px solid var(--border-dim);
}
.belt__item:first-child { border-left: none; }
/* Optional client logo. Hides itself when the file is not there yet, so a
   missing asset never ships as a broken-image icon. */
.belt__logo {
  height: 46px;
  width: auto;
  margin: 0 auto 1rem;
  opacity: 0.9;
}
.belt__logo:not([src]), .belt__logo[src=""] { display: none; }
.belt__name {
  display: block;
  font-family: var(--font-block);
  font-size: clamp(1.5rem, 2.6vw, 2.2rem);
  line-height: 1.05;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.belt__place {
  display: block;
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: var(--fs-body);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--white-dim);
  margin-top: 0.35rem;
}
.belt__claims { margin-top: 1.1rem; display: grid; gap: 0.6rem; }
.belt__claim {
  font-family: var(--font-cond);
  font-size: var(--fs-body);
  line-height: 1.25;
  color: var(--white);
}
.belt__claim b {
  font-family: var(--font-block);
  font-size: 2.1em;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--brass);
  margin-right: 0.3em;
}
.belt__src {
  display: block;
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--white-dim);
  margin-top: 0.2rem;
}
@media (max-width: 720px) {
  .belt__item { border-left: none; flex-basis: 100%; }
}

/* ── Service grid + process steps (video.html) ───────────────────────
   Added 2026-09-01 with the video production page, the fourth avenue from
   the locked 2026-04-28 structure and the one that was never built.
   ─────────────────────────────────────────────────────────────────── */
.svc-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--border-dim);
  border: 1px solid var(--border-dim);
}
.svc-card {
  background: var(--bg);
  padding: clamp(1.75rem, 3vw, 2.5rem);
  transition: background 0.25s ease;
}
.svc-card:hover { background: var(--bg-card); }
.svc-card__title {
  font-family: var(--font-block);
  font-size: clamp(1.3rem, 2vw, 1.75rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 0.6rem;
}
.svc-card__desc {
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--white-dim);
}

.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.5rem, 4vw, 3.5rem); }
.step__num {
  font-family: var(--font-block);
  font-size: clamp(3rem, 6vw, 5rem);
  line-height: 1;
  color: var(--red);
  opacity: 0.55;
}
.step__title {
  font-family: var(--font-block);
  font-size: clamp(1.2rem, 1.8vw, 1.5rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 0.5rem 0 0.6rem;
}
.step__desc {
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--white-dim);
}

/* Plain-terms block. Trades owners trust people who talk about money and
   process plainly, so these are the real contract standards, not fluff. */
.terms {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem 3rem;
  border-top: 1px solid var(--border);
  padding-top: 2.25rem;
}
.terms__item { display: flex; gap: 0.9rem; align-items: flex-start; }
.terms__item::before {
  content: '';
  flex: none;
  width: 8px;
  height: 8px;
  margin-top: 0.55rem;
  background: var(--red);
}
.terms__text {
  font-family: var(--font-cond);
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--white);
}
.terms__text b { font-family: var(--font-block); font-weight: 600; letter-spacing: 0.03em; }

@media (max-width: 900px) {
  .svc-grid { grid-template-columns: repeat(2, 1fr); }
  .steps { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .svc-grid { grid-template-columns: 1fr; }
  .terms { grid-template-columns: 1fr; }
}

/* ── Real logo ───────────────────────────────────────────────────────
   Swapped in 2026-09-06. Every logo on this site until now was a
   hand-drawn SVG stand-in built because the real file had not turned up;
   it was found in Tyler's TKP_Dashboard folder. Source is an 849KB PNG at
   907x618, downscaled to a 32KB WebP for the header and footer and an 85KB
   one for the hero, because the header mark loads on every page.
   ─────────────────────────────────────────────────────────────────── */
.header-logo__img {
  height: 52px;
  width: auto;
  display: block;
}
.footer-brand__img {
  height: 62px;
  width: auto;
  display: block;
}
/* Overrides the generic img max-width:100% so the hero mark is sized by its
   own rule rather than being capped by the container. Same trap the showcase
   hit on 2026-08-31. */
.hero__mark {
  width: clamp(190px, 22vw, 300px);
  height: auto;
  max-width: none;
  margin: 0 auto 1.5rem;
}
@media (max-width: 900px) {
  .header-logo__img { height: 42px; }
}

/* ── Flythrough ──────────────────────────────────────────────────────
   The 3D layered walkthrough. See js/flythrough.js for the reasoning;
   the short version is that each real section of a captured page becomes
   its own panel floating at a different depth, and the camera dollies
   through them.

   Depth is genuine: panels sit at real translateZ values inside a
   perspective, so they scale and separate like objects rather than like a
   slideshow. The blur is scaled by distance, which is what sells it as a
   lens instead of a fade.
   ─────────────────────────────────────────────────────────────────── */
.fly {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
  /* Lower perspective = stronger, more obviously 3D falloff. 1200 is far
     enough back that the front panel is not distorted at the corners. */
  perspective: 1200px;
  perspective-origin: 50% 45%;
  overflow: hidden;
  background: var(--bg);
  cursor: pointer;
}
.fly__scene {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transition: transform 1.15s cubic-bezier(0.5, 0.05, 0.2, 1);
  will-change: transform;
}
/* The scene is viewed from an angle, not head on. Without this the front
   panel is square to the camera and the whole thing reads as a flat
   screenshot with something blurry behind it - which is exactly how the
   first pass looked. The angle is what makes the depth legible.
   js/flythrough.js composes its translateZ on top of this. */
.fly {
  --fly-tilt: rotateY(-15deg) rotateX(5deg);
}
.fly:hover { --fly-tilt: rotateY(-7deg) rotateX(2deg); }
.fly__panel {
  position: absolute;
  /* Never full-bleed: the inset leaves room for the panels behind to be seen
     around the edges, which is what makes the stack legible as a stack. */
  inset: 15% 15% 17% 6%;   /* top room so the tilt does not clip the chrome bar */
  background-size: 100% auto;
  background-repeat: no-repeat;
  border: 1px solid rgba(240, 237, 232, 0.14);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.75);
  /* Panels march away from the camera, alternating slightly left and right
     so it reads as flying down a corridor rather than through a straight
     tunnel of identical rectangles. */
  /* Tuned 2026-09-06 after a first pass where the stagger was so slight that
     every panel behind sat dead centre and was completely hidden by the one
     in focus - real 3D that looked flat. They now fan up and to the right so
     the stack is visible as a stack. Clipping at the stage edge is intended:
     it reads as a corridor continuing past the frame. */
  transform: translate3d(calc(var(--i) * 4.5%), calc(var(--i) * -2.5%), calc(var(--i) * -460px))
             rotateY(calc(var(--i) * -3.5deg));
  padding-top: 22px;          /* room for the chrome bar */
  background-origin: content-box;
  background-clip: content-box;
  transition: opacity 1.15s ease, filter 1.15s ease;
  backface-visibility: hidden;
}
/* Each panel wears its own browser bar. The old showcase had chrome and this
   did not, which is most of why the first pass read as "an image" rather than
   "a website floating in space". */
.fly__panel::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 22px;
  background: #1b1b1b;
  border-bottom: 1px solid rgba(240, 237, 232, 0.1);
}
.fly__panel::after {
  content: '';
  position: absolute;
  top: 8px;
  left: 9px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--red);
  box-shadow: 11px 0 0 #3a3a3a, 22px 0 0 #3a3a3a;
}
.fly__panel.is-focus {
  border-color: rgba(204, 0, 0, 0.55);
  box-shadow: 0 30px 90px rgba(0,0,0,0.8), 0 0 0 1px rgba(204,0,0,0.25), 0 0 60px rgba(204,0,0,0.12);
}
.fly__label {
  position: absolute;
  left: 0;
  bottom: -2.1rem;
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--white-dim);
  opacity: 0;
  transition: opacity 0.5s ease;
}
.fly__panel.is-focus .fly__label { opacity: 1; color: var(--white); }

.fly__ticks {
  position: absolute;
  left: 50%;
  bottom: 1rem;
  transform: translateX(-50%);
  display: flex;
  gap: 6px;
  z-index: 2;
}
.fly__ticks span {
  width: 22px;
  height: 2px;
  background: rgba(240, 237, 232, 0.22);
  transition: background 0.4s ease;
}
.fly__ticks span.is-on { background: var(--red); }

@media (max-width: 720px) {
  /* Blur and large composited layers are the expensive part on a phone, and
     the falloff is wasted at this size anyway. Flatten the stack. */
  .fly { perspective: 900px; }
  .fly__panel { inset: 5% 4%; }
}
@media (prefers-reduced-motion: reduce) {
  .fly__scene, .fly__panel { transition: none; }
}

/* Four-up variant of the service grid, for the camera-shy block on
   video.html. The base grid is three columns, which would leave a lone card
   stranded on a second row. */
.svc-grid--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1100px) { .svc-grid--4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .svc-grid--4 { grid-template-columns: 1fr; } }

/* ═══════════════════════════════════════════════════════════════════
   HOMEPAGE REBUILD — 2026-09-07
   ═══════════════════════════════════════════════════════════════════
   The big "I need X" slabs stop being the homepage's spine. They are
   self-select navigation: they only work for a visitor who already knows
   what he wants, and they forced everyone to sort themselves before
   learning what TKM even does.

   The system story leads instead. Tyler's reasoning, and it is right: the
   customer worth having is the one who does not know he needs a dashboard
   yet and should come away thinking "one stop shop".
   ═══════════════════════════════════════════════════════════════════ */

/* ── The system: four steps ──────────────────────────────────────── */
.system {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  border-top: 1px solid var(--border-dim);
  border-left: 1px solid var(--border-dim);
}
.system__step {
  position: relative;
  padding: clamp(1.75rem, 3vw, 2.75rem) clamp(1.25rem, 2vw, 2rem);
  border-right: 1px solid var(--border-dim);
  border-bottom: 1px solid var(--border-dim);
  transition: background 0.3s ease;
}
.system__step:hover { background: var(--bg-card); }
/* A hairline runs through the row connecting the numbers, so the four read
   as one sequence rather than four unrelated cards. */
.system__step::before {
  content: '';
  position: absolute;
  top: calc(clamp(1.75rem, 3vw, 2.75rem) + 0.75em);
  left: 0; right: 0;
  height: 1px;
  background: var(--border);
  opacity: 0.5;
}
.system__step:first-child::before { left: 50%; }
.system__step:last-child::before { right: 50%; }
.system__num {
  position: relative;
  display: inline-block;
  font-family: var(--font-block);
  font-size: 1.5rem;
  line-height: 1;
  letter-spacing: 0.06em;
  color: var(--red-bright);
  background: var(--bg);
  padding-right: 0.75rem;
  margin-bottom: 1.1rem;
}
.system__step:hover .system__num { background: var(--bg-card); }
.system__title {
  font-family: var(--font-block);
  font-size: clamp(1.3rem, 2vw, 1.7rem);
  line-height: 1.05;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  margin-bottom: 0.7rem;
}
.system__desc {
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--white-dim);
}

/* ── The four doors, shrunk ──────────────────────────────────────── */
.doors {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--border-dim);
  border: 1px solid var(--border-dim);
}
.door {
  background: var(--bg);
  padding: clamp(1.1rem, 2vw, 1.5rem) clamp(1rem, 2vw, 1.5rem);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  transition: background 0.25s ease, color 0.25s ease;
}
.door:hover { background: var(--red); }
.door__label {
  font-family: var(--font-block);
  font-size: clamp(1rem, 1.5vw, 1.25rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.door__arrow { font-family: var(--font-block); color: var(--white-dim); transition: transform 0.3s var(--ease-snap), color 0.25s ease; }
.door:hover .door__arrow { color: var(--white); transform: translateX(5px); }

/* ── Reel row: one per company ───────────────────────────────────── */
.reel-row {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 2px;
  background: var(--border-dim);
}
.reel-tile { background: var(--bg-card); }
.reel-tile__frame { position: relative; width: 100%; padding-bottom: 177.78%; background: var(--bg-mid); }
.reel-tile__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: none; }
.reel-tile__cap { padding: 0.9rem 0.9rem 1.1rem; }
.reel-tile__client {
  font-family: var(--font-block);
  font-size: var(--fs-body);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.reel-tile__kind {
  display: block;
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--white-dim);
  margin-top: 0.25rem;
}

@media (max-width: 1100px) {
  .system { grid-template-columns: repeat(2, 1fr); }
  /* The connector only makes sense on a single row. */
  .system__step::before { display: none; }
  .reel-row { grid-template-columns: repeat(3, 1fr); }
  .doors { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .system { grid-template-columns: 1fr; }
  .reel-row { grid-template-columns: repeat(2, 1fr); }
  .doors { grid-template-columns: 1fr; }
}

/* ── Systems block (Websites & Systems page) ─────────────────────────
   Added 2026-09-07. Sits above the websites, because Tyler's plan is to
   use the word people already know as the door and then show them the
   thing they did not know they could buy.

   Brass rather than red because it is already the palette's "this is the
   serious part" colour AND it is the actual colour of his real dashboards.
   It reads as showing the product, not decorating.
   ─────────────────────────────────────────────────────────────────── */
.systems {
  position: relative;
  border-bottom: 1px solid rgba(201,162,39,0.28);
  background:
    radial-gradient(ellipse 70% 90% at 22% 20%, rgba(201,162,39,0.10), transparent 62%),
    linear-gradient(to bottom, rgba(201,162,39,0.05), transparent 55%);
  padding: clamp(2.5rem, 6vw, 5rem) 0 clamp(2.5rem, 5vw, 4rem);
}
.systems__title {
  font-family: var(--font-block);
  font-size: clamp(2.4rem, 6vw, 5rem);
  line-height: 0.95;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--brass);
  text-shadow: 0 0 60px rgba(201,162,39,0.22);
}
.systems__title em { font-style: normal; color: var(--white); display: block; }
.systems__grid {
  display: grid;
  grid-template-columns: 1.05fr 1.35fr;
  gap: clamp(1.75rem, 4vw, 3.5rem);
  align-items: center;
  margin-top: clamp(1.75rem, 3vw, 2.5rem);
}
.systems__tracks { display: grid; gap: 0.9rem; margin-top: 1.5rem; }
.systems__track { display: flex; gap: 0.85rem; align-items: baseline; }
.systems__track::before {
  content: '';
  flex: none;
  width: 7px; height: 7px;
  background: var(--brass);
  transform: translateY(-2px);
}
.systems__track b { font-family: var(--font-block); font-weight: 600; letter-spacing: 0.03em; font-size: var(--fs-lead); }
.systems__track span { font-family: var(--font-cond); font-weight: 400; color: var(--white-dim); }

/* The demo screenshot, framed like a screen rather than dropped in raw. */
.systems__screen {
  display: block;
  position: relative;
  border: 1px solid rgba(201,162,39,0.3);
  box-shadow: 0 34px 90px rgba(0,0,0,0.8), 0 0 70px rgba(201,162,39,0.07);
  overflow: hidden;
  transition: transform 0.4s var(--ease-snap), box-shadow 0.4s ease;
}
.systems__screen img { width: 100%; height: auto; display: block; }
.systems__screen:hover { transform: translateY(-5px); box-shadow: 0 42px 110px rgba(0,0,0,0.85), 0 0 90px rgba(201,162,39,0.14); }
.systems__screen::after {
  content: 'Open the live example \2197';
  position: absolute;
  right: 12px; bottom: 12px;
  font-family: var(--font-ui);
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #0d0c0a;
  background: var(--brass);
  padding: 0.45rem 0.8rem;
}

/* The liability line. Tyler wanted it as fine print; it is stated plainly
   instead. An owner handing data to a contractor is already nervous about
   exactly this, so saying it out loud is a reason to trust him - and it is
   the one line on the page that protects him, so it needs to be read. */
.systems__limit {
  margin-top: clamp(2rem, 4vw, 3rem);
  border: 1px solid var(--border-dim);
  border-left: 3px solid var(--brass);
  background: rgba(240,237,232,0.02);
  padding: clamp(1.1rem, 2.5vw, 1.6rem) clamp(1.25rem, 3vw, 2rem);
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--white);
  max-width: 84ch;
}
.systems__limit b { font-family: var(--font-block); font-weight: 600; letter-spacing: 0.03em; color: var(--brass); }

.systems__jump {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: clamp(1.75rem, 3vw, 2.25rem);
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--white);
  border-bottom: 1px solid var(--red);
  padding-bottom: 0.35rem;
  transition: gap 0.3s var(--ease-snap);
}
.systems__jump:hover { gap: 1rem; }

@media (max-width: 900px) {
  .systems__grid { grid-template-columns: 1fr; }
}

/* ── Quote cards (pricing page) ──────────────────────────────────────
   Added 2026-09-07. Replaces a nine-row table of hard prices.

   Tyler's call: too many blunt numbers scares people and reads like a menu,
   which invites comparison shopping. Four keep their price - the things a
   normal person actually shops for - and the rest carry a plain-English
   description and a Get a quote button instead.

   The descriptions matter more than the prices here. Tyler: "nobody knows
   what the fuck any of these video terms mean." He is right, and a price
   next to a word somebody does not understand converts nothing.
   ─────────────────────────────────────────────────────────────────── */
.quotes {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: var(--border-dim);
  border: 1px solid var(--border-dim);
}
.quote-card {
  background: var(--bg);
  padding: clamp(1.5rem, 3vw, 2.25rem);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  transition: background 0.25s ease;
}
.quote-card:hover { background: var(--bg-card); }
.quote-card__top { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.quote-card__name {
  font-family: var(--font-block);
  font-size: clamp(1.35rem, 2.2vw, 1.85rem);
  line-height: 1.05;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.quote-card__price {
  font-family: var(--font-block);
  font-size: 1.5rem;
  line-height: 1;
  color: var(--red-bright);
  white-space: nowrap;
}
.quote-card__price small {
  display: block;
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--white-dim);
  margin-top: 0.25rem;
  text-align: right;
}
.quote-card__desc {
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--white-dim);
  flex: 1;
}
.quote-card__desc b { color: var(--white); font-weight: 600; }
.quote-card__cta {
  align-self: flex-start;
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--white);
  border-bottom: 1px solid var(--red);
  padding-bottom: 0.3rem;
  transition: color 0.25s ease;
}
.quote-card__cta:hover { color: var(--red-bright); }

@media (max-width: 800px) { .quotes { grid-template-columns: 1fr; } }

/* ── Contact ─────────────────────────────────────────────────────────
   Rebuilt 2026-09-07. Tyler: "the little email contact form sucks, it's
   kinda difficult to see, it seems like it's not the real one."

   He was right and the reason is structural: it was two cramped inputs
   wedged into a quarter-width footer column, next to a sitemap. It looked
   like boilerplate because it was placed like boilerplate. Every CTA on the
   site points at #contact, so the thing they land on has to look like the
   destination.

   Now a full-width section of its own above the footer. The footer keeps
   the email address and a link up to here, so there is exactly one form on
   the site rather than two competing ones.
   ─────────────────────────────────────────────────────────────────── */
.contact {
  border-top: 1px solid var(--border);
  background:
    radial-gradient(ellipse 60% 80% at 78% 30%, rgba(204,0,0,0.09), transparent 62%),
    var(--bg);
  padding: clamp(3rem, 7vw, 6rem) 0;
}
.contact__grid {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
.contact__aside .t-body { max-width: 40ch; }
.contact__direct {
  margin-top: 1.75rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border-dim);
}
.contact__direct a {
  font-family: var(--font-block);
  font-size: clamp(1.1rem, 1.8vw, 1.45rem);
  letter-spacing: 0.03em;
  color: var(--white);
  border-bottom: 1px solid var(--red);
  padding-bottom: 2px;
}
.contact__direct a:hover { color: var(--red-bright); }
.contact__note {
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: var(--fs-body);
  color: var(--white-dim);
  margin-top: 0.75rem;
}

.form { display: grid; gap: 1.1rem; }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
.field { display: block; }
.field > span {
  display: block;
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--white-dim);
  margin-bottom: 0.5rem;
}
.field > span i { font-style: normal; color: var(--white-dim); opacity: 0.6; letter-spacing: 0.08em; }
.field input,
.field select,
.field textarea {
  width: 100%;
  background: var(--bg-card);
  border: 1px solid var(--border-dim);
  border-radius: 0;
  color: var(--white);
  font-family: var(--font-cond);
  font-size: var(--fs-body);
  padding: 0.85rem 1rem;
  transition: border-color 0.2s ease, background 0.2s ease;
  -webkit-appearance: none;
  appearance: none;
}
.field select {
  /* Native arrow is hidden by appearance:none, so draw one. */
  background-image: linear-gradient(45deg, transparent 50%, var(--white-dim) 50%),
                    linear-gradient(135deg, var(--white-dim) 50%, transparent 50%);
  background-position: calc(100% - 20px) center, calc(100% - 14px) center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 2.5rem;
}
.field textarea { min-height: 130px; resize: vertical; }
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--red);
  background: var(--bg-mid);
}
.field input::placeholder, .field textarea::placeholder { color: rgba(154,148,144,0.6); }

@media (max-width: 900px) {
  .contact__grid { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .form__row { grid-template-columns: 1fr; }
}

/* ── Perk banner ─────────────────────────────────────────────────────
   Added 2026-09-07. Brass, for "here is something extra you get" moments,
   which were previously buried in grey paragraphs under the thing they were
   meant to sell.

   This extends the palette rule rather than breaking it. It was red for
   action, brass for proof. It is now red for things you click, brass for
   value you are being handed. A perk is value, not an action, so it is
   brass - and it stops competing with the buttons for attention.
   ─────────────────────────────────────────────────────────────────── */
.perk {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
  border: 1px solid rgba(201, 162, 39, 0.45);
  background: linear-gradient(100deg, rgba(201,162,39,0.14), rgba(201,162,39,0.04) 55%, transparent);
  padding: clamp(0.9rem, 2vw, 1.15rem) clamp(1.1rem, 2.5vw, 1.6rem);
}
.perk__tag {
  flex: none;
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #0d0c0a;
  background: var(--brass);
  padding: 0.3rem 0.65rem;
}
.perk__text {
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--white);
}
.perk__text b {
  font-family: var(--font-block);
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--brass);
  font-size: 1.15em;
}

/* ── Tattoo shops: two studios side by side ──────────────────────────
   Added 2026-09-17. Holy Iron and Viper were separate client groups, but a
   shop owner scrolling wants to see that tattoo studios are a category
   Tyler shoots - not which two. One block, two columns, each name still
   attached to its own work. Stacks on narrow screens. */
.tattoo-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2.5rem;
  align-items: start;
}
@media (max-width: 760px) {
  .tattoo-cols { grid-template-columns: 1fr; gap: 3rem; }
}

/* ── Missed-call demo ────────────────────────────────────────────────
   Added 2026-09-28. Tyler is not standing up real phone infrastructure
   yet - registration alone takes 1-3 weeks - so this is the product shown
   rather than described.

   It is a simulation, clearly, and that is fine: it is a demo of a
   mechanism, not a fabricated result. A prospect watches a missed call
   turn into a booked job in about fifteen seconds, which no paragraph
   does. It also costs nothing to run and cannot break in front of a
   client the way a live integration can.
   ─────────────────────────────────────────────────────────────────── */
.mcd { display: grid; grid-template-columns: auto 1fr; gap: clamp(1.5rem,4vw,3.5rem); align-items: center; }
.phone {
  width: clamp(230px, 26vw, 290px);
  border: 10px solid #1a1a1a;
  border-radius: 34px;
  background: #0b0b0b;
  box-shadow: 0 30px 70px rgba(0,0,0,0.75), 0 0 0 1px rgba(240,237,232,0.08);
  overflow: hidden;
}
.phone__bar {
  background: #141414;
  padding: 0.55rem 0.9rem;
  border-bottom: 1px solid rgba(240,237,232,0.07);
  font-family: var(--font-ui);
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--white-dim);
  display: flex; justify-content: space-between; gap: 0.5rem;
}
.phone__thread { padding: 0.9rem; min-height: 310px; display: flex; flex-direction: column; gap: 0.6rem; }

.mcd__event {
  align-self: center;
  text-align: center;
  font-family: var(--font-ui);
  font-size: 0.56rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bad, #c4442f);
  border: 1px solid rgba(196,68,47,0.5);
  padding: 0.35rem 0.6rem;
}
.bub {
  max-width: 84%;
  padding: 0.55rem 0.75rem;
  border-radius: 14px;
  font-family: var(--font-cond);
  font-size: 0.92rem;
  line-height: 1.4;
}
.bub--out { align-self: flex-end; background: #0b6b3a; color: #fff; border-bottom-right-radius: 4px; }
.bub--in  { align-self: flex-start; background: #232323; color: var(--white); border-bottom-left-radius: 4px; }
.bub__meta {
  display: block;
  font-family: var(--font-ui);
  font-size: 0.52rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  opacity: 0.65;
  margin-top: 0.35rem;
}
/* Each line drops in as the script plays, rather than the whole thread
   appearing at once, because the point being sold is the speed. */
.mcd__step { opacity: 0; transform: translateY(8px); transition: opacity .4s ease, transform .4s var(--ease-snap); }
.mcd__step.is-on { opacity: 1; transform: none; }

.mcd__note { font-family: var(--font-cond); font-weight: 400; font-size: 1.05rem; line-height: 1.6; color: var(--white-dim); }
.mcd__note b { color: var(--white); font-weight: 600; }
.mcd__replay {
  margin-top: 1.25rem;
  font-family: var(--font-ui);
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--white);
  background: none;
  border: 1px solid rgba(240,237,232,0.25);
  padding: 0.6rem 1.1rem;
}
.mcd__replay:hover { border-color: var(--brass); color: var(--brass); }
@media (max-width: 800px) { .mcd { grid-template-columns: 1fr; justify-items: center; } }
@media (prefers-reduced-motion: reduce) { .mcd__step { transition: none; } }

/* ── Scroll pitch ────────────────────────────────────────────────────
   Added 2026-09-28, after Tyler pointed at umault.com. What he liked:
   one idea per scroll, impossible to skim. What annoyed him halfway
   through: they scroll-jack, so you are held hostage reading a brochure.

   So this PINS rather than hijacks. The stage is position:sticky inside a
   tall section, and scroll position picks the active beat. Native scroll
   speed is untouched - a reader who wants to blow past it can, and one who
   wants to read gets one line at a time. That is the whole difference
   between the technique working and being irritating.

   Beat 0 is the claim, which is Tyler's own line and not a borrowed one.
   Beats 1-4 are the four steps, so the claim and the mechanism arrive as
   one argument instead of two sections.
   ─────────────────────────────────────────────────────────────────── */
.pitch { position: relative; }
.pitch__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  display: grid;
  place-items: center;
}
/* Footage sits behind every beat. Until Tyler supplies cuts, each beat
   falls back to its poster image; the <video> covers it when a file lands. */
.pitch__media { position: absolute; inset: 0; z-index: 0; }
.pitch__shot {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .9s ease;
  background-size: cover;
  background-position: center;
}
.pitch__shot.is-on { opacity: 1; }
.pitch__shot video, .pitch__shot img {
  width: 100%; height: 100%; object-fit: cover; display: block; max-width: none;
}

/* height:100% is load-bearing. Every .pitch__beat inside is absolutely
   positioned, so without it this box collapses to zero height - the words
   still showed because the grid centres its overflow, but .beat-media had no
   height to fill and every beat rendered as a black screen. */
.pitch__beats {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  padding: 0 clamp(1.5rem,5vw,5rem);
}
.pitch__beat {
  position: absolute;
  inset: 0;
  display: grid;
  align-content: center;
  justify-items: center;
  text-align: center;
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .55s ease, transform .55s var(--ease-snap);
  pointer-events: none;
}
.pitch__beat.is-on { opacity: 1; transform: none; }
.pitch__num {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 600;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--red-bright);
  margin-bottom: 1.4rem;
}
.pitch__line {
  font-family: var(--font-block);
  font-size: clamp(2.6rem, 9vw, 8.5rem);
  line-height: .9;
  letter-spacing: .02em;
  text-transform: uppercase;
  max-width: 16ch;
}
.pitch__line .accent { display: block; }
.pitch__sub {
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: clamp(1.02rem, 1.5vw, 1.3rem);
  line-height: 1.55;
  color: var(--white);
  max-width: 46ch;
  margin-top: 1.6rem;
}

/* Progress ticks, one per beat, so a reader knows how long this lasts.
   Umault gives you no idea how much further it goes, which is most of why
   it starts to feel like a hostage situation. */
.pitch__ticks {
  position: absolute;
  left: 50%; bottom: clamp(1.5rem, 4vh, 3rem);
  transform: translateX(-50%);
  z-index: 3;
  display: flex; gap: 8px;
}
.pitch__ticks span { width: 30px; height: 2px; background: rgba(240,237,232,.2); transition: background .4s ease; }
.pitch__ticks span.is-on { background: var(--red); }

@media (max-width: 720px) {
  .pitch__line { font-size: clamp(2.2rem, 11vw, 3.4rem); }
}
@media (prefers-reduced-motion: reduce) {
  .pitch__beat, .pitch__shot { transition: none; }
}

/* ── Pitch word beats + collages ─────────────────────────────────────
   Added 2026-09-28. Tyler's direction: the hero carries the logo alone,
   then the claim arrives one word per scroll - YOU / DESERVE / BETTER /
   CONTENT - each with a collage or a short clip behind it.

   One word at very large size is the umault move and it is the right one
   here: a single word cannot be skimmed, so the reader is forced through
   the sentence at the pace of their own thumb. The four steps follow as
   the same kind of beat, so claim and mechanism are still one run.
   ─────────────────────────────────────────────────────────────────── */
/* Gigantic on purpose. Tyler: "you can't avoid reading it - that's the whole
   point." Size is set per beat rather than globally, because a six-letter
   word and a two-letter word need very different sizes to fill the same
   frame. --ch is roughly the character count; the clamp keeps IS from
   becoming absurd on a wide monitor.

   --lines is how many lines that beat wraps to, and it divides the height
   cap. Without it a two-line beat sized itself off the same height cap as a
   one-line beat and ran 840px tall inside a 900px frame. */
.pitch__word {
  position: relative;
  z-index: 1;
  font-family: var(--font-block);
  font-size: min(clamp(3.5rem, calc(250vw / var(--ch, 7)), 46rem), calc(82vh / var(--lines, 1)));
  line-height: .8;
  letter-spacing: -.035em;
  text-transform: uppercase;
  text-align: center;
  mix-blend-mode: normal;
  color: #fff;
  /* Keeps white readable where a still goes pale behind it. */
  text-shadow: 0 2px 28px rgba(0,0,0,.55), 0 0 90px rgba(0,0,0,.35);
  /* Rides the same push-in as the media, a touch slower, so the word feels
     bolted to the frame rather than floating over it. */
  transform: scale(calc(1 + (var(--z, 0) * .10)));
  will-change: transform;
}
.pitch__word .br { display: block; }
/* The difference-blend fallback came out 2026-10-06 with the blend itself. */

/* ── Beat media ──────────────────────────────────────────────────────
   Re-added 2026-09-28. This whole block was deleted by an earlier edit of
   mine, and the "restore" that followed silently did nothing because its
   anchor string had been deleted too. Without these rules .beat-media was a
   plain grid item: it stacked ABOVE the word instead of sitting behind it,
   sized itself to the image's natural 16:9, and shoved the word off the
   bottom of the frame. One missing rule, every symptom.
   ─────────────────────────────────────────────────────────────────── */
.beat-media {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}
.beat-media img,
.beat-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  max-width: none;
  opacity: 0;
  /* --z is scroll progress through this beat, 0 to 1, set by js/pitch.js.
     The push-in tracks the wheel so the four beats read as one move through
     a single space. Tyler is putting a dark patch at the centre of each
     collage so the next frame emerges out of it. */
  transform: scale(calc(1 + (var(--z, 0) * .34)));
  transition: opacity .7s ease;
  will-change: transform;
}
.pitch__beat.is-on .beat-media img,
.pitch__beat.is-on .beat-media video { opacity: 1; }

/* Scrim rides on the media so it keeps the word readable over whatever goes
   in the slot. The old .pitch__veil sat below the beats in z-order and
   darkened nothing. */
.beat-media::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(ellipse 75% 65% at 50% 50%, rgba(8,8,8,.22), rgba(8,8,8,.6) 78%),
    linear-gradient(180deg, rgba(8,8,8,.55), rgba(8,8,8,.12) 40%, rgba(8,8,8,.65));
}


/* -- Worklet: the short strip of real work --------------------------------
   Added 2026-09-28. Tyler's running order for the homepage is the pinned
   callout, then the formula, then "a little bit of video work", then the
   website and dashboard split. This is that little bit: four tiles, not a
   gallery. The full gallery is one click away and does not belong here. */
.worklet { padding: clamp(2rem,5vw,4rem) 0 clamp(2.5rem,5vw,4.5rem); }
.worklet__head {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  justify-content: space-between; gap: 1rem 2rem;
  margin-bottom: clamp(1.2rem,2.5vw,2rem);
}
.worklet__title {
  font-family: var(--font-block); text-transform: uppercase;
  font-size: clamp(1.6rem,3.4vw,2.6rem); letter-spacing: .02em;
  line-height: 1.02; margin: .5rem 0 0;
}
.worklet__title em { font-style: normal; color: var(--red-bright); }
.worklet__all {
  font-family: var(--font-block); text-transform: uppercase;
  font-size: var(--fs-cap); letter-spacing: .16em; color: var(--red-bright);
  text-decoration: none; border-bottom: 1px solid currentColor;
  padding-bottom: .2rem; white-space: nowrap;
}
.worklet__all:hover { color: var(--white); }
.worklet__strip {
  display: grid; gap: clamp(.5rem,1vw,.9rem);
  grid-template-columns: repeat(4, 1fr);
}
.worklet__tile {
  display: block; text-decoration: none; color: inherit;
  border: 1px solid rgba(240,237,232,.1); background: #0f0f0f;
}
.worklet__tile img {
  display: block; width: 100%; aspect-ratio: 16/9; object-fit: cover;
  transition: opacity .3s ease; opacity: .82;
}
.worklet__tile:hover { border-color: var(--red-bright); }
.worklet__tile:hover img { opacity: 1; }
.worklet__cap { display: block; padding: .7rem .8rem .8rem; }
.worklet__cap b {
  display: block; font-family: var(--font-block); text-transform: uppercase;
  font-size: var(--fs-cap); letter-spacing: .08em; font-weight: 600;
}
.worklet__cap span {
  display: block; margin-top: .2rem; font-size: var(--fs-cap);
  letter-spacing: .1em; text-transform: uppercase; color: var(--white-dim);
}
@media (max-width: 760px) { .worklet__strip { grid-template-columns: repeat(2,1fr); } }

/* -- Split: website on one side, lead board on the other ------------------
   Added 2026-09-28. Tyler asked for "a website and dashboard like split
   screen", and for the headline to be his own line: every missed call is a
   lost job. The two panels sit in one frame with a hairline between them
   rather than becoming two more cards in a grid, because they are two halves
   of one product, not two products.

   Both images are real: holy-iron.webp is a client site, demo.png is the
   example board. No invented screenshots. */
.split { padding: clamp(2.5rem,6vw,5rem) 0 clamp(3rem,7vw,6rem); }
.split__title {
  font-family: var(--font-block); text-transform: uppercase;
  font-size: clamp(2.1rem,5.4vw,4.2rem); line-height: .98;
  letter-spacing: -.01em; margin: .6rem 0 0;
}
.split__title em { font-style: normal; display: block; color: var(--brass); }
.split__panes {
  margin-top: clamp(1.6rem,3.5vw,2.8rem);
  display: grid; grid-template-columns: 1fr 1fr;
  border: 1px solid rgba(240,237,232,.14);
  background: rgba(240,237,232,.14);
  gap: 1px;
}
.split__pane {
  display: flex; flex-direction: column;
  background: #0c0c0c; text-decoration: none; color: inherit;
  transition: background .3s ease;
}
.split__pane:hover { background: #121110; }
.split__shot { display: block; overflow: hidden; border-bottom: 1px solid rgba(240,237,232,.1); }
.split__shot img {
  display: block; width: 100%; height: auto; aspect-ratio: 16/10;
  object-fit: cover; object-position: top center;
  transition: transform .5s ease; opacity: .9;
}
.split__pane:hover .split__shot img { transform: scale(1.03); opacity: 1; }
.split__body { display: block; padding: clamp(1.1rem,2.2vw,1.8rem); flex: 1; }
.split__kicker {
  display: block; font-family: var(--font-block); text-transform: uppercase;
  font-size: var(--fs-cap); letter-spacing: .18em; color: var(--brass);
}
.split__h {
  display: block; font-family: var(--font-block); text-transform: uppercase;
  font-size: clamp(1.2rem,2.2vw,1.65rem); letter-spacing: .03em;
  margin: .45rem 0 .6rem;
}
.split__p { display: block; color: var(--white-dim); font-size: var(--fs-body); line-height: 1.6; }
.split__go {
  display: inline-block; margin-top: .9rem;
  font-family: var(--font-block); text-transform: uppercase;
  font-size: var(--fs-cap); letter-spacing: .16em; color: var(--red-bright);
}
.split__pane:hover .split__go { color: var(--white); }
@media (max-width: 800px) { .split__panes { grid-template-columns: 1fr; } }
@media (prefers-reduced-motion: reduce) {
  .split__shot img, .worklet__tile img { transition: none; }
  .split__pane:hover .split__shot img { transform: none; }
}


/* -- Websites & lead catchers: the device rig -----------------------------
   Added 2026-09-28, replacing two raw screenshots side by side.

   Tyler's rule for the page: every section is a small advertisement for
   itself, and somebody should know what it is for without reading. A cropped
   screenshot of a website does not read as "a website" at a glance. A browser
   window with a title bar does. So the chrome is drawn in CSS and the real
   images sit inside it - the frames are decoration, the content is genuine.

   The whole cluster is one aspect-ratio box with the three devices placed as
   percentages, so it scales as a single picture instead of reflowing into a
   different composition at every width. Text inside the phone is sized in cqw
   off .rig's container, or it would stay 13px while the phone shrank. */
.rigsec { padding: clamp(2.5rem,6vw,5rem) 0 clamp(3rem,7vw,6rem); }
.rigsec__head { text-align: center; max-width: 34ch; margin: 0 auto; }
.rigsec__title {
  font-family: var(--font-block); text-transform: uppercase;
  font-size: clamp(2.4rem,7vw,5.6rem); line-height: .92;
  letter-spacing: -.02em; margin: 0;
}
.rigsec__title em { font-style: normal; display: block; color: var(--brass); }
.rigsec__sub {
  margin: 1rem auto 0; color: var(--white-dim);
  font-family: var(--font-ui); text-transform: uppercase;
  letter-spacing: .14em; font-size: var(--fs-body);
}

.rig {
  container-type: inline-size;
  position: relative;
  width: 100%; max-width: 1120px;
  margin: clamp(2rem,4.5vw,3.5rem) auto 0;
  aspect-ratio: 16 / 9;
}
.rig__win   { position: absolute; left: 0;   top: 0;     width: 70%;   z-index: 1; }
.rig__lap   { position: absolute; right: 0;  top: 25%;   width: 45%;   z-index: 2; }
.rig__phone { position: absolute; left: 13%; bottom: -6%; width: 13%;  z-index: 3; }

/* Browser window */
.win {
  border: 1px solid rgba(240,237,232,.16);
  background: #111; border-radius: .5cqw;
  overflow: hidden; box-shadow: 0 2cqw 5cqw rgba(0,0,0,.6);
}
.win__bar {
  display: flex; align-items: center; gap: .8cqw;
  padding: 1cqw 1.4cqw; background: #1a1a1a;
  border-bottom: 1px solid rgba(240,237,232,.1);
}
.win__bar i { width: .8cqw; height: .8cqw; border-radius: 50%; background: #3a3a3a; }
.win__bar span {
  margin-left: 1cqw; font-family: var(--font-ui); color: var(--white-dim);
  font-size: 1.1cqw; letter-spacing: .06em;
}
.win__body { aspect-ratio: 16 / 9.4; overflow: hidden; }
.win__body img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 16 / 9.4; object-fit: cover; object-position: top center;
}

/* Laptop */
.lap { filter: drop-shadow(0 2cqw 4cqw rgba(0,0,0,.65)); }
.lap__screen {
  border: .55cqw solid #2a2a2a; border-bottom: none;
  border-radius: .6cqw .6cqw 0 0; background: #0c0c0c;
  overflow: hidden;
}
.lap__screen img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 16 / 10; object-fit: cover; object-position: top left;
}
.lap__base {
  height: 1.1cqw; background: linear-gradient(180deg,#2a2a2a,#171717);
  border-radius: 0 0 .7cqw .7cqw;
  display: flex; align-items: center; justify-content: center;
  margin: 0 -2.2cqw;
}
.lap__base span { width: 14%; height: .3cqw; background: #0d0d0d; border-radius: .3cqw; }

/* Phone */
.fone {
  border: .5cqw solid #262626; border-radius: 1.8cqw;
  background: #0b0b0b; overflow: hidden;
  aspect-ratio: 9 / 19;
  box-shadow: 0 2cqw 4cqw rgba(0,0,0,.7);
  display: flex; flex-direction: column;
}
.fone__notch {
  height: 1.5cqw; flex: none;
  background: #161616; border-bottom: 1px solid rgba(240,237,232,.07);
}
.fone__thread {
  flex: 1; padding: .9cqw .7cqw;
  display: flex; flex-direction: column; gap: .55cqw; justify-content: flex-end;
}
.fbub, .fone__ev {
  margin: 0; opacity: 0; transform: translateY(.5cqw);
  transition: opacity .35s ease, transform .35s ease;
  font-family: var(--font-ui); font-size: .95cqw; line-height: 1.35;
}
.fbub { max-width: 88%; padding: .55cqw .7cqw; border-radius: .9cqw; }
.fbub--out { align-self: flex-end; background: var(--red); color: #fff; border-bottom-right-radius: .25cqw; }
.fbub--in  { align-self: flex-start; background: #232323; color: var(--white); border-bottom-left-radius: .25cqw; }
.fone__ev {
  align-self: center; text-align: center;
  font-size: .8cqw; letter-spacing: .1em; text-transform: uppercase;
  color: var(--white-dim); border: 1px solid rgba(240,237,232,.18);
  border-radius: .6cqw; padding: .35cqw .6cqw;
}
.fone__ev--win { color: var(--brass); border-color: rgba(201,162,39,.55); }
.mcd__step.is-on { opacity: 1; transform: none; }

/* Three labels, four words each. This is the entire explanation. */
.rigsec__legend {
  list-style: none; margin: clamp(1.6rem,3.5vw,2.6rem) 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(3,1fr); gap: 1rem 1.5rem;
  text-align: center;
}
.rigsec__legend b {
  display: block; font-family: var(--font-block); text-transform: uppercase;
  font-weight: 600; font-size: clamp(1rem,2.1vw,1.5rem); letter-spacing: .03em;
  color: var(--brass);
}
.rigsec__legend span {
  display: block; margin-top: .3rem; color: var(--white-dim);
  font-size: var(--fs-body);
}
.rigsec__cta {
  display: flex; flex-wrap: wrap; gap: .8rem;
  justify-content: center; margin-top: clamp(1.6rem,3.5vw,2.4rem);
}

/* Under 820px the cluster stops being one picture and becomes a stack.
   Percentage placement would put the phone on top of the laptop at phone
   width, which reads as a glitch rather than a composition. */
@media (max-width: 820px) {
  .rig { aspect-ratio: auto; display: flex; flex-direction: column;
         align-items: center; gap: 1.4rem; container-type: normal; }
  .rig__win, .rig__lap, .rig__phone { position: static; width: 100%; }
  .rig__lap { width: 86%; }
  .rig__phone { width: 48%; max-width: 230px; }
  .win, .lap, .fone { box-shadow: 0 10px 30px rgba(0,0,0,.6); filter: none; }
  .win__bar { padding: 7px 10px; gap: 6px; }
  .win__bar i { width: 6px; height: 6px; }
  .win__bar span { font-size: 10px; margin-left: 8px; }
  .win, .lap__screen { border-radius: 6px 6px 0 0; }
  .lap__screen { border-width: 5px; }
  .lap__base { height: 10px; margin: 0 -14px; border-radius: 0 0 8px 8px; }
  .lap__base span { height: 3px; }
  .fone { border-radius: 20px; border-width: 5px; }
  .fone__notch { height: 16px; }
  .fone__thread { padding: 10px 8px; gap: 6px; }
  .fbub, .fone__ev { font-size: 11px; transform: translateY(5px); }
  .fbub { padding: 6px 9px; border-radius: 11px; }
  .fone__ev { font-size: 9px; padding: 4px 7px; border-radius: 7px; }
  .rigsec__legend { grid-template-columns: 1fr; gap: 1.1rem; }
}
@media (prefers-reduced-motion: reduce) {
  .fbub, .fone__ev { transition: none; }
}


/* -- Hero proof line ------------------------------------------------------
   Proof sitting next to the CTA rather than in a section of its own. It used
   to be a full "course belt" block far down the page, where it was doing
   nothing for the decision being made at the top. */
.hero__quiet {
  font-family: var(--font-cond); font-weight: 400;
  color: var(--white-dim); text-decoration: none;
  border-bottom: 1px solid rgba(240,237,232,.3); padding-bottom: 2px;
}
.hero__quiet:hover { color: var(--white); border-color: var(--red-bright); }
.hero__proof {
  margin: clamp(1.4rem,3vw,2.2rem) 0 0;
  font-family: var(--font-ui); font-size: var(--fs-cap);
  letter-spacing: .12em; text-transform: uppercase; color: var(--white-dim);
  line-height: 1.9;
}
.hero__proof span {
  display: block; color: var(--brass); letter-spacing: .2em;
  font-size: .9em; margin-bottom: .25rem;
}

/* -- Three steps (.how, not .steps: video.html owns that one) ----------------------------------------------------------
   Replaces four numbered paragraphs. The number is the size of the heading on
   purpose: at a glance this reads as 1, 2, 3 and stops there, which is the
   whole job of the section. */
.how { padding: clamp(2.5rem,6vw,5rem) 0; }
.how__row {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3,1fr);
  gap: clamp(1.2rem,3vw,2.5rem);
}
.how__item { border-top: 2px solid var(--red); padding-top: clamp(.8rem,1.6vw,1.2rem); }
.how__n {
  display: block; font-family: var(--font-block);
  font-size: clamp(2.2rem,5vw,3.6rem); line-height: 1; color: var(--red-bright);
}
.how__t {
  font-family: var(--font-block); text-transform: uppercase;
  font-size: clamp(1.4rem,3.2vw,2.4rem); letter-spacing: .02em;
  line-height: 1.02; margin: .5rem 0 .4rem;
}
.how__d { color: var(--white-dim); font-size: var(--fs-body); margin: 0; }
@media (max-width: 720px) {
  .how__row { grid-template-columns: 1fr; gap: 1.6rem; }
}



/* ── One spine ────────────────────────────────────────────────────────
   Added 2026-09-28 after Tyler walked the page out loud: centered, then a
   left third, then centered, then stacked centered, with the column count
   going three, four, three, two. His words: "it doesn't flow."

   He was right, and his own reference site proves it - umault.com is centered
   in every section from the hero to the newsletter, and that is the only
   reason it reads as smooth. It is not better designed section by section, it
   just never changes the spine.

   So: every section on this page is centered, every grid is three across, and
   every section closes with at most one button. The rules below exist to
   enforce that, and anything added later has to obey them or the page goes
   back to feeling like five pages stapled together.
   ─────────────────────────────────────────────────────────────────── */

/* Three steps */
.how__row { text-align: center; }
.how__item { border-top-width: 3px; }
.how__d { margin-left: auto; margin-right: auto; max-width: 24ch; }

/* The work */
.worklet__head { display: block; text-align: center; }
.worklet__title { margin: .5rem auto 0; max-width: 20ch; }
.worklet__title em { font-style: normal; display: block; color: var(--red-bright); }
.worklet__strip { grid-template-columns: repeat(3, 1fr); }
.worklet__cap { text-align: center; }
.worklet__more { text-align: center; margin-top: clamp(1.4rem,3vw,2.2rem); }

/* Websites & lead capture. Brass appears once per section, on the three
   labels, because that is the value being handed over. It was also on the
   title, which put yellow directly above a red button - Tyler: "the red next
   to the yellow looks fucking weird." He is right, and the rule was already
   written down: red for what you click, brass for what you are handed. */
.rigsec__head { max-width: 22ch; }
.rigsec__title em { display: inline; color: inherit; }

/* Section headers everywhere else follow the same spine. */
.contact .section-header, .worklet .section-header { text-align: center; }

/* In a band: the footer line that replaced the one in the middle of the work
   section. */
.footer-band {
  text-align: center;
  padding: clamp(1.4rem,3vw,2rem) 0 0;
  font-family: var(--font-cond); font-weight: 400;
  color: var(--white-dim);
}
.footer-band a {
  color: var(--white); text-decoration: none;
  border-bottom: 1px solid var(--red); padding-bottom: 1px;
}
.footer-band a:hover { border-color: var(--red-bright); color: var(--red-bright); }

@media (max-width: 760px) {
  .worklet__strip { grid-template-columns: 1fr; }
}


/* ── Oxblood type and field ───────────────────────────────────────────
   Appended 2026-09-29. Everything below overrides the old system rather
   than editing 2,600 lines in place.
   ─────────────────────────────────────────────────────────────────── */

body {
  background: var(--oxblood);
  color: var(--bone);
  font-family: var(--font-ui);
  font-variation-settings: 'wdth' var(--normal);
}

/* Display type is the wide cut. This is the one place the width axis earns
   its keep: the same family, stretched, reads as machinery rather than as a
   second font bolted on. */
.t-section, .hero__title, .pitch__word, .how__t, .worklet__title,
.rigsec__title, .cta-strip__title, .systems__title, .priceline__title {
  font-family: var(--font-block);
  font-variation-settings: 'wdth' var(--wide);
  font-weight: 800;
  letter-spacing: -0.015em;
}

/* Tyler's own voice, and nothing else. Client quotes and the lines he
   actually says out loud. Held back so it still means something when it
   shows up. */
.t-voice, .pullquote__text, .hero__sub, .rigsec__sub {
  font-family: var(--font-voice);
  font-style: italic;
  font-weight: 400;
  letter-spacing: 0;
}

/* The eyebrow label loses its all-caps tracking. It was 0.75rem, 600 weight,
   0.18em tracked, uppercase, on top of nearly every section - the single
   most repeated generic tell on the site. Where a label genuinely carries
   information it now reads as a small plain word; where it was decoration it
   is deleted from the markup instead. */
.t-label {
  font-family: var(--font-ui);
  font-size: var(--fs-cap);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--dew);
}

/* Reading measure. Nothing that is meant to be read runs past 66 characters. */
.t-body, .how__d, .worklet__cap span, .split__p, .systems__limit {
  max-width: 66ch;
}

/* Sections sit on the field; footage and the pitch sit in ink wells, so the
   footage always has a dark surround and the red never fights the picture. */
.section { background: var(--oxblood); }
.pitch, .hero, .worklet, .featured-video-main, .rigsec { background: var(--ink); }
.contact { background: var(--rust); }

/* Buttons: orange fill, ink text. On oxblood this is the only thing that
   glows, which is the entire point of an accent. */
.btn--red, .btn--primary {
  background: var(--dew);
  border-color: var(--dew);
  color: var(--ink);
  font-variation-settings: 'wdth' 112;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: none;
}
.btn--red:hover, .btn--primary:hover {
  background: var(--bone);
  border-color: var(--bone);
  color: var(--ink);
}


/* ── Oxblood, second pass ─────────────────────────────────────────────
   Screenshot review. Three things were still wrong.
   ─────────────────────────────────────────────────────────────────── */

/* 1. .accent painted one phrase of every headline a different colour. That
      is top of the skill's list of typographic tells, and it was applied
      globally, so every heading on the site had it. The class still breaks
      the line - that is real structure - but it no longer changes colour.
      The page now spends its boldness in one place: the pitch. */
.accent { color: inherit; }
.hero__title .accent,
.pitch__line .accent,
.worklet__title em,
.t-section .accent { color: inherit; }

/* 2. The hero headline was sized for a condensed face. Archivo Expanded sets
      roughly 40% wider at the same point size, so 8rem wrapped a four-word
      line onto four lines and pushed the logo out of the top of the frame. */
.hero__title {
  font-size: clamp(2.3rem, 5.6vw, 5.2rem);
  line-height: 0.92;
  letter-spacing: -0.02em;
}
.hero__sub { font-size: var(--fs-lead); line-height: 1.55; }
.hero__content { padding-block: clamp(1rem, 3vh, 2.5rem); }

/* 3. Small orange text measures 3.16:1 on the oxblood field, which fails.
      Labels are bone by default and only go orange where they sit on ink. */
.t-label { color: var(--bone); }
.hero .t-label,
.worklet .t-label,
.rigsec .t-label { color: var(--dew); }

/* Flat field. Several older rules paint a gradient over dark sections, which
   on oxblood read as a muddy wash rather than a colour. */
.section, .how, .priceline { background-image: none; }

/* The numbers stay: make it, post it, nothing is a real sequence, which is
   the only thing that earns numbered markers. They are large display type,
   so orange clears the 3:1 bar for large text on the field. */
.how__n { font-variation-settings: 'wdth' 112; font-weight: 700; }

/* Body copy in Archivo at normal width, with a real reading measure. */
.t-body, .how__d, .split__p {
  font-family: var(--font-text);
  font-variation-settings: 'wdth' 100;
  font-weight: 400;
  line-height: 1.6;
}


/* ── Oxblood, third pass: the last of the caps labels ─────────────────
   The markup already said "Your name" and "Services" in sentence case; CSS
   was shouting them. Tracked all-caps is the skill's most-cited tell and it
   was on every form field, every footer column and the scroll cue. Sentence
   case also matches how Tyler talks, which is the actual argument.
   ─────────────────────────────────────────────────────────────────── */
.field > span,
.form-label,
.footer-col__title,
.scroll-cue__label,
.hero__proof,
.hero__proof span {
  text-transform: none;
  letter-spacing: 0;
}
.field > span, .form-label {
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--white-dim);
}
.footer-col__title {
  font-variation-settings: 'wdth' 112;
  font-weight: 700;
  font-size: var(--fs-body);
}
.hero__proof {
  font-size: var(--fs-body);
  line-height: 1.6;
  max-width: 54ch;
  margin-inline: auto;
  color: var(--white-dim);
}
.hero__proof span { display: inline; color: inherit; }
.scroll-cue__label { font-size: var(--fs-cap); color: var(--white-dim); }

/* The quiet hero link: its underline was a flex-stretched border running the
   full width of the item rather than the width of the words. */
.hero__quiet {
  display: inline;
  border-bottom: 0;
  text-decoration: underline;
  text-decoration-color: var(--dew);
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
}
.hero__quiet:hover { color: var(--bone); text-decoration-color: var(--bone); }


/* ── Oxblood, polish ──────────────────────────────────────────────────
   Ghost buttons were the last all-caps holdout, and the tile strip was
   colliding with the featured film's caption row. */
.hero__ghost, .worklet__all, .systems__jump, .split__go {
  text-transform: none;
  letter-spacing: 0;
  font-variation-settings: 'wdth' 106;
  font-weight: 600;
}
.worklet__strip { margin-top: clamp(1.8rem, 4vw, 3rem); }
.worklet .featured-video-main { margin-bottom: clamp(1rem, 2vw, 1.6rem); }


/* -- Palette, second pass -------------------------------------------------
   The loudest thing on a red field is near-white, not another hot hue, so
   the primary button is bone and the accent is held back for rules, labels
   and links. One shouting element per screen. */
.btn--red, .btn--primary {
  background: var(--bone);
  border-color: var(--bone);
  color: var(--ink);
}
.btn--red:hover, .btn--primary:hover {
  background: var(--dew);
  border-color: var(--dew);
  color: var(--ink);
}
.hero .t-label, .worklet .t-label, .rigsec .t-label { color: var(--dew); }
.how__n { color: var(--dew); }
.how__item { border-top-color: var(--dew); }
.hero__quiet { text-decoration-color: var(--dew); }

/* -- The scroll word ------------------------------------------------------
   js/pitch.js measures the rendered word and scales it to fit. The rule
   below is only what shows before that script runs.

   It is no longer a CSS formula. It used to be `250vw / var(--ch)`, where
   --ch was a character count hand-written onto each beat. That constant was
   really standing in for the average character width of Bebas Neue, so when
   the site moved to Archivo Expanded, about 1.8x wider per character, every
   word blew out to 2.4x the viewport and got clipped by its container.
   Nothing threw an error; it just looked wrong. Measuring removes the
   constant, so the next font swap cannot repeat it. */
.pitch__word {
  font-size: clamp(2.5rem, 8vw, 8rem);
  white-space: nowrap;
}
.pitch__word .br { display: block; }


/* The pitch word runs at the NARROW end of Archivo's width axis, which is the
   opposite of every other display heading on the site. Reason: this word is
   sized to fill the frame, so width is what limits it. Expanded, "Nobody"
   filled 94% of the width while standing only 21% tall - a thin ribbon, not
   the poster-sized word Tyler asked for. Condensed, the same 94% of width
   buys roughly twice the height.

   So the width axis is doing real work in both directions: wide where a
   headline should feel like machinery, narrow where a word has to be huge. */
.pitch__word { font-variation-settings: 'wdth' 66; font-weight: 800; }


/* 20ch broke the line as "Made for people who had / better things to do",
   leaving HAD stranded. The <em> already forces the break in the right
   place; the measure just needs room for the first clause. */
.worklet__title { max-width: 26ch; }


/* ── Carousels, and the shape of a month ──────────────────────────────
   Added 2026-09-29 to Tyler's spec: "big video, then three vertical cut
   downs, then seven four-by-five slides."

   The seven slides lie flat in one row rather than sliding. A slider shows
   one frame at a time and hides the argument; a carousel's argument IS the
   sequence, so showing all seven at once is the honest presentation and it
   happens to be the better one. At a 1200px container each slide lands
   around 165x206, so the seven together occupy the same width as the video
   above them and about a third of its height - which is the proportion Tyler
   described.

   Numbering is on because a carousel genuinely is a sequence. That is the
   only thing that earns numbered markers.
   ─────────────────────────────────────────────────────────────────── */

/* The stack: one deliverable set, in the order it gets made. */
.stack { display: grid; gap: clamp(.8rem, 1.8vw, 1.4rem); }
.stack__label {
  font-size: var(--fs-cap);
  color: var(--white-dim);
}

/* Row 1: the film. */
.stack__film { aspect-ratio: 16 / 9; background: var(--ink); }
.stack__film iframe { width: 100%; height: 100%; border: 0; display: block; }

/* Row 2: three vertical cutdowns, sized so the trio matches the film's width. */
.stack__cuts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(.4rem, 1vw, .8rem);
}
.stack__cut { aspect-ratio: 9 / 16; background: var(--ink); overflow: hidden; }
.stack__cut iframe { width: 100%; height: 100%; border: 0; display: block; }

/* Row 3: the carousel, all seven slides at once. */
.carousel {
  display: grid;
  grid-template-columns: repeat(var(--slides, 7), 1fr);
  gap: clamp(.25rem, .6vw, .55rem);
}
.slide {
  position: relative;
  aspect-ratio: 4 / 5;
  background: var(--ink);
  border: 1px solid var(--border-dim);
  overflow: hidden;
}
.slide img { width: 100%; height: 100%; object-fit: cover; display: block; }
.slide__n {
  position: absolute;
  left: 0; top: 0;
  padding: .2em .45em;
  font-size: clamp(.6rem, 1vw, .72rem);
  font-weight: 600;
  line-height: 1;
  color: var(--ink);
  background: var(--dew);
}
/* An empty slot reads as a slot, not as a broken image. */
.slide--empty {
  border-style: dashed;
  border-color: rgba(201, 214, 192, .45);
}

/* On a phone seven across would be 50px wide. Below the breakpoint it becomes
   what a carousel actually is on a phone: a swipe, with snap points. */
@media (max-width: 760px) {
  .carousel {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 46%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    padding-bottom: .5rem;
  }
  .slide { scroll-snap-align: start; }
  .stack__cuts { gap: .35rem; }
}


/* A slide takes a video as readily as an image. Same box, same crop - the
   clips are exported 1080x1350 like the stills, so nothing letterboxes. */
.slide video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Marks the slides that move, because at 182px wide a short muted loop is
   easy to miss entirely. */
.slide__play {
  position: absolute;
  right: .3rem;
  bottom: .3rem;
  font-size: clamp(.55rem, .9vw, .66rem);
  letter-spacing: .04em;
  color: var(--bone);
  background: rgba(26, 21, 18, .72);
  padding: .18em .4em;
}
.carousel-set + .carousel-set { margin-top: clamp(1.4rem, 3vw, 2.4rem); }
.carousel-set__name {
  font-size: var(--fs-body);
  font-weight: 600;
  margin: 0 0 .5rem;
}
.carousel-set__name span { color: var(--white-dim); font-weight: 400; }


/* Two cutdowns rather than three: the grid takes a modifier instead of
   stretching two clips across a three-column track. */
/* 66% made each cutdown ~440x780 - taller than the episode that spawned
   them, which inverts the hierarchy. 44% puts them clearly under it. */
.stack__cuts--2 { grid-template-columns: repeat(2, 1fr); max-width: 44%; }
@media (max-width: 760px) { .stack__cuts--2 { max-width: none; } }

/* An empty deliverable slot. Dashed and plainly worded, because the one thing
   worse than a gap is a gap that looks like finished work. */
.slot--empty {
  border: 1px dashed rgba(201, 214, 192, .45);
  background: rgba(239, 233, 223, .03);
  padding: clamp(1.4rem, 3vw, 2.4rem);
  text-align: center;
}
.slot--empty p {
  margin: 0;
  color: var(--white-dim);
  font-size: var(--fs-body);
}
.stack__label { font-weight: 600; color: var(--dew); }


/* Four cutdowns, full width. Tyler wants every row in the stack to share one
   edge-to-edge measure so the film, the cutdowns and the carousels read as one
   object. Each clip lands about 331x589, which is still under the 745px film
   it came from, so the hierarchy survives the change. */
.stack__cuts--4 { grid-template-columns: repeat(4, 1fr); max-width: none; }
@media (max-width: 760px) {
  .stack__cuts--4 { grid-template-columns: repeat(2, 1fr); max-width: none; }
}


/* The day, in numbers. This is the shoot-day timeline Tyler asked for, done as
   a tally rather than a clock: the hours are one figure among the outputs,
   which is the actual argument. Six hours in, five things out. */
.tally {
  list-style: none; margin: 0 0 1rem; padding: 0;
  display: grid; grid-template-columns: repeat(5, auto);
  gap: clamp(1.2rem, 4vw, 3.2rem); justify-content: start; align-items: end;
}
.tally li { display: block; }
.tally b {
  display: block;
  font-family: var(--font-block);
  font-variation-settings: 'wdth' 118;
  font-weight: 800;
  font-size: clamp(2rem, 5vw, 3.6rem);
  line-height: .9;
  color: var(--dew);
}
.tally span {
  display: block; margin-top: .25rem;
  font-size: var(--fs-body);
  color: var(--white-dim);
}
.tally__note { margin: 0 0 2rem; color: var(--white-dim); font-size: var(--fs-body); }
@media (max-width: 760px) {
  .tally { grid-template-columns: repeat(3, auto); gap: 1.1rem 1.6rem; }
}


/* The podcast sits under the film it was cut from, half width and indented.
   The offset is doing real work: it is what tells you this is derived from the
   piece above rather than a second headline competing with it. */
.aside {
  display: grid;
  grid-template-columns: 48% 1fr;
  gap: clamp(1.2rem, 3vw, 2.4rem);
  align-items: center;
  padding-left: clamp(0rem, 6vw, 5rem);
}
.aside__film { aspect-ratio: 16 / 9; background: var(--ink); }
.aside__film iframe { width: 100%; height: 100%; border: 0; display: block; }
.aside__note p:last-child {
  margin: .4rem 0 0;
  color: var(--white-dim);
  font-size: var(--fs-body);
  line-height: 1.6;
  max-width: 44ch;
}
@media (max-width: 760px) {
  .aside { grid-template-columns: 1fr; padding-left: 0; gap: .9rem; }
}


/* -- Click-to-play posters ------------------------------------------------
   Replaces the YouTube iframes. The chrome Tyler wanted gone (channel name,
   subscriber count, title bar) cannot be removed from inside a real embed, so
   the embed does not exist until somebody clicks. */
.ytf {
  display: block; position: relative;
  width: 100%; height: 100%;
  padding: 0; border: 0; margin: 0;
  background: var(--ink);
  cursor: pointer; overflow: hidden;
}
.embed-16-9 .ytf, .embed-9-16 .ytf { position: absolute; inset: 0; }
.ytf img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .45s ease, opacity .3s ease;
}
.ytf:hover img, .ytf:focus-visible img { transform: scale(1.04); opacity: .8; }
.ytf:focus-visible { outline: 2px solid var(--dew); outline-offset: -2px; }

/* Bone, not YouTube red. The play button is the only thing on the poster, so
   it may as well belong to this site. */
.ytf__play {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: clamp(38px, 12%, 64px); aspect-ratio: 1;
  border-radius: 50%;
  background: var(--bone);
  transition: background .25s ease, transform .25s ease;
}
.ytf__play::after {
  content: ''; position: absolute;
  left: 54%; top: 50%; transform: translate(-50%, -50%);
  border-style: solid;
  border-width: .42em 0 .42em .68em;
  border-color: transparent transparent transparent var(--ink);
  font-size: clamp(14px, 4vw, 20px);
}
.ytf:hover .ytf__play { background: var(--dew); transform: translate(-50%,-50%) scale(1.08); }

/* The one clip YouTube serves no thumbnail for at any size. Rather than a
   blank black box it gets the field colour and a visible play control. */
.ytf--nothumb { background: linear-gradient(160deg, var(--rust), var(--ink)); }

@media (prefers-reduced-motion: reduce) {
  .ytf img, .ytf__play { transition: none; }
  .ytf:hover img { transform: none; }
}


/* The drifting thumbnail walls are absolutely positioned with negative insets
   and a rotation, and on a couple of pages they escaped their container by a
   few pixels and gave the whole document a horizontal scrollbar. clip rather
   than hidden: clip does not turn the element into a scroll container, so it
   cannot break position:sticky elsewhere on the page. */
html, body { overflow-x: clip; }


/* Five across for the product row. Declared here rather than in a page's own
   <style> so any page can use it. */
.shorts-grid--5 { grid-template-columns: repeat(5, 1fr); }
@media (max-width: 900px) { .shorts-grid--5 { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 560px) { .shorts-grid--5 { grid-template-columns: repeat(2, 1fr); } }


/* -- The plan behind it ---------------------------------------------------
   Numbered because both lists genuinely are ordered: six principles applied
   in sequence, and beats that happen at a timecode. Numbering anything else
   on this site would be decoration. */
.plan__sub {
  margin: clamp(1.4rem,3vw,2.2rem) 0 .8rem;
  font-weight: 600;
  color: var(--dew);
}
.principles-list, .beats-list { list-style: none; margin: 0; padding: 0; }
.principles-list { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;
                   background: var(--border-dim); border: 1px solid var(--border-dim); }
.principles-list li { background: var(--oxblood); padding: clamp(.9rem,2vw,1.3rem); }
.principles-list .pr__n {
  display: block; font-family: var(--font-block); font-variation-settings: 'wdth' 112;
  font-size: var(--fs-cap); color: var(--dew); letter-spacing: .06em;
}
.principles-list b, .beats-list b {
  display: block; margin: .3rem 0 .25rem; font-weight: 600;
  font-size: var(--fs-lead);
}
.principles-list span:last-child, .beats-list span:last-child {
  display: block; color: var(--white-dim); font-size: var(--fs-body); line-height: 1.5;
}
.beats-list { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(.8rem,2vw,1.6rem); }
.beats-list li { border-top: 2px solid var(--dew); padding-top: .7rem; }
.beats-list .beat__t {
  font-family: var(--font-block); font-variation-settings: 'wdth' 112;
  font-size: 1.25rem; color: var(--dew);
}
.plan__note { margin: clamp(1.2rem,2.5vw,1.8rem) 0 0; color: var(--white-dim); font-size: var(--fs-body); max-width: 62ch; }
@media (max-width: 900px) { .principles-list { grid-template-columns: repeat(2,1fr); }
                            .beats-list { grid-template-columns: repeat(2,1fr); } }
@media (max-width: 560px) { .principles-list { grid-template-columns: 1fr; } }


/* Card that opens the full treatment. Deliberately not an iframe preview:
   claude.ai sends X-Frame-Options SAMEORIGIN, so the original cannot be framed
   on this domain at any sharing setting. */
.tr-card { border: 1px solid var(--dew); background: rgba(201,214,192,.05);
  padding: clamp(1.2rem,3vw,2rem); }
.tr-card__t { margin: 0; font-family: var(--font-block);
  font-variation-settings: 'wdth' 118; font-weight: 700;
  font-size: clamp(1.1rem,2.2vw,1.5rem); }
.tr-card__n { margin: .5rem 0 1.1rem; color: var(--white-dim); font-size: var(--fs-body);
  line-height: 1.6; max-width: 60ch; }


/* -- Top tier and the objection ------------------------------------------
   The $10,000 tier sits below the row of three rather than inside it. Shown
   with its price so it anchors the others, framed so an ordinary buyer does
   not feel like the target. */
.topline {
  display: grid; grid-template-columns: minmax(0,.9fr) minmax(0,1.4fr);
  gap: clamp(1.4rem,4vw,3rem);
  border: 1px solid var(--dew);
  background: rgba(201,214,192,.05);
  padding: clamp(1.4rem,3.5vw,2.6rem);
  margin-top: clamp(1.6rem,4vw,2.6rem);
}
.topline__label { margin: 0 0 .6rem; color: var(--dew); font-size: var(--fs-body); }
.topline__name {
  margin: 0; font-family: var(--font-block); font-variation-settings: 'wdth' 118;
  font-weight: 800; text-transform: uppercase; line-height: .95;
  font-size: clamp(1.8rem,4.4vw,3rem);
}
.topline__price {
  margin: .5rem 0 0; font-family: var(--font-block);
  font-variation-settings: 'wdth' 112; font-size: clamp(1.6rem,3.4vw,2.4rem);
}
.topline__price span { font-family: var(--font-ui); font-size: var(--fs-body); color: var(--white-dim); }
.topline__lead { margin: 0 0 1rem; color: var(--white-dim); line-height: 1.6; max-width: 60ch; }
.topline .btn { margin-top: 1.2rem; }

.objection { max-width: 68ch; }
.objection__q {
  font-family: var(--font-voice); font-style: italic; font-weight: 400;
  font-size: clamp(1.5rem,3.4vw,2.3rem); line-height: 1.25; margin: 0 0 1rem;
}
.objection__a { margin: 0 0 .9rem; line-height: 1.7; color: var(--white-dim); }
@media (max-width: 800px) { .topline { grid-template-columns: 1fr; } }


/* A few videos sit in the old padding-bottom aspect boxes rather than
   .embed-16-9. The iframe they used to hold carried its own inline
   position:absolute, so when it became a click-to-play button the button fell
   into normal flow and stacked its height on top of the box's padding. The
   featured film on the homepage rendered 1630px tall for a 745px video, which
   is the blank space under it. */
.aspect-box > .ytf { position: absolute; inset: 0; }


/* ── The closing beat ─────────────────────────────────────────────────
   The first three beats are one word, centred. This one is the landing, so it
   splits: the question on the left two thirds, the two doors on the right
   third. The break in rhythm is the point. Three beats accuse, the fourth
   resolves and hands you somewhere to go.

   Same typeface and weight as the other three, just smaller, because it is
   now sharing the frame. Tyler: "make it smaller, whatever you gotta do to
   make it fit, I just want it to be the same bold font."
   ─────────────────────────────────────────────────────────────────── */
.pitch__beat--end {
  grid-template-columns: 2fr 1fr;
  align-items: center;
  justify-items: stretch;
  gap: clamp(1rem, 4vw, 3.5rem);
  padding: 0 clamp(1.2rem, 5vw, 4rem);
}
.beat-end__word { position: relative; z-index: 1; }
.pitch__beat--end .pitch__word {
  /* Composed with the push-in scale that --z drives, so the word still tracks
     the wheel while sitting at an angle. */
  transform: perspective(1100px) rotateY(17deg) scale(calc(1 + (var(--z, 0) * .10)));
  transform-origin: left center;
  text-align: left;
  /* width:max-content is load-bearing. In beats one to three the h2 is a
     centred grid item, so it shrinks to its text and can be measured. Here it
     sits inside a stretched wrapper, where a block-level h2 fills the column
     at whatever the column is. getBoundingClientRect then returned 837px no
     matter the font size, so js/pitch.js was fitting against a constant and
     the word stayed oversized however many correction passes ran. */
  width: max-content;
}
.beat-end__doors {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; gap: .7rem;
  /* The beat is pointer-events:none until it is the active one, so without
     this the buttons would look clickable and do nothing. */
  pointer-events: none;
}
.pitch__beat--end.is-on .beat-end__doors { pointer-events: auto; }
.beat-cta {
  display: block;
  padding: clamp(.8rem, 1.8vw, 1.1rem) clamp(1rem, 2vw, 1.4rem);
  background: var(--bone);
  color: var(--ink);
  text-decoration: none;
  font-family: var(--font-block);
  font-variation-settings: 'wdth' 112;
  font-weight: 700;
  font-size: var(--fs-lead);
  line-height: 1.15;
  transition: background .25s ease, transform .25s ease;
}
.beat-cta:hover { background: var(--dew); transform: translateX(4px); }
.beat-cta:focus-visible { outline: 3px solid var(--dew); outline-offset: 3px; }

@media (max-width: 820px) {
  .pitch__beat--end { grid-template-columns: 1fr; align-content: center; gap: 1.4rem; }
  .pitch__beat--end .pitch__word {
    transform: perspective(900px) rotateY(10deg) scale(calc(1 + (var(--z, 0) * .10)));
  }
  .beat-end__doors { flex-direction: row; }
  .beat-cta { flex: 1; text-align: center; }
}
@media (prefers-reduced-motion: reduce) {
  .beat-cta { transition: none; }
  .beat-cta:hover { transform: none; }
}


/* A small line over the two doors on the closing beat, so the buttons read as
   an answer to the question rather than two stray links. */
.beat-end__title {
  margin: 0 0 .25rem;
  font-family: var(--font-block);
  font-variation-settings: 'wdth' 118;
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(1.1rem, 2vw, 1.5rem);
  color: var(--bone);
}

/* The formula picks up a prompt above and a door below. The prompt is a line
   rather than a button: a button above and a button below the same three
   steps, both pointing at the same page, is one button too many. */
.how__prompt {
  margin: 0 0 clamp(1.2rem, 2.5vw, 1.8rem);
  color: var(--dew);
  font-size: var(--fs-lead);
  font-weight: 600;
}
.how__door { margin-top: clamp(1.6rem, 3.5vw, 2.6rem); }


/* -- Work bars ------------------------------------------------------------
   Replaced three sample tiles that were three unrelated things under one film.
   A bar is a door, not a sample, so it needs no thumbnail to earn its place. */
.workbar {
  display: grid; grid-template-columns: auto 1fr; align-items: baseline;
  gap: clamp(.8rem, 2.5vw, 2rem);
  padding: clamp(1.1rem, 2.6vw, 1.8rem) clamp(1.1rem, 2.5vw, 2rem);
  margin-top: clamp(.6rem, 1.4vw, 1rem);
  border: 1px solid var(--border-dim);
  background: rgba(239, 233, 223, .03);
  text-decoration: none; color: inherit;
  transition: background .25s ease, border-color .25s ease;
}
.workbar:hover { background: rgba(201, 214, 192, .07); border-color: var(--dew); }
.workbar__k { font-size: var(--fs-cap); color: var(--dew); white-space: nowrap; }
.workbar__t {
  font-family: var(--font-block); font-variation-settings: 'wdth' 118;
  font-weight: 800; text-transform: uppercase; line-height: 1;
  font-size: clamp(1.3rem, 3.6vw, 2.6rem);
}
@media (max-width: 640px) { .workbar { grid-template-columns: 1fr; gap: .3rem; } }

/* The prompt over the three steps is a headline now, not a caption. */
.how__prompt {
  font-family: var(--font-block); font-variation-settings: 'wdth' 118;
  font-weight: 800; text-transform: uppercase;
  font-size: clamp(1.8rem, 4.6vw, 3.2rem); line-height: .98;
  color: var(--bone); margin-bottom: clamp(1.4rem, 3vw, 2.2rem);
}
.how__door { text-align: center; }
.tally__lead { margin: 0 0 .9rem; font-weight: 600; font-size: var(--fs-lead); }


/* Superseded 2026-10-04. See TYPE, REBUILT at the end of this file. */
.t-lg {
  font-family: var(--font-block);
  font-variation-settings: 'wdth' 118;
  font-weight: 800;
  font-style: normal;
}
.t-md {
  font-family: var(--font-ui);
  font-variation-settings: 'wdth' 100;
  font-weight: 600;
  font-style: normal;
  font-size: clamp(1rem, 1.9vw, 1.25rem);
  letter-spacing: 0;
  text-transform: none;
}
.t-sm {
  font-family: var(--font-voice);
  font-weight: 600;
  font-style: italic;
  font-size: var(--fs-lead);
}

/* Existing elements pulled onto the scale. */
.rigsec__sub {
  font-family: var(--font-ui);
  font-weight: 600;
  font-style: normal;
  font-size: clamp(1rem, 1.9vw, 1.25rem);
  letter-spacing: 0;
  text-transform: none;
  color: var(--bone);
}
/* The voice face was running at display size in three places. It is a small
   face, so these come down and keep the italic. */
.hero__sub, .pullquote__text, .objection__q {
  font-family: var(--font-voice);
  font-weight: 600;
  font-style: italic;
}
.objection__q { font-size: clamp(1.15rem, 2.1vw, 1.45rem); }
.pullquote__text { font-size: clamp(1.15rem, 2.4vw, 1.6rem); }
.tally b i, .tally span i {
  font-style: normal;
  font-weight: 400;
  font-size: .82em;
  color: var(--white-dim);
}


/* ══ TYPE, REBUILT 2026-10-04 ═════════════════════════
   Tyler: the small text "looks lazy, like we gave up on coming up with a
   style design." The cause was real. Three of the five font tokens were the
   same family, so every small line was the headline face shrunk and
   unbolded, and twelve different sizes were in use below 20px.

     DISPLAY  Archivo 800, var(--font-block). Headlines, numbers, buttons.
     TEXT     Literata, var(--font-text). Anything a person reads.
     LABEL    Archivo, var(--font-ui). Tags, badges, form labels, mock UI.

   Sans for what you click, serif for what you read. Everything below display
   size comes from --fs-lead, --fs-body or --fs-cap. Three steps. A fourth
   means editing this block, not setting a font-size inside a component.
   ══════════════════════════════════════════════════ */
body { font-family: var(--font-text); font-size: var(--fs-body); }
p, li { font-size: var(--fs-body); }
.t-lead { font-family: var(--font-text); font-size: var(--fs-lead); }
.t-cap  { font-family: var(--font-ui);   font-size: var(--fs-cap); }
/* A serif wants more leading than the sans it replaced. */
p, li, .t-body, .how__d, .split__p, .svc-card__desc, .step__desc,
.system__desc, .quote-card__desc { line-height: 1.6; }
.t-md { font-family: var(--font-text); font-size: var(--fs-lead); font-weight: 500; }
.t-sm { font-family: var(--font-text); font-size: var(--fs-body);
        font-weight: 500; font-style: italic; }

/* Literata needs 400 as its floor. The old 300 was set for Archivo, where a
   light weight reads as restrained; on a serif at 17px it just looks faded. */
body { font-weight: 400; }

/* Nav was the last thing off the scale, at 12px against a 13px caption step. */
.nav-link { font-size: var(--fs-cap); }

/* The three formula lines are the payload of that section, not captions under
   it. They take the lead step, which is still inside the scale. */
.how__d { font-size: var(--fs-lead); }

/* Founding client band. Sits above the tiers because it is an offer on all
   of them, not a fourth tier. */
.founding {
  display: grid; grid-template-columns: minmax(200px, 1fr) 2fr;
  gap: clamp(1rem, 3vw, 2.5rem);
  padding: clamp(1.4rem, 3vw, 2.2rem);
  margin-bottom: clamp(1.4rem, 3vw, 2.2rem);
  border: 1px solid var(--dew);
  background: rgba(201, 214, 192, .06);
}
.founding__tag { margin: 0 0 .4rem; font-family: var(--font-ui);
  font-size: var(--fs-cap); letter-spacing: .12em; text-transform: uppercase;
  color: var(--dew); }
.founding__name { margin: 0; font-family: var(--font-block);
  font-variation-settings: 'wdth' 118; font-weight: 800; line-height: .95;
  text-transform: uppercase; font-size: clamp(1.6rem, 4vw, 2.6rem);
  color: var(--bone); }
.founding__lead { margin: 0 0 1.1rem; font-size: var(--fs-lead); }
@media (max-width: 760px) { .founding { grid-template-columns: 1fr; } }

/* Site pricing ladder. Three cards, equal weight: there is no "most popular"
   here because the right one depends entirely on how big the business is. */
.sitetiers {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: 2px; background: var(--border-dim); margin-top: 2rem;
}
.sitetier { background: var(--bg-card); padding: clamp(1.4rem, 3vw, 2rem) 1.5rem;
  display: flex; flex-direction: column; gap: .5rem; }
.sitetier__name { margin: 0; font-family: var(--font-block);
  font-variation-settings: 'wdth' 118; font-weight: 800; text-transform: uppercase;
  line-height: 1; font-size: clamp(1.15rem, 2.6vw, 1.5rem); color: var(--bone); }
.sitetier__price { margin: 0; font-family: var(--font-block); font-weight: 800;
  font-size: clamp(1.9rem, 5vw, 2.8rem); line-height: 1; color: var(--dew); }
.sitetier__price span { font-family: var(--font-text); font-weight: 400;
  font-size: var(--fs-cap); color: var(--stone); margin-left: .45rem; }
.sitetier__desc { margin: .2rem 0 0; font-size: var(--fs-body); color: var(--white-dim); }
.sitetiers__note { margin: 1.5rem 0 0; font-size: var(--fs-lead); max-width: 62ch; }
.sitetiers__note b { color: var(--bone); font-weight: 600; }

/* The two limit notes read as a pair, so they sit as a pair. Side by side on
   desktop closes the dead space that opened under them. */
.systems__limits {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(1rem, 2.5vw, 2rem); margin-top: clamp(1.4rem, 3vw, 2rem);
}
.systems__limits .systems__limit { margin: 0; }
@media (max-width: 760px) { .systems__limits { grid-template-columns: 1fr; } }

/* Bold markup had no weight behind it: nine component rules pinned b to 400,
   so every "<b>Lead phrase.</b>" rendered identical to the sentence after it.
   600 is the semibold already used by .sitetiers__note b and the beats list. */
b, strong { font-weight: 600; }

/* Drone loops. Source is 4:5, so the tiles are too and nothing gets cropped.
   Silent, no controls, nothing to click: they are texture, not a gallery. */
.droneloops {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(.6rem, 1.4vw, 1.1rem);
}
.droneloop {
  display: block; width: 100%; aspect-ratio: 4 / 5;
  object-fit: cover; background: var(--ink);
}
@media (max-width: 860px) { .droneloops { grid-template-columns: repeat(2, 1fr); } }

/* Film grain over the scroller stills. Sits above the vignette and below the
   word, so it textures the image without touching the type. One inline SVG,
   no extra request. */
.beat-media::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: .13;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 170px 170px;
}

/* Podcast: the episode runs full width, then the two cutdowns sit beside the
   hole map underneath. Column widths are the aspect ratios themselves
   (9/16 = 0.5625, 16/9 = 1.778), so all three land on one height. */
.podmain { display: block; margin-bottom: clamp(.6rem, 1.4vw, 1.1rem); }
.podrow {
  display: grid;
  grid-template-columns: 0.5625fr 0.5625fr 1.778fr;
  gap: clamp(.6rem, 1.4vw, 1.1rem);
  align-items: start;
}
.podrow > * { min-width: 0; }
@media (max-width: 820px) {
  .podrow { grid-template-columns: 1fr 1fr; }
  .podrow > :last-child { grid-column: 1 / -1; }
}

/* Motion-graphics tiles. 16:9 like the video embeds beside them, because that
   is the frame these were delivered in. The alpha masters are flattened onto
   the ink tone at export, so the tile edge is the animation's own edge. */
.animtile {
  display: block; width: 100%; aspect-ratio: 16 / 9;
  object-fit: cover; background: var(--ink);
}
.animrow {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(.5rem, 1.2vw, 1rem);
}
@media (max-width: 680px) { .animrow { grid-template-columns: 1fr; } }
