/* ============================================================
   Home — Apple TV-style layout
   Floating side panel on the left, full-bleed hero carousel,
   and horizontal shelves of project cards. The hero is always
   dark (it's a "screen"); the rest follows the theme tokens.
   ============================================================ */
.tv,
.has-panel {
  --panel-w: 280px;
  --panel-gap: 12px;
  --gutter: clamp(20px, 4vw, 64px);
  --tv-accent: var(--accent);
  /* Space the floating panel takes up; content starts after it. */
  --inset: calc(var(--panel-w) + var(--panel-gap) * 2);
  /* Charcoal panels with a hairline border and a faint top-edge
     highlight (Linear surface ladder), no glass or ambient colour. */
  --glass-bg: var(--surface);
  --glass-border: var(--rule);
  --glass-highlight: rgba(255, 255, 255, 0.05);
  --glass-fill: var(--surface-3);
  --glass-hover: var(--surface-2);
  --glass-blur: none;
  background: var(--bg);
}


/* The container guide lines don't fit a full-bleed layout. */
.tv::before,
.tv::after,
.has-panel::before,
.has-panel::after { display: none; }

/* ------------------------------------------------------------
   Side panel
   ------------------------------------------------------------ */
.tv-panel {
  position: fixed;
  top: var(--panel-gap);
  bottom: var(--panel-gap);
  left: var(--panel-gap);
  width: var(--panel-w);
  z-index: 40;
  display: flex;
  flex-direction: column;
  padding: 20px 14px 16px;
  border-radius: 16px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow:
    inset 0 1px 0 var(--glass-highlight),
    inset 0 0 0 0.5px rgba(255, 255, 255, 0.02);
  font-family: var(--font-display);
}

.tv-panel-brand {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 4px 8px 20px;
  line-height: 1.25;
}
.tv-panel-brand strong { display: block; font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
.tv-panel-brand small { display: block; font-size: 12.5px; color: var(--text-muted); }

.tv-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 20%;
  flex-shrink: 0;
}

.tv-nav { display: flex; flex-direction: column; gap: 2px; }

.tv-nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 10px;
  font-size: 16px;
  font-weight: 500;
  color: var(--text);
  transition: background-color 180ms ease;
}
.tv-nav-item:hover { background: var(--glass-hover); }
.tv-nav-item.is-active {
  background: var(--glass-fill);
  box-shadow: inset 0 0 0 1px var(--rule);
}

.tv-nav-item svg {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tv-panel-label {
  margin: 28px 12px 8px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-muted);
}

.tv-nav--library .tv-nav-item { font-size: 15px; padding-block: 8px; }

/* iOS sidebar-style icons: monochrome outline glyphs. */
.tv-ico {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  color: inherit; /* monochrome: follows the text color in both themes */
}
.tv-nav-item .tv-ico svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tv-panel-foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 10px 0;
  border-top: 1px solid var(--glass-border);
}
.tv-panel-foot .theme-toggle { margin: 0; }

/* Inner pages (about, case studies) share the panel: their
   centred content column starts after it. */
.has-panel { padding-left: var(--inset); }
.case-study.has-panel main { padding-top: var(--space-8); }

/* ------------------------------------------------------------
   Main column
   ------------------------------------------------------------ */
.tv-main {
  padding-left: var(--inset);
  min-width: 0;
}

/* ------------------------------------------------------------
   Hero carousel
   ------------------------------------------------------------ */
.tv-hero {
  position: relative;
  height: clamp(460px, 70vh, 720px);
  /* Full bleed: runs under the glass panel so its colors show through. */
  margin-left: calc(-1 * var(--inset));
  overflow: hidden;
  background: transparent; /* page background shows through */
  color: var(--text);
}

.tv-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 700ms ease, visibility 0s linear 700ms;
}
.tv-slide.is-active {
  opacity: 1;
  visibility: visible;
  transition: opacity 700ms ease;
}

/* Artwork sits on the right half; a gradient keeps text legible. */
.tv-slide-art {
  position: absolute;
  inset: 0 0 0 38%;
  width: auto;
  height: auto;
  background:
    radial-gradient(60% 70% at 55% 45%, rgba(255, 255, 255, 0.10), transparent 70%),
    #000;
}
.tv-slide-art.phone-cover--3d { padding: 6% 0 10%; }
.tv-slide-art .device-3d { height: 100%; }

