/* =============================================================
   components.css: cards, buttons, chips, badges, inputs and the
   live module. No literal colour values: everything reads from
   tokens.css. Step 1 lays down the primitives; Step 3 completes
   the component set.
   ============================================================= */

/* ---- Text roles ---- */
.kicker {
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: var(--kicker-weight);
  letter-spacing: var(--tracking-kicker);
  text-transform: var(--kicker-transform);
  color: var(--kicker-color);
}
.meta { font-family: var(--font-ui); font-size: var(--text-sm); color: var(--text-2); }
.dek { color: var(--text-2); }

/* ---- Buttons. 44px targets. Callout buttons are never pills. ---- */
.btn {
  font-family: var(--font-ui);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: var(--target);
  padding: 0 var(--space-2);
  border: 1px solid transparent;
  border-radius: var(--radius-button);
  background: transparent;
  font-size: var(--text-ui);
  font-weight: var(--weight-medium);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--hover-duration), border-color var(--hover-duration), box-shadow var(--hover-duration);
}
/* Buttons read by fill, so the link hover colour stops at their edge. */
.btn:hover { color: inherit; }
.btn-primary { background: var(--accent); color: var(--text-on-accent); border-color: var(--accent); }
.btn-primary:hover { box-shadow: var(--shadow-2); color: var(--text-on-accent); }
.btn-secondary { background: var(--raised); border-width: var(--btn-border-width); border-color: var(--border-strong); }
.btn-secondary:hover { background: var(--accent-soft); }
.btn-quiet:hover { background: var(--accent-soft); }
/* Icon button: a square target with the mark drawn from currentColor, so
   the row's text colour and hover carry into the glyph. Always sits next
   to a visible label for the group. */
.btn-icon { width: var(--target); padding: 0; }
.btn-icon svg { width: var(--icon-size); height: var(--icon-size); display: block; }

/* ---- Chips. Functional only: topics, filters, guest tags. ---- */
.chip {
  font-family: var(--font-ui);
  display: inline-flex;
  align-items: center;
  gap: var(--space-half);
  min-height: var(--target);
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--raised);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--hover-duration), border-color var(--hover-duration);
}
.chip:hover { color: inherit; border-color: var(--border-strong); }
.chip.is-active, .chip[aria-pressed="true"] {
  background: var(--accent);
  color: var(--text-on-accent);
  border-color: var(--accent);
}
.chip-row { display: flex; flex-wrap: wrap; gap: var(--space-1); }

/* ---- Badges ---- */
.badge {
  font-family: var(--font-ui);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  line-height: 1.2;
}
.badge-live { background: var(--live); color: var(--text-on-accent); }
.badge-live::before {
  content: "";
  width: 8px; height: 8px;
  border-radius: 50%;
  background: currentColor;
}

/* ---- Inputs ---- */
.input {
  width: 100%;
  min-height: var(--target);
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-input);
  background: var(--sunk);
  transition: border-color var(--hover-duration);
}
.input:hover, .input:focus { border-color: var(--border-strong); outline: none; }
/* The line above drops the ring for the mouse; keyboard focus keeps it. */
.input:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.input::placeholder { color: var(--text-3); }

/* ---- Header search. A real field rather than a link, so it reads as somewhere
        to type. Tucker's header box is 253px wide; --search-w is the smaller one.
        The magnifier is inset on the left and the placeholder carries the label.
        Search results are out of scope, so the form goes nowhere. ---- */
.search-field {
  position: relative;
  display: flex;
  align-items: center;
  flex: none;
  width: var(--search-w);
  margin-inline: var(--space-half);
}
.search-field .glyph {
  position: absolute;
  left: var(--space-2);
  color: var(--text-3);
  pointer-events: none;
}
.search-field .input {
  padding-left: calc(var(--space-2) + 1em + var(--space-1));
  font-size: var(--text-ui);
}
/* The browser draws its own clear button in its accent blue. Nothing here is
   allowed a colour off the token scale, so it goes; retyping clears the field. */
.search-field .input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

/* ---- Card base. Image large, title below. Never text on the image. The one
        reachable exception is the episode badge, which the show-page comps put
        on the thumbnail; it is off by default and lives behind
        --card-badge-position at the foot of this file. ---- */
.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}
/* The ruled reading: a line along the top of every card, then the image,
   then the title. Off by default. The padding is a switch, 0 until a rule
   exists and then one step of air, the same multiplier the image radius uses.
   Zero specificity on purpose: a stacked list and the article-rail card draw
   their own row rule in a plain class selector, and that has to keep winning. */
:where(.card) {
  border-top: var(--card-rule) solid var(--card-rule-color);
  padding-top: min(calc(var(--card-rule) * 999), var(--space-2));
}
/* --media-radius is local, not a brand token: it exists so the image can
   round concentrically inside whatever radius the card variant carries.
   The lead and film variants raise it; nothing else touches it. */
.card__media {
  --media-radius: var(--radius-card);
  position: relative;
  aspect-ratio: var(--card-ratio);
  overflow: hidden;
  border: var(--card-border-width) solid var(--card-border-color);
  border-radius: var(--media-radius);
  padding: var(--card-media-inset);
  background: var(--sunk);
  background-clip: content-box;
  box-shadow: var(--card-shadow);
}
.card__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  /* No inset means no frame, and with no frame the parent's clip is the
     only one the image needs: a radius here would clip a second time and
     lighten every corner. The multiplier makes this a switch, 0 until an
     inset exists, then the radius that sits concentric inside the frame. */
  border-radius: min(
    calc(var(--media-radius) - var(--card-border-width) - var(--card-media-inset)),
    calc(var(--card-media-inset) * 999)
  );
  filter: var(--media-filter);
}
/* Empty state: no image. A large share of the editorial archive has none. */
.card__media[data-label]:not(:has(img))::after {
  content: attr(data-label);
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: var(--space-2);
  text-align: center;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--text-3);
}
.card__body { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--card-pad); }
/* The anchor wraps media and body, so the card's own gap never reaches
   between them. This is the one place that distance is set. */
.card__media + .card__body { margin-top: var(--card-body-gap); }
.card__title {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: var(--display-weight);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-display);
}
.card__meta {
  font-family: var(--font-ui);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  font-size: var(--text-sm);
  color: var(--text-2);
}
.card__meta > * + *::before { content: "·"; margin-right: var(--space-1); color: var(--text-3); }
/* The title inherits the link hover colour; kicker, meta and dek set their
   own colour and stay put, so only the headline answers the cursor. */

