/* ═══════════════════════════════════════════════════════════════════════════
   CONCALLS — "India's First Live Concall Streaming Platform"
   Namespace: .cp- .

   The page is a broadcast surface, and it is organised the way one reads:
   what time is it (the strip) → what's on air (the cards) → the thing itself
   (the stage) → what's on later (the board). Nothing here invents its own
   palette or typeface: the display serif, the mono figures and the mint/red
   pair all come from common.css, so this file stays theme-agnostic and both
   light and dark keep working.

   One light source. The only glow on the page sits behind the player, because
   the player is the only thing that is actually on. Everything else is flat.
   ═══════════════════════════════════════════════════════════════════════════ */

.concalls-page {
  display: flex; flex-direction: column; gap: 0;
  min-height: calc(100vh - 140px); overflow-x: hidden;
}

/* ── Broadcast strip ───────────────────────────────────────────────────────
   One line: what this is, what time it is, what's on. It replaced a 150px
   centred block (40px glyph + 42px serif title + tagline) that read exactly
   the same whether two calls were on air or nothing was happening all day —
   and pushed the player below the fold on a laptop for the privilege. */
.cp-bar {
  display: flex; align-items: center; gap: 16px;
  padding: 20px 0 14px;
}
.cp-bar-mark { display: inline-flex; align-items: center; gap: 10px; min-width: 0; }
.cp-bar-icon { color: var(--accent); opacity: 0.85; line-height: 0; flex-shrink: 0; }
.cp-bar-title {
  font-family: var(--font-heading); font-size: 27px; font-weight: 800;
  line-height: 1.05; letter-spacing: -0.01em; color: var(--text-primary); margin: 0;
  white-space: nowrap;
}
.cp-bar-title em { font-style: italic; color: var(--accent); }
.cp-bar-rule { flex: 1; height: 1px; background: var(--border); min-width: 12px; }
.cp-bar-meta { display: flex; align-items: center; gap: 16px; flex-shrink: 0; }

/* The clock is the page's heartbeat and the one place tabular figures matter:
   without them the seconds digit shifts the whole string every tick. */
.cp-clock {
  font-family: var(--font-mono); font-size: 12px; font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em; color: var(--text-secondary); white-space: nowrap;
}
.cp-clock span { color: var(--text-tertiary); opacity: 0.7; }

/* Red means on air, and only ever that — the same rule the nav dot follows. */
.cp-onair-pill {
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
  padding: 5px 12px 5px 10px; border-radius: 999px;
  border: 1px solid var(--red-border-vivid); background: var(--red-tint-bg);
  font-size: 11px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--red);
}
/* Nothing on air is still information — the strip says how long until the next
   call rather than going blank or, worse, saying nothing at all. */
.cp-offair-pill {
  font-size: 11.5px; font-weight: 600; color: var(--text-tertiary); white-space: nowrap;
}
.cp-offair-pill b { color: var(--text-secondary); font-weight: 700; font-family: var(--font-mono); }

.cp-bar-claim {
  margin: 0 0 4px; font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-tertiary);
}
.cp-bar-claim span { color: var(--accent); }

/* ── Section heads ─────────────────────────────────────────────────────────
   Serif title, a quiet count, a hairline that runs to the right-hand link.
   The rule is what makes a head read as a head without a box around it. */
.cp-sec { margin-top: 26px; }
.cp-sechead { display: flex; align-items: baseline; gap: 14px; padding-bottom: 12px; }
.cp-sechead h2 {
  font-family: var(--font-heading); font-size: 22px; font-weight: 800;
  line-height: 1; margin: 0; letter-spacing: -0.005em; color: var(--text-primary);
  white-space: nowrap;
}
.cp-sechead-aside {
  font-family: var(--font-mono); font-size: 11.5px; color: var(--text-tertiary); white-space: nowrap;
}
.cp-rule { flex: 1; height: 1px; background: var(--border); min-width: 10px; }
.cp-linkish {
  font-size: 12px; color: var(--text-tertiary); text-decoration: none; white-space: nowrap;
  border-bottom: 1px solid var(--border); padding-bottom: 2px;
  transition: color 0.2s, border-color 0.2s;
}
.cp-linkish:hover { color: var(--accent); border-color: var(--accent-border); }

/* ── On air ────────────────────────────────────────────────────────────────
   Every call streaming right now, visible at once. This replaced a "2 LIVE
   NOW ▾" pill that only revealed its company list on hover — which meant that
   with two calls on air, the second one was in practice invisible. */