.tv-slide-art--intro {
  inset: 0;
  background: transparent;
}

/* ---------- Hero: ambient background ----------
   A full-bleed canvas of slow, dark flowing light behind the intro. It
   fades in once the first frame is drawn and fades out into the page at
   the bottom, so the hero has no hard edge. */
.hero-vibe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0;
  transition: opacity 1600ms ease;
  -webkit-mask-image: linear-gradient(to bottom, #000 78%, transparent);
  mask-image: linear-gradient(to bottom, #000 78%, transparent);
}
.hero-vibe.is-ready { opacity: 1; }

.tv-slide-text {
  position: absolute;
  left: calc(var(--inset) + var(--gutter));
  bottom: 72px;
  max-width: min(520px, 55%);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
  font-family: var(--font-display);
}

/* Frosted glass over the entire hero, edge to edge (behind the sidebar
   too); the clouds move softly blurred beneath it. It fades out at the
   bottom with the canvas, so the hero still has no hard edge. */
.hero-glass {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(160deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.02) 55%),
    rgba(12, 12, 16, 0.16);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-mask-image: linear-gradient(to bottom, #000 78%, transparent);
  mask-image: linear-gradient(to bottom, #000 78%, transparent);
}

/* Over the bright sky the muted greys wash out, so lift them in the hero. */
.tv-slide-art--intro ~ .tv-slide-text .tv-hero-note {
  color: rgba(247, 248, 248, 0.72);
}

.tv-badge {
  display: inline-block;
  padding: 3px 10px;
  border: 1.5px solid rgba(255, 255, 255, 0.9);
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
}

.tv-title {
  font-size: clamp(44px, 6.4vw, 92px);
  font-weight: 600;
  line-height: 0.95;
  letter-spacing: -0.04em;
}

/* Intro: one big name line, then a short blurb (left) and CTA (right). */
.tv-intro {
  font-family: var(--font-display);
  font-size: clamp(56px, 6.4vw, 104px);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.0375em;
  word-spacing: -0.02em;
  white-space: nowrap;
  /* Optical alignment: pull the H's side bearing back to the text edge. */
  margin-left: -0.045em;
  color: var(--text);
  font-feature-settings: "kern", "liga";
  text-rendering: optimizeLegibility;
}
.tv-slide:first-child .tv-slide-text {
  /* Vertically centered in the glass pane (12px from the top, 72px
     from the bottom of the hero). */
  top: calc(50% - 30px);
  bottom: auto;
  transform: translateY(-50%);
  right: var(--gutter);
  max-width: none;
  align-items: stretch;
  gap: 44px;
}
.tv-hero-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 700ms ease 500ms, transform 700ms cubic-bezier(0.165, 0.84, 0.44, 1) 500ms;
}
.tv-intro.is-revealed + .tv-hero-row { opacity: 1; transform: none; }
.tv-hero-blurb {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-family: var(--font-sans);
  font-weight: 400;
  letter-spacing: -0.01em;
}
.tv-hero-role {
  font-size: clamp(20px, 2vw, 28px);
  line-height: 1.4;
  color: var(--text);
}
.tv-hero-note {
  font-size: clamp(17px, 1.4vw, 20px);
  line-height: 1.5;
  color: var(--text-muted);
}

.tv-intro .word-mask {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  line-height: 1.04;
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}
.tv-intro .word-inner {
  display: inline-block;
  transform: translateY(110%);
  transition: transform 900ms cubic-bezier(0.165, 0.84, 0.44, 1);
  will-change: transform;
}
.tv-intro.is-revealed .word-inner { transform: translateY(0); }

.tv-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 17px;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.9);
}
.tv-meta-logo { height: 16px; width: auto; }

.tv-desc {
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.62);
}

.tv-actions { display: flex; align-items: center; gap: 16px; margin-top: 10px; }

.tv-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 30px 14px 24px;
  border-radius: 999px;
  background: #fff;
  color: #000;
  font-size: 17px;
  font-weight: 600;
  transition: transform 200ms ease, background-color 200ms ease;
}
.tv-btn:hover { transform: scale(1.04); }
.tv-btn svg { width: 18px; height: 18px; fill: currentColor; }