/* ---- Live module. Three states, one visible, driven by data-live on <html>. ---- */
.module-live {
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-card-lg);
  background: var(--raised);
  box-shadow: var(--shadow-1);
}
.module-live [data-state] { display: none; }
html[data-live="countdown"] .module-live [data-state="countdown"],
html[data-live="live"]      .module-live [data-state="live"],
html[data-live="replay"]    .module-live [data-state="replay"] { display: block; }

/* =============================================================
   Step 3: the shared component set
   ============================================================= */

/* ---- Card variants ---- */

/* Row card: media left, text right. Used in stacked lists (variant C, up next). */
.card--row { flex-direction: row; align-items: flex-start; gap: var(--space-2); }
.card--row > a { display: flex; gap: var(--space-2); width: 100%; }
.card--row .card__media { flex: 0 0 38%; }
.card--row .card__body { flex: 1 1 auto; min-width: 0; margin-top: 0; }

/* Lead card: one large item, title at headline size. */
.card--lead .card__title { font-size: var(--text-xl); }
.card--lead .card__media { --media-radius: var(--radius-card-lg); isolation: isolate; }
/* The hero wash. The pseudo-element sits over the photograph and blends into
   it; in brand 0 its opacity is 0 and the image filter equals --media-filter,
   so nothing changes. isolation keeps the blend inside the media box. */
.card--lead .card__media img { filter: var(--hero-media-filter); }
.card--lead .card__media::before {
  content: "";
  position: absolute;
  inset: var(--card-media-inset);
  z-index: 1;
  pointer-events: none;
  border-radius: inherit;
  background-color: var(--hero-wash-color);
  background-image: var(--hero-grain);
  mix-blend-mode: var(--hero-wash-blend);
  opacity: var(--hero-wash-opacity);
}

/* Card duration slot: shown only when the data exists. */
.card__meta [data-duration=""] { display: none; }

/* Article card: kicker, title, dek, date. No image by default,
   because most of the editorial archive has none. */
.card-article .card__title { font-size: var(--text-md); }
.card-article .dek { font-size: var(--text-sm); }
.card-article--rule { padding-top: var(--space-2); border-top: 1px solid var(--border); }

/* ---- Topic tile: image, name, subtopics. Works with no image. ---- */
.tile-topic { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.tile-topic__media {
  position: relative;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--sunk);
}
.tile-topic__media img { width: 100%; height: 100%; object-fit: cover; filter: var(--media-filter); }
.tile-topic__media[data-label]:not(:has(img))::after {
  content: attr(data-label);
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  color: var(--text-3);
}
.tile-topic__name { font-family: var(--font-display); font-size: var(--text-md); font-weight: var(--weight-bold); margin-top: var(--space-1); }
.tile-topic__sub { font-size: var(--text-sm); color: var(--text-2); }

/* Compact topic link row, for the browse-more block. */
.list-topics { display: grid; grid-template-columns: repeat(var(--grid-cols), minmax(0, 1fr)); gap: var(--space-1) var(--space-3); }
.list-topics a {
  display: flex; align-items: center; justify-content: space-between;
  min-height: var(--target);
  padding: var(--space-1) 0;
  border-bottom: 1px solid var(--border);
  font-weight: var(--weight-medium);
}
.list-topics a span { color: var(--text-3); font-size: var(--text-sm); }

/* ---- Show tile: host photograph, show name below. Never a lockup on the image. ---- */
.tile-show { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.tile-show__media {
  position: relative;
  aspect-ratio: 16 / 9;  /* landscape crop from the top: the source portraits carry a lockup low on the chest */
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--sunk);
}
.tile-show__media img { width: 100%; height: 100%; object-fit: cover; object-position: top; filter: var(--media-filter); }
.tile-show__media[data-label]:not(:has(img))::after {
  content: attr(data-label);
  position: absolute; inset: 0;
  display: grid; place-items: center;
  padding: var(--space-2); text-align: center;
  font-size: var(--text-xs); letter-spacing: var(--tracking-kicker); text-transform: uppercase;
  color: var(--text-3);
}
.tile-show__name { font-family: var(--font-display); font-size: var(--text-md); font-weight: var(--weight-bold); margin-top: var(--space-1); }

/* ---- People ---- */
.avatar {
  width: 48px; height: 48px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--sunk);
  border: 1px solid var(--border);
  flex: 0 0 auto;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; filter: var(--media-filter); }
/* Initials, for a byline we hold no photograph for. Better than a broken
   image, and the house rule rules out a stock face. */
.avatar__monogram {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%;
  font-family: var(--font-display); font-size: var(--text-sm);
  font-weight: var(--weight-medium); letter-spacing: var(--tracking-kicker);
  color: var(--text-2);
}
.avatar--lg { width: 72px; height: 72px; }
.avatar--sm { width: 28px; height: 28px; }
/* A chip that carries a face: host and guest tags on the episode page. */
.chip--person { padding-left: var(--space-half); gap: var(--space-1); }
.person { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.person__name { font-weight: var(--weight-medium); }
.person__role { font-size: var(--text-sm); color: var(--text-2); }

/* ---- Live module, complete ---- */
.module-live__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.module-live__title { font-family: var(--font-display); font-size: var(--text-lg); font-weight: var(--weight-bold); line-height: var(--leading-tight); margin-top: var(--space-1); }
.module-live__actions { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-top: var(--space-3); }
.module-live .card { margin-top: var(--space-2); }

.countdown { display: flex; align-items: baseline; gap: var(--space-1); margin-top: var(--space-2); }
.countdown__n { font-family: var(--font-display); font-size: var(--text-2xl); font-weight: var(--weight-bold); line-height: 1; font-variant-numeric: tabular-nums; }
.countdown__unit { font-size: var(--text-sm); color: var(--text-2); }

/* Slim variant: one row, for the homes that don't lead with it. */
.module-live--strip { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); }
.module-live--strip [data-state] { flex: 1 1 auto; }
html[data-live="countdown"] .module-live--strip [data-state="countdown"],
html[data-live="live"]      .module-live--strip [data-state="live"],
html[data-live="replay"]    .module-live--strip [data-state="replay"] { display: flex; align-items: center; gap: var(--space-3); }
.module-live--strip .module-live__title { font-size: var(--text-md); margin: 0; }
.module-live--strip .module-live__title { flex: 1 1 auto; }
.module-live--strip .meta, .module-live--strip .kicker { white-space: nowrap; }
.module-live--strip .module-live__actions { margin: 0 0 0 auto; }
.module-live--strip .countdown { margin: 0; }
.module-live--strip .countdown__n { font-size: var(--text-lg); }