.cp-oncards {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 12px;
}

/* Two or more calls on air: a rail you scroll, not a grid that squeezes. Cards
   keep one size at every count, so a third call arriving mid-session doesn't
   silently reflow the two already on screen. Same behaviour on desktop and touch
   — arrows are the desktop affordance, the swipe and the peeking next card are
   the touch one. */
.cp-oncards.is-rail {
  display: flex; gap: 12px;
  overflow-x: auto; overflow-y: visible;
  scroll-snap-type: x proximity; scroll-behavior: smooth;
  scrollbar-width: none; -ms-overflow-style: none;
  overscroll-behavior-x: contain;      /* a swipe past the end doesn't page-navigate */
  -webkit-overflow-scrolling: touch;
  /* overflow-x:auto forces overflow-y to `auto`, which would clip the NOW PLAYING
     pill (it sits half outside the card's top edge) and the 2px hover lift. Pad
     the box out and pull it back with a negative margin: nothing clipped, and the
     row sits exactly where it did before. */
  padding: 14px 0 6px; margin: -14px 0 -6px;
}
.cp-oncards.is-rail::-webkit-scrollbar { display: none; }
.cp-oncards.is-rail .cp-oncard {
  /* A fixed card width is what makes the next one peek — the affordance that says
     "keep going" without any chrome at all. */
  flex: 0 0 clamp(272px, 76vw, 420px); max-width: none; scroll-snap-align: start;
}

/* Arrows live in the section head, beside the rule — the same place the highlights
   column puts its own. Desktop only: on touch the swipe IS the control, and a pair
   of arrows there is a target you hit by accident while scrolling the page. */
.cp-onair-nav { display: flex; gap: 6px; flex-shrink: 0; align-self: center; }
.cp-onair-arrow {
  width: 26px; height: 26px; border-radius: 8px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--card-bg); border: 1px solid var(--border); color: var(--text-tertiary);
  font-size: 15px; line-height: 1; cursor: pointer;
  transition: color 0.2s, border-color 0.2s, background 0.2s, opacity 0.2s;
}
.cp-onair-arrow:hover { border-color: var(--accent-border); color: var(--accent); background: var(--accent-tint-bg); }
.cp-onair-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* At an end the arrow stays in place but stops asking to be pressed — the row
   must not shift sideways every time you reach an edge. */
.cp-onair-arrow.is-off { opacity: 0.3; pointer-events: none; }
/* Set by updateOnAirNav when the rail doesn't overflow — two calls on a wide
   screen already fit, and a control that can't do anything shouldn't be drawn. */
.cp-onair-nav.is-idle { display: none; }
@media (hover: none) {
  .cp-onair-nav { display: none; }
}
/* A single call on air is the common case, and letting its card stretch the full
   1200px left the company name marooned at one end and the NOW PLAYING tab at
   the other, with half a metre of nothing between them. The cap keeps one card
   looking deliberate and still lets two or three share the row. */
.cp-oncard {
  position: relative; display: flex; gap: 14px; align-items: center;
  width: 100%; max-width: 560px; padding: 14px; border-radius: 16px; text-align: left;
  background: var(--card-bg); border: 1px solid var(--border);
  color: inherit; font: inherit; cursor: pointer;
  transition: border-color 0.2s ease, transform 0.2s ease, background 0.2s ease;
}
.cp-oncard:hover { border-color: var(--tint-15); transform: translateY(-2px); }
.cp-oncard:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.cp-oncard[aria-selected="true"] {
  border-color: var(--accent-border-vivid);
  background: linear-gradient(180deg, var(--accent-tint-soft), transparent 60%), var(--card-bg);
  cursor: default;
}
/* The selected card carries the label rather than a second colour: with one
   call on air there is nothing to compare it against, so the tab is what says
   "this is the one playing below". */