.tv-btn-round {
  width: 52px;
  height: 52px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.2);
  color: #fff;
  backdrop-filter: blur(10px);
  transition: background-color 200ms ease;
}
.tv-btn-round:hover { background: rgba(255, 255, 255, 0.32); }
.tv-btn-round svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }

.tv-dots {
  position: absolute;
  left: 50%;
  bottom: 32px;
  transform: translateX(-50%);
  display: flex;
  gap: 10px;
  z-index: 2;
}
.tv-dots button {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.35);
  cursor: pointer;
  transition: background-color 200ms ease, transform 200ms ease;
}
.tv-dots button[aria-selected="true"] { background: #fff; transform: scale(1.25); }

/* ------------------------------------------------------------
   Shelves
   ------------------------------------------------------------ */
.tv-row { padding: 36px 0 12px; }

.tv-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-inline: var(--gutter);
  margin-bottom: 16px;
}

.tv-row-title {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.tv-row-arrows { display: flex; gap: 8px; }
.tv-arrow {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  transition: background-color 180ms ease;
}
.tv-arrow:hover { background: var(--rule); }
.tv-arrow svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

.tv-shelf {
  list-style: none;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: clamp(260px, 30%, 420px);
  gap: 20px;
  padding: 8px var(--gutter) 24px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gutter);
  scrollbar-width: none;
}
.tv-shelf::-webkit-scrollbar { display: none; }
.tv-shelf > li { scroll-snap-align: start; }

.tv-grid {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 40px 24px;
  padding: 8px var(--gutter) 24px;
}

.tv-card { display: block; }

.tv-card-art {
  aspect-ratio: 16 / 10;
  height: auto;
  border-radius: 18px;
  overflow: hidden;
  border: 1px solid var(--glass-border);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
  transition: transform 350ms cubic-bezier(0.165, 0.84, 0.44, 1),
              box-shadow 350ms cubic-bezier(0.165, 0.84, 0.44, 1);
}
.tv-card-art.phone-cover { padding: 24px 16px; gap: 16px; }
.tv-card-art.phone-cover--3d { padding: 8% 0 6%; }
.tv-card-art .device-3d { height: 100%; }

.tv-card:hover .tv-card-art,
.tv-card:focus-visible .tv-card-art {
  transform: scale(1.035);
  box-shadow: 0 24px 40px -20px rgba(0, 0, 0, 0.55);
}
.tv-card:hover .device-3d {
  animation-play-state: paused;
  transform: translateY(-2%);
}
.tv-card:hover .phone-left  { transform: rotate(-6deg) translateY(4px) translateX(-6px); }
.tv-card:hover .phone-right { transform: rotate(6deg) translateY(4px) translateX(6px); }
.tv-card:hover .phone-center { transform: translateY(-6px) scale(1.06); }

.tv-card-title {
  margin-top: 14px;
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 500;
  letter-spacing: -0.018em;
}
.tv-card-sub { font-size: 15px; color: var(--text-muted); }

/* Contact tiles */
.tv-shelf--contact { grid-auto-columns: clamp(240px, 28%, 340px); }