/* ---- Support ask. End of content. Never a header pill. ---- */
.module-ask {
  padding: var(--space-6);
  border: 1px solid var(--border);
  border-radius: var(--radius-card-lg);
  background: var(--raised);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-4);
  align-items: center;
}
.module-ask h2 { font-size: var(--text-xl); }
.module-ask p { margin-top: var(--space-1); color: var(--text-2); max-width: var(--measure); }
.module-ask__actions { display: flex; flex-wrap: wrap; gap: var(--space-1); }

/* ---- Newsletter signup. One field. ---- */
.module-signup {
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-card-lg);
  background: var(--sunk);
}
.module-signup h2 { font-size: var(--text-lg); }
.module-signup p { margin-top: var(--space-1); color: var(--text-2); }
.module-signup form { display: flex; gap: var(--space-1); margin-top: var(--space-3); max-width: 520px; }
.module-signup .input { background: var(--raised); }
.module-signup small { display: block; margin-top: var(--space-1); font-size: var(--text-xs); color: var(--text-3); }

/* ---- Contrast example: copy over the image, Instagram style.
        The one deliberate exception, always labelled. ---- */
.card-overlay { position: relative; overflow: hidden; border-radius: var(--radius-card); aspect-ratio: 4 / 5; background: var(--sunk); border: 1px solid var(--border); }
.card-overlay img { width: 100%; height: 100%; object-fit: cover; filter: var(--media-filter); }
.card-overlay__text {
  position: absolute; inset: auto 0 0 0;
  padding: var(--space-3);
  background: linear-gradient(to top, var(--overlay), transparent);
  color: var(--text-on-image);
}
.card-overlay__text .card__title { color: inherit; }
.card-overlay__text .card__meta { color: inherit; opacity: 0.8; }
.example-label {
  display: inline-block;
  margin-bottom: var(--space-1);
  padding: 2px 8px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--text-2);
}

/* ---- Icon glyphs as text, always with a label beside them ---- */
.glyph { display: inline-block; width: 1em; text-align: center; }

/* =============================================================
   Step 4: weekly schedule table. Retired from A on 2026-09-09 in favour
   of the rotating bar; kept for the specimen and for reference.
   ============================================================= */
.schedule {
  border: 1px solid var(--border);
  border-radius: var(--radius-card-lg);
  background: var(--raised);
  overflow: hidden;
}
.schedule__row {
  display: grid;
  grid-template-columns: 120px minmax(0, 2fr) minmax(0, 2fr) auto;
  gap: var(--space-3);
  align-items: center;
  padding: var(--space-2) var(--space-3);
  min-height: 72px;
}
.schedule__row + .schedule__row { border-top: 1px solid var(--border); }
.schedule__day { font-family: var(--font-display); font-size: var(--text-md); font-weight: var(--weight-bold); }
.schedule__show { font-weight: var(--weight-medium); }
.schedule__host { font-size: var(--text-sm); color: var(--text-2); }
.schedule__time { font-size: var(--text-sm); color: var(--text-2); display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; }
.schedule__actions { display: flex; gap: var(--space-half); }
.schedule__row .badge-live { display: none; }
html[data-live="live"] .schedule__row[data-slot="live"] { background: var(--accent-soft); }
html[data-live="live"] .schedule__row[data-slot="live"] .badge-live { display: inline-flex; }
.schedule__foot { padding: var(--space-2) var(--space-3); border-top: 1px solid var(--border); font-size: var(--text-sm); color: var(--text-2); display: flex; justify-content: space-between; gap: var(--space-2); }

/* =============================================================
   Step 6: byline on cards, descriptive browse-more list
   ============================================================= */
.card__byline { font-size: var(--text-sm); font-weight: var(--weight-medium); }
.list-topics--desc a { flex-direction: column; align-items: flex-start; gap: 2px; padding: var(--space-2) 0; }
.list-topics--desc a span { font-size: var(--text-sm); color: var(--text-2); }

/* =============================================================
   Step 7: player, chapters, tabs panel, transcript, chat, sources
   ============================================================= */

/* ---- Player. Chrome specified here so Ark's default skin never ships. ---- */
.player { border-radius: var(--radius-card-lg); border: 1px solid var(--border); background: var(--raised); overflow: hidden; }
.player__screen { position: relative; aspect-ratio: 16 / 9; background: var(--sunk); }
.player__screen img { width: 100%; height: 100%; object-fit: cover; filter: var(--media-filter); }
.player__play {
  position: absolute; inset: 0; margin: auto;
  width: 96px; height: 96px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--raised);
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-2);
  font-size: var(--text-lg);
}
.player__live { position: absolute; top: var(--space-2); left: var(--space-2); display: none; }
html[data-live="live"] .player__live { display: inline-flex; }

/* Transport is the player's own: scrub bar, play, skip, speed, captions and full
   screen draw inside the frame on hover, so nothing sits under the screen. */

/* ---- Episode header ---- */
/* The head sits one step off the player, closer than a section gap: the
   title belongs to the frame above it. */
.theatre { margin-block-end: var(--theatre-gap); }
.episode__title { font-size: var(--text-2xl); margin-top: var(--space-1); }
.episode__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); margin-top: var(--space-2); font-size: var(--text-sm); color: var(--text-2); }
.episode__meta > * + *::before { content: "\00b7"; margin-right: var(--space-1); color: var(--text-3); }
.episode__people { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); margin-top: var(--space-2); }
.episode__people .kicker { margin-right: var(--space-half); }
/* Actions: three bare share marks, Save as the row's one bordered button, a
   hairline, then the two quiet format buttons. The quiet pair sits on half
   padding so its words fall in the same rhythm as Save's text. The share
   marks butt up: each already holds a 44px target, so a gap between them
   would only spread the row. */
.episode__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); margin-top: var(--space-3); }
.episode__actions .share { gap: 0; }
.episode__actions-rule { width: 1px; height: var(--space-3); background: var(--border); margin-inline: var(--space-1); }
.episode__actions .btn-quiet:not(.btn-icon) { padding-inline: var(--space-1); }
.episode__dek { margin-top: var(--space-3); max-width: var(--measure); color: var(--text-2); }

/* ---- Tabs panel: one panel, three tabs ---- */
.tabs { border: 1px solid var(--border); border-radius: var(--radius-card-lg); background: var(--raised); overflow: hidden; }
.tabs__list { display: flex; border-bottom: 1px solid var(--border); padding: 0 var(--space-2); }
.tabs__list button {
  min-height: 52px; padding: 0 var(--space-2);
  border: 0; border-bottom: 3px solid transparent;
  background: transparent;
  font-size: var(--text-ui); font-weight: var(--weight-medium);
  color: var(--text-2);
  cursor: pointer;
  margin-bottom: -1px;
}
.tabs__list button[aria-selected="true"] { color: var(--text); border-bottom-color: var(--accent); }
.tabs__list button:hover { color: var(--text); }
.tabs__panel { padding: var(--space-3); }
.tabs__panel[hidden] { display: none; }
.tabs__tools { display: flex; flex-wrap: wrap; gap: var(--space-1); align-items: center; margin-bottom: var(--space-3); }
.tabs__tools .input { max-width: 360px; }

