/* ===========================================================================
   SCENES

   What goes on the screen. The apparatus is in set.css, the motion grammar
   and the palettes are in channel.css, and this is the content.
   ========================================================================= */

/* ---------------------------------------------------------------------------
   Shared primitives
   ------------------------------------------------------------------------ */
.scene {
  position: relative;
  /* The bottom inset reserves the corner the lower third lives in. It is
     furniture that appears on every tune, so no channel may put readable
     content there, and fixing it per channel just means finding it again on
     the next one. */
  padding: clamp(40px, 6vh, 88px) var(--safe) calc(var(--safe) + 70px);
  min-height: 100%;
  display: flex; flex-direction: column; justify-content: safe center;
}
.scene + .scene { border-top: 1px solid color-mix(in srgb, var(--ink) 9%, transparent); }

/* On a phone the channel bug sits where a kicker wants to be, so content
   starts below it. */
@media (max-width: 900px) {
  .scene { padding-top: calc(var(--safe) + 52px); }
}

/* A beat is a group whose elements arrive one at a time. */
.beat { display: flex; flex-direction: column; gap: clamp(16px, 2.1vh, 26px); }
.beat.wide { max-width: none; }

.cols {
  display: grid; gap: clamp(28px, 4vw, 66px);
  /* The picture gets the larger half. A frame showing a running channel is
     the argument; the paragraph beside it is only the caption. */
  grid-template-columns: minmax(0, 0.94fr) minmax(0, 1.3fr);
  align-items: safe center;
}
@media (max-width: 1100px) { .cols { grid-template-columns: 1fr; } }

/* --- Calls to action ---------------------------------------------------- */
.ctas { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }

.cta {
  display: inline-flex; align-items: center; gap: 12px;
  height: 60px; padding: 0 32px; border-radius: 999px;
  /* Buttons are set in the text face, upright. The serif italic is for large
     display type; at button size it reads as decoration rather than as
     something you press. */
  font-family: var(--text); font-style: normal;
  font-size: clamp(16px, 1.2vw, 20px); font-weight: 600;
  letter-spacing: 0.012em; text-decoration: none; cursor: pointer; border: 0;
  transition: transform 160ms var(--ease), box-shadow 200ms, background 200ms, color 200ms;
}
.cta:active { transform: translateY(1px); }

/* Both buttons are solid, the same shape and the same weight, and they differ
   only in which of the channel's two strong colors they are cut from. A
   hairline outline for the second one read as something you were not really
   meant to press.

   The pairing is the channel's own, never one fixed navy: a dark accent is
   right on a paper ground and invisible on a dark one. */
.cta.primary {
  background: var(--accent); color: var(--on-accent, #0B0A1C);
  box-shadow: 0 8px 28px -8px color-mix(in srgb, var(--accent) 80%, transparent);
}
.cta.primary:hover { box-shadow: 0 14px 40px -8px color-mix(in srgb, var(--accent) 100%, transparent); }

.cta.ghost {
  background: var(--ink); color: var(--ground-a, #0B0A1C);
  box-shadow: 0 8px 28px -10px color-mix(in srgb, var(--ink) 70%, transparent);
}
.cta.ghost:hover { box-shadow: 0 14px 40px -10px color-mix(in srgb, var(--ink) 90%, transparent); }

.cta .dot { width: 11px; height: 11px; border-radius: 50%; background: currentColor; }

/* The glint.

   One diagonal pass of light across the button, a long pause, then another.
   It is the only thing on a finished fold that moves, so the eye finds the
   one thing worth pressing without anything having to shout. The idle is
   nine tenths of the cycle on purpose: a button that flashes constantly is a
   banner advertisement, and people have been trained to look away. */
.cta { position: relative; overflow: hidden; isolation: isolate; }
.cta.primary::after,
.cta.ghost::after {
  content: ''; position: absolute; z-index: -1;
  top: -60%; bottom: -60%; width: 38%;
  background: linear-gradient(100deg,
    transparent 0%, rgba(255,255,255,0.58) 50%, transparent 100%);
  transform: translateX(-260%) rotate(9deg);
  animation: cta-glint 7.5s cubic-bezier(0.5, 0, 0.5, 1) 900ms infinite;
  pointer-events: none;
}
/* On a light button the sheen has to be dark to be a sheen at all. */
.cta.ghost::after {
  background: linear-gradient(100deg,
    transparent 0%, color-mix(in srgb, var(--ground-a, #000) 62%, transparent) 50%, transparent 100%);
}
@keyframes cta-glint {
  0%, 84%  { transform: translateX(-260%) rotate(9deg); }
  100%     { transform: translateX(420%) rotate(9deg); }
}
@media (prefers-reduced-motion: reduce) {
  .cta.primary::after, .cta.ghost::after { animation: none; opacity: 0; }
}
[data-reduced='1'] .cta.primary::after,
[data-reduced='1'] .cta.ghost::after { animation: none; opacity: 0; }

/* ---------------------------------------------------------------------------
   MORE BELOW

   Every fold says what is under it and points at it. Without this the
   composition reads as a finished page and most people never scroll.
   ------------------------------------------------------------------------ */
.more {
  position: absolute; z-index: 6;
  left: 50%; bottom: clamp(18px, 3.2vh, 34px); transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 14px;
  height: 54px; padding: 0 12px 0 26px; border-radius: 999px;
  text-decoration: none; cursor: pointer;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  backdrop-filter: blur(12px);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 18%, transparent);
  transition: box-shadow 220ms var(--ease), background 220ms, transform 220ms var(--ease);
}
.more:hover {
  background: color-mix(in srgb, var(--ink) 12%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 70%, transparent);
}
.more-label {
  font-family: var(--text); font-size: clamp(15px, 1.05vw, 18px);
  font-weight: 600; letter-spacing: 0.02em; color: var(--ink); white-space: nowrap;
}
.more-arrow {
  width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--accent); color: var(--on-accent, #0B0A1C);
}
.more-arrow svg {
  width: 19px; height: 19px; fill: none; stroke: currentColor;
  stroke-width: 2.1; stroke-linecap: round; stroke-linejoin: round;
  animation: more-bob 2.1s var(--ease) infinite;
}
@keyframes more-bob {
  0%, 100% { transform: translateY(-2px); }
  50%      { transform: translateY(3px); }
}

/* On CH 01 it waits for the set to finish assembling, so it does not compete
   with the one moment the whole channel is built around. */
.more-tuned { opacity: calc(var(--m-reveal, 1) * 1.4 - 0.4); }

/* A hairline under a paragraph, cut from the same line the fact rows use, so
   the prose above them belongs to the same list rather than floating over it. */
.hair {
  height: 1px; width: 100%; max-width: 46ch;
  background: color-mix(in srgb, var(--ink) 13%, transparent);
  margin-top: 2px;
}

/* --- Fact rows ---------------------------------------------------------- */
.facts { display: flex; flex-direction: column; gap: 14px; max-width: 46ch; }
.facts .datarow {
  padding-bottom: 14px;
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 13%, transparent);
}

/* ---------------------------------------------------------------------------
   A REAL CHANNEL IN A BOX

   Not a reimplementation of the player. The actual built channel, in an
   iframe: the same index.html that ships to a client's television, with its
   own fonts, photographs, palette and invented transitions. It is composed at
   1920x1080 and drawn into a centered 16:9 box, so it survives being shrunk
   to the size of a postcard without a second layout.

   The iframe is created only when the frame scrolls into view, because these
   carry real photography and there are several of them on a page.
   ------------------------------------------------------------------------ */
.mini {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
  border-radius: 12px;
  overflow: hidden;
  background: #05070C;
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.12),
    0 30px 60px -22px rgba(0,0,0,0.9),
    0 0 60px -20px color-mix(in srgb, var(--accent) 40%, transparent);
}

.mini iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0; display: block;
  /* The page scrolls over the top of a channel rather than the channel
     swallowing the wheel, and a click selects the frame instead of landing
     inside somebody else's document. */
  pointer-events: none;
}

/* Until the channel has painted, the frame is a dark screen rather than a
   white flash. */
.mini::before {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: #05070C;
  opacity: 1; transition: opacity 600ms var(--ease);
}
.mini.is-live::before { opacity: 0; }

/* Without script the iframes are never built, so an empty black rectangle
   would be all there was to show. The copy carries the page instead. */
html:not([data-js]) .mini,
html:not([data-js]) .mini-tag,
html:not([data-js]) .wall { display: none; }

/* Who the channel belongs to, above the frame rather than on it. Every
   channel already brands all four corners of its own picture, so a caption
   laid over the bottom covers the client's own chassis. */
.mini-tag {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 12px; flex-wrap: wrap;
  font-family: var(--ui); font-size: clamp(13px, 0.95vw, 16px); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--meta);
}
.mini-tag .live {
  width: 9px; height: 9px; border-radius: 50%; background: #FF4D4D;
  animation: live 2s ease-in-out infinite;
}
@keyframes live { 0%,100% { opacity: 1; } 50% { opacity: 0.25; } }

/* The client's name carries the weight; "live" is the qualifier. */
.mini-tag .who { color: var(--ink); }
.mini-tag .sep { color: var(--meta); opacity: 0.5; }

.wall .mini-tag { margin-bottom: 9px; font-size: clamp(11px, 0.78vw, 13px); }

/* ---------------------------------------------------------------------------
   THE WALL

   Four sets, all running, all out of step. It fills the half of the frame
   that was empty with the one thing worth putting there: the product, moving.
   The offsets are what stop it reading as a grid of thumbnails.
   ------------------------------------------------------------------------ */
.wall {
  display: grid; gap: clamp(14px, 1.8vw, 26px);
  grid-template-columns: 1fr 1fr;
  align-content: center;
}

/* Three sets, all the same size: one centered above, two under it. A 2x2 grid
   with one empty cell reads as a mistake, and a smaller set on top reads as a
   thumbnail of the other two rather than a third channel.

   The width is one column, stated outright. `margin-inline: auto` cannot do
   this: auto margins on a grid item cancel the stretch that would otherwise
   size it, so the set collapsed to the width of its own caption and showed as
   a postage stamp above two full-size neighbours. */
.wall {
  --wall-gap: clamp(14px, 1.8vw, 26px);
  gap: var(--wall-gap);
}
.wall .set-on-a-shelf:first-child {
  grid-column: 1 / -1;
  justify-self: center;
  width: calc((100% - var(--wall-gap)) / 2);
}
.wall .mini { border-radius: 10px; }