.tv-contact {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 24px;
  border-radius: 12px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: inset 0 1px 0 var(--glass-highlight);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  transition: transform 300ms ease, background-color 200ms ease;
}
.tv-contact:hover { background: var(--surface-2); border-color: var(--rule-strong); }
.tv-contact svg {
  width: 40px;
  height: 40px;
  padding: 9px;
  border-radius: 8px;
  background: var(--surface-3);
  box-shadow: inset 0 0 0 1px var(--rule);
  color: var(--text);
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.tv-contact span { min-width: 0; }
.tv-contact strong { display: block; font-family: var(--font-display); font-size: 16px; }
.tv-contact small {
  display: block;
  font-size: 13.5px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tv-copy { padding: 24px var(--gutter) 48px; }

/* ------------------------------------------------------------
   Tablet / mobile: panel becomes a bottom tab bar, like the
   Apple TV app on iPhone.
   ------------------------------------------------------------ */

/* ---------- About me: scroll-driven reveal ----------
   tv.js sets --p (0 → 1) as the section scrolls through the viewport.
   Linear-style type. The title starts as an outline and fills with ink;
   each copy line wipes in left to right, staggered by --i. */
.tv-about {
  --p: 0;
  position: relative;
  height: 200vh;
  margin-top: 48px;
}
.tv-about-sticky {
  position: sticky;
  top: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  padding: 0 var(--gutter);
  text-align: center;
}
.tv-about-title {
  position: relative;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(48px, 6.4vw, 96px);
  line-height: 1.05;
  letter-spacing: -0.0375em;
  color: transparent;
  -webkit-text-stroke: 1.5px rgba(247, 248, 248, 0.4);
  transform: translateY(calc((1 - min(var(--p) * 2.5, 1)) * 60px));
  opacity: min(var(--p) * 4, 1);
}
/* Solid ink fill layered on top of the outline, fading in with scroll. */
.tv-about-title::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  color: var(--text);
  -webkit-text-stroke: 0;
  opacity: clamp(0, (var(--p) - 0.32) * 3, 1);
}
.tv-about-copy {
  margin: 0;
  max-width: 680px;
  font-size: clamp(18px, 1.6vw, 22px);
  line-height: 1.5;
  font-weight: 400;
  letter-spacing: -0.011em;
  color: var(--text-muted);
}
.tv-about-line {
  --lp: clamp(0, (var(--p) - 0.42 - var(--i, 0) * 0.07) * 5, 1);
  display: block;
  color: var(--text);
  clip-path: inset(0 calc((1 - var(--lp)) * 100%) 0 0);
}
.tv-about-line:nth-child(1) { --i: 0; }
.tv-about-line:nth-child(2) { --i: 1; }
.tv-about-line:nth-child(3) { --i: 2; }
.tv-about-line:nth-child(4) { --i: 3; }
.tv-about-line:nth-child(5) { --i: 4; }
.tv-about-btn {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 10px 16px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--rule);
  opacity: clamp(0, (var(--p) - 0.82) * 6, 1);
  transform: translateY(calc((1 - clamp(0, (var(--p) - 0.82) * 6, 1)) * 16px));
  margin-top: 8px;
  transition: background 200ms ease;
}
.tv-about-btn:hover { background: var(--surface-2); border-color: var(--rule-strong); }


/* ---------- Projects: scroll showcase ----------
   The stage pins for one viewport per project. tv.js marks the active
   <li>; the art and copy swap with a lift-and-turn transition. */
.tv-row--show { padding-bottom: 0; }
.tv-row--show .tv-row-head {
  margin-inline: var(--gutter);
  padding: 0 0 20px;
  border-bottom: 1px solid var(--rule);
}
.tv-show {
  position: relative;
  height: calc(var(--n) * 100vh);
  /* Full bleed, like the hero. */
  margin-left: calc(-1 * var(--inset));
}
/* The pinned stage centres the phone in the viewport, which left a tall
   empty band under the heading: tuck the stage up under it. */
@media (min-width: 901px) {
  .tv-show { margin-top: -9vh; }
}
.tv-show-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}
.tv-show-bg {
  position: absolute;
  inset: 0;
  background: transparent;
}
.tv-show-list { list-style: none; margin: 0; padding: 0; }
.tv-show-list > li {
  position: absolute;
  inset: 0;
  padding: 0 calc(var(--gutter) + 40px) 0 calc(var(--inset) + var(--gutter));
  pointer-events: none;
}
.tv-show-list > li.is-active { pointer-events: auto; }
.tv-show .tv-card {
  height: 100%;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  align-items: center;
  gap: 40px;
}
.tv-show .tv-card-text {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.tv-show .tv-card-sub,
.tv-show .tv-card-title,
.tv-show .tv-card-desc,
.tv-show .tv-card-cta {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 500ms ease, transform 700ms cubic-bezier(0.165, 0.84, 0.44, 1);
}
.tv-show li.is-active .tv-card-sub   { transition-delay: 150ms; }
.tv-show li.is-active .tv-card-title { transition-delay: 220ms; }
.tv-show li.is-active .tv-card-desc  { transition-delay: 290ms; }
.tv-show li.is-active .tv-card-cta   { transition-delay: 360ms; }
.tv-show li.is-active :is(.tv-card-sub, .tv-card-title, .tv-card-desc, .tv-card-cta) {
  opacity: 1;
  transform: none;
}
/* Linear type: small tracked eyebrow, 600 display headline with
   tight negative tracking, muted body at reading size. */
.tv-show .tv-card-text { gap: 0; }
.tv-show .tv-card-sub {
  margin: 0 0 16px;
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: 0.03em;
  color: var(--text-muted);
}
.tv-show .tv-card-title {
  margin: 0 0 16px;
  font-family: var(--font-display);
  font-size: clamp(40px, 4vw, 56px);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.032em;
  color: var(--text);
}
.tv-card-desc {
  max-width: 28em;
  font-family: var(--font-sans);
  font-size: 18px;
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: -0.006em;
  color: var(--text-muted);
}
/* Text link CTA: light, large label with an up-right arrow, no fill. */
.tv-card-cta {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: 0.3em;
  margin-top: 32px;
  padding: 6px 0;
  font-size: clamp(17px, 1.35vw, 20px);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--text);
  background: none;
}
.tv-card-cta svg {
  /* Sized to the lowercase letters and nudged down to sit on the
     same optical line as the text. */
  flex: none;
  width: 0.82em;
  height: 0.82em;
  margin-top: 0.1em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 250ms cubic-bezier(0.165, 0.84, 0.44, 1);
}
.tv-card:hover .tv-card-cta svg,
.tv-card:focus-visible .tv-card-cta svg { transform: translate(3px, -3px); }