/* Transcript: timestamp column that seeks the player. The column scrolls inside
   its own box at --transcript-h so a 49-minute transcript does not push the ask
   off the page; the current paragraph follows playback. */
.transcript { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: var(--space-1) var(--space-2); max-width: var(--measure); max-height: var(--transcript-h); overflow-y: auto; padding-right: var(--space-2); scrollbar-width: thin; align-content: start; }
.transcript__t { font-size: var(--text-sm); color: var(--text-3); font-variant-numeric: tabular-nums; text-decoration: none; padding-top: 2px; }
.transcript__t:hover { color: var(--accent); }
.transcript__h { grid-column: 1 / -1; font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-md); margin-top: var(--space-2); }
.transcript__p { margin: 0 0 var(--space-1); line-height: var(--leading-body); }
.transcript__p.is-current { background: var(--accent-soft); margin-left: calc(-1 * var(--space-1)); padding-left: var(--space-1); border-radius: var(--radius-sm); }
.transcript__note { font-size: var(--text-sm); color: var(--text-3); margin: 0 0 var(--space-2); }
.transcript__slot { padding: var(--space-3); border: 1px dashed var(--border-strong); border-radius: var(--radius-card); color: var(--text-2); font-size: var(--text-sm); }

/* Theatre: the player with the live chat beside it. The chat panel exists only
   while live (gated by .only-live); off air the player runs the full column. */
.theatre { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-3); align-items: stretch; }
html[data-live="live"] .theatre { grid-template-columns: minmax(0, 1fr) var(--chat-w); }

/* Chat panel. The inner wrapper is absolute so the panel takes the player's height
   rather than growing with the feed; the feed scrolls inside its own box. */
.chat-panel { position: relative; min-height: 0; border: 1px solid var(--border); border-radius: var(--radius-card-lg); background: var(--raised); overflow: hidden; }
.chat-panel__inner { position: absolute; inset: 0; display: flex; flex-direction: column; }
.chat-panel__head { display: flex; align-items: center; gap: var(--space-1); padding: var(--space-2); border-bottom: 1px solid var(--border); }
.chat-panel__title { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-md); }
.chat-panel__head .meta { margin-left: auto; font-size: var(--text-xs); color: var(--text-3); }
.chat__feed { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-2); scrollbar-width: thin; }
.chat__feed > :first-child { margin-top: auto; } /* short rooms sit at the bottom, long rooms scroll */
.chat__feed:empty::after { content: "Nobody has said anything yet. Be the first."; margin: auto; font-size: var(--text-sm); color: var(--text-3); text-align: center; }
.chat__msg { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: var(--space-1); align-items: start; font-size: var(--text-sm); line-height: var(--leading-snug); }
.chat__msg p { margin-top: 4px; overflow-wrap: anywhere; }
.chat__avatar { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; background: var(--sunk); border: 1px solid var(--border); font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--text-2); }
.chat__user { font-weight: var(--weight-medium); margin-right: var(--space-half); }
.chat__role { display: inline-block; margin-right: var(--space-half); padding: 1px var(--space-half); border-radius: var(--radius-sm); background: var(--accent-soft); font-size: var(--text-xs); letter-spacing: var(--tracking-kicker); text-transform: uppercase; color: var(--text-2); vertical-align: 1px; }
.chat__msg--host .chat__avatar, .chat__msg--host .chat__role { background: var(--accent); border-color: var(--accent); color: var(--text-on-accent); }
.chat__msg--mod .chat__avatar { border-color: var(--border-strong); }
.chat__composer { display: flex; gap: var(--space-1); align-items: center; padding: var(--space-2) var(--space-2) 0; border-top: 1px solid var(--border); }
.chat__composer .btn { white-space: nowrap; }
/* The field shares the row with the sign-in button, so it runs at meta size on
   half padding: "Message the room" fits at the chat's width. */
.chat__composer .input { flex: 1 1 auto; min-width: 0; font-size: var(--text-sm); padding-inline: var(--space-1); }
.chat__note { font-size: var(--text-xs); color: var(--text-3); padding: var(--space-1) var(--space-2) var(--space-2); }

/* Sources: the fixed component under every video */
.sources { display: flex; flex-direction: column; }
.sources__item { display: grid; grid-template-columns: 120px minmax(0, 1fr) auto; gap: var(--space-2); align-items: center; padding: var(--space-2) 0; border-top: 1px solid var(--border); }
.sources__item:first-child { border-top: 0; }
.sources__type { font-size: var(--text-xs); letter-spacing: var(--tracking-kicker); text-transform: uppercase; color: var(--text-3); }
.sources__title { font-weight: var(--weight-medium); }
.sources__meta { font-size: var(--text-sm); color: var(--text-2); }

/* Page-level state gates */
html:not([data-live="countdown"]) .only-countdown { display: none; }
html[data-live="live"] .not-live { display: none; }
html:not([data-live="live"]) .only-live { display: none; }
html[data-live="replay"] .not-replay { display: none; }
html:not([data-live="replay"]) .only-replay { display: none; }
html:not([data-live="countdown"]) .only-countdown { display: none; }

/* =============================================================
   Direction D additions, plus the rotating schedule bar now used by A
   ============================================================= */

/* ---- Schedule bar. One row that steps through the upcoming shows on a
        dwell timer, with a progress line along its bottom edge. Pauses on hover and focus. Reduced motion
        turns the timer off and leaves the previous and next buttons. ---- */
.module-schedule {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius-card-lg);
  background: var(--raised);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}
.module-schedule__slide {
  display: none;
  align-items: center;
  gap: var(--space-3);
  min-height: 72px;
  padding: var(--space-2) var(--space-3);
}
.module-schedule__slide.is-active { display: flex; }
.module-schedule__kicker { white-space: nowrap; }
.module-schedule__day { font-family: var(--font-display); font-size: var(--text-md); font-weight: var(--weight-bold); white-space: nowrap; min-width: 96px; }
.module-schedule__body { flex: 1 1 auto; min-width: 0; }
.module-schedule__title { font-family: var(--font-display); font-size: var(--text-md); font-weight: var(--weight-bold); line-height: var(--leading-tight); }
/* The show name is the route to the show page, so it carries the ink colour
   of the text around it rather than reading as a stray link. */