/* The offsets live on a wrapper. An entry effect ends on transform:none, so
   putting them on the frame itself means the animation wipes them out the
   moment the set arrives. */
/* The pair underneath sit level and at the same size. They were staggered to
   keep the wall from reading as a grid of thumbnails, but two sets side by
   side at different heights just looks like a mistake. The wide set above
   them is what stops it being a grid. */
.wall .set-on-a-shelf:nth-child(n + 2) { align-self: start; }

/* The type inside a small frame is scaled by the frame, so a set at 94% is
   still legible rather than just smaller. Nothing else needs saying. */
@media (max-width: 1100px) {
  .wall { grid-template-columns: 1fr 1fr; }
  .wall .set-on-a-shelf { transform: none !important; }
  .wall .set-on-a-shelf:nth-child(n + 2) { display: none; }
}

/* ===========================================================================
   CH 01: THE MELT

   You arrive on what looks like an ordinary corporate website. As you scroll
   it stops behaving, collapses to a line the way a picture tube does, and
   comes back as a television. The URL never changes, which is the joke and
   also the entire product in one gesture.

   Every value below is driven from a single scroll position by melt.js, which
   writes seven custom properties onto .melt. Nothing here animates on its own
   and nothing reads layout, so scrubbing backwards costs the same as
   scrubbing forwards.
   ========================================================================= */
.melt {
  position: relative;
  height: 260cqh;            /* the scroll distance the scrub is spread over */
  margin: 0;
  --m-plain: 1;
  --m-tuned: 0;
  --m-sy: 1;
  --m-sx: 1;
  --m-bright: 1;
  --m-grade: 0;
  --m-reveal: 0;
  --m-pad: 0px;
}

/* The stage is exactly one screenful and sticks while the section scrolls
   past it. Its height has to come from the screen, not from .melt, so it is
   measured in the page's own container units. A percentage here would
   resolve against .melt's 260 and the stage would never stick. */
.page { container-type: size; }
.melt-stage {
  position: sticky; top: 0;
  height: 100cqh;
  overflow: hidden;
}

.melt-squeeze {
  position: absolute; inset: var(--m-pad);
  border-radius: calc(var(--m-pad) * 0.34);
  overflow: hidden;
  transform: scale(var(--m-sx), var(--m-sy));
  transform-origin: 50% 50%;
  filter: brightness(var(--m-bright));
  will-change: transform, filter;
}

/* --- The ordinary website ----------------------------------------------- */
.plain {
  position: absolute; inset: 0;
  background: #FFFFFF;
  opacity: var(--m-plain);
  display: flex; flex-direction: column;
  font-family: 'Outfit', sans-serif;
  color: #1B1F2A;
  /* As the scroll goes on, the page quietly stops being well. */
  filter:
    saturate(calc(1 - var(--m-grade) * 0.55))
    contrast(calc(1 + var(--m-grade) * 0.25))
    hue-rotate(calc(var(--m-grade) * -8deg));
}

.plain-top {
  display: flex; align-items: center; justify-content: space-between;
  padding: 20px clamp(26px, 4vw, 60px);
  border-bottom: 1px solid #E6E8EE;
  flex-shrink: 0;
}
.plain-logo { font-size: 19px; font-weight: 800; letter-spacing: -0.01em; color: #00058B; }
.plain-nav { display: flex; gap: 26px; }
.plain-nav span {
  font-size: 13px; font-weight: 500; color: #5B6274;
  /* The letters start drifting apart before anything else goes wrong. */
  letter-spacing: calc(var(--m-grade) * 0.16em);
}
@media (max-width: 760px) { .plain-nav { display: none; } }

.plain-body {
  flex: 1;
  display: grid; align-items: center; gap: clamp(28px, 5vw, 70px);
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  padding: 0 clamp(26px, 4vw, 60px);
}
@media (max-width: 900px) { .plain-body { grid-template-columns: 1fr; } }

.plain-kicker {
  margin: 0 0 14px; font-size: 14px; font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase; color: #8A91A3;
}
.plain-h1 {
  margin: 0 0 18px; font-size: clamp(32px, 4vw, 58px); font-weight: 700;
  line-height: 1.08; letter-spacing: -0.022em; color: #10131C;
}
.plain-p {
  margin: 0 0 26px; font-size: clamp(14px, 1.05vw, 17px); line-height: 1.6;
  color: #565E71; max-width: 46ch;
}
.plain-btns { display: flex; gap: 12px; flex-wrap: wrap; }
.plain-btn {
  display: inline-flex; align-items: center; height: 44px; padding: 0 22px;
  border-radius: 6px; font-size: 13.5px; font-weight: 600;
  background: #00058B; color: #fff;
}
.plain-btn.ghost { background: transparent; color: #00058B; box-shadow: inset 0 0 0 1px #C8CBDD; }

/* The obligatory stock photograph, standing in for every one of them. */
.plain-shot {
  aspect-ratio: 4 / 3; max-height: 56vh; margin-left: auto; width: 100%;
  max-width: 560px; border-radius: 8px;
  background:
    linear-gradient(135deg, #DDE2EC 0%, #C6CEDE 46%, #E4E8F0 100%);
  box-shadow: 0 20px 40px -26px rgba(16,19,28,0.5);
  display: grid; place-items: center;
}
/* Declared after .plain-shot, because that rule sets display:grid to center
   its label and would otherwise win over a hide placed higher up. */
@media (max-width: 900px) { .plain-shot { display: none; } }

.plain-shot span {
  font-size: 14px; font-weight: 700; letter-spacing: 0.18em;
  text-transform: uppercase; color: rgba(27,31,42,0.32);
}

/* The scanline that says the picture is not well. Only visible once the
   grade starts, and it drifts rather than crawling, which reads as signal
   rather than as decoration. */
.plain::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  opacity: calc(var(--m-grade) * 0.5);
  background: repeating-linear-gradient(
    180deg, rgba(0,0,0,0.10) 0 1px, transparent 1px 4px);
  mix-blend-mode: multiply;
}

/* --- The television it becomes ------------------------------------------ */
.tuned {
  position: absolute; inset: 0;
  opacity: var(--m-tuned);
  display: flex; flex-direction: column; justify-content: center;
  /* Same reserved corner as .scene: the lower third lands there. */
  padding: var(--safe) var(--safe) calc(var(--safe) + 70px);
  background:
    radial-gradient(90% 68% at 76% 8%, rgba(0,5,139,0.62) 0%, transparent 62%),
    radial-gradient(70% 55% at 10% 96%, rgba(177,229,81,0.13) 0%, transparent 60%),
    linear-gradient(168deg, #0A0E28 0%, #04050F 100%);
}
.tuned .beat { max-width: none; gap: clamp(14px, 2vh, 22px); }

/* The payoff is a statement screen, and a statement screen is type on a
   field. It only reads that way if the type owns the frame, so this hero is
   bigger than the house one rather than the house one being shouty
   everywhere else. */
.tuned .hero {
  font-size: clamp(52px, 7.6vw, 146px); line-height: 0.94;
  max-width: 15ch; text-wrap: balance;
}
.tuned .lede { font-size: clamp(17px, 1.34vw, 25px); max-width: 46ch; }

/* The tuned layer's elements arrive on the scrub rather than on a timer, so
   scrubbing back takes them away again. --s is each element's place in the
   queue, so they still arrive one at a time. */
.tuned .el { opacity: 1; animation: none; }
.tuned .t-step {
  --p: clamp(0, calc((var(--m-reveal) - var(--s)) * 5), 1);
  opacity: var(--p);
  transform: translateY(calc((1 - var(--p)) * 18px));
}

/* The cue to keep going, which fades out the moment it is obeyed. */
.melt-cue {
  position: absolute; z-index: 6; left: 50%; bottom: 26px;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  font-family: var(--ui); font-size: 14px; font-weight: 700;
  letter-spacing: 0.22em; text-transform: uppercase;
  color: rgba(27,31,42,0.4);
  opacity: calc(1 - var(--m-grade) * 3);
  pointer-events: none;
}
.melt-cue .bar {
  width: 1px; height: 26px;
  background: linear-gradient(180deg, currentColor, transparent);
  animation: cue 1.9s ease-in-out infinite;
}
@keyframes cue {
  0%, 100% { transform: scaleY(0.4); opacity: 0.35; transform-origin: top; }
  50%      { transform: scaleY(1);   opacity: 1;    transform-origin: top; }
}

/* ---------------------------------------------------------------------------
   Reduced motion: no squeeze, no grade. The tuned layer is simply what is
   there, and the section shrinks to one screen so nothing has to be scrolled
   through to reach the rest of the channel.
   ------------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .melt { height: 100%; }
  .melt-squeeze { transform: none !important; filter: none !important; }
  .plain, .melt-cue { display: none; }
  .tuned { opacity: 1 !important; }
  .tuned .t-step { opacity: 1 !important; transform: none !important; }
  .mini-tag .live { animation: none; }
}
/* Forced with ?reduced=1, and taken automatically when script never booted:
   the melt is a scrubbed animation and there is nothing to scrub it. */
[data-reduced='1'] .melt, .melt.tv-first,
html:not([data-js]) .melt { height: 100%; }

[data-reduced='1'] .plain, [data-reduced='1'] .melt-cue,
.melt.tv-first .plain, .melt.tv-first .melt-cue,
html:not([data-js]) .plain, html:not([data-js]) .melt-cue { display: none; }

[data-reduced='1'] .tuned, .melt.tv-first .tuned,
html:not([data-js]) .tuned { opacity: 1 !important; }

[data-reduced='1'] .tuned .t-step, .melt.tv-first .tuned .t-step,
html:not([data-js]) .tuned .t-step { opacity: 1 !important; transform: none !important; }

/* The squeeze is driven from script too, so without it the picture is simply
   open rather than collapsed to a line nobody will ever reopen. */
html:not([data-js]) .melt-squeeze,
.melt.tv-first .melt-squeeze { transform: none !important; filter: none !important; }

/* ===========================================================================
   CH 09: CONTACT

   One form, three intents. Nothing here is small, and every control is big
   enough to hit with a thumb without thinking about it.
   ========================================================================= */
.cols-form { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); }

.panel {
  padding: clamp(24px, 2.6vw, 40px);
  border-radius: 18px;
  background: color-mix(in srgb, var(--ink) 5%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 14%, transparent);
  backdrop-filter: blur(10px);
}

.ask { display: flex; flex-direction: column; gap: 20px; }


/* The form's own heading. .ask-lead is meta-coloured and sized for a question
   above a row of buttons; the form now leads with what it gives you, and that
   has to carry like a heading rather than like a caption. */
.ask-h {
  margin: 0;
  font-family: var(--display); font-style: italic;
  font-size: clamp(22px, 1.9vw, 32px); line-height: 1.15;
  letter-spacing: -0.01em; color: var(--ink);
}
.ask-sub { margin: 0; font-size: clamp(14px, 0.98vw, 17px); line-height: 1.5; color: var(--meta); }
.ask-lead {
  margin: 0;
  font-size: clamp(15px, 1.05vw, 18px); font-weight: 600;
  color: var(--meta); letter-spacing: 0.01em;
}

/* --- Which of these is you ---------------------------------------------- */
.intents { display: flex; flex-wrap: wrap; gap: 9px; }

.intents button {
  flex: 1 1 auto;
  height: 50px; padding: 0 18px; border: 0; border-radius: 11px;
  cursor: pointer; font-family: var(--text);
  font-size: clamp(14px, 0.98vw, 16px); font-weight: 600;
  color: var(--meta); white-space: nowrap;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent);
  transition: background 180ms var(--ease), color 180ms, box-shadow 180ms;
}
.intents button:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 12%, transparent); }