/* Art: lifts in with a slight turn, leaves the same way. */
.tv-show .tv-card-art {
  aspect-ratio: auto;
  height: min(78vh, 720px);
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background: none;
  opacity: 0;
  transform: translateY(80px) rotate(-8deg) scale(0.9);
  transition: opacity 600ms ease, transform 900ms cubic-bezier(0.165, 0.84, 0.44, 1);
}
.tv-show .tv-card-art { order: 2; width: 100%; padding: 0; }
.tv-show .tv-card-art.phone-cover--3d { height: min(68vh, 620px); padding: 2% 0; background: none; overflow: visible; }
/* Front-facing iPhones in the showcase (frame: .iphone in base.css).
   A faint mirrored reflection sits under the video phones. */
.tv-show .device-3d,
.tv-show .tv-card:hover .device-3d {
  transform: none;
  animation: none;
  -webkit-box-reflect: below 6px linear-gradient(to bottom, transparent 86%, rgba(255, 255, 255, 0.1) 100%);
}
/* Three-phone covers: the centre phone is large and the sides overlap
   it, sized by column width. */
.tv-show .tv-card-art.phone-cover:not(.phone-cover--3d) { overflow: visible; gap: 0; }
.tv-show .phone-cover:not(.phone-cover--3d) .iphone {
  flex: 0 0 auto;
  width: 36%;
  height: auto;
}
/* Fan on scroll: tv.js sets --f (0 → 1) per project. At 0 the side
   phones hide stacked behind the centre one; at 1 they swing out. */
.tv-show .phone-cover:not(.phone-cover--3d) .iphone {
  transition: transform 250ms cubic-bezier(0.165, 0.84, 0.44, 1);
}
.tv-show .phone-cover .phone-left,
.tv-show .tv-card:hover .phone-cover .phone-left {
  z-index: 1;
  margin-right: -6%;
  transform-origin: 50% 100%;
  transform:
    translateX(calc((1 - var(--f, 1)) * 70%))
    rotate(calc(var(--f, 1) * -5deg))
    translateY(calc(var(--f, 1) * 3%))
    scale(0.88);
}
.tv-show .phone-cover .phone-center,
.tv-show .tv-card:hover .phone-cover .phone-center {
  z-index: 3;
  transform: none;
}
.tv-show .phone-cover .phone-right,
.tv-show .tv-card:hover .phone-cover .phone-right {
  z-index: 1;
  margin-left: -6%;
  transform-origin: 50% 100%;
  transform:
    translateX(calc((1 - var(--f, 1)) * -70%))
    rotate(calc(var(--f, 1) * 5deg))
    translateY(calc(var(--f, 1) * 3%))
    scale(0.88);
}
.tv-show li.was-active .tv-card-art { transform: translateY(-80px) rotate(8deg) scale(0.9); }
.tv-show li.is-active .tv-card-art { opacity: 1; transform: none; }
.tv-show .tv-card:hover .tv-card-art { transform: none; }