.module-schedule__title a { color: inherit; text-decoration: none; }
.module-schedule__when { white-space: nowrap; font-variant-numeric: tabular-nums; }
.module-schedule__when:empty { display: none; }
.module-schedule .module-live__actions { margin: 0; flex-wrap: nowrap; }

/* Step controls sit at the right edge of every slide, outside the slide markup. */
.module-schedule__nav {
  position: absolute;
  inset: 0 var(--space-2) 3px auto;
  display: flex;
  align-items: center;
  gap: var(--space-half);
  font-size: var(--text-xs);
  color: var(--text-3);
}
.module-schedule__nav button {
  width: var(--target); height: var(--target);
  display: grid; place-items: center;
  border: 0; border-radius: var(--radius-button);
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
  transition: background-color var(--hover-duration);
}
.module-schedule__nav button:hover { background: var(--accent-soft); color: var(--text); }
.module-schedule__count { min-width: 40px; text-align: center; font-variant-numeric: tabular-nums; }
.module-schedule--has-nav .module-schedule__slide { padding-right: calc(var(--space-3) + 136px); }

/* Progress line: the bottom edge of the bar fills over one dwell. */
.module-schedule__progress { height: 3px; background: var(--border); }
.module-schedule__progress::before {
  content: "";
  display: block;
  height: 100%;
  width: 0;
  background: var(--accent);
}
.module-schedule.is-running .module-schedule__progress::before { animation: schedule-fill var(--schedule-dwell) linear forwards; }
.module-schedule.is-paused .module-schedule__progress::before { animation-play-state: paused; }
@keyframes schedule-fill { from { width: 0; } to { width: 100%; } }
@media (prefers-reduced-motion: reduce) {
  .module-schedule__progress::before { animation: none; }
}

/* Live: the hero carries the live state, so the bar drops the show that is
   on air and keeps stepping through what comes after. */
html[data-live="live"] .module-schedule__slide[data-live-show] { display: none; }

/* ---- Film card: films and specials at 16:9, fewer across and larger than the
        episode shelf, so the section changes rhythm without cropping the art. ---- */
.grid-films {
  display: grid;
  grid-template-columns: repeat(var(--film-cols), minmax(0, 1fr));
  gap: var(--card-gap);
}
.card--film .card__media { aspect-ratio: var(--film-ratio); --media-radius: var(--radius-card-lg); }

/* ---- Top-anchored crop, for a portrait frame shown in a landscape card. ---- */
.card__media--top img { object-position: top; }

/* ---- Topic row: the topic tile in a direction-set column count. ---- */
.grid-topics {
  display: grid;
  grid-template-columns: repeat(var(--topic-cols), minmax(0, 1fr));
  gap: var(--card-gap);
}

/* ---- Article card with an image and a read time. Both are real: every
        article carries its own featured image and a read time computed from
        the body, so the category placeholders are gone from these cards. ---- */
.card-article--image .card__media { aspect-ratio: var(--card-ratio); }

/* ---- Weekly schedule strip: the week in one line. Label, three day cells,
        the block actions. Directions D and E carry it; D leads with it. The
        live slot is tagged and tints while live. Stays on one line at the
        1120 column; below that the cells wrap, the strip never scrolls. ---- */
.schedule-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-half) var(--space-1);
  min-height: 56px;
  padding: var(--space-half) var(--space-1) var(--space-half) var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--raised);
}
.schedule-strip__label { white-space: nowrap; padding-right: var(--space-2); border-right: 1px solid var(--border); margin-right: var(--space-half); }
.schedule-strip__cell {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--target);
  padding: 0 var(--space-1);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  white-space: nowrap;
  transition: background-color var(--hover-duration);
}
.schedule-strip__cell:hover { background: var(--sunk); }
.schedule-strip__cell:hover .schedule-strip__show { color: var(--link-hover); }
.schedule-strip__day abbr { text-decoration: none; }
.schedule-strip__day { font-size: var(--text-xs); letter-spacing: var(--tracking-kicker); text-transform: uppercase; color: var(--text-3); }
.schedule-strip__show { font-weight: var(--weight-medium); color: var(--text); }
.schedule-strip__time { color: var(--text-2); }
.schedule-strip__actions { margin-left: auto; display: flex; gap: var(--space-half); }
.schedule-strip__actions .btn { min-height: 40px; padding: 0 var(--space-1); font-size: var(--text-sm); }
html[data-live="live"] .schedule-strip__cell[data-slot="live"] { background: var(--accent-soft); }

/* ---- Weekly schedule board: the middle weight, direction D. One frame, a slim
        head row (label, block actions), then three compact cells: full day name,
        show, host, time. About 120px against the strip's 56. ---- */
.schedule-board { border: 1px solid var(--border); border-radius: var(--radius-card); background: var(--raised); overflow: hidden; }
.schedule-board__head { display: flex; align-items: center; gap: var(--space-2); min-height: var(--target); padding: 0 var(--space-1) 0 var(--space-2); border-bottom: 1px solid var(--border); }
.schedule-board__actions { margin-left: auto; display: flex; gap: var(--space-half); }
.schedule-board__actions .btn { min-height: 40px; padding: 0 var(--space-1); font-size: var(--text-sm); }
.schedule-board__cells { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.schedule-board__cell { display: flex; flex-direction: column; gap: var(--space-half); padding: var(--space-2); min-width: 0; transition: background-color var(--hover-duration); }
.schedule-board__cell + .schedule-board__cell { border-left: 1px solid var(--border); }
.schedule-board__cell:hover { background: var(--sunk); }
.schedule-board__cell:hover .schedule-board__show { color: var(--link-hover); }
.schedule-board__day { display: flex; align-items: center; gap: var(--space-1); min-height: 24px; /* the badge row and the plain rows share one height */ font-size: var(--text-xs); letter-spacing: var(--tracking-kicker); text-transform: uppercase; color: var(--text-3); }
.schedule-board__line { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-half) var(--space-1); }
.schedule-board__show { font-family: var(--font-display); font-weight: var(--weight-bold); font-size: var(--text-base); color: var(--text); }
.schedule-board__meta { font-size: var(--text-sm); color: var(--text-2); white-space: nowrap; }
.schedule-board__meta::before { content: "\00B7"; margin-right: var(--space-1); }
html[data-live="live"] .schedule-board__cell[data-slot="live"] { background: var(--accent-soft); }

/* =============================================================
   The latest news bar. D carries it under the episode lead, E above it.
   ============================================================= */