/* The class is the state before script runs, so the right button is lit with
   JavaScript off. Once form.js is running it marks every button with
   aria-pressed, and the false rule below un-lights the stale class. Equal
   specificity, so it wins on source order. */
.intents button.is-on,
.intents button[aria-pressed='true'] {
  color: var(--on-accent, #0B0A1C); background: var(--accent);
  box-shadow: 0 6px 20px -8px color-mix(in srgb, var(--accent) 80%, transparent);
}
.intents button[aria-pressed='false'] {
  color: var(--meta); background: color-mix(in srgb, var(--ink) 7%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent);
}
.intents button[aria-pressed='false']:hover {
  color: var(--ink); background: color-mix(in srgb, var(--ink) 12%, transparent);
}

/* --- Fields -------------------------------------------------------------- */
/* An author rule that sets display beats the browser's own [hidden] rule, so
   any block that is hidden by script has to say so again here. */
[hidden] { display: none !important; }

.rows { display: grid; gap: 16px; grid-template-columns: 1fr 1fr; }
.rows:has(> label:only-child) { grid-template-columns: 1fr; }
@media (max-width: 640px) { .rows { grid-template-columns: 1fr; } }

.ask label { display: flex; flex-direction: column; gap: 8px; }
.ask label.wide { grid-column: 1 / -1; }

.ask label > span {
  font-size: clamp(13px, 0.92vw, 15px); font-weight: 600;
  letter-spacing: 0.06em; color: var(--meta);
}
.ask label em {
  font-style: normal; font-weight: 500;
  color: color-mix(in srgb, var(--ink) 42%, transparent);
}

.ask input,
.ask textarea {
  width: 100%; padding: 14px 16px;
  font-family: var(--text); font-size: clamp(16px, 1.06vw, 18px);
  color: var(--ink); background: color-mix(in srgb, var(--ink) 7%, transparent);
  border: 0; border-radius: 11px;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 16%, transparent);
  transition: box-shadow 180ms var(--ease), background 180ms;
}
.ask textarea { resize: vertical; min-height: 88px; line-height: 1.5; }
.ask input:focus,
.ask textarea:focus {
  outline: 0;
  background: color-mix(in srgb, var(--ink) 11%, transparent);
  box-shadow: inset 0 0 0 2px var(--accent);
}

.ask button[type='submit'] { align-self: flex-start; margin-top: 4px; }