/* Progress on the right edge: one continuous rail split into equal
   segments, one per project. Passed segments are full, the current one
   fills as you scroll (--fill from tv.js), the rest stay faint. Hovering
   a segment shows the project name. */
.tv-show-dots {
  position: absolute;
  z-index: 5;
  right: calc(var(--gutter) - 14px);
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 0;
  list-style: none;
  margin: 0;
  padding: 0;
}
.tv-show-dots button {
  --fill: 0;
  position: relative;
  display: block;
  width: 22px;
  height: 40px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.tv-show-dots button::before,
.tv-show-dots button::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 3px;
  bottom: 3px;
  width: 2px;
  margin-left: -1px;
  border-radius: 999px;
}
.tv-show-dots button::before {
  background: rgba(247, 248, 248, 0.14);
  transition: background 200ms ease;
}
.tv-show-dots button::after {
  background: var(--text);
  transform-origin: top;
  transform: scaleY(var(--fill));
}
.tv-show-dots button:hover::before { background: rgba(247, 248, 248, 0.32); }
.tv-show-dots li { position: relative; }
/* Project name, shown beside the rail on hover. */
.tv-show-dots li::after {
  content: attr(data-label);
  position: absolute;
  right: 100%;
  top: 50%;
  margin-right: 6px;
  padding: 4px 10px;
  border-radius: 8px;
  background: var(--surface-2, #141516);
  border: 1px solid var(--rule);
  color: var(--text);
  font-size: 13px;
  white-space: nowrap;
  opacity: 0;
  transform: translate(4px, -50%);
  transition: opacity 160ms ease, transform 160ms ease;
  pointer-events: none;
}
@media (hover: hover) {
  .tv-show-dots li:hover::after { opacity: 1; transform: translate(0, -50%); }
}
.tv-show-dots button:focus-visible { outline: none; }
.tv-show-dots button:focus-visible::before { box-shadow: 0 0 0 2px var(--accent); }



@media (max-width: 900px) {
  .tv,
  .has-panel { --inset: 0px; }
  .tv-main,
  .has-panel { padding-bottom: 96px; }

  .tv-panel {
    top: auto;
    left: 50%;
    right: auto;
    bottom: 14px;
    transform: translateX(-50%);
    width: auto;
    padding: 6px;
    border-radius: 999px;
    flex-direction: row;
    /* Tab bar sits over busy content, so the glass is a touch denser. */
    background: var(--surface);
    box-shadow:
      inset 0 1px 0 var(--glass-highlight),
      0 12px 32px -12px rgba(0, 0, 0, 0.8);
  }
  .tv-panel-brand,
  .tv-panel-label,
  .tv-nav--library,
  .tv-panel-foot { display: none; }

  .tv-nav { flex-direction: row; gap: 4px; }
  .tv-nav .tv-ico { color: inherit; }
  .tv-nav-item.is-active { color: var(--text); }
  .tv-nav-item {
    flex-direction: column;
    gap: 2px;
    padding: 8px 18px;
    border-radius: 999px;
    font-size: 11.5px;
    white-space: nowrap;
  }

  .tv-hero { height: auto; min-height: 520px; }
  .tv-slide-art { inset: 0 0 46% 0; }
  .tv-slide-art.phone-cover--3d { padding: 8% 0 2%; }
  .tv-slide-art--intro { inset: 0; }
  .tv-slide-text {
    left: 20px;
    right: 20px;
    bottom: 64px;
    max-width: none;
    gap: 10px;
  }
  .tv-title { font-size: 48px; }
  .tv-intro { font-size: clamp(44px, 14vw, 64px); }
  .tv-slide:first-child .tv-slide-text { gap: 18px; top: calc(50% - 16px); left: 28px; right: 28px; }
  .tv-hero-row { flex-direction: column; align-items: flex-start; gap: 16px; }
  .tv-hero-role { font-size: 20px; }
  .tv-hero-note { font-size: 17px; }
  .tv-meta, .tv-desc { font-size: 15px; }
  .tv-btn { padding: 12px 24px 12px 20px; font-size: 16px; }
  .tv-btn-round { width: 46px; height: 46px; }

  .tv-row-arrows { display: none; }
  .tv-grid { grid-template-columns: 1fr; gap: 28px; }
  .tv-show-list > li { padding: 0 20px 96px; }
  .tv-show .tv-card {
    grid-template-columns: 1fr;
    grid-template-rows: auto minmax(0, 1fr);
    align-content: center;
    gap: 8px;
    padding-top: 72px;
  }
  .tv-show .tv-card-text { gap: 10px; }
  .tv-show .tv-card-title { font-size: 36px; letter-spacing: -0.028em; margin-bottom: 10px; }
  .tv-show .tv-card-sub { font-size: 13px; margin-bottom: 10px; }
  .tv-card-cta { margin-top: 20px; font-size: 17px; }
  .tv-show .tv-card-art { height: 48vh; order: 0; }
  .tv-show .tv-card-art.phone-cover--3d { height: 44vh; padding: 0; }
  .tv-show-dots { right: 2px; }
  .tv-card-desc { font-size: 16px; }
  .tv-shelf--contact {
    grid-auto-flow: row;
    grid-auto-columns: auto;
    gap: 10px;
    overflow: visible;
  }
}

@media (prefers-reduced-motion: reduce) {
  .tv-slide, .tv-card-art, .tv-btn, .tv-contact { transition: none; }
  .tv .device-3d { animation: none; }
  .tv-intro .word-inner { transform: none; transition: none; }
  .tv-hero-row { opacity: 1; transform: none; transition: none; }
  .tv-about { --p: 1 !important; height: auto; }
  .tv-about-sticky { position: static; }
}

/* Tori card: three answer cards stacked like a cover flow, the middle
   one in front. Glass edge, no device frame. */
.tv-show .tv-card-art.card-stack {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
  perspective: 1400px;
}
.card-stack-item {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(46%, 42vh, 300px);
  aspect-ratio: 1;
  padding: 0;
  border-radius: 6.2%;
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.14),
    0 40px 80px -30px rgba(0, 0, 0, 0.9);
  transition: transform 700ms cubic-bezier(0.165, 0.84, 0.44, 1);
}
.card-stack-item img,
.card-stack-item svg {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: inherit;
}
/* The answer cards are drawn in SVG so they stay sharp at any size. */
.card-stack-item svg { font-family: var(--font-sans); }
.card-stack-item .cs-t { font-size: 38px; font-weight: 700; letter-spacing: -0.01em; fill: #fff; }
.card-stack-item .cs-n { font-size: 27px; font-weight: 400; font-variant-numeric: tabular-nums; }
.card-stack-item .cs-m { font-weight: 500; }
.card-stack-item .cs-big { font-size: 100px; font-weight: 700; letter-spacing: -0.03em; fill: #fff; }
.card-stack-item--center {
  z-index: 3;
  transform: translate(-50%, -50%);
}
.card-stack-item--left,
.card-stack-item--right { z-index: 2; }
.card-stack-item--left  { transform: translate(-50%, -50%) translateX(-54%) rotateY(22deg) scale(0.86); }
.card-stack-item--right { transform: translate(-50%, -50%) translateX(54%) rotateY(-22deg) scale(0.86); }
/* Side cards sit back in the dark. */
.card-stack-item--left::after,
.card-stack-item--right::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgba(0, 0, 0, 0.14);
  pointer-events: none;
}
.tv-card:hover .card-stack-item--left  { transform: translate(-50%, -50%) translateX(-60%) rotateY(18deg) scale(0.86); }
.tv-card:hover .card-stack-item--right { transform: translate(-50%, -50%) translateX(60%) rotateY(-18deg) scale(0.86); }
@media (max-width: 900px) {
  .card-stack-item { width: min(46%, 30vh); }
}
@media (prefers-reduced-motion: reduce) {
  .card-stack-item { transition: none; }
}
/* A soft glow from the front card's chart colour. */
.tv-show .tv-card-art.card-stack::before {
  content: "";
  position: absolute;
  inset: 12% 8%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(74, 222, 128, 0.16), transparent);
  filter: blur(24px);
  pointer-events: none;
}

/* Memoth card: a product shot on its own dark ground, faded into the page. */
.tv-show .tv-card-art.shot-cover {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
}
.shot-cover img {
  width: auto;
  height: auto;
  max-width: 82%;
  max-height: 82%;
  filter: drop-shadow(0 30px 40px rgba(0, 0, 0, 0.6));
}