/* ---- News bar. One story, the newest in News, in a framed band: text on the
        left, image on the right and held inside the frame rather than bleeding
        to it, the way Fortune's front page runs its lead. That reads as a
        picture sitting in a band, not two glued halves, and it is the reverse
        of the episode lead so the two stay different things. The title sits one
        step below the episode title, so the video stays the hero.
        Works with no image: the frame shows its label.
        --news-media-inset and --news-media-radius are local, not brand tokens:
        they exist so the strip below can tighten both in one place. ---- */
.module-news {
  --news-media-inset: var(--space-3);
  --news-media-radius: var(--radius-card);
  display: grid;
  grid-template-columns: 3fr 2fr;
  border: 1px solid var(--border);
  border-radius: var(--radius-card-lg);
  background: var(--raised);
  box-shadow: var(--shadow-1);
}
.module-news__body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: var(--space-4);
}
.module-news__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); }
.module-news__head .more { font-size: var(--text-sm); color: var(--text-2); white-space: nowrap; }
.module-news__head .more:hover { color: var(--link-hover); }
.module-news__title { font-size: var(--text-xl); margin-top: var(--space-2); }
.module-news__dek { margin-top: var(--space-2); color: var(--text-2); font-size: var(--text-base); max-width: var(--measure); }
.module-news__body .card__meta { margin-top: var(--space-2); }
.module-news__actions { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-top: var(--space-3); }
.module-news__media {
  position: relative;
  display: block;
  /* Three sides come from the inset; the fourth is the body's own padding, so
     the gap between words and picture stays a step wider than the frame edge.
     No border-left any more: with air on both sides that hairline read as a
     seam. The frame tokens are the card's, so a brand that drops the hairline
     on cards drops it here too. */
  margin: var(--news-media-inset) var(--news-media-inset) var(--news-media-inset) 0;
  overflow: hidden;
  border: var(--card-border-width) solid var(--card-border-color);
  border-radius: var(--news-media-radius);
  background: var(--sunk);
}
/* The frame is never shorter than the card ratio; taller text stretches it and the image covers. */
.module-news__media::before { content: ""; display: block; width: 100%; aspect-ratio: var(--card-ratio); }
.module-news__media img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  filter: var(--media-filter);
}
.module-news__media[data-label]:not(:has(img))::after {
  content: attr(data-label);
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: var(--space-2);
  text-align: center;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--text-3);
}

/* ---- News strip: the same bar at half the height, direction E, where it leads
        the page. Kicker row, headline one step down and clamped to two lines,
        then one foot row with the byline and the video cross-link. The dek and
        the Read the story button are gone: the headline is the link and the
        story page carries the dek. The image is --news-strip-h less its inset,
        at the card ratio, so the band still lands on the weight of D's weekly
        board. Smaller band, so the inset and the radius both step down.
        With no image the column still holds its shape and shows the label. ---- */
.module-news--strip {
  --news-media-inset: var(--space-2);
  --news-media-radius: var(--radius-sm);
  grid-template-columns: minmax(0, 1fr) auto;
  min-height: var(--news-strip-h);
  border-radius: var(--radius-card);
}
.module-news--strip .module-news__body { padding: var(--space-2) var(--space-3); }
.module-news--strip .module-news__title {
  margin-top: var(--space-1);
  font-size: var(--text-lg);
  line-height: var(--leading-tight);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
/* Height first, width from the ratio, so one token still sets the band: the
   image gives back what the inset takes and --news-strip-h stays the band. */
.module-news--strip .module-news__media::before {
  width: auto;
  height: calc(var(--news-strip-h) - var(--news-media-inset) * 2 - var(--card-border-width) * 2);
}
.module-news__foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-half) var(--space-2); margin-top: var(--space-1); }
/* Pull the quiet action out by its own padding so its label lines up with All news. */
.module-news__foot .btn { margin-left: auto; margin-right: calc(var(--space-2) * -1); }


/* ---- Article reading view. Lifted out of the styleguide workbench so there
        is one implementation. The four reading tokens keep the long-form
        column adjustable without moving nav, cards or chips with it. ---- */
.read { max-width: var(--read-measure); }
.read h1 { font-family: var(--font-display); font-size: var(--text-3xl); line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display); margin: 0 0 var(--space-3); }
.read__byline { display: flex; align-items: center; gap: var(--space-2); }
.read p { font-size: var(--read-size); line-height: var(--read-leading); margin: 0 0 var(--para-gap); }
/* No lede treatment. Every paragraph sets the same, Jeremy's call 2026-09-10. */
.read h2 { font-family: var(--font-display); font-size: var(--text-lg); line-height: var(--leading-snug);
  margin: var(--space-6) 0 var(--space-2); }
.read h3 { font-family: var(--font-display); font-size: var(--text-md); line-height: var(--leading-snug);
  margin: var(--space-4) 0 var(--space-1); }
/* Ties with .read p on specificity, so it has to stay below it. */
.read__byline p { margin: 0; }
.read blockquote { margin: var(--space-4) 0; padding-left: var(--space-3);
  border-left: var(--quote-border) solid var(--accent); font-family: var(--font-display);
  font-size: var(--text-md); line-height: var(--leading-snug); color: var(--text); }
.read figure { margin: var(--space-4) 0; }
.read figure img { width: 100%; border-radius: var(--radius-card); filter: var(--media-filter); display: block; }
.read figcaption { font-size: var(--caption-size); color: var(--text-3); margin-top: var(--space-1); }
.read a { color: var(--accent-text); text-decoration: underline; text-underline-offset: 3px; }
/* ---- Article page frame. Head, then body beside a sticky rail. The source
        list and newsletter below keep the full column width, so the page
        reads as article then furniture. ---- */

/* Head: headline, byline and share on the left, the featured image on the
   right. The text column is a flex column the height of the image, so the
   byline and share row sit on the image's bottom edge the way the flush
   lead does on home. */