.cp-oncard[aria-selected="true"]::after {
  content: "NOW PLAYING"; position: absolute; top: 0; right: 16px;
  transform: translateY(-50%);
  font-size: 9px; font-weight: 800; letter-spacing: 0.14em;
  color: var(--on-accent, #04150f); background: var(--accent);
  padding: 3px 8px; border-radius: 999px;
}
:root[data-theme="light"] .cp-oncard[aria-selected="true"]::after { color: #fff; }

/* The plate is the same wordmark-on-gradient language the player's album art
   uses, at card scale — one visual idea, two sizes. */
/* A rectangle, not a square: tickers run to twelve characters and a 74px square
   could not hold them at any legible size. 96px wide gives every real symbol
   room to set whole (see plateFontSize, which sizes the type to fit). */
.cp-plate {
  width: 96px; height: 74px; flex: none; border-radius: 12px; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  background:
    radial-gradient(circle at 30% 24%, var(--accent-tint-bg), transparent 62%),
    linear-gradient(150deg, var(--bg-elevated), var(--card-bg));
  border: 1px solid var(--border); padding: 0 6px;
}
.cp-plate-tick {
  font-family: var(--font-heading); font-weight: 800; line-height: 1;
  color: var(--accent); letter-spacing: 0.01em; max-width: 100%;
  white-space: nowrap; text-align: center;
}

/* The equaliser is the page's second piece of persistent motion after the live
   dot, and it means exactly one thing: audio is flowing. */
.cp-eq { display: flex; align-items: flex-end; gap: 2px; height: 14px; }
.cp-eq i { width: 2px; height: 20%; border-radius: 1px; background: var(--accent); opacity: 0.75; animation: cpBob 1.1s ease-in-out infinite; }
.cp-eq i:nth-child(1) { animation-delay: -0.10s; animation-duration: 1.00s; }
.cp-eq i:nth-child(2) { animation-delay: -0.55s; animation-duration: 1.30s; }
.cp-eq i:nth-child(3) { animation-delay: -0.28s; animation-duration: 0.90s; }
.cp-eq i:nth-child(4) { animation-delay: -0.80s; animation-duration: 1.15s; }
.cp-eq i:nth-child(5) { animation-delay: -0.04s; animation-duration: 1.45s; }
.cp-eq i:nth-child(6) { animation-delay: -0.62s; animation-duration: 0.95s; }
.cp-eq i:nth-child(7) { animation-delay: -0.36s; animation-duration: 1.25s; }
.cp-eq i:nth-child(8) { animation-delay: -0.90s; animation-duration: 1.05s; }
.cp-eq i:nth-child(9) { animation-delay: -0.20s; animation-duration: 1.35s; }
@keyframes cpBob { 0%, 100% { height: 18%; } 50% { height: 100%; } }

.cp-oncard-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.cp-oncard-name {
  font-size: 15px; font-weight: 700; letter-spacing: -0.01em; color: var(--text-primary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cp-oncard-sub { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
.cp-oncard-stats {
  display: flex; flex-wrap: wrap; gap: 12px; margin-top: 9px;
  font-family: var(--font-mono); font-size: 11px; color: var(--text-tertiary);
}
.cp-oncard-stats b { color: var(--text-secondary); font-weight: 600; }
.cp-oncard-stats span:empty { display: none; }

@media (prefers-reduced-motion: reduce) {
  .cp-eq i { animation: none; height: 55%; }
  .cp-oncard { transition: none; }
  .cp-oncard:hover { transform: none; }
}

/* ── The stage: highlights → player → chat ─────────────────────────────────
   Not three equal columns. The player is the event; the two side panels are
   what surrounds it. Equal thirds read as three peers and left the centre —
   the only column with a control in it — looking like the emptiest one. */
.cp-hero-section { margin-top: 18px; margin-bottom: 8px; }
.cp-hero {
  --cp-hero-h: 560px;
  display: grid; grid-template-columns: 320px minmax(0, 1fr) 320px;
  gap: 16px; align-items: stretch;
}
.cp-hero.is-upcoming { --cp-hero-h: 396px; }
.cp-hero-player { position: relative; min-width: 0; display: flex; flex-direction: column; gap: 8px; }

/* The player is the event, so it is the one object on the page that is lit —
   a soft accent lift beneath the card. The glow itself lives INSIDE the frame
   (live-player.css, .lv-shell-embed): an iframe paints its own opaque page, so
   anything drawn behind it is simply invisible. The frame's background matches
   the side panels exactly for the same reason — before this the centre column
   rendered a shade darker than everything around it, which made the one thing
   that was actually on look like the flattest box in the row. */
.cp-hero-frame {
  position: relative; z-index: 1;
  width: 100%; height: var(--cp-hero-h); border: 1px solid var(--border); border-radius: 16px;
  background: var(--card-bg);
  box-shadow: 0 26px 60px -34px var(--accent-tint-20);
}
.cp-hero:not(.is-upcoming) .cp-hero-frame { border-color: var(--accent-border-soft); }

@media (min-width: 901px) {
  /* A compact shared column height so the whole stage — on-air row included —
     fits in view on load. The highlights column keeps its box and scrolls as
     newer 15-min cards stack on top; the chat matches it. */
  .cp-hero:not(.is-upcoming) { --cp-hero-h: 452px; }
}
@media (max-width: 1240px) { .cp-hero { grid-template-columns: 284px minmax(0, 1fr) 284px; } }
@media (max-width: 1080px) { .cp-hero { grid-template-columns: 250px minmax(0, 1fr) 250px; gap: 12px; } }

/* Hero pager — only rendered for 2+ calls clashing at the same upcoming slot.
   Live calls no longer need it: the On air row shows every one of them. */
.cp-hero-nav {
  display: flex; align-items: center; justify-content: flex-end; gap: 10px;
  margin-bottom: 10px;
}
.cp-hero-nav-count {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--accent);
}
.cp-hero-nav-arrow {
  display: flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--bg-elevated);
  color: var(--text-secondary); cursor: pointer; font-size: 15px; line-height: 1;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.cp-hero-nav-arrow:hover { border-color: var(--accent-border); color: var(--accent); background: var(--accent-tint-bg); }

/* ── Panels (highlights + chat) ─────────────────────────────────────────── */
.cp-hl-col {
  min-width: 0; height: var(--cp-hero-h); overflow-y: auto;
  border: 1px solid var(--border); border-radius: 16px; background: var(--card-bg);
  scrollbar-width: thin;
}
/* A long summary guillotined mid-word at the column's bottom edge reads as
   broken rather than scrollable; fading the last 40px says "there's more"
   in the same gesture. Desktop only — below 900px this column stops being a
   scroller and becomes a plain stack. */
@media (min-width: 901px) {
  .cp-hl-col {
    -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 40px), transparent 100%);
    mask-image: linear-gradient(to bottom, #000 calc(100% - 40px), transparent 100%);
  }
}
/* One header shape for both side panels: a live dot, an uppercase label, and a
   mono count on the right. They are peers, so they look like peers. */
.cp-hl-col-head, .cp-chat-head {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 15px; border-bottom: 1px solid var(--border);
}
.cp-hl-col-head { position: sticky; top: 0; z-index: 2; background: var(--card-bg); margin-bottom: 12px; }
.cp-hl-col-title, .cp-chat-title {
  display: inline-flex; align-items: center; gap: 8px; flex: 1; min-width: 0;
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--text-secondary);
}
.cp-hl-col-dot {
  width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;
  background: var(--accent); box-shadow: 0 0 6px var(--accent);
}
.cp-panel-count, .cp-chat-viewers {
  font-family: var(--font-mono); font-size: 11px; color: var(--text-tertiary);
  white-space: nowrap; flex-shrink: 0;
}
.cp-panel-count:empty { display: none; }

/* Carousel arrows — hidden on desktop (the column scrolls); shown on mobile. */
.cp-hl-nav { display: none; gap: 6px; flex-shrink: 0; }
.cp-hl-arrow {
  display: flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--bg-elevated);
  color: var(--text-secondary); cursor: pointer; font-size: 15px; line-height: 1;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.cp-hl-arrow:hover { border-color: var(--accent-border); color: var(--accent); background: var(--accent-tint-bg); }

.cp-hl-cards { display: flex; flex-direction: column; gap: 10px; padding: 0 15px 16px; }
.cp-hl-card {
  border: 1px solid var(--border); border-radius: 12px; padding: 12px;
  background: var(--bg-elevated);
  animation: cpSlideIn 0.45s cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
@keyframes cpSlideIn { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .cp-hl-card { animation: none; } }
/* The last-quarter card is context, not the headline: one accent rule on the
   leading edge marks it as the anchor without competing with the hero. */
.cp-hl-card.is-summary {
  border-color: var(--border); background: var(--bg-elevated);
  border-left: 2px solid var(--accent-border);
}
.cp-hl-card-head { margin-bottom: 8px; }
/* The window chip is the card's timestamp — mono, tinted, and unmistakably a
   time rather than a title. It is what lets you read the column as a record of
   when things were said. */
.cp-hl-card-win {
  display: inline-block;
  font-family: var(--font-mono); font-size: 10px; font-weight: 500;
  letter-spacing: 0.05em; color: var(--accent);
  background: var(--accent-tint); padding: 2px 7px; border-radius: 5px;
}
.cp-hl-card.is-summary .cp-hl-card-win { color: var(--accent); }
.cp-hl-card-body { font-size: 12.5px; color: var(--text-primary); line-height: 1.55; }
.cp-hl-card-body strong, .cp-hl-card-body b { color: var(--text-primary); font-weight: 700; }
.cp-hl-card-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 10px; }
.cp-hl-tag {
  font-size: 10px; font-weight: 600; color: var(--text-secondary);
  background: transparent; border: 1px solid var(--border);
  padding: 3px 8px; border-radius: 999px;
}
/* Guidance block on a live highlight card — the single highest-value extract, set
   apart with an accent rail. The "live" tag flags it as from the real-time transcript
   (provisional) until the verified post-call version lands. */
.cp-hl-guidance {
  margin-top: 10px; padding: 8px 10px; border-left: 2px solid var(--accent);
  background: var(--accent-tint-bg); border-radius: 0 6px 6px 0;
}
.cp-hl-guidance-head {
  font-size: 10px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 4px;
}
.cp-hl-guidance-live {
  margin-left: 4px; font-size: 8.5px; font-weight: 700; letter-spacing: 0.03em;
  color: #fff; background: var(--accent); border-radius: 3px; padding: 1px 4px; vertical-align: 1px;
}
.cp-hl-guidance-list { margin: 0; padding-left: 16px; list-style: disc; }
.cp-hl-guidance-list li { font-size: 12px; color: var(--text-primary); line-height: 1.5; margin: 2px 0; }
.cp-hl-guidance-meta { color: var(--text-secondary, #888); font-weight: 400; }
/* Pre-live "what they promised" list — verbatim last-call commitments. */
.cp-hl-promises { margin: 0; padding-left: 16px; list-style: disc; }
.cp-hl-promises li { font-size: 12.5px; color: var(--text-primary); line-height: 1.5; margin: 4px 0; }
.cp-hl-empty { font-size: 12px; color: var(--text-tertiary); text-align: center; padding: 20px 0; }
.cp-hl-card-ghost {
  display: flex; align-items: center; justify-content: center; text-align: center;
  min-height: 88px; color: var(--text-tertiary); font-size: 12.5px; line-height: 1.5;
  animation: none;
}

/* ── Live chat ─────────────────────────────────────────────────────────── */
.cp-chat {
  min-width: 0; display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: 16px; background: var(--card-bg);
  height: var(--cp-hero-h); overflow: hidden;
}
.cp-chat-head { flex-shrink: 0; }
.cp-chat-msgs {
  flex: 1; min-height: 0; overflow-y: auto; padding: 12px 15px; display: flex; flex-direction: column; gap: 12px;
  scrollbar-width: thin;
}
/* Messages sit on the composer, the way every chat anyone has ever used works.
   An auto-margin pseudo-element does it without justify-content: flex-end,
   which clips the top of the list once it overflows in some browsers. */
.cp-chat-msgs::before { content: ""; margin-top: auto; }
.cp-chat-loading { color: var(--text-tertiary); font-size: 12px; text-align: center; margin: auto; }
/* An empty room reads as a broken feature unless it invites something. */
.cp-chat-empty {
  margin: auto; text-align: center; max-width: 230px;
  color: var(--text-tertiary); font-size: 12.5px; line-height: 1.6;
}
.cp-chat-empty b {
  display: block; color: var(--text-secondary); font-weight: 700;
  margin-bottom: 5px; font-size: 13px;
}
.cp-chat-row { display: flex; flex-direction: column; gap: 3px; position: relative; }
.cp-chat-author { font-size: 11px; font-weight: 700; color: var(--text-tertiary); }
.cp-chat-text {
  font-size: 12.5px; color: var(--text-primary); line-height: 1.5; word-break: break-word;
}
.cp-chat-report {
  position: absolute; right: 0; top: 0; border: none; background: transparent;
  color: var(--text-tertiary); font-size: 10px; cursor: pointer; opacity: 0;
  transition: opacity 0.15s; padding: 2px;
}
.cp-chat-row:hover .cp-chat-report { opacity: 0.6; }
.cp-chat-report:hover { opacity: 1 !important; color: var(--red); }
/* AI analyst notes — set apart from investor chatter with an accent rail + badge
   so they read as the house voice, never a human. */
.cp-chat-row-ai {
  padding: 8px 10px; border-radius: 8px; border-left: 2px solid var(--accent);
  background: var(--accent-tint-bg);
}
.cp-chat-row-ai .cp-chat-author { color: var(--accent); }
.cp-chat-ai-badge {
  margin-left: 6px; padding: 1px 5px; border-radius: 4px; font-size: 9px;
  font-weight: 700; letter-spacing: 0.04em; color: #fff; background: var(--accent);
  vertical-align: middle;
}
.cp-chat-blocked {
  margin: 0 15px 8px; padding: 7px 10px; border-radius: 8px;
  background: var(--red-tint-badge); border: 1px solid var(--red-tint);
  color: var(--red); font-size: 11px; line-height: 1.4;
}
.cp-chat-composer {
  display: flex; gap: 8px; padding: 11px 15px 0; flex-shrink: 0;
}
.cp-chat-input {
  flex: 1; min-width: 0; padding: 10px 11px; border-radius: 9px;
  border: 1px solid var(--border); background: var(--bg-elevated);
  color: var(--text-primary); font-family: inherit; font-size: 12.5px;
  transition: border-color 0.15s;
}
.cp-chat-input:focus { border-color: var(--accent-border-vivid); outline: none; }
.cp-chat-input:disabled { opacity: 0.5; }
.cp-chat-send {
  padding: 8px 15px; border: none; border-radius: 9px; background: var(--accent);
  color: var(--on-accent, #04150f); font-weight: 700; font-size: 12.5px; cursor: pointer; flex-shrink: 0;
  transition: filter 0.15s;
}
:root[data-theme="light"] .cp-chat-send { color: #fff; }
.cp-chat-send:hover:not(:disabled) { filter: brightness(1.08); }
.cp-chat-send:disabled { opacity: 0.5; cursor: not-allowed; }
.cp-chat-disclaimer {
  padding: 9px 15px 12px; font-size: 10px; color: var(--text-tertiary); line-height: 1.45;
}
.cp-chat-close {
  display: none; background: none; border: none; color: var(--text-tertiary);
  font-size: 15px; line-height: 1; cursor: pointer; padding: 2px 4px;
}
.cp-chat-close:hover { color: var(--text-primary); }
.cp-chat-fab, .cp-chat-backdrop, .cp-chat-trigger { display: none; }

/* ── Pre-live side panel ──────────────────────────────────────────────────
   The third stage column BEFORE a call starts, where the live chat sits once
   it's on air. Same shell as .cp-chat so the stage doesn't visibly reflow at
   the moment the call goes live — only the contents swap. */
.cp-side {
  min-width: 0; display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: 16px; background: var(--card-bg);
  height: var(--cp-hero-h); overflow: hidden;
}
.cp-side-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 13px 15px; border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.cp-side-title {
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--text-secondary);
}
.cp-side-body {
  flex: 1; overflow-y: auto; padding: 15px; display: flex; flex-direction: column; gap: 18px;
  scrollbar-width: thin;
}
.cp-side-block { display: flex; flex-direction: column; gap: 8px; }
.cp-side-label {
  font-size: 10px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-tertiary);
}
.cp-side-cta {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; padding: 11px 14px; border: none; border-radius: 10px;
  background: var(--accent); color: var(--on-accent, #04150f); font-family: inherit;
  font-size: 13px; font-weight: 800; cursor: pointer;
  transition: filter 0.15s ease, transform 0.15s ease;
}
:root[data-theme="light"] .cp-side-cta { color: #fff; }
.cp-side-cta:hover:not(:disabled) { filter: brightness(1.08); transform: translateY(-1px); }
.cp-side-cta:disabled { opacity: 0.6; cursor: not-allowed; }
/* Already subscribed: a settled, quiet confirmation — deliberately NOT a button.
   Re-pressing would toggle the subscription off, which is the one outcome
   someone who asked to be notified can't want. */
.cp-side-done {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 11px 12px; border-radius: 10px;
  background: var(--accent-tint-bg); border: 1px solid var(--accent-border);
  color: var(--accent); font-size: 12.5px; font-weight: 600; line-height: 1.45;
}
.cp-side-note { font-size: 11.5px; color: var(--text-tertiary); line-height: 1.5; }
.cp-side-err {
  padding: 7px 10px; border-radius: 8px;
  background: var(--red-tint-badge); border: 1px solid var(--red-tint);
  color: var(--red); font-size: 11px; line-height: 1.4;
}
/* Each bullet is one verbatim commitment from last call's guidance — a short
   checklist to hold this call against, not prose to read through. */
.cp-side-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.cp-side-list li {
  position: relative; padding-left: 15px;
  font-size: 12.5px; color: var(--text-primary); line-height: 1.5;
}
.cp-side-list li::before {
  content: ''; position: absolute; left: 0; top: 8px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--accent); opacity: 0.75;
}
.cp-side-list li strong { color: var(--accent); font-weight: 700; }

/* ── Up next: the departures board ─────────────────────────────────────────
   A schedule is read down a column of times, so it is laid out as one. This
   replaced a row of five 16:10 tiles whose entire artwork was a ticker set in
   green serif: five large rectangles carrying one word each, and no way to
   compare two calls without reading left to right. The board fits six columns
   of real information in the same width and carries its own reminder control,
   so setting one never costs you your place. */
.cp-board { border-top: 1px solid var(--border); }
.cp-board-row {
  position: relative; display: grid;
  grid-template-columns: 86px 108px minmax(0, 1fr) 90px 104px 40px;
  align-items: center; gap: 14px;
  padding: 13px 8px; border-bottom: 1px solid var(--border);
  color: inherit;
  transition: background 0.18s ease;
}
.cp-board-row:hover { background: var(--tint-2); }
/* Stretched link: the anchor sits on the company name (so its accessible name
   is the company, and focus order is sane) but its ::after covers the whole
   row, which is what makes the entire row clickable without wrapping a button
   inside an anchor. The bell is lifted onto its own layer so it stays pressable. */
.cp-b-name a { color: inherit; text-decoration: none; }
.cp-b-name a::after { content: ""; position: absolute; inset: 0; }
.cp-b-name a:focus-visible::after { outline: 2px solid var(--accent); outline-offset: -3px; border-radius: 6px; }
.cp-bell { position: relative; z-index: 1; }
.cp-board-head { padding: 10px 8px; border-bottom: 1px solid var(--border); }
.cp-board-head > * {
  font-size: 9.5px; font-weight: 800; letter-spacing: 0.15em; text-transform: uppercase;
  color: var(--text-tertiary);
}
.cp-day-sep { display: flex; align-items: center; gap: 14px; padding: 20px 8px 9px; }
.cp-day-lbl {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--text-secondary); white-space: nowrap;
}
.cp-b-time {
  font-family: var(--font-mono); font-size: 14px; font-variant-numeric: tabular-nums;
  color: var(--text-primary); letter-spacing: 0.01em; white-space: nowrap;
}
.cp-b-tick {
  font-family: var(--font-heading); font-weight: 800; font-size: 14px; color: var(--accent);
  letter-spacing: 0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cp-b-name {
  font-size: 13.5px; font-weight: 500; color: var(--text-primary); letter-spacing: -0.005em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cp-b-call { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-tertiary); white-space: nowrap; }
.cp-b-status {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.02em;
  color: var(--text-tertiary); white-space: nowrap;
}
/* Amber, not red: red on this page means a call is on air, and a call that has
   not started is not on air. */
.cp-b-status.is-soon { color: var(--amber); }
.cp-bell {
  display: grid; place-items: center; width: 32px; height: 32px; padding: 0;
  border-radius: 50%; border: 1px solid var(--border); background: transparent;
  color: var(--text-tertiary); cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.cp-bell:hover { color: var(--text-primary); border-color: var(--tint-15); }
.cp-bell[aria-pressed="true"] {
  color: var(--accent); border-color: var(--accent-border-vivid); background: var(--accent-tint);
}
.cp-bell.is-busy { opacity: 0.45; cursor: progress; }
.cp-board-empty {
  padding: 40px 0; text-align: center; color: var(--text-tertiary); font-size: 13px;
  border: 1px solid var(--border); border-radius: 16px; background: var(--card-bg);
}

/* ── Mobile ────────────────────────────────────────────────────────────────
   Player first — the one thing that must be immediately visible — then the
   highlights stack. Chat leaves the flow entirely and becomes a bottom sheet. */
@media (max-width: 900px) {
  .cp-bar { flex-wrap: wrap; gap: 10px 14px; padding: 16px 0 10px; }
  .cp-bar-rule { display: none; }
  .cp-bar-mark { flex: 1; }
  .cp-bar-title { font-size: 23px; }
  .cp-bar-meta { width: 100%; gap: 12px; }
  .cp-sechead h2 { font-size: 19px; }
  .cp-sec { margin-top: 20px; }

  .cp-hero { display: flex; flex-direction: column; gap: 12px; }
  .cp-hero-player { order: 1; }
  .cp-hl-col { order: 2; }
  .cp-hero { --cp-hero-h: 420px; }
  .cp-hero.is-upcoming { --cp-hero-h: 340px; }

  /* Highlights become a plain full-width stack — the SAME card size as
     everywhere else, so the page reads as one column of identical cards. */
  .cp-hl-col {
    height: auto; overflow: visible; border: none; background: transparent; padding: 0;
  }
  .cp-hl-col-head { padding: 0 0 10px; margin-bottom: 0; border-bottom: none; position: static; background: transparent; }
  .cp-hl-nav { display: none; }
  .cp-hl-cards { gap: 12px; padding: 0; }

  /* The pre-live panel stays INLINE on phones — it's short, read once, and has
     no incoming stream to stay open for. */
  .cp-side { order: 3; height: auto; }
  .cp-side-body { overflow: visible; }

  /* Inline chat → floating bottom sheet. The element stays in the DOM (SSE keeps
     appending into #cp-chat-msgs while it's hidden); only a class toggles it up. */
  .cp-chat {
    /* Anchored to the VISUAL viewport, not the layout viewport: when the soft keyboard
       opens it shrinks the visible area, so bottom:var(--cp-kb) lifts the sheet above the
       keyboard and the height caps to what's actually visible — otherwise the composer
       (input + Send) slid under the keyboard, off-screen. JS keeps the vars in sync (see
       bindChatViewport); with no keyboard both resolve to the full-height default. */
    position: fixed; left: 0; right: 0; bottom: var(--cp-kb, 0px); z-index: 330;
    height: min(72dvh, calc(var(--cp-vvh, 100dvh) - 8px)); border-radius: 18px 18px 0 0;
    transform: translateY(105%); transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
    box-shadow: 0 -18px 44px -20px rgba(0, 0, 0, 0.7);
  }
  .concalls-page.cp-chat-open .cp-chat { transform: translateY(0); }
  .cp-chat-close { display: block; }
  .cp-chat-backdrop {
    display: block; position: fixed; inset: 0; z-index: 320;
    background: rgba(0, 0, 0, 0.5); opacity: 0; visibility: hidden;
    transition: opacity 0.28s ease, visibility 0.28s;
  }
  .concalls-page.cp-chat-open .cp-chat-backdrop { opacity: 1; visibility: visible; }
  body.cp-chat-lock { overflow: hidden; }

  /* Live-chat entry, anchored under the player. A calm card, not another loud
     accent pill — the page already carries enough red. */
  .cp-chat-trigger {
    display: flex; align-items: center; gap: 9px; width: 100%;
    margin-top: 2px; padding: 12px 15px; border-radius: 12px;
    border: 1px solid var(--border); background: var(--card-bg);
    color: var(--text-primary); font-weight: 700; font-size: 13px;
    cursor: pointer; transition: border-color 0.15s ease, background 0.15s ease;
  }
  .cp-chat-trigger:hover { border-color: var(--accent-border); }
  .cp-chat-trigger:active { transform: scale(0.99); }
  .cp-chat-trigger-hint { margin-left: auto; color: var(--accent); font-weight: 600; font-size: 12px; }

  /* Drop the two narrowest board columns first: the quarter is the same for
     nearly every row in a results week, and the status is carried by the time. */
  .cp-board-row { grid-template-columns: 78px 96px minmax(0, 1fr) 96px 36px; gap: 12px; }
  .cp-board-row .cp-b-call, .cp-board-head > :nth-child(4) { display: none; }
}

@media (max-width: 640px) {
  .cp-bar-title { font-size: 21px; }
  .cp-bar-claim { font-size: 9.5px; letter-spacing: 0.1em; }
  .cp-sechead { gap: 10px; }
  .cp-sechead h2 { font-size: 18px; }
  .cp-oncards:not(.is-rail) { grid-template-columns: 1fr; }
  /* Time and company are what a thumb scans; the ticker and the status are
     both derivable from the row you tap into. */
  .cp-board-row { grid-template-columns: 66px minmax(0, 1fr) 36px; gap: 10px; padding: 12px 4px; }
  .cp-board-row .cp-b-tick, .cp-board-row .cp-b-status,
  .cp-board-head > :nth-child(2), .cp-board-head > :nth-child(5) { display: none; }
  .cp-day-sep { padding: 18px 4px 8px; }
  .cp-b-time { font-size: 13px; }
}