.form-status { margin: 0; font-size: clamp(14px, 1vw, 16px); color: var(--meta); }
.form-status.bad { color: #FF8A8E; }

/* The honeypot. Off screen rather than display:none, which more bots fill. */
.trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* The confirmation form.js swaps in once a lead is accepted. */
.on-air { text-align: center; padding: clamp(18px, 3vh, 40px) 0; }
.on-air .kicker { display: flex; align-items: center; justify-content: center; gap: 10px; }
.on-air .kicker .dot {
  width: 10px; height: 10px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 12px var(--accent);
}

/* --- The other doors ----------------------------------------------------- */
.doors {
  display: grid; gap: clamp(14px, 1.6vw, 22px);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  margin-top: 8px;
}

/* Each card takes one of the logo's three colors as a wash, so a row of them
   is not three grey rectangles. The wash is faint enough to work on the light
   channel and the dark ones without being restated. */
/* The label takes its own card's color. On a dark channel the raw navy would
   disappear, so it is mixed toward white there and used neat on the light one. */
.door { --tint-ink: color-mix(in srgb, rgb(var(--tint)) 42%, #FFFFFF); }
/* Used neat on the light channel the purple and the slate blue are too
   pale to read, so they are taken down toward black instead. */
[data-theme='what'] .door { --tint-ink: color-mix(in srgb, rgb(var(--tint)) 58%, #000); }

/* Deliberately NOT the logo's three colors. The logo is navy, slate blue and
   purple, which is also the furniture, the ground and the accent, so a row of
   cards cut from it came out as three more panels of the same room. These are
   borrowed from nowhere and exist to put some life on the screen. */
.door:nth-child(3n + 1) { --tint: 14, 159, 142; }    /* teal */
.door:nth-child(3n + 2) { --tint: 224, 148, 26; }    /* amber */
.door:nth-child(3n + 3) { --tint: 216, 85, 127; }    /* rose */

.door {
  position: relative; overflow: hidden; isolation: isolate;
  display: flex; flex-direction: column; gap: 8px;
  padding: clamp(20px, 2vw, 30px);
  border-radius: 16px; text-decoration: none;
  background:
    linear-gradient(158deg, rgba(var(--tint), 0.26) 0%, rgba(var(--tint), 0.05) 66%),
    color-mix(in srgb, var(--ink) 5%, transparent);
  box-shadow:
    inset 0 3px 0 0 rgb(var(--tint)),
    inset 0 0 0 1px rgba(var(--tint), 0.34);
  transition: box-shadow 260ms var(--ease), transform 260ms var(--ease),
              background 260ms var(--ease);
}

/* A glint crossing the card, one card at a time so the row never flashes
   together. Six seconds each, two seconds apart. */
.door::before {
  content: ''; position: absolute; z-index: 2;
  top: -60%; bottom: -60%; width: 26%;
  background: linear-gradient(100deg,
    transparent 0%, rgba(255,255,255,0.42) 50%, transparent 100%);
  transform: translateX(-320%) rotate(12deg);
  animation: door-glint 6s cubic-bezier(0.4, 0, 0.3, 1) infinite;
  pointer-events: none;
}
.door:nth-child(3n + 2)::before { animation-delay: 2s; }
.door:nth-child(3n + 3)::before { animation-delay: 4s; }
@keyframes door-glint {
  0%, 84% { transform: translateX(-320%) rotate(12deg); }
  100%    { transform: translateX(560%) rotate(12deg); }
}

.door:hover {
  transform: translateY(-5px);
  background:
    linear-gradient(158deg, rgba(var(--tint), 0.42) 0%, rgba(var(--tint), 0.10) 70%),
    color-mix(in srgb, var(--ink) 7%, transparent);
  box-shadow:
    inset 0 3px 0 0 rgb(var(--tint)),
    inset 0 0 0 1px rgba(var(--tint), 0.62),
    0 20px 44px -18px rgba(var(--tint), 0.6);
}

/* The ripple. Rings leave the cursor and travel out across the card, the way
   a stone leaves a ring on a puddle. Injected by set.js, so a card without
   script is simply a card. */
.door-fx {
  position: absolute; inset: 0; z-index: 1;
  pointer-events: none; opacity: 0;
  transition: opacity 320ms var(--ease);
}
.door:hover .door-fx { opacity: 1; }

.door-fx::before,
.door-fx::after {
  content: ''; position: absolute;
  left: var(--mx, 50%); top: var(--my, 50%);
  width: 26vmax; height: 26vmax; margin: -13vmax 0 0 -13vmax;
  border-radius: 50%;
  border: 1.5px solid rgba(var(--tint), 0.55);
  transform: scale(0);
  animation: ripple 2.6s cubic-bezier(0.2, 0.6, 0.3, 1) infinite;
  animation-play-state: paused;
}
.door-fx::after { animation-delay: 1.3s; }
.door:hover .door-fx::before,
.door:hover .door-fx::after { animation-play-state: running; }

@keyframes ripple {
  0%   { transform: scale(0);    opacity: 0; }
  12%  { opacity: 0.75; }
  100% { transform: scale(1);    opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .door::before, .door-fx::before, .door-fx::after { animation: none; opacity: 0; }
  .door:hover { transform: none; }
}
[data-reduced='1'] .door::before,
[data-reduced='1'] .door-fx::before,
[data-reduced='1'] .door-fx::after { animation: none; opacity: 0; }

/* The swarm.

   A handful of colored dots in the top corner of each card, drifting a few
   pixels and never arriving anywhere. It is the only thing moving on a fold
   of otherwise still boxes, and movement at that size reads as life rather
   than as something demanding to be looked at.

   Six background layers on one element, each its own dot, so the whole swarm
   costs a single composited paint and no markup at all. */
.door::after {
  content: ''; position: absolute; z-index: 1; pointer-events: none;
  top: 0; right: 0; width: 148px; height: 124px;
  background-repeat: no-repeat;
  background-image:
    radial-gradient(circle, rgba(14,159,142,0.95)  0 46%, transparent 47%),
    radial-gradient(circle, rgba(224,148,26,0.95)  0 46%, transparent 47%),
    radial-gradient(circle, rgba(216,85,127,0.95)  0 46%, transparent 47%),
    radial-gradient(circle, rgba(94,201,255,0.90)  0 46%, transparent 47%),
    radial-gradient(circle, rgba(255,214,102,0.90) 0 46%, transparent 47%),
    radial-gradient(circle, rgba(139,224,168,0.90) 0 46%, transparent 47%);
  background-size: 11px 11px, 7px 7px, 14px 14px, 6px 6px, 9px 9px, 8px 8px;
  background-position: 112px 26px, 68px 44px, 128px 70px, 88px 18px, 48px 74px, 134px 38px;
  animation: door-swarm 9s ease-in-out infinite alternate;
}
.door:nth-child(3n + 2)::after { animation-delay: -3s; }
.door:nth-child(3n + 3)::after { animation-delay: -6s; }
@keyframes door-swarm {
  to {
    background-position: 100px 40px, 78px 28px, 118px 54px, 96px 32px, 60px 60px, 124px 54px;
  }
}
@media (prefers-reduced-motion: reduce) { .door::after { animation: none; } }
[data-reduced='1'] .door::after { animation: none; }

.door-k {
  font-size: clamp(13px, 0.92vw, 15px); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--tint-ink);
}
.door-v {
  font-family: var(--display); font-style: italic;
  font-size: clamp(22px, 1.9vw, 32px); color: var(--ink); line-height: 1.1;
}
/* Full ink, not the muted prose color. These cards carry the whole of what
   somebody gets, and at 70% on a tinted wash they read as a footnote. On the
   paper channel that is black; on the dark ones it is the channel's white. */
.door-m {
  font-size: clamp(16px, 1.18vw, 20px); line-height: 1.5; color: var(--ink);
}

/* ---------------------------------------------------------------------------
   THE BACKDROP

   A room, drawn once and worn very faintly behind a fold that would otherwise
   be boxes on a flat ground. It is drawn as a MASK rather than as a picture,
   so it is filled with the channel's own ink: dark figures on the paper
   channel, pale ones on the dark channels, and nothing to restate per theme.

   It is set at the strength of a watermark on purpose. If you notice it, it
   is too strong: the job is to stop the screen reading as empty, not to be
   looked at.
   ------------------------------------------------------------------------ */
.backdrop {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: var(--ink);
  opacity: 0.085;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center bottom; mask-position: center bottom;
  -webkit-mask-size: cover; mask-size: cover;
}
/* Paper takes ink far more readily than a dark ground takes light, so the
   light channel needs less of it to read the same. */
[data-theme='what'] .backdrop { opacity: 0.05; }

.backdrop[data-scene='room'] {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1600 900'%3E%3Cg fill='%23fff'%3E%3Crect x='0' y='700' width='1600' height='3' opacity='.35'/%3E%3Crect x='960' y='140' width='540' height='312' rx='12' opacity='.42'/%3E%3Crect x='976' y='156' width='508' height='280' rx='6' opacity='.85'/%3E%3Crect x='1140' y='470' width='180' height='12' rx='6' opacity='.34'/%3E%3Crect x='1210' y='452' width='40' height='22' opacity='.3'/%3E%3Crect x='210' y='556' width='560' height='150' rx='44' opacity='.4'/%3E%3Crect x='232' y='498' width='516' height='96' rx='38' opacity='.34'/%3E%3Ccircle cx='372' cy='452' r='46' opacity='.5'/%3E%3Cpath d='M296 556c0-42 34-76 76-76s76 34 76 76z' opacity='.45'/%3E%3Ccircle cx='610' cy='466' r='42' opacity='.5'/%3E%3Cpath d='M540 562c0-39 31-70 70-70s70 31 70 70z' opacity='.45'/%3E%3Ccircle cx='884' cy='372' r='38' opacity='.44'/%3E%3Cpath d='M824 700c0-52 27-94 60-94s60 42 60 94z' opacity='.4'/%3E%3Crect x='138' y='430' width='6' height='272' opacity='.34'/%3E%3Cpath d='M96 430h90l-26-72h-38z' opacity='.4'/%3E%3Crect x='430' y='742' width='300' height='10' rx='5' opacity='.3'/%3E%3Crect x='452' y='752' width='8' height='44' opacity='.26'/%3E%3Crect x='700' y='752' width='8' height='44' opacity='.26'/%3E%3Crect x='540' y='716' width='40' height='26' rx='4' opacity='.3'/%3E%3C/g%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1600 900'%3E%3Cg fill='%23fff'%3E%3Crect x='0' y='700' width='1600' height='3' opacity='.35'/%3E%3Crect x='960' y='140' width='540' height='312' rx='12' opacity='.42'/%3E%3Crect x='976' y='156' width='508' height='280' rx='6' opacity='.85'/%3E%3Crect x='1140' y='470' width='180' height='12' rx='6' opacity='.34'/%3E%3Crect x='1210' y='452' width='40' height='22' opacity='.3'/%3E%3Crect x='210' y='556' width='560' height='150' rx='44' opacity='.4'/%3E%3Crect x='232' y='498' width='516' height='96' rx='38' opacity='.34'/%3E%3Ccircle cx='372' cy='452' r='46' opacity='.5'/%3E%3Cpath d='M296 556c0-42 34-76 76-76s76 34 76 76z' opacity='.45'/%3E%3Ccircle cx='610' cy='466' r='42' opacity='.5'/%3E%3Cpath d='M540 562c0-39 31-70 70-70s70 31 70 70z' opacity='.45'/%3E%3Ccircle cx='884' cy='372' r='38' opacity='.44'/%3E%3Cpath d='M824 700c0-52 27-94 60-94s60 42 60 94z' opacity='.4'/%3E%3Crect x='138' y='430' width='6' height='272' opacity='.34'/%3E%3Cpath d='M96 430h90l-26-72h-38z' opacity='.4'/%3E%3Crect x='430' y='742' width='300' height='10' rx='5' opacity='.3'/%3E%3Crect x='452' y='752' width='8' height='44' opacity='.26'/%3E%3Crect x='700' y='752' width='8' height='44' opacity='.26'/%3E%3Crect x='540' y='716' width='40' height='26' rx='4' opacity='.3'/%3E%3C/g%3E%3C/svg%3E");
}
.backdrop[data-scene='cafe'] {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1600 900'%3E%3Cg fill='%23fff'%3E%3Crect x='60' y='120' width='430' height='520' rx='8' opacity='.22'/%3E%3Crect x='60' y='120' width='430' height='14' opacity='.4'/%3E%3Crect x='268' y='120' width='10' height='520' opacity='.3'/%3E%3Crect x='0' y='642' width='1600' height='4' opacity='.3'/%3E%3Crect x='940' y='560' width='620' height='120' rx='10' opacity='.36'/%3E%3Crect x='940' y='548' width='620' height='16' rx='8' opacity='.46'/%3E%3Crect x='1010' y='150' width='500' height='290' rx='12' opacity='.42'/%3E%3Crect x='1026' y='166' width='468' height='258' rx='6' opacity='.85'/%3E%3Crect x='1130' y='40' width='4' height='84' opacity='.3'/%3E%3Cpath d='M1104 124h56l-14-34h-28z' opacity='.4'/%3E%3Crect x='1330' y='40' width='4' height='110' opacity='.3'/%3E%3Cpath d='M1304 150h56l-14-34h-28z' opacity='.4'/%3E%3Crect x='560' y='690' width='260' height='9' rx='4' opacity='.3'/%3E%3Crect x='684' y='699' width='10' height='120' opacity='.26'/%3E%3Ccircle cx='566' cy='548' r='40' opacity='.5'/%3E%3Cpath d='M498 660c0-40 30-72 68-72s68 32 68 72z' opacity='.44'/%3E%3Ccircle cx='812' cy='536' r='38' opacity='.5'/%3E%3Cpath d='M748 660c0-38 29-68 64-68s64 30 64 68z' opacity='.44'/%3E%3Ccircle cx='1080' cy='448' r='40' opacity='.44'/%3E%3Cpath d='M1014 560c0-44 29-80 66-80s66 36 66 80z' opacity='.4'/%3E%3Crect x='600' y='664' width='30' height='26' rx='5' opacity='.34'/%3E%3C/g%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1600 900'%3E%3Cg fill='%23fff'%3E%3Crect x='60' y='120' width='430' height='520' rx='8' opacity='.22'/%3E%3Crect x='60' y='120' width='430' height='14' opacity='.4'/%3E%3Crect x='268' y='120' width='10' height='520' opacity='.3'/%3E%3Crect x='0' y='642' width='1600' height='4' opacity='.3'/%3E%3Crect x='940' y='560' width='620' height='120' rx='10' opacity='.36'/%3E%3Crect x='940' y='548' width='620' height='16' rx='8' opacity='.46'/%3E%3Crect x='1010' y='150' width='500' height='290' rx='12' opacity='.42'/%3E%3Crect x='1026' y='166' width='468' height='258' rx='6' opacity='.85'/%3E%3Crect x='1130' y='40' width='4' height='84' opacity='.3'/%3E%3Cpath d='M1104 124h56l-14-34h-28z' opacity='.4'/%3E%3Crect x='1330' y='40' width='4' height='110' opacity='.3'/%3E%3Cpath d='M1304 150h56l-14-34h-28z' opacity='.4'/%3E%3Crect x='560' y='690' width='260' height='9' rx='4' opacity='.3'/%3E%3Crect x='684' y='699' width='10' height='120' opacity='.26'/%3E%3Ccircle cx='566' cy='548' r='40' opacity='.5'/%3E%3Cpath d='M498 660c0-40 30-72 68-72s68 32 68 72z' opacity='.44'/%3E%3Ccircle cx='812' cy='536' r='38' opacity='.5'/%3E%3Cpath d='M748 660c0-38 29-68 64-68s64 30 64 68z' opacity='.44'/%3E%3Ccircle cx='1080' cy='448' r='40' opacity='.44'/%3E%3Cpath d='M1014 560c0-44 29-80 66-80s66 36 66 80z' opacity='.4'/%3E%3Crect x='600' y='664' width='30' height='26' rx='5' opacity='.34'/%3E%3C/g%3E%3C/svg%3E");
}

/* The light the drawn set throws into the drawn room. It breathes, slowly,
   which is the only motion on the fold apart from the swarms. */
.backdrop::after {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(26% 30% at 77% 33%,
    color-mix(in srgb, var(--accent) 70%, transparent) 0%, transparent 70%);
  filter: blur(30px);
  animation: backdrop-breathe 11s ease-in-out infinite alternate;
}
@keyframes backdrop-breathe { from { opacity: 0.5; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .backdrop::after { animation: none; } }
[data-reduced='1'] .backdrop::after { animation: none; }

/* Everything in a fold that has a backdrop sits above it. Not .more: that one
   is already positioned, above everything, and giving it position:relative
   drops it back into the flow as a full width bar across the cards. */
.scene > .beat, .scene > .cols { position: relative; z-index: 1; }

/* The caret that blinks while the address is being typed. It is drawn as a
   border rather than a character, so it cannot be selected or read aloud. */
/* Drawn after the text rather than on the box: the address bar is a full
   width pill, so a border put the caret out at the far right of the bar with
   nothing in front of it. */
.sitecard-url.is-typing::after {
  content: ''; display: inline-block;
  width: 2px; height: 1em; margin-left: 3px; vertical-align: -0.14em;
  background: currentColor;
  animation: sitecard-caret 900ms steps(1) infinite;
}
@keyframes sitecard-caret {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0.1; }
}

/* The next-step button clears the rule it was sitting on. */
#next-step { bottom: calc(clamp(18px, 3.2vh, 34px) + 12px); }

/* A headline with a remark set beside it. The remark sits on the headline's
   last baseline at full width and drops under it when there is no room, so it
   reads as an aside either way rather than as a second heading. */
.head-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: clamp(16px, 2.4vw, 40px); flex-wrap: wrap;
}
.head-aside {
  font-family: var(--display); font-style: italic;
  font-size: clamp(22px, 2vw, 34px); line-height: 1.1;
  color: var(--accent); white-space: nowrap;
}

/* ===========================================================================
   CH 04: DEMOS

   One large set and three names beside it. Picking a name retunes the set,
   which is the remote's gesture again, one level down.
   ========================================================================= */
.stage {
  display: grid; gap: clamp(22px, 2.6vw, 44px);
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  align-items: safe center;
  margin-top: clamp(18px, 2.4vh, 32px);
}
@media (max-width: 1100px) { .stage { grid-template-columns: 1fr; } }

.stage-screen { min-width: 0; }
.stage .mini { border-radius: 14px; }

.picker { display: flex; flex-direction: column; gap: 10px; min-width: 0; }

.pick {
  display: flex; align-items: flex-start; gap: 14px;
  width: 100%; padding: 16px 18px;
  border: 0; border-radius: 14px; cursor: pointer; text-align: left;
  font-family: var(--text);
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent);
  transition: background 190ms var(--ease), box-shadow 190ms, transform 140ms var(--ease);
}
.pick:hover { background: color-mix(in srgb, var(--ink) 11%, transparent); }
.pick:active { transform: translateY(1px); }

.pick-n {
  flex-shrink: 0; width: 34px; height: 34px; border-radius: 9px;
  display: grid; place-items: center;
  font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--meta);
  background: color-mix(in srgb, var(--ink) 9%, transparent);
  transition: background 190ms, color 190ms;
}
.pick-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.pick-name {
  font-family: var(--text); font-weight: 600;
  font-size: clamp(17px, 1.3vw, 23px); line-height: 1.2; color: var(--ink);
}
.pick-what {
  font-size: clamp(14px, 1vw, 17px); line-height: 1.45; color: var(--meta);
}

/* The one being watched. The accent bar down the left is the same signal the
   remote uses for the channel you are on. */
.pick.is-on {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  box-shadow:
    inset 3px 0 0 var(--accent),
    inset 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent);
}
.pick.is-on .pick-n { background: var(--accent); color: var(--on-accent, #0B0A1C); }

.pick-note {
  margin: 6px 0 4px;
  font-size: clamp(14px, 1vw, 16px); line-height: 1.5; color: var(--meta);
}
.picker .cta { align-self: flex-start; }

/* ===========================================================================
   CH 03: HOW, the sideways channel
   ========================================================================= */
.track {
  display: flex;
  width: 100%; height: 100%;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  scroll-behavior: smooth;
}
.track::-webkit-scrollbar { display: none; }

.panel-step {
  position: relative;
  flex: 0 0 100%;
  scroll-snap-align: start;
  display: grid; align-items: safe center;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: clamp(26px, 3.4vw, 64px);
  /* The bottom inset clears the lower third and the horizontal rail, both of
     which live in that corner. Without it the step text lands on top of them
     on any window that is not tall. */
  padding: clamp(34px, 5vh, 72px) var(--safe) calc(var(--safe) + 74px);
  border-right: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
}
.panel-step .beat { min-width: 0; }
.panel-step .hero { font-size: clamp(30px, 3.5vw, 62px); max-width: 15ch; }
.panel-step .lede { max-width: 44ch; font-size: clamp(16px, 1.16vw, 20px); }

@media (max-width: 1100px) {
  .panel-step { grid-template-columns: 1fr; align-content: center; }
  .panel-step > .beat:last-of-type { display: none; }
}

/* The step number, set enormous and faint behind the words. It gives the
   sideways channel a sense of place that a scrollbar cannot. */
.step-n {
  position: absolute; z-index: 0;
  left: clamp(20px, 3vw, 64px); bottom: clamp(-18px, -2vh, 0px);
  font-family: var(--display); font-style: italic;
  font-size: clamp(180px, 34vh, 420px); line-height: 0.8;
  color: color-mix(in srgb, var(--ink) 6%, transparent);
  pointer-events: none; user-select: none;
}
.panel-step > .beat { position: relative; z-index: 1; }

.step-time {
  margin: 0;
  font-size: clamp(14px, 1vw, 17px); font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent);
}
/* A whole sentence set in tracked out capitals is a shout, and this one is a
   caveat. It keeps the color and the weight and drops the case. */
.step-time.long {
  text-transform: none; letter-spacing: 0.01em;
  font-size: clamp(15px, 1.1vw, 19px); max-width: 44ch;
}

/* A horizontal channel gets a horizontal rail. */
.rail-h {
  position: absolute; z-index: 7; pointer-events: none;
  left: var(--safe); right: var(--safe); bottom: calc(var(--safe) / 2.4);
  height: 3px; border-radius: 3px;
  background: color-mix(in srgb, var(--ink) 22%, transparent);
}
.rail-h .thumb-h {
  position: absolute; top: 0; bottom: 0; left: 0;
  border-radius: 3px; background: var(--accent);
  box-shadow: 0 0 10px -2px var(--accent);
}

/* ===========================================================================
   CH 05: WHO IT'S FOR, the channel that does not scroll
   ========================================================================= */
.scene-fixed {
  height: 100%;
  justify-content: safe center;
  gap: clamp(16px, 2.4vh, 30px);
  overflow: hidden;
}

.choose { display: flex; flex-wrap: wrap; gap: 10px; }

.choice {
  height: 58px; padding: 0 26px; border: 0; border-radius: 999px;
  cursor: pointer; font-family: var(--text);
  font-size: clamp(15px, 1.12vw, 19px); font-weight: 600;
  color: var(--meta); white-space: nowrap;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 14%, transparent);
  transition: background 190ms var(--ease), color 190ms, box-shadow 190ms, transform 120ms;
}
.choice:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 12%, transparent); }
.choice:active { transform: translateY(1px); }
.choice.is-on {
  color: var(--on-accent, #0B0A1C); background: var(--accent);
  box-shadow: 0 8px 26px -8px color-mix(in srgb, var(--accent) 80%, transparent);
}

.says { position: relative; min-height: 0; }
.say { max-width: 62ch; }

/* ---------------------------------------------------------------------------
   A SET WITH WORDS ON IT

   An actual television: a cabinet with a bezel around a lit picture, standing
   on a neck and a foot, throwing light at the wall behind it. The first go was
   a dark rectangle with a hairline, which read as a card rather than a set.
   ------------------------------------------------------------------------ */
.screenbox {
  position: relative;
  /* A set is 16:9 and about as wide as an arm. Left to fill the column it came
     out four times wider than it was tall, which is a soundbar. */
  width: 100%; max-width: 540px; margin-inline: auto;
  padding: 13px 13px 15px;
  border-radius: 15px;
  margin-bottom: 40px;                 /* the stand needs somewhere to stand */
  background: linear-gradient(178deg, #343945 0%, #1C1F29 52%, #0D0F16 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.26),
    inset 0 0 0 1px rgba(255,255,255,0.08),
    0 30px 52px -28px rgba(0,0,0,0.95),
    0 0 70px -16px color-mix(in srgb, var(--accent) 60%, transparent);
}

/* The picture. Lit from the top, the way a panel is. */
.screenbox .facts {
  position: relative;
  /* The shape of a picture, with the words held in the middle of it. */
  aspect-ratio: 16 / 9;
  justify-content: center;
  max-width: none; gap: 12px;
  padding: clamp(16px, 1.7vw, 28px) clamp(16px, 1.8vw, 30px);
  border-radius: 7px;
  background: radial-gradient(84% 74% at 50% 30%, #1E2437 0%, #090B13 78%);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,0.09),
    inset 0 14px 44px -22px rgba(255,255,255,0.3);
}
.screenbox .datarow:last-child { border-bottom: 0; padding-bottom: 0; }

/* The neck. */
.screenbox::before {
  content: ''; position: absolute; left: 50%; bottom: -19px;
  width: 86px; height: 21px; transform: translateX(-50%);
  background: linear-gradient(180deg, #262A35 0%, #14161E 100%);
  clip-path: polygon(20% 0, 80% 0, 100% 100%, 0 100%);
}
/* The foot. */
.screenbox::after {
  content: ''; position: absolute; left: 50%; bottom: -26px;
  width: min(62%, 280px); height: 9px; transform: translateX(-50%);
  border-radius: 7px;
  background: linear-gradient(180deg, #2E323D 0%, #101219 100%);
  box-shadow: 0 12px 20px -10px rgba(0,0,0,0.95);
}

/* Scanlines belong to the picture, not to the cabinet. */
.screenbox-scan {
  position: absolute; inset: 13px 13px 15px; pointer-events: none; z-index: 1;
  border-radius: 7px;
  background: repeating-linear-gradient(180deg,
    rgba(255,255,255,0.05) 0 1px, transparent 1px 3px);
  mix-blend-mode: overlay;
}

/* The set already reserves the height of its own stand, and the grid's row gap
   does the rest, so the button needs nothing of its own. */

/* On the paper channel a black set in the middle of a light page is a hole,
   so there the screen is switched off and the facts stand on their own. */
[data-theme='what'] .screenbox {
  background: none; box-shadow: none; padding: 0; margin-bottom: 0;
}
[data-theme='what'] .screenbox .facts { background: none; box-shadow: none; padding: 0; }
[data-theme='what'] .screenbox::before,
[data-theme='what'] .screenbox::after,
[data-theme='what'] .screenbox-scan { display: none; }

/* The row of cards on the deal channel carries the whole fold, so it is given
   air above and below rather than sitting hard against the heading and the
   buttons. */
#included .doors { margin-block: clamp(14px, 3.2vh, 40px); }

/* ---------------------------------------------------------------------------
   A PHOTOGRAPH

   Held the same way the live frames are held: same corner radius, same lift
   off the ground, same wash of the channel's accent underneath it, so a still
   sits beside a running set without looking like it came from somewhere else.
   ------------------------------------------------------------------------ */
/* A still does not need the larger half the way a running channel does, and
   the headline beside it was wrapping to four lines to pay for it. */
#what-to-watch .cols { grid-template-columns: minmax(0, 1.12fr) minmax(0, 1fr); }

.shot {
  position: relative; margin: 0;
  border-radius: 14px; overflow: hidden;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--ink) 14%, transparent),
    0 34px 64px -26px rgba(0,0,0,0.9),
    0 0 70px -22px color-mix(in srgb, var(--accent) 55%, transparent);
}
.shot img { display: block; width: 100%; height: auto; }
/* The photograph was lit for a white room. A breath of the channel's own
   color over it stops it reading as a stock picture dropped onto the page. */
.shot::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(200deg,
    color-mix(in srgb, var(--accent) 16%, transparent) 0%,
    transparent 46%,
    color-mix(in srgb, var(--ground-b, #000) 34%, transparent) 100%);
}

/* An ident that is a picture rather than a mark on a plaque: the plate fills
   the screen edge to edge, and the screen behind it stays white for the moment
   before it loads. The sweep across the glass is the same one channel 01 uses,
   so both sets read as the same object. */
.ident-plate { background: #FFFFFF; }
.ident-full {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
}

/* ===========================================================================
   CH 06: DEAL
   ========================================================================= */
.clock { display: flex; flex-wrap: wrap; gap: clamp(10px, 1.2vw, 18px); }

.cell {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  min-width: clamp(72px, 5.8vw, 112px);
  padding: clamp(14px, 1.5vw, 22px) clamp(10px, 1vw, 18px);
  border-radius: 14px;
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 14%, transparent);
}
.cell-n {
  font-family: var(--display); font-style: italic;
  font-size: clamp(34px, 3.4vw, 58px); line-height: 1;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.cell-k {
  font-size: clamp(12px, 0.86vw, 15px); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--meta);
}
.clock-over { margin: 0; font-size: clamp(17px, 1.28vw, 23px); color: var(--prose); }

/* The price block. This is the one page whose job is the number, so the figure
   is set in the display face at the weight of the countdown beside it, and
   what it used to cost sits next to it as a label rather than struck through:
   a strike reads as a mistake at a glance, a label does not. */
.price { margin: 0; display: grid; gap: clamp(8px, 1vh, 14px); max-width: 30rem; }
.price-row {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 6px clamp(12px, 1.4vw, 22px);
  padding-bottom: clamp(8px, 1vh, 14px);
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 12%, transparent);
}
.price-row:last-child { border-bottom: 0; padding-bottom: 0; }
.price-k {
  flex: 1 1 8rem; min-width: 0;
  font-size: clamp(12px, 0.86vw, 15px); font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--meta);
}
.price-v {
  margin: 0; display: flex; align-items: baseline; gap: clamp(8px, 0.8vw, 14px);
  font-family: var(--display); font-style: italic;
  font-size: clamp(28px, 2.6vw, 44px); line-height: 1;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.price-was {
  font-family: var(--text); font-style: normal;
  font-size: clamp(13px, 0.92vw, 16px); font-weight: 600;
  letter-spacing: 0.03em; color: var(--meta); white-space: nowrap;
}

/* Fine print: small and quiet, but still sized to be read rather than to
   technically be present. */
.fine {
  margin: 0; max-width: 54ch;
  font-size: clamp(12px, 0.84vw, 14px); line-height: 1.5; color: var(--meta);
}

/* A channel that does not scroll has to fit, at any height. Everything on
   CH 05 is a size down from the house scale and the answer lays out in two
   columns so it never runs off the bottom of the screen. */
.scene-fixed .hero { font-size: clamp(26px, 3.1vw, 54px); max-width: 18ch; }
.scene-fixed .hero.sm { font-size: clamp(22px, 2.2vw, 38px); max-width: none; }
.scene-fixed .lede { font-size: clamp(17px, 1.28vw, 23px); max-width: 46ch; }
.scene-fixed .kicker.lg { font-size: clamp(15px, 1.1vw, 19px); }
.scene-fixed .beat { gap: clamp(10px, 1.4vh, 18px); }
/* .say is a beat as well, and the rule above was setting its row gap to a
   third of what the layout asks for. */
.scene-fixed .say { row-gap: clamp(18px, 2.6vh, 30px); }
.scene-fixed .choice { height: 50px; padding: 0 22px; }
.scene-fixed .cta { height: 52px; padding: 0 26px; font-size: clamp(15px, 1.08vw, 18px); }

.say {
  display: grid;
  /* A generous gap between the rows, so the headline and the paragraph under
     it read as two beats rather than one block with a hole in it. */
  gap: clamp(22px, 4vh, 54px) clamp(24px, 3vw, 56px);
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  /* The set spans both text rows rather than sharing one with the headline.
     Sharing meant the headline's row was as tall as the television, which put
     a screenful of nothing between the headline and the paragraph under it. */
  grid-template-areas:
    'kicker kicker'
    'hero   facts'
    'lede   facts'
    '.      facts'
    '.      ctas';
  /* The set is taller than the words beside it, and that slack has to land
     somewhere. Rows two and three are pinned to their own content and row four
     takes all of it, so the headline sits the same distance under the kicker as
     the paragraph sits under the headline. Left to themselves, auto rows share
     the slack out and the gap under the headline comes out four times the one
     above it. */
  grid-template-rows: auto min-content min-content 1fr auto;
  align-items: start;
  max-width: none;
}
.say > .kicker { grid-area: kicker; }
/* Held at the top of its row rather than the bottom. The row is as tall as the
   set beside it, so hanging the headline off the bottom of it left a screenful
   of nothing under the kicker. */
.say > .hero   { grid-area: hero; align-self: start; }
.say > .lede   { grid-area: lede; }
.say > .facts  { grid-area: facts; align-self: start; max-width: none; }
.say > .screenbox { grid-area: facts; align-self: start; }
/* Centered under the set, which is the thing it is asking about. */
.say > .ctas   { grid-area: ctas; align-self: start; justify-self: center; }
.say .datarow { font-size: clamp(16px, 1.2vw, 21px); }
.say .datarow .k { width: 118px; }

@media (max-width: 1100px) {
  .say {
    grid-template-columns: 1fr;
    grid-template-areas: 'kicker' 'hero' 'lede' 'facts' 'ctas';
    grid-template-rows: auto;
  }
  .say > .hero, .say > .facts { align-self: start; }
}

/* --- Step one: the website as it is today -------------------------------- */
.sitecard {
  width: 100%; max-width: 620px; margin-left: auto;
  border-radius: 14px; overflow: hidden;
  background: #FFFFFF;
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.12),
    0 34px 70px -26px rgba(0,0,0,0.85);
}
.sitecard-bar {
  display: flex; align-items: center; gap: 7px;
  padding: 12px 16px; background: #EDEEF3;
  border-bottom: 1px solid #DDDFE7;
}
.sitecard-dot { width: 10px; height: 10px; border-radius: 50%; background: #C9CCD6; }
.sitecard-url {
  flex: 1; margin-left: 10px; padding: 7px 14px;
  background: #fff; border-radius: 999px;
  font-family: var(--ui); font-size: 14px; color: #6B7286;
  box-shadow: inset 0 0 0 1px #DDDFE7;
}
.sitecard-body {
  display: flex; flex-direction: column; gap: 14px;
  padding: clamp(22px, 2.4vw, 34px);
}
.sitecard-logo { width: 104px; height: 18px; border-radius: 5px; background: #00058B; }
.sitecard-h    { width: 78%;   height: 30px; border-radius: 7px; background: #20232E; }
.sitecard-l    { width: 92%;   height: 12px; border-radius: 4px; background: #CED2DC; }
.sitecard-l.short { width: 64%; }
.sitecard-img {
  height: clamp(120px, 15vh, 190px); border-radius: 10px; margin-top: 4px;
  background: linear-gradient(135deg, #DDE2EC 0%, #C6CEDE 48%, #E4E8F0 100%);
}

/* --- Home, any screen: a real channel inside a browser window -------------- */
.sitecard.browser { max-width: 660px; }
.sitecard.browser .mini { border-radius: 0; box-shadow: none; }

/* The screens it plays on, as small labels under the window. */
.screens {
  display: flex; flex-wrap: wrap; gap: 8px;
  max-width: 660px; margin: 18px 0 0 auto;
  justify-content: flex-end;
}
.screens span {
  padding: 6px 12px; border-radius: 999px;
  font-family: var(--ui); font-size: clamp(12px, 0.85vw, 14px); font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent);
}
html:not([data-js]) .sitecard.browser { display: none; }

@media (max-width: 900px) {
  .sitecard.browser, .screens { margin-left: 0; justify-content: flex-start; }
}

/* --- Step three: the channel on a wall ----------------------------------- */
.room {
  position: relative;
  width: 100%; max-width: 660px; margin-left: auto;
  padding: clamp(26px, 3vw, 52px) clamp(22px, 2.6vw, 46px) clamp(46px, 5vw, 76px);
  border-radius: 16px;
  /* A wall, lit from above the way a lobby is. */
  background:
    radial-gradient(120% 70% at 50% -10%, rgba(255,255,255,0.12) 0%, transparent 62%),
    linear-gradient(176deg, #2A2F45 0%, #171A28 100%);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.07);
}
.room-tv {
  border-radius: 8px; overflow: hidden;
  /* A real set on a wall: a thin dark edge, and a shadow under it. */
  box-shadow:
    0 0 0 5px #0A0B12,
    0 0 0 6px rgba(255,255,255,0.10),
    0 26px 44px -18px rgba(0,0,0,0.9);
}
.room-tv .mini { border-radius: 0; box-shadow: none; }

/* The shadow the set casts on the wall under it. */
.room-shelf {
  position: absolute; left: 14%; right: 14%;
  bottom: clamp(22px, 2.6vw, 40px); height: 14px; border-radius: 50%;
  background: radial-gradient(60% 100% at 50% 0%, rgba(0,0,0,0.55), transparent 72%);
}

/* ---------------------------------------------------------------------------
   THE STATION IDENT, on CH 01

   A set on the wall beside the headline, showing the Website2TV ident. It fills
   the half of the frame that was empty, and it is the only place on the site
   the mark appears at any size.

   The screen is light. That is not a style choice: the mark is navy line work
   on transparency and it vanishes on a dark ground. A lit screen is what a
   station ident is anyway, so the fix and the idea are the same thing.
   ------------------------------------------------------------------------ */
.tuned {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.82fr);
  align-items: center;
  gap: clamp(26px, 3.6vw, 70px);
}
.tuned .hero { font-size: clamp(42px, 5.6vw, 104px); max-width: 13ch; }
.tuned .lede { max-width: 40ch; }

.tvset { position: relative; width: 100%; }

.tvset .room-tv {
  border-radius: 10px; overflow: hidden;
  box-shadow:
    0 0 0 6px #090A12,
    0 0 0 7px rgba(255,255,255,0.12),
    0 34px 60px -22px rgba(0,0,0,0.95);
}

/* The light the set throws onto the wall around it. */
.tvset-glow {
  position: absolute; inset: -14% -10% -6%;
  z-index: -1; pointer-events: none; border-radius: 50%;
  background: radial-gradient(52% 46% at 50% 46%,
    color-mix(in srgb, var(--accent) 30%, transparent) 0%, transparent 72%);
  filter: blur(26px);
}
.tvset .room-shelf {
  left: 18%; right: 18%; bottom: -18px; height: 18px;
}

.ident {
  position: relative; overflow: hidden;
  aspect-ratio: 16 / 9;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 5%;
  background:
    radial-gradient(90% 76% at 50% 22%, #FFFFFF 0%, #EDEFF7 58%, #DADDEA 100%);
}
/* The mark arrives out of nothing as the set comes on, driven by the same
   scroll position as everything else in the melt, so it can never fall out of
   step with the reveal and scrubbing back takes it away again. */
/* The mark arrives when the screen lights, as a real animation rather than a
   value scrubbed off the scroll position. Tied to scroll it only played while
   the wheel was actually moving through one particular stretch, so scrolling
   briskly, or arriving already past it, meant never seeing it at all.

   Lit by melt.js the moment the picture swaps, and unlit if you scrub back,
   so it plays again on the way down. */
.ident-mark {
  /* The wordmark is about 2.7:1 once its white margin is trimmed, so this is
     the width that fills the set without crowding the rule beneath it. Sized
     by width, never by height, because the file is the only thing that decides
     how tall it is. */
  width: 78%; height: auto; display: block;
  /* The logo file has a white ground rather than transparency, and the screen
     behind it is a gradient that is only white in the middle. Without this the
     file's edge shows as a hard white rectangle against the grey. The halo
     pools the same white outwards so the card has no edge to see. */
  box-shadow: 0 0 calc(90 * var(--px)) calc(55 * var(--px)) #FFFFFF;
  transform: scale(0); opacity: 0;
  transform-origin: 50% 52%;
}
.ident.is-lit .ident-mark {
  animation: ident-zoom 1600ms cubic-bezier(0.34, 1.4, 0.5, 1) forwards;
}
@keyframes ident-zoom {
  0%   { transform: scale(0);    opacity: 0; }
  30%  { opacity: 1; }
  100% { transform: scale(1);    opacity: 1; }
}

.ident-rule { transform: scaleX(0); opacity: 0; }
.ident.is-lit .ident-rule {
  animation: ident-rule 760ms 950ms cubic-bezier(0.2, 0, 0.1, 1) forwards;
}
@keyframes ident-rule {
  from { transform: scaleX(0); opacity: 0; }
  to   { transform: scaleX(1); opacity: 1; }
}

.ident-sweep {
  position: absolute; top: -40%; bottom: -40%; width: 44%;
  background: linear-gradient(100deg,
    transparent 0%, rgba(255,255,255,0.85) 48%, transparent 100%);
  transform: translateX(-160%) rotate(8deg);
  animation: ident-sweep 7.5s cubic-bezier(0.5, 0, 0.5, 1) infinite;
  pointer-events: none;
}
@keyframes ident-sweep {
  0%, 62%  { transform: translateX(-160%) rotate(8deg); }
  100%     { transform: translateX(340%) rotate(8deg); }
}

/* The set can play a promo instead of the ident: a black screen until the
   iframe paints, and the page scrolls over it rather than into it. */
.ident-promo { background: #000; }
.ident-promo iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0; display: block;
  pointer-events: none;
}

@media (max-width: 1100px) {
  .tuned { grid-template-columns: 1fr; }
  .tvset { display: none; }
  .tuned .hero { font-size: clamp(40px, 8vw, 72px); max-width: 14ch; }
}

@media (prefers-reduced-motion: reduce) { .ident-sweep { animation: none; opacity: 0; } }
[data-reduced='1'] .ident-sweep { animation: none; opacity: 0; }

/* No scrub to drive them: the mark is simply there.

   The real media query has to be in this list, not just the ?reduced flag and
   the no-script case. melt.js returns early when motion is reduced and never
   lights the ident, so a visitor who has asked their system for less motion
   was getting a lit television with nothing on it. */
@media (prefers-reduced-motion: reduce) {
  .ident-mark, .ident-rule { transform: none !important; opacity: 1 !important; }
  /* A fade is not motion, so the mark is still allowed to arrive rather than
     simply being there. It runs on load because melt.js, which would normally
     light it, stands down in this mode. */
  .ident-mark { animation: ident-fade 1400ms var(--ease) 500ms both !important; }
}
@keyframes ident-fade { from { opacity: 0; } to { opacity: 1; } }
[data-reduced='1'] .ident-mark, [data-reduced='1'] .ident-rule,
html:not([data-js]) .ident-mark, html:not([data-js]) .ident-rule {
  transform: none !important; opacity: 1 !important;
}

/* ===========================================================================
   CH 08: FAQ, a program guide

   Listings down the left, the answer on a set beside them. Without script, or
   on a phone, .is-guide is never added (or is overruled) and every answer is
   shown in order, each carrying its own question, so nothing depends on it.
   ========================================================================= */
.guide { display: flex; flex-direction: column; gap: clamp(24px, 3.4vh, 44px); }
.guide-list, .guide-glow { display: none; }

.guide-tv {
  position: relative;
  padding: 14px 14px 16px; border-radius: 16px;
  background: linear-gradient(178deg, #343945 0%, #1C1F29 52%, #0D0F16 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.26),
    inset 0 0 0 1px rgba(255,255,255,0.08),
    0 30px 52px -28px rgba(0,0,0,0.95),
    0 0 80px -18px color-mix(in srgb, var(--accent) 55%, transparent);
}
.guide-picture {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: clamp(28px, 4vh, 44px);
  padding: clamp(22px, 2.4vw, 42px) clamp(22px, 2.6vw, 46px);
  border-radius: 8px;
  background: radial-gradient(90% 80% at 50% 20%, #13303F 0%, #060C14 80%);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.09), inset 0 14px 44px -22px rgba(255,255,255,0.3);
}
.guide-scan {
  position: absolute; inset: 14px 14px 16px; pointer-events: none; z-index: 2;
  border-radius: 8px;
  background: repeating-linear-gradient(180deg, rgba(255,255,255,0.05) 0 1px, transparent 1px 3px);
  mix-blend-mode: overlay;
}

.answer { display: flex; flex-direction: column; gap: 14px; }
.answer-n {
  margin: 0; font-size: clamp(13px, 0.9vw, 15px); font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--accent);
}
.answer-q {
  margin: 0 0 4px; font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: clamp(28px, 2.5vw, 44px); line-height: 1.08; color: var(--ink); text-wrap: balance;
}
.answer p:not(.answer-n) {
  margin: 0; font-size: clamp(17px, 1.2vw, 21px); line-height: 1.55;
  color: var(--prose); max-width: 58ch; text-wrap: pretty;
}
.answer p.answer-key { color: var(--ink); font-weight: 600; }

.answer a { color: var(--accent); font-weight: 600; text-underline-offset: 3px; }
.answer-price { margin: 4px 0 6px; display: flex; flex-direction: column; }
.answer-price > div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 18px;
  padding: 11px 0; border-bottom: 1px solid color-mix(in srgb, var(--ink) 12%, transparent);
}
.answer-price dt {
  font-size: clamp(13px, 0.92vw, 16px); font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--meta);
}
.answer-price dd {
  margin: 0; text-align: right; font-size: clamp(22px, 1.8vw, 32px); font-weight: 700; color: var(--ink);
}
.answer-price dd span { display: block; font-size: clamp(13px, 0.9vw, 15px); font-weight: 500; color: var(--meta); }
.answer-price .all-in { border-bottom: 0; }
.answer-price .all-in dd { color: var(--accent); }

/* --- The guide, once script has taken it over ------------------------------ */
@media (min-width: 901px) {
  .guide.is-guide {
    display: grid; align-items: start;
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.25fr);
    grid-template-areas: 'head head' 'list screen';
    gap: clamp(24px, 3.6vh, 46px) clamp(28px, 3.4vw, 64px);
  }
  .is-guide .guide-head   { grid-area: head; }
  .is-guide .guide-list   { grid-area: list; display: flex; }
  .is-guide .guide-screen { grid-area: screen; position: relative; }
  .is-guide .guide-glow {
    display: block; position: absolute; inset: 10% 6% auto; height: 60%; z-index: -1;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 30%, transparent), transparent);
    filter: blur(30px); pointer-events: none;
  }

  /* One answer on the set at a time, all stacked in the same cell so the set
     is as tall as the longest answer and never jumps when you change. */
  .is-guide .guide-picture { display: grid; }
  .is-guide .answer { grid-area: 1 / 1; visibility: hidden; }
  .is-guide .answer.is-on { visibility: visible; }
  .is-guide .answer.is-in > * { animation: guide-line 620ms var(--delay, 0ms) cubic-bezier(0.16,0.8,0.28,1) both; }

  /* The tune: a flash of the picture and a roll of static, then the answer. */
  .guide-tv.is-tuning .guide-picture::after {
    content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none;
    background:
      repeating-linear-gradient(0deg, rgba(255,255,255,0.18) 0 2px, transparent 2px 5px),
      color-mix(in srgb, var(--accent) 22%, #fff 6%);
    animation: guide-static 420ms ease-out both;
  }
}
@keyframes guide-line {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}
@keyframes guide-static {
  0%   { opacity: 0.9; transform: translateY(-6%); }
  60%  { opacity: 0.35; transform: translateY(4%); }
  100% { opacity: 0; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .is-guide .answer.is-in > * { animation: none; }
  .guide-tv.is-tuning .guide-picture::after { display: none; }
}
[data-reduced='1'] .is-guide .answer.is-in > * { animation: none; }
[data-reduced='1'] .guide-tv.is-tuning .guide-picture::after { display: none; }

/* The listings. Each one is a row of the guide: a slot number and a title. */
.listings { display: flex; flex-direction: column; gap: 8px; width: 100%; }
.listing {
  display: flex; align-items: center; gap: 16px; width: 100%;
  padding: 15px 18px; border: 0; border-radius: 12px; cursor: pointer;
  font-family: var(--text); text-align: left;
  font-size: clamp(16px, 1.12vw, 20px); font-weight: 600; line-height: 1.3;
  color: var(--meta);
  background: color-mix(in srgb, var(--ink) 5%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 10%, transparent);
  transition: background 190ms var(--ease), color 190ms, box-shadow 190ms, transform 120ms;
}
.listing:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 10%, transparent); }
.listing:active { transform: translateY(1px); }
.listing:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.listing-n {
  flex-shrink: 0; width: 38px; height: 30px; display: grid; place-items: center;
  border-radius: 7px; font-size: 14px; font-weight: 700; letter-spacing: 0.04em;
  background: color-mix(in srgb, var(--ink) 9%, transparent); color: var(--meta);
  transition: background 190ms, color 190ms;
}
.listing.is-on {
  color: var(--ink);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 60%, transparent),
              0 10px 30px -14px color-mix(in srgb, var(--accent) 70%, transparent);
}
.listing.is-on .listing-n { background: var(--accent); color: var(--on-accent, #0B0A1C); }

.guide-screen .ctas { margin-top: clamp(22px, 3vh, 36px); justify-content: center; }

/* A phone, or no script: every answer, in order, on the one tall set. */
.answer + .answer { padding-top: 34px; border-top: 1px solid color-mix(in srgb, var(--ink) 12%, transparent); }
@media (min-width: 901px) { .is-guide .answer + .answer { padding-top: 0; border-top: 0; } }

/* ===========================================================================
   CH 07: PRICING

   Three plans side by side, the middle one lifted and edged in the channel's
   gold, the way the printed price sheet has it. The buy buttons sit on one
   line at the foot of every card, however long the list above them runs.
   ========================================================================= */
.plans-head { max-width: 62rem; }

.beat.plans {
  display: grid; gap: clamp(16px, 1.6vw, 26px);
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: stretch;
  margin-top: clamp(26px, 4vh, 48px);
}
@media (max-width: 1100px) { .beat.plans { grid-template-columns: 1fr; max-width: 34rem; } }

/* The entry animates the slot, so the card itself is free to move on hover. */
.plan-slot { display: flex; }

.plan {
  position: relative; flex: 1;
  display: flex; flex-direction: column; gap: 10px;
  padding: clamp(24px, 2.2vw, 34px);
  border-radius: 20px;
  background:
    linear-gradient(170deg, color-mix(in srgb, var(--ink) 8%, transparent) 0%, color-mix(in srgb, var(--ink) 3%, transparent) 100%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 14%, transparent);
  transition: transform 260ms var(--ease), box-shadow 260ms var(--ease);
}
.plan:hover {
  transform: translateY(-4px);
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--ink) 26%, transparent),
    0 24px 50px -24px rgba(0,0,0,0.8);
}

.plan.is-pick {
  background:
    radial-gradient(120% 70% at 50% 0%, color-mix(in srgb, var(--accent) 16%, transparent) 0%, transparent 70%),
    linear-gradient(170deg, color-mix(in srgb, var(--ink) 10%, transparent) 0%, color-mix(in srgb, var(--ink) 4%, transparent) 100%);
  box-shadow:
    inset 0 0 0 2px var(--accent),
    0 26px 60px -26px color-mix(in srgb, var(--accent) 60%, transparent);
}
.plan.is-pick:hover {
  box-shadow:
    inset 0 0 0 2px var(--accent),
    0 30px 70px -24px color-mix(in srgb, var(--accent) 80%, transparent);
}
@media (min-width: 1101px) {
  .plan.is-pick { transform: translateY(-10px); }
  .plan.is-pick:hover { transform: translateY(-14px); }
}

.plan-chip {
  position: absolute; top: 0; left: 50%;
  transform: translate(-50%, -50%);
  padding: 7px 16px; border-radius: 999px;
  background: var(--accent); color: var(--on-accent);
  font-size: 13px; font-weight: 800; letter-spacing: 0.16em;
  text-transform: uppercase; white-space: nowrap;
}

.plan-k {
  margin: 0; color: var(--accent);
  font-size: clamp(13px, 0.92vw, 15px); font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase;
}
.plan-name {
  margin: 0; font-family: var(--display); font-style: italic; font-weight: 400;
  font-size: clamp(28px, 2.3vw, 40px); line-height: 1.05; color: var(--ink);
}
.plan-price {
  margin: 6px 0 0; font-family: var(--display); font-style: italic;
  font-size: clamp(52px, 4.6vw, 80px); line-height: 0.95; letter-spacing: -0.01em;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.plan-per {
  margin-left: 6px; font-family: var(--text); font-style: normal;
  font-size: clamp(17px, 1.3vw, 22px); font-weight: 600; color: var(--meta);
  letter-spacing: 0;
}
.plan-sub {
  margin: 0; font-size: clamp(15px, 1.05vw, 18px); line-height: 1.45; color: var(--meta);
}

.plan-list {
  list-style: none; margin: 10px 0 0; padding: 0;
  border-top: 1px solid color-mix(in srgb, var(--ink) 14%, transparent);
}
.plan-list li {
  position: relative;
  padding: 12px 0 12px 22px;
  font-size: clamp(15px, 1.08vw, 18px); line-height: 1.45; color: var(--prose);
  border-bottom: 1px solid color-mix(in srgb, var(--ink) 9%, transparent);
}
.plan-list li:last-child { border-bottom: 0; }
.plan-list li::before {
  content: ''; position: absolute; left: 2px; top: calc(12px + 0.42em);
  width: 9px; height: 9px; border-radius: 50%; background: var(--accent);
}
.plan-list b { color: var(--ink); font-weight: 700; }
.em-up { color: var(--accent); font-weight: 700; }

/* The foot of the card. margin-top: auto is what lines the buttons up across
   all three cards. */
.plan-buy {
  margin-top: auto; padding-top: 18px;
  display: flex; flex-direction: column; gap: 10px;
}
.plan-buy .cta { justify-content: center; width: 100%; }

/* A second way to buy from the same card: a quiet row with its price on the
   right, so the main button stays the main button. */
.buy {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  min-height: 50px; padding: 0 20px; border-radius: 999px;
  text-decoration: none; color: var(--ink);
  font-size: clamp(15px, 1.05vw, 17px); font-weight: 600;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 24%, transparent);
  transition: box-shadow 200ms, background 200ms;
}
.buy:hover {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.buy-p { color: var(--accent); font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* --- The October band --------------------------------------------------- */
.band {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 18px 28px;
  margin-top: clamp(26px, 4vh, 44px);
  padding: clamp(22px, 2.2vw, 32px) clamp(24px, 2.6vw, 40px);
  border-radius: 18px;
  background: linear-gradient(100deg, #EDC88E 0%, #E2B575 55%, #D2A167 100%);
  color: var(--on-accent);
  box-shadow: 0 22px 50px -26px rgba(230,189,124,0.7);
}
.band-copy { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.band-t {
  margin: 0; font-family: var(--display); font-style: italic;
  font-size: clamp(24px, 2.1vw, 36px); line-height: 1.1;
}
.band-m { margin: 0; font-size: clamp(15px, 1.08vw, 18px); line-height: 1.45; opacity: 0.85; }
.cta.band-cta {
  background: var(--on-accent); color: #FFF3DC;
  box-shadow: 0 8px 24px -10px rgba(14,24,56,0.8);
}
.cta.band-cta:hover { box-shadow: 0 14px 34px -10px rgba(14,24,56,0.95); }

/* --- Audio add-ons ------------------------------------------------------ */
.addons {
  display: grid; gap: clamp(14px, 1.6vw, 22px);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  margin: 6px 0 4px;
}
.addon {
  display: grid; grid-template-columns: 1fr auto;
  gap: 6px 16px; align-items: end;
  padding: clamp(20px, 2vw, 28px) clamp(22px, 2vw, 30px);
  border-radius: 16px; text-decoration: none; color: var(--ink);
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  box-shadow: inset 4px 0 0 0 var(--accent), inset 0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent);
  transition: transform 220ms var(--ease), background 220ms, box-shadow 220ms;
}
.addon:hover {
  transform: translateY(-4px);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  box-shadow: inset 4px 0 0 0 var(--accent), inset 0 0 0 1px var(--accent),
              0 20px 44px -22px color-mix(in srgb, var(--accent) 70%, transparent);
}
.addon-t {
  grid-column: 1 / -1;
  font-size: clamp(16px, 1.15vw, 19px); font-weight: 700; color: var(--ink);
}
.addon-p {
  font-family: var(--display); font-style: italic;
  font-size: clamp(40px, 3.2vw, 56px); line-height: 1; color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.addon-go {
  justify-self: end; align-self: center;
  padding: 10px 18px; border-radius: 999px;
  background: var(--ink); color: var(--ground-a);
  font-size: 15px; font-weight: 700; white-space: nowrap;
}
.addon:hover .addon-go { background: var(--accent); color: var(--on-accent); }

.after-addons { margin-top: clamp(36px, 6vh, 72px); }

.inline-buy {
  color: var(--accent); font-weight: 700;
  text-decoration: underline; text-underline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .plan:hover, .addon:hover { transform: none; }
}
[data-reduced='1'] .plan:hover,
[data-reduced='1'] .addon:hover { transform: none; }