.read-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) calc((100% - var(--space-6)) / 2 + var(--read-hero-grow));
  gap: var(--space-6);
  align-items: stretch;
  margin-block-end: var(--space-6);
  padding-block-end: var(--space-6);
  border-bottom: 1px solid var(--border);
}
.read-head__text { display: flex; flex-direction: column; min-width: 0; }
.read-head__text > .kicker { margin-bottom: var(--space-1); }
.read-head h1 {
  font-family: var(--font-display);
  font-size: var(--read-title-size);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
  margin: 0;
}
.read-head__foot { margin-top: auto; padding-top: var(--space-4); display: flex; flex-direction: column; gap: var(--space-3); }
.read-head__foot p { margin: 0; }
.read-head figure { margin: 0; min-width: 0; }
.read-head figure img {
  width: 100%; height: 100%;
  aspect-ratio: var(--read-hero-ratio);
  object-fit: cover;
  border-radius: var(--radius-card);
  filter: var(--media-filter);
  display: block;
}
/* No featured image: the slot holds the ratio and names what belongs in it. */
.read-head figure:not(:has(img)) {
  aspect-ratio: var(--read-hero-ratio);
  display: grid; place-items: center;
  border-radius: var(--radius-card);
  background: var(--sunk);
  font-size: var(--text-xs); letter-spacing: var(--tracking-kicker); text-transform: uppercase; color: var(--text-3);
}

/* Share row. The network marks sit bare, the way the watch page draws
   them, under one visible "Share" label for the group: no box, a 44px
   target, the soft fill on hover. Copy link is bare too, underlined so it
   still reads as an action, and stays text because it has to say "Copied". */
.share { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-half); }
.share__label { font-family: var(--font-ui); font-size: var(--text-sm); color: var(--text-3); margin-right: var(--space-half); }
.share__copy { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; padding: 0 var(--space-1); }
.share .btn[data-copied="true"] { background: var(--accent-soft); }

/* The support ask at the foot of the copy, before the sources. The column
   is narrower than the band on home, so the buttons drop under the text. */
.module-ask--stack { grid-template-columns: minmax(0, 1fr); }
.module-ask--stack .module-ask__actions { margin-top: var(--space-2); }

/* Body beside the rail. The copy, the source list and the More-from shelf
   stack in the left column at the reading measure; the rail hugs the right
   edge of the column, in line with the featured image above it, and sticks
   for the full height of that stack, so it is on screen until the
   newsletter. */
.read-layout {
  display: grid;
  grid-template-columns: minmax(0, var(--read-measure)) var(--read-rail-w);
  justify-content: space-between;
  column-gap: var(--space-6);
  align-items: start;
  margin-block-end: var(--section-gap);
}
.read-layout__main { min-width: 0; }
.read-layout__main .read { margin-block-end: var(--section-gap); }
.read-layout__main .section:last-child { margin-block-end: 0; }
.read-rail { position: sticky; top: var(--read-rail-top); }
.read-rail h2 { font-family: var(--font-ui); font-size: var(--text-xs); letter-spacing: var(--tracking-kicker); text-transform: uppercase; color: var(--text-3); font-weight: var(--weight-medium); margin: 0 0 var(--space-1); }
.read-rail .card-article--rule { padding-block: var(--space-2); }
/* The row card stretches its thumbnail to the text height. Three titles of
   different lengths would give three thumbnail heights, so pin the ratio. */
.read-rail .card__media { align-self: flex-start; }
.read-rail .card__title { font-size: var(--text-base); }
/* The rail body is too narrow for date and read time on one line, and a
   wrapped meta left the separator dot stranded at the start of line two.
   Two clean lines instead, no dot. */
.read-rail .card__meta { flex-direction: column; gap: 0; }
.read-rail .card__meta > * + *::before { content: none; }
/* The route to the archive is a full-width button, so the rail ends on a
   call to action rather than a quiet link. */
.read-rail .btn { width: 100%; margin-top: var(--space-3); }

/* ---- Show landing page ---------------------------------------------------
        Hero band, then a two column intro, then the shelves the prototype
        already has. Nothing here is a new card. ---- */

/* Full bleed, outside the container. A fixed-height bar on a dark ground with
   the art centred in it, fading out at both sides so the slice has no hard
   edge. The art is not the hero any more; the name and description are. */
.show-hero {
  height: var(--show-hero-h);
  overflow: hidden;
  background: var(--show-hero-ground);
  display: flex; align-items: center; justify-content: center;
}
.show-hero img {
  width: var(--show-hero-art-w); max-width: 100%; height: 100%;
  object-fit: cover;
  object-position: var(--show-hero-focus);
  filter: var(--media-filter);
  display: block;
  -webkit-mask-image: var(--show-hero-fade);
  mask-image: var(--show-hero-fade);
}
/* No key art yet. The bar holds its height and names what belongs in it. */
.show-hero[data-label]:not(:has(img))::after {
  content: attr(data-label);
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--text-3);
}

/* Centred under the bar: kicker, name, tagline, description at the measure,
   then host, cadence and actions as one centred block. The two column
   version put the metadata beside the measure; with a slim bar the name
   arrives early enough that a centred stack reads faster. */
.show-intro {
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
  gap: var(--show-intro-gap);
  margin-block-end: var(--section-gap);
}
.show-intro__text { max-width: var(--measure); }
.show-intro h1 {
  font-family: var(--font-display);
  font-size: var(--headline-size);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
  margin: 0;
}
.show-intro__tagline {
  font-size: var(--text-md);
  line-height: var(--leading-snug);
  color: var(--text-2);
  margin: var(--space-1) 0 var(--space-3);
}
.show-intro__body { font-size: var(--text-base); line-height: var(--read-leading); margin: 0; }
/* The tagline carries the air under the name. A show with no tagline needs it
   on the paragraph instead. */
.show-intro h1 + .show-intro__body, .show-intro h1 + .show-intro__slot { margin-top: var(--space-3); }
/* A show with no description yet renders a named slot at the size the
   paragraph will be, not filler copy. */
.show-intro__slot {
  padding: var(--space-3);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-card);
  color: var(--text-2);
  font-size: var(--text-sm);
  line-height: var(--read-leading);
}

.show-meta { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); }
.show-meta__rows { display: flex; flex-direction: column; gap: var(--space-half); }
.show-meta__row { font-size: var(--text-sm); color: var(--text-2); }
.show-meta__row--quiet { color: var(--text-3); }
.show-meta__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-1); }

/* ---- Episode badges on the media. Reachable only through the token, so the
        comparison is one attribute on <html> and nothing here forks. ---- */
.card__badges {
  display: var(--badge-on-media);
  position: absolute; inset: var(--space-1) var(--space-1) auto;
  justify-content: space-between;
  gap: var(--space-1);
  pointer-events: none;
}
.card__badge {
  display: inline-flex; align-items: center; gap: var(--space-half);
  padding: var(--space-half) var(--space-1);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-kicker);
  background: var(--accent); color: var(--text-on-accent);
}
/* The duration badge is empty until the CMS carries durations, and an empty
   pill is worse than none. */
.card__badge:empty, .card__badge[data-duration=""] { display: none; }
/* In media mode these move onto the thumbnail rather than printing twice.
   Only cards that carry a badge are marked, so nothing else in the prototype
   changes when the switch is flipped. */
.card__meta [data-duration]:not([data-duration=""]),
.card__meta [data-episode] { display: var(--badge-in-meta); }

/* ---- Running time on a segment. Tucker's highlights chip, bottom left of
        the media, so a clip reads as a short watch beside the full episodes.
        A chip, not artwork: it is UI that moves with the card, so the
        no-text-on-images rule holds. Always on, unlike the episode badges,
        because the number is the point of the row. Digits are tabular. ---- */
.card__duration {
  position: absolute;
  left: calc(var(--card-media-inset) + var(--space-1));
  bottom: calc(var(--card-media-inset) + var(--space-1));
  display: inline-flex; align-items: center; gap: var(--space-half);
  padding: var(--space-half) var(--space-1);
  border-radius: var(--radius-sm);
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: 1.2;
  letter-spacing: var(--tracking-kicker);
  background: var(--chip-media-fill); color: var(--chip-media-ink);
  pointer-events: none;
}
/* A drawn play triangle, so the chip says "watch" without an icon font. */
.card__duration::before {
  content: "";
  width: 0; height: 0;
  border-style: solid;
  border-width: 4px 0 4px 6px;
  border-color: transparent transparent transparent currentColor;
}

/* =============================================================
   The HighWire Protocol: closing statement band.
   A full-bleed band at the foot of the homepage, inverted from the
   page so it reads as a statement rather than another section.

   All copy is The HighWire's own, from /the-highwire-protocol/.
   Nothing here is written on their behalf. Do not embellish it.

   Every value is a token, so this band wears whichever brand
   direction is active. The inversion works in a dark direction too,
   because it swaps positions on the ramp rather than naming colours.
   ============================================================= */

.protocol {
  /* Invert against the page. The --inverse-* tokens read the ramp, not
     fixed colours, so in a dark direction this flips the other way on its
     own. Greyscale's accent fix lives with them in tokens.css. */
  --ground: var(--inverse-ground);
  --raised: var(--inverse-raised);
  --text: var(--inverse-text);
  --text-2: var(--inverse-text-2);
  --text-3: var(--inverse-text-3);
  --border: var(--inverse-border);
  --accent: var(--inverse-accent);
  --accent-text: var(--inverse-accent-text);
  /* --focus reads --accent but was resolved at the root, with the page's
     accent. Re-point it here or the focus ring vanishes in greyscale. */
  --focus: var(--accent);

  background: var(--ground);
  color: var(--text);
  padding-block: var(--space-16) var(--space-12);
  margin-top: var(--space-16);
}
/* The same frame as <main>: the container's gutter outside the direction's
   column, so the band's left edge lines up with the page above it. */
.protocol__inner {
  box-sizing: content-box;
  max-width: min(var(--column), var(--container) - 2 * var(--gutter));
  margin: 0 auto; padding-inline: var(--gutter);
}

.protocol__kicker {
  font-family: var(--font-ui);
  font-size: var(--text-xs); letter-spacing: var(--tracking-kicker);
  text-transform: var(--kicker-transform, uppercase);
  font-weight: var(--kicker-weight, 500);
  color: var(--accent-text, var(--text-3));
}
.protocol__statement {
  font-family: var(--font-display);
  font-weight: var(--display-weight, 700);
  font-size: clamp(2rem, 4.4vw, var(--text-3xl));
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
  max-width: 20ch;
  margin: var(--space-3) 0 var(--space-4);
  text-wrap: balance;
}
.protocol__dek {
  font-size: var(--text-md); line-height: var(--leading-snug);
  color: var(--text-2); max-width: 54ch; margin: 0;
}

/* ---- The wire. Five values strung along a single line, which is
        the logo's own metaphor and the "High Road" language from
        the protocol itself. ---- */
.protocol__wire { margin: var(--space-12) 0 var(--space-8); }
.protocol__line {
  position: relative; height: 1px; background: var(--border);
  margin-bottom: var(--space-6);
}
.protocol__line::after {
  content: ""; position: absolute; inset: 0 auto 0 0;
  width: 100%; height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent) 22%, var(--accent) 78%, transparent);
  opacity: .55;
}
.protocol__values {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--space-4);
}
/* Each value is a size container, so the name below can cap itself at its
   own column's width in any direction, brand or window. */
.protocol__value { position: relative; padding-top: var(--space-4); container-type: inline-size; }
.protocol__value::before {
  content: ""; position: absolute; top: calc(var(--space-6) * -1 - 4px); left: 0;
  width: 9px; height: 9px; border-radius: 999px;
  background: var(--accent); box-shadow: 0 0 0 4px var(--ground);
}
.protocol__num {
  font-family: var(--font-ui);
  font-size: var(--text-xs); letter-spacing: var(--tracking-kicker);
  color: var(--text-3); display: block; margin-bottom: var(--space-half);
}
.protocol__name {
  font-family: var(--font-display); font-weight: var(--display-weight, 700);
  font-size: min(var(--protocol-name-size), var(--protocol-name-fit)); line-height: var(--leading-tight);
  margin: 0 0 var(--space-1);
}
.protocol__gloss { font-size: var(--protocol-body-size); line-height: var(--leading-body); color: var(--text-2); margin: 0; }

/* ---- The checkable promises. This is the part nobody else can copy. ---- */
.protocol__proof {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-6);
  border-top: 1px solid var(--border); padding-top: var(--space-6);
  margin-top: var(--space-8);
}
.protocol__proof h4 {
  font-family: var(--font-display); font-weight: var(--display-weight, 700);
  font-size: var(--text-md); line-height: var(--leading-snug); margin: 0 0 var(--space-1);
}
.protocol__proof p { font-size: var(--protocol-body-size); line-height: var(--leading-body); color: var(--text-2); margin: 0; }

.protocol__foot { margin-top: var(--space-8); display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.protocol__link { font-family: var(--font-ui); color: var(--accent-text); font-size: var(--text-ui); text-underline-offset: 4px; }
.protocol__stamp { font-family: var(--font-ui); font-size: var(--text-xs); color: var(--text-3); }

@media (max-width: 900px) {
  .protocol__values { grid-template-columns: 1fr 1fr; gap: var(--space-6); }
  .protocol__proof { grid-template-columns: 1fr; gap: var(--space-4); }
}
@media (max-width: 560px) {
  .protocol__values { grid-template-columns: 1fr; }
  .protocol__line { display: none; }
  .protocol__value { border-left: 1px solid var(--border); padding-left: var(--space-3); padding-top: 0; }
  .protocol__value::before { top: 4px; left: -5px; }
}
