/* Stage layout v2: 3-column pitch layout (nav | content | rating) with
   a single active "stage" section in the center, prev/next stage
   navigation, and a fixed bottom CTA bar that is always visible.

   v2 (2026-06-08):
   - Page-chrome band lives OUTSIDE the 3-column grid (title only)
   - The right aside is the home of HonestScore, byline, audience,
     countdown, vote widget, and the Report link
   - The CTA bar is renamed (.pitch-cta-center) and contains only
     the primary CTA — the Report link has moved
   - Archived / test-listing pitches tint the full page via body class
   - The legacy mobile-rating-toggle is removed */

.pitch-page--stage {
  max-width: none;
  width: 100%;
  /* Reserve bottom padding so the fixed CTA bar never covers
     pitch content. The bar is ~5rem tall; add a little more for
     breathing room. */
  padding-bottom: 7rem;
}

.pitch-page--stage .pitch-main {
  max-width: none;
  width: 100%;
  padding-left: 1rem;
  padding-right: 1rem;
}

/* ─── Page-chrome band (sits OUTSIDE the 3-column grid) ─────────────
   v3 (2026-06-09): the h1.pitch-title moved out of .pitch-chrome
   into .pitch-toolbar. The chrome band now hosts only the top-of-
   page status strips (archived / test-listing). The .pitch-title
   rule below scopes to the toolbar; the chrome block keeps its
   centering padding so the strips align with the rest of the
   centered 1200px content column. */
.pitch-chrome {
  max-width: 1200px;
  margin: 0 auto;
  padding: 1.5rem 1rem 0;
}

/* ─── Toolbar-hosted h1 (v3) ────────────────────────────────────────
   Stage-specific override on top of the .pitch-toolbar .pitch-title
   base in pitch-mockup.css. Slightly larger so it reads as a hero
   element even in the slim 52px toolbar row, and tighter letter-
   spacing to fit long titles like "Founding Pitcher: throw in $1,
   lock permanent pitch economics before launch" without truncation
   on a 1200px-wide content area. */
.pitch-toolbar .pitch-title {
  font-size: clamp(1.125rem, 1.8vw, 1.375rem);
  font-weight: 800;
  letter-spacing: -0.02em;
}

/* ─── Top-of-page banner strips (inside .pitch-chrome) ────────────── */
/* Shared base for any top-of-page strip (.pitch-archived-strip,
   .pitch-test-strip). Concrete color variants come below. */

.pitch-archived-strip {
  background: #b45309;
}


/* ─── Page-level tints driven by body class ───────────────────────── */
body.pitch-archived {
  background: #fef3c7; /* amber wash, full page */
}

body.pitch-test-listing {
  background: #f9fafb; /* soft gray wash, full page */
}

/* ─── HonestScore: enlarged + ring-on-left (prototype shape) ────── */
.honestscore-hero {
  /* v2 (rating overhaul 2026-06-08): the prototype puts the
     ring on the LEFT and the meta block on the RIGHT, so the
     eye lands on the score first and reads the proof copy
     second. The previous centered variant (ring stacked above
     the meta) is kept as a fallback for narrow viewports via
     the @media rule below. */
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 1.25rem;
  padding: 1.25rem 1rem;
  border: 1px solid var(--hp-border);
  border-radius: 16px;
  background: var(--hp-surface, transparent);
  margin-bottom: 1.25rem;
}

.honestscore-ring {
  min-width: 7.5rem;
  min-height: 7.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border: 3px solid var(--hp-score-green, #34d399);
  border-radius: 50%;
  padding: 0.5rem;
  box-shadow: 0 0 24px rgba(52, 211, 153, 0.18);
}

.honestscore-value {
  font-size: 3rem;
  font-weight: 900;
  line-height: 1;
  color: var(--hp-score-green, #34d399);
  font-variant-numeric: tabular-nums;
}

.honestscore-label {
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-top: 0.15rem;
  color: var(--hp-text-muted, #6b7280);
}

.honestscore-meta {
  min-width: 0;
}

.honestscore-kicker {
  margin: 0 0 0.25rem;
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--hp-text-muted, #6b7280);
}

.honestscore-blurb {
  margin: 0 0 0.5rem;
  font-size: 0.875rem;
  line-height: 1.4;
  color: var(--hp-text, #111827);
}

.honestscore-stats {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--hp-text-muted, #6b7280);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.375rem;
}
.honestscore-stats strong {
  color: var(--hp-text, #111827);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.honestscore-stats-sep {
  opacity: 0.5;
}
.honestscore-hpcode {
  font-family: var(--hp-mono, ui-monospace, monospace);
  font-size: 0.75rem;
  background: var(--hp-surface-muted, #f3f4f6);
  border: 1px solid var(--hp-border, #e5e7eb);
  border-radius: 4px;
  padding: 0 0.25rem;
}

/* v2 (rating rebuild 2026-06-12): the "of 5" ceiling label
   sits inside the ring, below the value, so the eye reads the
   score and its max as one block. */
.honestscore-scale {
  font-size: 0.625rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--hp-text-muted, #6b7280);
  margin-top: 0.125rem;
}

/* v2: 5-face visual ladder — one face per dim, the
   active face is highlighted when its value matches the
   rounded HonestScore. */
.honestscore-faces {
  display: flex;
  /* Center the 5-face ladder inside the hero meta block. The
     parent (.honestscore-meta) is a 1fr grid cell in the
     desktop aside; without this rule the row hugs the left
     edge of the cell and the icons read as a misaligned
     aside. `justify-content: center` keeps the ladder
     optically centered under the ring. */
  justify-content: center;
  gap: 0.5rem;
  list-style: none;
  margin: 0 0 0.5rem;
  padding: 0;
}
.honestscore-face {
  /* 2026-06-16 (round 1): the face ladder was 1.75rem — readable
     in the prototype but visually thin next to the 3rem ring
     value ("the eyes have to leave the score to read the
     ladder"). Bumped the pill to 3.15rem (1.8×) and the gap
     from 0.375rem to 0.5rem so the row reads as a single
     visual block.
     2026-06-16 (round 2): the pill got bigger but the
     `font-size: 1rem` was unchanged — the emoji glyph stayed
     at 16px inside a 50px pill, which read as a "small dot
     inside a big circle". Bumped the font to 1.8rem (1.8×
     the prior 1rem) so the glyph scales with the pill. */
  width: 3.15rem;
  height: 3.15rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--hp-surface-muted, #f3f4f6);
  border: 1px solid var(--hp-border, #e5e7eb);
  font-size: 1.8rem;
  line-height: 1;
  filter: grayscale(0.6);
  opacity: 0.55;
  transition: filter 0.15s, opacity 0.15s, transform 0.15s;
}
.honestscore-face--active {
  filter: grayscale(0);
  opacity: 1;
  background: color-mix(in srgb, var(--hp-primary, #e51923) 10%, var(--hp-surface, #fff));
  border-color: var(--hp-primary, #e51923);
  transform: scale(1.08);
}

/* v2: below-threshold progress copy (Phase 5). The
   background is a low-alpha orange tint that reads as orange
   on either the dark or light surface (the alpha lets the
   --hp-surface below show through, so it never looks like a
   flat #fff7ed "white" patch in dark mode). The text color
   flips via the [data-pitch-theme] selector so it stays AA
   contrast on both surfaces. */
.honestscore-threshold {
  margin: 0.5rem 0 0;
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  background: color-mix(in srgb, var(--hp-score-orange, #f59e0b) 12%, var(--hp-surface, #111827));
  border: 1px solid var(--hp-score-orange, #f59e0b);
  color: var(--hp-score-orange, #f59e0b);
  font-size: 0.8125rem;
  line-height: 1.4;
}

html[data-pitch-theme="light"] .honestscore-threshold {
  /* On a light surface the orange tint is too washed out, and
     the orange-on-cream text is below AA contrast. Fall back to
     a darker amber text on the same translucent fill. */
  color: #92400e;
}

/* v2 (Phase 7): the version stamp on the rating surfaces. */
.honestscore-version,
.pitch-score-version {
  margin: 0.5rem 0 0;
  font-family: var(--hp-mono, ui-monospace, monospace);
  font-size: 0.6875rem;
  color: var(--hp-text-muted, #6b7280);
  letter-spacing: 0.04em;
}

/* ─── Score breakdown: collapsible six-dim card with bar rows ─
   Wrapped in a native <details> for the disclosure — collapsed
   by default. The summary IS the title row; the [open] selector
   rotates the caret to give the user visual feedback that the
   card is now expanded. ────────────────────────────────────────── */
.pitch-score-breakdown {
  border: 1px solid var(--hp-border, #e5e7eb);
  border-radius: 12px;
  padding: 0.75rem 1.25rem 0.75rem;
  background: var(--hp-surface, transparent);
  margin-bottom: 1.25rem;
}
.pitch-score-breakdown[open] {
  padding-bottom: 1rem;
}

.pitch-score-breakdown-title {
  /* The summary is the disclosure trigger. Reset the native
     marker + cursor so it looks like the old <h2> title row. */
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  padding: 0.25rem 0;
  list-style: none;
  cursor: pointer;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--hp-text, #111827);
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
/* Firefox renders the disclosure marker on <summary> by default;
   Chrome/Safari do too unless we explicitly suppress it. */
.pitch-score-breakdown-title::-webkit-details-marker {
  display: none;
}
.pitch-score-breakdown-title::marker {
  display: none;
  content: "";
}
.pitch-score-breakdown-title:focus-visible {
  outline: 2px solid var(--hp-primary, #e51923);
  outline-offset: 2px;
  border-radius: 4px;
}
.pitch-score-breakdown-caret {
  color: var(--hp-score-orange, #f59e0b);
  font-size: 0.75rem;
  transform: translateY(-1px);
  transition: transform 0.15s ease-out;
  display: inline-block;
}
.pitch-score-breakdown[open] .pitch-score-breakdown-caret {
  transform: translateY(-1px) rotate(90deg);
}

.pitch-score-breakdown-list {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.pitch-score-breakdown-empty {
  margin: 0.75rem 0 0;
  color: var(--hp-text-muted, #6b7280);
  font-size: 0.875rem;
}

/* v2 (Phase 5): the breakdown's per-state below-threshold
   progress copy. Sits below the row list (above the version
   stamp) so the disclosure body reads: title → list → progress
   copy → version. Same dark/light handling as
   .honestscore-threshold above. */
.pitch-score-threshold {
  margin: 0.75rem 0 0;
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  background: color-mix(in srgb, var(--hp-score-orange, #f59e0b) 12%, var(--hp-surface, #111827));
  border: 1px solid var(--hp-score-orange, #f59e0b);
  color: var(--hp-score-orange, #f59e0b);
  font-size: 0.8125rem;
  line-height: 1.4;
}

html[data-pitch-theme="light"] .pitch-score-threshold {
  color: #92400e;
}

.pitch-score-row {
  display: grid;
  /* v2 (2026-06-12): added a column for the per-row face
     emoji (the 1..5 ladder face that matches the dim's
     rounded average). Order: label · bar · num · face · count. */
  grid-template-columns: 6.5rem 1fr 3rem 1.5rem 3.5rem;
  align-items: center;
  gap: 0.625rem;
  font-size: 0.875rem;
  line-height: 1.2;
}
.pitch-score-row-label {
  color: var(--hp-text, #111827);
  font-weight: 500;
}
.pitch-score-bar {
  display: block;
  height: 0.5rem;
  border-radius: 999px;
  background: var(--hp-surface-muted, #e5e7eb);
  overflow: hidden;
}
.pitch-score-bar-fill {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--hp-score-green, #34d399), #10b981);
  border-radius: 999px;
  transition: width 0.4s ease-out;
}
.pitch-score-row-num {
  text-align: right;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--hp-text, #111827);
}
.pitch-score-row-face {
  text-align: center;
  font-size: 1.125rem;
  line-height: 1;
}
.pitch-score-row-count {
  text-align: right;
  color: var(--hp-text-muted, #6b7280);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 480px) {
  .pitch-score-row {
    grid-template-columns: 5rem 1fr 2.5rem 1.5rem 3rem;
    gap: 0.5rem;
  }
}

@media (max-width: 600px) {
  .honestscore-hero {
    grid-template-columns: 1fr;
    text-align: center;
    justify-items: center;
  }
}

.honestscore-meta h2 {
  font-size: 1.25rem;
  margin: 0 0 0.5rem;
}

.pitch-layout--stage {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  width: 100%;
}

.pitch-layout--stage .pitch-col--nav,
.pitch-layout--stage .pitch-col--aside {
  display: none;
}

/* Primary pitch video (Bunny Stream iframe embed).
   Rendered by `pitch-layout-stage.njk` for any pitch with
   `pitch.videoSource === "native_bunny"` and a non-empty
   `pitch.bunnyVideoId`. Without these rules, the iframe falls
   back to its UA stylesheet (~300x150px with a 2px inset border)
   — the symptom reported on 2026-06-21 on HP-BG5JM-C's page.
   Pinned by `src/__tests__/primary-pitch-video-css.contract.test.ts`.
   Why aspect-ratio on the wrapper and not the iframe:
     - Putting `aspect-ratio` on the iframe would only apply AFTER
       the iframe's content has loaded (the UA computes the iframe's
       height from its content). Putting it on the wrapper means
       the wrapper reserves the right vertical space at first paint
       and the iframe fills it via `height: 100%`. The layout
       doesn't shift when the video starts playing.
   Why border: 0 is on BOTH the wrapper and the iframe:
     - `border: 0` on the wrapper is redundant (the wrapper has no
       UA border), but documents the intent.
     - `border: 0` on the iframe kills the UA's 2px inset border
       (Firefox/Chrome/Safari all apply it).
     - `overflow: hidden` on the wrapper is the belt-and-suspenders:
       a future Bunny embed param that re-introduces a border via
       the iframe's `style` attribute would be clipped by the
       wrapper's rounded corners instead of overflowing them. */
.pitch-primary-video {
  width: 100%;
  max-width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  background: #000;
  border-radius: 8px;
  overflow: hidden;
  margin: 0 0 1.25rem;
}

.pitch-primary-video iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

.pitch-nav--chips {
  display: block;
  margin: 0.5rem 0 1rem;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.pitch-nav--chips .pitch-nav__list {
  display: flex;
  flex-direction: row;
  gap: 0.5rem;
  list-style: none;
  margin: 0;
  padding: 0 0 0.25rem;
}

.pitch-nav--chips .pitch-nav__link {
  display: inline-block;
  white-space: nowrap;
  padding: 0.35rem 0.75rem;
  border-radius: 999px;
  border: 1px solid var(--hp-border);
  background: var(--hp-surface-raised);
  font-size: 0.8125rem;
  text-decoration: none;
  color: var(--hp-text-muted);
}

.pitch-nav--chips .pitch-nav__link[aria-current="true"] {
  border-color: var(--hp-primary);
  color: var(--hp-text);
  background: color-mix(in srgb, var(--hp-primary) 12%, var(--hp-surface-raised));
}

.pitch-clip-player--hidden {
  display: none;
}

.pitch-clip-player:not(.pitch-clip-player--hidden) {
  width: 100%;
}

.pitch-clip-player iframe,
.pitch-clip-player video {
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: var(--hp-radius);
  background: #000;
}

/* Per-section media wrapper (rendered by pitchSectionMedia in
   pitch-sections.njk). Only the active section's media is
   visible — the rest are hidden by the [data-pitch-active="false"]
   rule below. */
.pitch-section-media {
  margin: 0 0 1.25rem;
}

.pitch-section-media__wrapper {
  position: relative;
  padding-bottom: 56.25%;
  height: 0;
  background: #000;
  border-radius: var(--hp-radius);
  overflow: hidden;
  border: 1px solid var(--hp-border);
}

/* 2026-06-22: mobile — the 12px radius + 1px border on a 16:9
   wrapper reads heavy on small viewports (a 320px viewport
   produces an ~180px-tall card with 12px corners, which looks
   chunky next to the body text). Drop the border (the black
   background is the visible edge) and halve the radius. The
   desktop styles above are unchanged. The @media (min-width:
   600px) breakpoint matches the .pitch-page rule in
   pitch-mockup.css so the two flip at the same viewport
   boundary. */
@media (max-width: 599.98px) {
  .pitch-section-media__wrapper {
    border-radius: 6px;
    border: 0;
  }
  .pitch-primary-video {
    border-radius: 6px;
  }
}

.pitch-section-media__wrapper iframe,
.pitch-section-media__wrapper video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  background: #000;
}

.pitch-section-media__meta {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 1.5rem;
  color: var(--hp-text-muted);
}

/* 2026-06-11: per-section hero image (joined at build time from
   pitch_assets rows of kind `segment_image`). The <img> already
   has explicit width/height from the upload-time metadata, so we
   don't need the 56.25% aspect-ratio trick used for video. We
   also drop the black background (no letterboxing for a still).
   The figure keeps the same border + radius as the video wrapper
   for visual consistency, but the img fills naturally to its
   intrinsic aspect ratio. */
.pitch-section-media--still {
  margin: 0 0 1.25rem;
  border: 1px solid var(--hp-border);
  border-radius: var(--hp-radius);
  overflow: hidden;
  background: var(--hp-surface-2, #f5f5f5);
  line-height: 0; /* collapse the inline-img whitespace under the figure */
}

.pitch-section-media--still img {
  display: block;
  width: 100%;
  height: auto;
  max-width: 100%;
  background: var(--hp-surface-2, #f5f5f5);
}

/* ─── Stage: the visible "now playing" section ───────────────────────── */
.pitch-stage {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.pitch-stage__body {
  position: relative;
}

/* The state machine flips data-pitch-active on the .pitch-block
   elements (pitch-cues.js does this). Inactive sections are hidden
   so only the active one takes the stage. We use the [hidden]
   attribute as a fallback AND the data-attribute for CSS. */
.pitch-block[hidden],
.pitch-block[data-pitch-active="false"] {
  display: none !important;
}

.pitch-block[data-pitch-active="true"] {
  display: block;
  animation: pitch-stage-fade-in 220ms ease-out;
}

/* 2026-06-22: layout stability — give the active section a
   minimum height so switching between a section with a 16:9 video
   and one with only body text doesn't yank the page. The video
   wrapper reserves ~56.25% of the column width via
   padding-bottom (e.g. a 700px-wide desktop column gets ~395px
   of video). A body-only section takes ~0px from media +
   the heading + body. Without a min-height, switching between
   them causes the prev/next nav and the CTA bar to jump several
   hundred pixels.

   The values are deliberately conservative: small enough to not
   create huge empty space in body-only sections on mobile (where
   the video is naturally small), large enough that the page
   doesn't collapse. The desktop override at 1100px (where the
   3-column layout kicks in and the center column gets the
   700-800px width that makes the video big) lifts the floor
   proportionally.

   The min-height only applies to the VISIBLE section (the
   selector targets [data-pitch-active="true"]) so the hidden
   inactive sections don't reserve any space — pitch-cues.js
   already sets `display: none` on them via the rule above. */
.pitch-block[data-pitch-active="true"] {
  min-height: 22rem;
}
@media (min-width: 1100px) {
  .pitch-block[data-pitch-active="true"] {
    min-height: 32rem;
  }
}

@keyframes pitch-stage-fade-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ─── Stage nav (prev / next) ───────────────────────────────────────── */
.pitch-stage__nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--hp-border);
}

.pitch-stage__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.9rem;
  background: var(--hp-surface-raised);
  color: var(--hp-text);
  border: 1px solid var(--hp-border);
  border-radius: 8px;
  font: inherit;
  font-weight: 600;
  font-size: 0.875rem;
  cursor: pointer;
  min-width: 0;
  flex: 1 1 auto;
  max-width: 14rem;
  text-align: left;
}

.pitch-stage__btn--next {
  justify-content: flex-end;
  text-align: right;
}

.pitch-stage__btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.pitch-stage__btn:hover:not(:disabled) {
  border-color: var(--hp-primary);
  color: var(--hp-text);
}

.pitch-stage__btn-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pitch-stage__position {
  margin: 0;
  font-size: 0.75rem;
  color: var(--hp-text-muted);
  font-variant-numeric: tabular-nums;
  text-align: center;
  flex: 0 0 auto;
}

/* ─── Pitch Sharing Zone (bottom-of-page) ──────────────────────────
   2026-06-26 (operator request): the bottom share widget's
   trigger must be right-aligned within the page column so the
   dropdown menu (ShareWidget.vue positions the panel with
   `right: 0;` so it opens to the LEFT of the trigger) stays
   inside the viewport. The trigger itself is `display: inline-
   block` (matches its content width), so `text-align: right`
   on the wrapper is enough to push the trigger to the right
   edge of the column. Without this, the trigger sits at the
   document-flow left edge and the panel overflows the left
   edge of the page on narrow viewports.

   Top-of-page share button does NOT use this wrapper — the
   toolbar version (`.pitch-toolbar__share`) is grid-positioned
   by `.pitch-toolbar` and gets its right alignment from
   `justify-self: end` on the grid cell (see pitch-mockup.css).
   This wrapper is specifically for the bottom-of-page
   rendering in pitch-layout-stage.njk.

   Width / max-width match the page's centered content column
   (1200px) so the right alignment reads as "right edge of the
   content", not "right edge of the viewport" on ultra-wide
   displays where the page has horizontal padding. */
.pitch-share-zone {
  max-width: 1200px;
  margin: 1.5rem auto 0;
  padding: 0 1rem;
  text-align: right;
}

/* ─── Fixed bottom CTA bar (v2: .pitch-cta-center) ───────────────── */
.pitch-cta-center {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 20;
  background: linear-gradient(180deg, transparent, var(--hp-bg) 20%, var(--hp-bg));
  padding: 1rem 1rem 1rem;
  border-top: 1px solid var(--hp-border);
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.35);
}

html[data-pitch-theme="light"] .pitch-cta-center {
  background: linear-gradient(180deg, transparent, var(--hp-bg) 25%, var(--hp-bg));
}

.pitch-cta-center__inner {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: stretch;
  max-width: 1200px;
  margin: 0 auto;
}

.pitch-cta-center .pitch-cta {
  /* Unmissable. The user said "can't miss it large". */
  display: block;
  width: 100%;
  text-align: center;
  background: var(--hp-primary);
  color: #fff;
  padding: 1.4rem 1.25rem;
  border-radius: 12px;
  font-size: 1.25rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  text-decoration: none;
  transition: background 0.15s, transform 0.1s;
  box-shadow: 0 8px 24px rgba(229, 25, 35, 0.35);
}

.pitch-cta-center .pitch-cta:hover {
  background: var(--hp-primary-dark);
  text-decoration: none;
  transform: translateY(-1px);
}

.pitch-cta-center .pitch-cta:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 3px;
}

/* ─── Aside: the right-side rating panel + migrated meta ─────────── */
.pitch-col--aside .pitch-report-link {
  margin: 1rem 0 0;
  text-align: center;
  font-size: 0.8125rem;
}

.pitch-col--aside .pitch-report-link a {
  color: var(--hp-text-muted);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.pitch-col--aside .pitch-byline,
.pitch-col--aside .pitch-audience,
.pitch-col--aside .listing-countdown {
  margin: 0.75rem 0;
  font-size: 0.875rem;
  text-align: center;
  color: var(--hp-text-muted);
}

.pitch-col--aside .pitch-byline {
  color: var(--hp-text);
  font-weight: 500;
}

/* ─── Desktop: 3-column grid + horizontal stage nav ────────────────── */
@media (min-width: 1100px) {
  .pitch-page--stage .pitch-toolbar,
  .pitch-page--stage .disclosure-ribbon {
    max-width: none;
  }

  .pitch-layout--stage {
    display: grid;
    grid-template-columns: minmax(12rem, 16rem) minmax(0, 1fr) minmax(18rem, 22rem);
    gap: 1.5rem 2rem;
    align-items: start;
  }

  .pitch-layout--stage .pitch-col--nav,
  .pitch-layout--stage .pitch-col--aside {
    display: block;
  }

  .pitch-layout--stage .pitch-col--nav {
    position: sticky;
    top: 1rem;
    align-self: start;
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
  }

  .pitch-layout--stage .pitch-col--aside {
    position: sticky;
    top: 1rem;
    align-self: start;
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
  }

  .pitch-layout--stage .pitch-nav--chips {
    display: none;
  }

  .pitch-layout--stage .pitch-col--nav > .pitch-nav {
    display: block;
  }

  .pitch-cta-center__inner {
    flex-direction: row;
    align-items: center;
    justify-content: center;
    max-width: none;
    gap: 1.5rem;
  }

  .pitch-cta-center .pitch-cta {
    width: auto;
    min-width: 16rem;
    max-width: 32rem;
    flex: 0 0 auto;
  }

  .pitch-layout--stage .pitch-col--aside .honestscore-hero {
    grid-template-columns: 1fr;
    text-align: center;
    /* The 1fr grid cell now spans the full aside width; the
       ring is a block-level child, so `text-align: center`
       alone is no-op for it. `justify-items: center` centers
       the ring (and the meta block) inside the grid cell, so
       the circle and the proof copy land centered on the
       vertical axis of the aside. Without this, the 96–120px
       ring hugs the left edge of the cell while the inline
       text below it is centered — the asymmetry reads as
       "broken layout". */
    justify-items: center;
  }

  .pitch-layout--stage .pitch-col--aside .pitch-pros-cons {
    grid-template-columns: 1fr;
  }
}

.pitch-nav__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.pitch-nav__link {
  display: block;
  padding: 0.5rem 0.75rem;
  border-radius: 8px;
  text-decoration: none;
  color: var(--hp-text-muted);
  font-size: 0.9375rem;
  font-weight: 500;
}

.pitch-nav__link:hover {
  background: var(--hp-surface-raised);
  color: var(--hp-text);
}

.pitch-nav__link[aria-current="true"] {
  background: color-mix(in srgb, var(--hp-primary) 14%, transparent);
  color: var(--hp-text);
  font-weight: 700;
}


/* ─────────────────────────────────────────────────────────────────────
   v3 (2026-06-15) — Responsive drawer panels for the segment nav
   and the ratings aside. The desktop 3-column grid (above 1100px)
   shows both columns inline; below 1100px they become off-canvas
   drawers that the user opens via a sub-bar of two open buttons in
   the page chrome (right under the toolbar). Always visible on
   mobile; hidden on desktop.
   2026-06-16 — Removed a second set of "Segments" / "Ratings"
   triggers that were pinned to the viewport edges. They
   duplicated the sub-bar's actions and cluttered the viewport
   at mobile breakpoints; the stationary sub-bar is the single
   source of truth for the drawer open affordance. See the
   `pitch-drawer-trigger` rule below — the selector is no
   longer combined with the removed `.pitch-drawer-edge` class.
   Open behavior: overlay + scrim, ESC closes, scrim click closes,
   body scroll lock while a drawer is open, focus is moved to the
   panel's close button on open and returned to the trigger on
   close. The left drawer auto-closes when the user picks a section
   (it would be a dead end to leave it open after a nav click).
   The breakpoints deliberately mirror the existing @media
   (min-width: 1100px) desktop rule in this file so the
   mobile<->desktop flip is atomic — both rules are evaluated
   against the same viewport boundary.
   ───────────────────────────────────────────────────────────────────── */

/* Sub-bar of drawer triggers. Sits between the toolbar and the
   main content. Hidden on desktop; on mobile it is a flex row
   with one button at each end of the row so the user's left
   thumb can hit Segments and the right thumb can hit Ratings. */
.pitch-drawer-subbar {
  display: none;
}

/* Drawer close buttons live inside the off-canvas panels
   (nav + aside). On desktop (>=1100px) the panels are part
   of the inline 3-column grid, so there is no drawer to
   close — the button must be hidden. The mobile media query
   below re-enables it (display: inline-flex) so the visible
   close affordance + focus target inside the off-canvas
   panel still work.

   2026-06-16: the previous code had BOTH the `display: none`
   AND the `display: inline-flex` rule inside the mobile
   @media block, so on desktop the button fell through to its
   native display (inline-block for <button>) and showed up
   as a stray "✕" pill at the top of each column. The base
   rule below is the regression guard. */
.pitch-drawer-close {
  display: none;
}

@media (max-width: 1099.98px) {
  .pitch-drawer-subbar {
    display: flex;
    align-items: stretch;
    gap: 0.5rem;
    max-width: var(--hp-max);
    margin: 0 auto 1rem;
    padding: 0 1rem;
  }
}

/* Trigger button — the sub-bar pill that opens the segment
   nav (left) or the ratings aside (right) on mobile. 2026-06-16:
   the matching rules for the floating buttons were removed
   (those floating buttons were duplicating these actions and
   cluttering the viewport at mobile breakpoints), so this
   selector is now sub-bar-only. The base shape is a pill with
   an icon and a short label. */
.pitch-drawer-trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.55rem 0.9rem;
  background: var(--hp-surface-raised);
  color: var(--hp-text);
  border: 1px solid var(--hp-border);
  border-radius: 999px;
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  text-decoration: none;
  transition: border-color 0.15s, background 0.15s, color 0.15s, transform 0.1s;
  min-width: 0;
}

.pitch-drawer-trigger:hover {
  border-color: var(--hp-primary);
  color: var(--hp-text);
}

.pitch-drawer-trigger:focus-visible {
  outline: 2px solid var(--hp-primary, #e51923);
  outline-offset: 2px;
}

.pitch-drawer-trigger:active {
  transform: translateY(1px);
}

/* Reflect the open state on the trigger so the user gets a
   consistent "this drawer is open" affordance from the sub-bar
   trigger. The JS controller updates aria-expanded and the
   matching body data attribute. */
.pitch-drawer-trigger[aria-expanded="true"] {
  background: color-mix(in srgb, var(--hp-primary) 14%, var(--hp-surface-raised));
  border-color: var(--hp-primary);
  color: var(--hp-text);
}

.pitch-drawer-trigger__icon {
  font-size: 1rem;
  line-height: 1;
  /* The star (★) sits visually lower than the burger (☰) in
     most fonts; nudge it up a touch for optical alignment. */
  display: inline-block;
}
.pitch-drawer-trigger--aside .pitch-drawer-trigger__icon {
  transform: translateY(-1px);
}

/* Scrim. Sits over the whole viewport, including the fixed CTA
   bar zone. The bar still renders behind the scrim, but with
   z-index ordering the scrim is on top while a drawer is open
   so taps land on the scrim, not the CTA. */
.pitch-drawer-scrim {
  display: none;
}

@media (max-width: 1099.98px) {
  .pitch-drawer-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 24;
    background: rgba(0, 0, 0, 0.55);
    /* The scrim is also behind the panels (z-index 25+). The
       fade is applied via opacity tied to [hidden] AND the body
       data attribute, so the transition runs in both directions. */
    opacity: 0;
    transition: opacity 0.18s ease-out;
  }

  body[data-drawer-open] .pitch-drawer-scrim {
    opacity: 1;
  }

  .pitch-drawer-scrim[hidden] {
    /* The HTML `hidden` attribute implies display:none. The
       selector below forces the element to exist (display:block)
       when the body data attribute is set, so the transition
       runs from the element's current opacity. Otherwise the
       hidden element would just pop into view. */
    display: block !important;
    opacity: 0;
    pointer-events: none;
  }
}

/* Mobile: the .pitch-col--nav and .pitch-col--aside become
   off-canvas panels. They use position:fixed so they overlay
   the page (not push it). The desktop rules above already
   display:none them below 1100px; here we override that to
   re-show them as fixed panels with a transform. */
@media (max-width: 1099.98px) {
  .pitch-layout--stage .pitch-col--nav,
  .pitch-layout--stage .pitch-col--aside {
    display: block;
    position: fixed;
    top: 0;
    bottom: 0;
    width: min(86vw, 22rem);
    max-width: 22rem;
    /* Sits above the scrim (24) so the panel never gets covered. */
    z-index: 26;
    background: var(--hp-bg);
    border-right: 1px solid var(--hp-border);
    padding: 1rem;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* A small inset on the inner padding so the panel's close
       button + content don't sit flush against the viewport
       edge. */
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
    transition: transform 0.22s ease-out;
  }

  .pitch-layout--stage .pitch-col--nav {
    left: 0;
    transform: translateX(-100%);
  }

  .pitch-layout--stage .pitch-col--aside {
    right: 0;
    left: auto;
    transform: translateX(100%);
    border-right: 0;
    border-left: 1px solid var(--hp-border);
  }

  body[data-drawer-open="nav"] .pitch-layout--stage .pitch-col--nav {
    transform: translateX(0);
  }

  body[data-drawer-open="aside"] .pitch-layout--stage .pitch-col--aside {
    transform: translateX(0);
  }

  /* While a drawer is open, the OTHER panel is also off-screen
     (it would already be off-screen, but explicitly pinning
     it ensures a stale state from a previous open can't leak
     through). */
  body[data-drawer-open="nav"] .pitch-layout--stage .pitch-col--aside,
  body[data-drawer-open="aside"] .pitch-layout--stage .pitch-col--nav {
    /* No change — they were already off-screen — but this
       block is here as a guard against future CSS drift. */
  }

  /* Inside the panel, the close button sits at the top-right.
     The base rule (outside the media query) hides it on desktop,
     where the panel is part of the inline 3-column grid and there
     is no drawer to close. The mobile media query below re-enables
     it (display: inline-flex) so the visible close affordance
     + focus target inside the off-canvas panel still work. */
  .pitch-drawer-close {
    display: none;
  }
  .pitch-drawer-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    margin: 0 0 0.75rem;
    padding: 0;
    background: var(--hp-surface-raised);
    color: var(--hp-text);
    border: 1px solid var(--hp-border);
    border-radius: 999px;
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .pitch-drawer-close:hover {
    border-color: var(--hp-primary);
  }
  .pitch-drawer-close:focus-visible {
    outline: 2px solid var(--hp-primary, #e51923);
    outline-offset: 2px;
  }

  /* Body scroll lock while a drawer is open. The CTA bar
     already has position:fixed; we don't want the page to
     scroll under it (it would look like the CTA is floating
     over different content as the user scrolls). */
  body[data-drawer-open] {
    overflow: hidden;
  }
}

/* Respect users who prefer reduced motion: kill the transform
   transition. Without this, the slide-in can trigger vestibular
   issues on a small subset of users. */
@media (max-width: 1099.98px) and (prefers-reduced-motion: reduce) {
  .pitch-layout--stage .pitch-col--nav,
  .pitch-layout--stage .pitch-col--aside,
  .pitch-drawer-scrim {
    transition: none;
  }
}

/* ─── Audience feedback — Phase 4 (2026-06-21) ───────────────────
   The audience-feedback section is the home of two surfaces:
     (a) the no-JS server-rendered list of questions
         (the .audience-feedback block in pitch-audience-questions.njk)
     (b) the interactive overlay that the islands widget hydrates
         into the same section (the .audience-feedback-widget block
         in AudienceFeedbackWidget.vue).
   Before this commit the section had no styles — the static list
   rendered as unstyled HTML, the interactive overlay was invisible
   because there was nothing telling the browser to put it in a
   usable position. The fix:
     1. Style the section as a visible card so the no-JS fallback
        is readable.
     2. When the interactive widget is present and has questions,
        pin it to the bottom of the viewport as a sticky panel so
        the visitor sees the prompt while navigating the pitch
        (the previous "widget mounts at the bottom of the page"
        UX bug — the visitor had to scroll all the way down before
        they saw the first question).
     3. Surface the deactivating-section prompts above the
        active-section prompts inside the panel (so the "you just
        saw X — does this framing land?" question is visually
        adjacent to the new section's on-enter prompt).
   Dark/light theme: both are AA-readable on the
   `var(--hp-surface-muted)` and `var(--hp-surface)` tokens
   already used by HonestScore chips (see the
   `--hp-surface-muted` definitions in `site.css`). */

/* The outer section. Always a visible card, even with no JS. */
.pitch-page .audience-feedback {
  margin: 1.5rem auto;
  max-width: 56rem;
  padding: 1rem 1.25rem 1.25rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.12));
  border-radius: 0.75rem;
  background: var(--hp-surface, #1a1a1a);
  color: var(--hp-text, inherit);
}
html[data-pitch-theme="light"] .pitch-page .audience-feedback {
  background: var(--hp-surface, #ffffff);
  border-color: var(--hp-border, rgba(0, 0, 0, 0.12));
}
.pitch-page .audience-feedback__heading {
  margin: 0 0 0.25rem;
  font-size: 1.1rem;
  font-weight: 600;
}
.pitch-page .audience-feedback__lede {
  margin: 0 0 0.75rem;
  font-size: 0.9rem;
  opacity: 0.8;
}
.pitch-page .audience-feedback__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.pitch-page .audience-feedback__item {
  padding: 0.5rem 0;
  border-top: 1px solid var(--hp-border, rgba(255, 255, 255, 0.08));
}
.pitch-page .audience-feedback__item:first-child {
  border-top: 0;
}
.pitch-page .audience-feedback__prompt {
  margin: 0 0 0.25rem;
  font-weight: 500;
}
.pitch-page .audience-feedback__anchor {
  margin: 0;
  font-size: 0.8rem;
  opacity: 0.75;
}
.pitch-page .audience-feedback__hint {
  font-size: 0.75rem;
  opacity: 0.7;
  margin-left: 0.5rem;
}
.pitch-page .audience-feedback__nojs,
.pitch-page .audience-feedback__nojs-hint {
  font-size: 0.85rem;
  opacity: 0.75;
  margin: 0.25rem 0 0;
}
.pitch-page .audience-feedback__empty {
  font-size: 0.9rem;
  opacity: 0.7;
  margin: 0;
}

/* The interactive widget — 2026-06-21 modal rewrite.
   The previous shape was `position: sticky; bottom: 1rem;`, a
   subtle bottom-pinned card. The visitor reported "they're easy
   to miss as they are" — the sticky card was visible only while
   the parent `<section class="audience-feedback">` was in the
   viewport, and the parent is at the bottom of the page. When
   the visitor scrolled back up to the actual pitch content, the
   sticky behavior released (parent out of view) and the widget
   disappeared. The desired UX is "demands immediate attention" —
   a modal pattern: fixed-position overlay, dim backdrop, centered
   card, body scroll lock, focus the first interactive element.

   The widget root is now:
     position: fixed;
     inset: 0;
     z-index: 9999;             # above the CTA bar (z:5) and any
                                   page-level chrome, below
                                   GTM/consent banners (1000+)
     display: flex;
     align-items: center;
     justify-content: center;
     background: rgba(0,0,0,0.6);  # the dim backdrop

   Inside is .audience-feedback-widget__panel — the visible
   card, max-width: 32rem, with vertical scroll if the prompt
   batch is taller than the viewport. The dismiss × button
   floats top-right of the root. */
.pitch-page .audience-feedback-widget {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  padding: 1rem;
  animation: audience-feedback-fade-in 120ms ease-out;
}
@keyframes audience-feedback-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
html[data-pitch-theme="light"] .pitch-page .audience-feedback-widget {
  background: rgba(0, 0, 0, 0.55);
}
.pitch-page .audience-feedback-widget__panel {
  position: relative;
  width: 100%;
  max-width: 32rem;
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  padding: 1.25rem 1.25rem 1.5rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.18));
  border-radius: 0.75rem;
  background: var(--hp-surface-muted, #232323);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.55);
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  animation: audience-feedback-pop-in 140ms ease-out;
}
@keyframes audience-feedback-pop-in {
  from { transform: translateY(0.5rem) scale(0.98); opacity: 0; }
  to { transform: translateY(0) scale(1); opacity: 1; }
}
html[data-pitch-theme="light"] .pitch-page .audience-feedback-widget__panel {
  background: var(--hp-surface, #ffffff);
  border-color: var(--hp-border, rgba(0, 0, 0, 0.18));
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
}
.pitch-page .audience-feedback-widget__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--hp-border, rgba(255, 255, 255, 0.12));
}
.pitch-page .audience-feedback-widget__eyebrow {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--hp-primary, #e51923);
}
.pitch-page .audience-feedback-widget__counter {
  margin: 0;
  font-size: 0.78rem;
  opacity: 0.7;
}
/* The dismiss button. Pinned top-right of the PANEL (the dialog),
   not the modal root. The selector is scoped to the panel so its
   absolute coordinates resolve against the dialog box, not the
   full-viewport overlay — the previous shape had the button as a
   sibling of the panel, and the absolute positioning resolved
   against the modal root (the viewport), placing the × in the
   screen's top-right corner many inches away from the popup card
   on wide desktops. 2026-06-24 fix, my lord: move the button
   inside the panel. The visitor can also press Escape to dismiss
   — see AudienceFeedbackWidget.vue#onKeydown. */
.pitch-page .audience-feedback-widget__panel .audience-feedback-widget__dismiss {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  width: 2rem;
  height: 2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.25));
  border-radius: 999px;
  background: var(--hp-surface, #1a1a1a);
  color: var(--hp-text, inherit);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  z-index: 1;
}
html[data-pitch-theme="light"] .pitch-page .audience-feedback-widget__panel .audience-feedback-widget__dismiss {
  background: var(--hp-surface, #ffffff);
  border-color: var(--hp-border, rgba(0, 0, 0, 0.25));
}
.pitch-page .audience-feedback-widget__panel .audience-feedback-widget__dismiss:hover {
  border-color: var(--hp-primary, #e51923);
}
.pitch-page .audience-feedback-widget__panel .audience-feedback-widget__dismiss:focus-visible {
  outline: 2px solid var(--hp-primary, #e51923);
  outline-offset: 2px;
}
/* The header reserves space on the right so the absolutely-
   positioned dismiss button doesn't overlap the eyebrow/counter
   text. The dismiss is 2rem wide + 0.5rem from the panel's right
   edge + 0.5rem gap = ~3rem of reserved right-edge space. We pad
   the header on the right by 3rem so the eyebrow/counter don't
   get visually clipped. */
.pitch-page .audience-feedback-widget__panel .audience-feedback-widget__header {
  padding-right: 3rem;
}
/* Body scroll lock. Set by AudienceFeedbackWidget.vue's watcher
   on `activeQuestionsForRender` whenever the modal is open. Same
   attribute name as the existing drawer convention. */
body[data-audience-feedback-open] {
  overflow: hidden;
}
/* Respect prefers-reduced-motion: kill the pop-in / fade-in. */
@media (prefers-reduced-motion: reduce) {
  .pitch-page .audience-feedback-widget,
  .pitch-page .audience-feedback-widget__panel {
    animation: none;
  }
}
.pitch-page .audience-feedback-widget__card {
  padding: 0.5rem 0;
  border-top: 1px solid var(--hp-border, rgba(255, 255, 255, 0.08));
  /* 2026-06-29: the card is a flex item inside the modal panel's
     column flex. Default min-width: auto lets long text children
     push the card wider than the panel. min-width: 0 lets the
     card shrink to its container so the prompt's overflow-wrap
     can take effect. */
  min-width: 0;
}
.pitch-page .audience-feedback-widget__card:first-child {
  border-top: 0;
}
.pitch-page .audience-feedback-widget__prompt {
  margin: 0 0 0.65rem;
  font-size: 1.05rem;
  font-weight: 500;
  line-height: 1.35;
  /* 2026-06-29: long question prompts ("Have you spent more hours
     pitching this week than actually building") used to overflow
     the 32rem panel and force a horizontal scrollbar. The panel
     already has overflow-y: auto but no overflow-x, so a single
     unbreakable token pushes the panel wider than max-width and
     triggers horizontal scroll on the whole page. overflow-wrap:
     anywhere breaks at any character if needed, and
     word-break: break-word is the legacy fallback for browsers
     that don't recognize overflow-wrap. Together they guarantee
     the prompt always wraps inside the card. */
  overflow-wrap: anywhere;
  word-break: break-word;
}
.pitch-page .audience-feedback-widget__choices,
.pitch-page .audience-feedback-widget__scale,
.pitch-page .audience-feedback-widget__multi {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}
.pitch-page .audience-feedback-widget__choice,
.pitch-page .audience-feedback-widget__scale-button,
.pitch-page .audience-feedback-widget__multi-submit,
.pitch-page .audience-feedback-widget__short-text-submit {
  padding: 0.65rem 1rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.2));
  border-radius: 0.5rem;
  background: transparent;
  color: inherit;
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  transition: background 80ms ease, border-color 80ms ease;
}
.pitch-page .audience-feedback-widget__choice:focus-visible,
.pitch-page .audience-feedback-widget__scale-button:focus-visible,
.pitch-page .audience-feedback-widget__multi-submit:focus-visible,
.pitch-page .audience-feedback-widget__short-text-submit:focus-visible {
  outline: 2px solid var(--hp-primary, #e51923);
  outline-offset: 2px;
}
.pitch-page .audience-feedback-widget__choice:hover,
.pitch-page .audience-feedback-widget__scale-button:hover,
.pitch-page .audience-feedback-widget__multi-submit:hover,
.pitch-page .audience-feedback-widget__short-text-submit:hover {
  background: var(--hp-surface-muted, rgba(255, 255, 255, 0.08));
}
.pitch-page .audience-feedback-widget__choice:disabled,
.pitch-page .audience-feedback-widget__scale-button:disabled,
.pitch-page .audience-feedback-widget__multi-submit:disabled,
.pitch-page .audience-feedback-widget__short-text-submit:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.pitch-page .audience-feedback-widget__scale-anchor {
  font-size: 0.8rem;
  opacity: 0.7;
}
.pitch-page .audience-feedback-widget__multi-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.pitch-page .audience-feedback-widget__short-text {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.pitch-page .audience-feedback-widget__short-text-input {
  width: 100%;
  min-height: 4.5rem;
  resize: vertical;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.2));
  border-radius: 0.5rem;
  background: transparent;
  color: inherit;
  font: inherit;
}
.pitch-page .audience-feedback-widget__expansion {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-top: 0.5rem;
}
.pitch-page .audience-feedback-widget__expansion-input {
  width: 100%;
  min-height: 3.5rem;
  resize: vertical;
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.15));
  border-radius: 0.4rem;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 0.85rem;
}
.pitch-page .audience-feedback-widget__submit-error {
  font-size: 0.8rem;
  color: #c33;
  margin: 0;
}
html[data-pitch-theme="light"] .pitch-page .audience-feedback-widget__submit-error {
  color: #b22;
}
.pitch-page .audience-feedback-widget__jump {
  font-size: 0.85rem;
  text-decoration: underline;
}

/* ─── Collapsed "you answered" pill (Part 1 of the less-invasive-
     answered feature, 2026-06-22) ────────────────────────────────
   When the visitor returns to a section whose questions they've
   already answered, the widget renders this collapsed pill INSTEAD
   of the full question card. The pill:
     - has a success-tinted left border (the visitor's engagement is
       acknowledged, not a prompt to act);
     - shows the question prompt + the recorded answer (one-line
       clamp, full body visible in the "Edit" tooltip);
     - has a small Edit button on the right that re-opens the full
       card for the edit.

   The pill lives inside the same `.audience-feedback-widget`
   modal shell as the full card, so it inherits the modal's
   positioning, dim backdrop, body scroll lock, and focus-trap
   behavior. The CSS variables (`--afw-radius`, `--afw-color-*`)
   are scoped to the widget on the modal-block line above; this
   pill block reuses them so the dark/light theme tokens apply
   uniformly. */
.pitch-page .audience-feedback-widget__pill {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "prompt actions"
    "answer actions";
  grid-gap: 0.4rem 0.75rem;
  align-items: center;
  padding: 0.85rem 1rem 0.85rem 1.1rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.12));
  border-left: 3px solid var(--hp-color-success, #2da44e);
  border-radius: 0.6rem;
  /* 2026-06-29: the grid-template-columns change to
     minmax(0, 1fr) lets the prompt column shrink below its
     intrinsic content width, so a long question prompt
     ("Have you spent more hours pitching this week than
     actually building") is clamped by the existing
     text-overflow: ellipsis on .__pill-prompt-text instead
     of pushing the pill wider than the card and triggering
     a horizontal scrollbar. The previous `1fr` was
     equivalent to `minmax(auto, 1fr)`, which honors the
     longest unbreakable token in the cell as the column
     minimum width. */
  background: var(--hp-surface-muted, rgba(255, 255, 255, 0.04));
  color: inherit;
  font: inherit;
  text-align: left;
}
.pitch-page .audience-feedback-widget__pill-prompt {
  grid-area: prompt;
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  font-weight: 500;
  font-size: 0.95rem;
  line-height: 1.3;
  /* 2026-06-29: min-width: 0 on the flex container lets the
     pill-prompt-text child shrink below its intrinsic content
     width so the existing text-overflow: ellipsis clamp kicks
     in for long question prompts. Without it, the flex item's
     default min-width: auto honors the longest unbreakable
     token as its minimum width and the pill overflows the
     card. The grid's minmax(0, 1fr) on .__pill is the
     outer fix; this is the inner fix. */
  min-width: 0;
}
.pitch-page .audience-feedback-widget__pill-check {
  color: var(--hp-color-success, #2da44e);
  font-weight: 700;
  flex-shrink: 0;
}
.pitch-page .audience-feedback-widget__pill-prompt-text {
  /* 2026-06-29: the pill prompt is now allowed to wrap onto
     multiple lines so the visitor can always read the full
     question without expanding the card or opening the
     "Edit" view. The previous shape used a one-line clamp
     (white-space: nowrap + overflow: hidden +
     text-overflow: ellipsis) which truncated long prompts
     with an ellipsis — useful when the pill is a one-liner
     in a sidebar layout, but the modal version wants the
     full text. We keep the overflow: hidden + min-width: 0
     so the text can't push the pill wider than its grid
     cell, but drop the nowrap so the words wrap at the
     cell boundary. */
  overflow-wrap: anywhere;
  word-break: break-word;
  min-width: 0;
  flex: 1 1 0;
}
.pitch-page .audience-feedback-widget__pill-answer {
  grid-area: answer;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem;
  font-size: 0.85rem;
  opacity: 0.85;
}
.pitch-page .audience-feedback-widget__pill-answer-label {
  font-weight: 500;
  opacity: 0.7;
}
.pitch-page .audience-feedback-widget__pill-answer-value {
  font-weight: 400;
  word-break: break-word;
}
.pitch-page .audience-feedback-widget__pill-actions {
  grid-area: actions;
  align-self: center;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.pitch-page .audience-feedback-widget__pill-edit {
  appearance: none;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.25));
  border-radius: 0.4rem;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 0.85rem;
  font-weight: 500;
  padding: 0.35rem 0.75rem;
  cursor: pointer;
  transition: background 80ms ease, border-color 80ms ease;
}
.pitch-page .audience-feedback-widget__pill-edit:hover {
  background: var(--hp-surface-muted, rgba(255, 255, 255, 0.08));
  border-color: var(--hp-border, rgba(255, 255, 255, 0.4));
}
.pitch-page .audience-feedback-widget__pill-edit:focus-visible {
  outline: 2px solid var(--hp-primary, #e51923);
  outline-offset: 2px;
}
.pitch-page .audience-feedback-widget__cancel-edit {
  appearance: none;
  border: 1px dashed var(--hp-border, rgba(255, 255, 255, 0.25));
  border-radius: 0.4rem;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 0.8rem;
  padding: 0.3rem 0.65rem;
  margin-top: 0.5rem;
  cursor: pointer;
  opacity: 0.8;
}
.pitch-page .audience-feedback-widget__cancel-edit:hover {
  opacity: 1;
}


/* ─── End-of-pitch review modal (Part 3 of the less-invasive-
   answered feature, 2026-06-22) ─────────────────────────────────────
   When the visitor has finished the pitch and the active section
   becomes the final `cta` kind, this modal auto-opens. The modal:
     - reuses the audience-feedback modal shell (fixed inset:0,
       dim backdrop, body scroll lock);
     - shows the visitor's rating summary OR a prominent CTA card
       asking them to rate (the modal IS the prompt per the plan
       decision Q4);
     - lists every question + recorded answer in the order the
       visitor saw them (using formatAnswerSummary from Part 1);
     - has a per-question Edit button that emits a
       `hp:review:edit-question` event for the host page to wire
       to the audience-feedback widget's edit affordance;
     - has a Close button that just dismisses the modal.

   Closed-state: a single "Review your answers" / "Rate this pitch"
   trigger button (renders in the right aside, above the
   #vote-widget-mount slot). The trigger re-reads the
   `[data-vote-summary]` attribute on the honestscore breakdown
   each time it opens, so the rating CTA / summary stays in sync
   with the live vote state. */
.pitch-page .review-feedback-root {
  margin: 0.85rem 0 0;
}
.pitch-page .review-feedback-trigger {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.2rem;
  width: 100%;
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.18));
  border-radius: 0.5rem;
  background: var(--hp-surface-muted, rgba(255, 255, 255, 0.04));
  color: inherit;
  font: inherit;
  cursor: pointer;
  text-align: left;
}
.pitch-page .review-feedback-trigger:hover {
  background: var(--hp-surface, rgba(255, 255, 255, 0.07));
}
.pitch-page .review-feedback-trigger-label {
  font-weight: 600;
  font-size: 0.95rem;
}
.pitch-page .review-feedback-trigger-summary {
  font-size: 0.8rem;
  opacity: 0.75;
}
.pitch-page .review-feedback-trigger-summary--prompt {
  color: var(--hp-color-primary, #d33);
  opacity: 1;
}
.pitch-page .review-feedback-modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  max-width: 36rem;
  max-height: 80vh;
  margin: auto;
  padding: 1.2rem 1.2rem 1rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.18));
  border-radius: 0.8rem;
  background: var(--hp-surface, #1a1a1a);
  color: inherit;
  overflow-y: auto;
  box-shadow: 0 1.2rem 3rem rgba(0, 0, 0, 0.45);
}
html[data-pitch-theme="light"] .pitch-page .review-feedback-modal {
  background: #fff;
  box-shadow: 0 1.2rem 3rem rgba(0, 0, 0, 0.18);
}
.pitch-page .review-feedback-modal::backdrop {
  background: rgba(0, 0, 0, 0.55);
}
html[data-pitch-theme="light"] .pitch-page .review-feedback-modal::backdrop {
  background: rgba(0, 0, 0, 0.4);
}
.pitch-page .review-feedback-modal__close {
  position: absolute;
  top: 0.5rem;
  right: 0.7rem;
  width: 2rem;
  height: 2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 0.4rem;
  background: transparent;
  color: inherit;
  font-size: 1.4rem;
  cursor: pointer;
  opacity: 0.7;
}
.pitch-page .review-feedback-modal__close:hover {
  opacity: 1;
}
.pitch-page .review-feedback-modal__header {
  margin: 0 0 0.8rem;
}
.pitch-page .review-feedback-modal__eyebrow {
  margin: 0 0 0.15rem;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 0.7;
}
.pitch-page .review-feedback-modal__title {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
}
.pitch-page .review-feedback-modal__rating-summary {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 0.85rem 1rem;
  margin: 0 0 1rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.12));
  border-radius: 0.6rem;
  background: var(--hp-surface-muted, rgba(255, 255, 255, 0.04));
}
.pitch-page .review-feedback-modal__rating-summary-label {
  margin: 0;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.7;
}
.pitch-page .review-feedback-modal__rating-summary-value {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
}
.pitch-page .review-feedback-modal__rating-cta {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1rem;
  margin: 0 0 1rem;
  border: 1px solid var(--hp-color-primary, #d33);
  border-radius: 0.6rem;
  background: var(--hp-surface-muted, rgba(255, 255, 255, 0.04));
}
.pitch-page .review-feedback-modal__rating-cta-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
}
.pitch-page .review-feedback-modal__rating-cta-body {
  margin: 0;
  font-size: 0.9rem;
  opacity: 0.8;
}
.pitch-page .review-feedback-modal__answer-list {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin: 0 0 1rem;
}
.pitch-page .review-feedback-modal__answer-list-heading {
  margin: 0 0 0.2rem;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.7;
}
.pitch-page .review-feedback-modal__answer-card {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "prompt edit"
    "value edit";
  grid-gap: 0.3rem 0.5rem;
  align-items: center;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.12));
  border-radius: 0.5rem;
  background: var(--hp-surface-muted, rgba(255, 255, 255, 0.03));
}
.pitch-page .review-feedback-modal__answer-card-prompt {
  grid-area: prompt;
  margin: 0;
  font-weight: 500;
  font-size: 0.9rem;
}
.pitch-page .review-feedback-modal__answer-card-value {
  grid-area: value;
  margin: 0;
  font-size: 0.85rem;
  opacity: 0.85;
}
.pitch-page .review-feedback-modal__answer-card-value-label {
  display: block;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.6;
  margin-bottom: 0.1rem;
}
.pitch-page .review-feedback-modal__answer-card-value-text {
  display: block;
}
.pitch-page .review-feedback-modal__edit-button {
  grid-area: edit;
  align-self: center;
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.2));
  border-radius: 0.4rem;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 0.8rem;
  cursor: pointer;
}
.pitch-page .review-feedback-modal__edit-button:hover {
  background: var(--hp-surface, rgba(255, 255, 255, 0.08));
}
.pitch-page .review-feedback-modal__edit-button--primary {
  border-color: var(--hp-color-primary, #d33);
  background: var(--hp-color-primary, #d33);
  color: #fff;
  align-self: flex-start;
}
.pitch-page .review-feedback-modal__empty {
  padding: 0.85rem 1rem;
  border: 1px dashed var(--hp-border, rgba(255, 255, 255, 0.18));
  border-radius: 0.5rem;
  margin: 0 0 1rem;
  font-size: 0.9rem;
  opacity: 0.85;
}
.pitch-page .review-feedback-modal__footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.4rem;
}
.pitch-page .review-feedback-modal__close-button {
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--hp-border, rgba(255, 255, 255, 0.2));
  border-radius: 0.4rem;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.pitch-page .review-feedback-modal__close-button:hover {
  background: var(--hp-surface, rgba(255, 255, 255, 0.06));
}
.pitch-page body.review-feedback-modal-open {
  overflow: hidden;
}


/* ─────────────────────────────────────────────────────────────────────
   2026-06-28 (operator request, mobile-friendly image zoom):
   Fullscreen lightbox for per-section hero images. The
   `.pitch-section-media--still` figure wraps the <img> in a
   <button data-pitch-zoom-trigger> (see pitch-sections.njk). Tapping
   or clicking the trigger opens a fixed-position overlay that
   fills the viewport and shows the image at its intrinsic size,
   centered, against a dim backdrop. Body scroll is locked while
   the overlay is open; ESC, the close button, and a backdrop tap
   all close it. Focus is moved to the close button on open and
   returned to the trigger on close.

   Why a dedicated lightbox module instead of the existing
   <dialog>-based review-feedback modal: the image lightbox is a
   passive "see it bigger" surface with no inner form, so a
   dedicated module is simpler than reusing the review-feedback
   scaffold. Both modules share the body-scroll-lock + focus-
   restore + escape-to-close contract; the lightbox controller
   lives in pitch-cues.js (PitchCues.Lightbox) and the CSS lives
   here.

   Dark/light theme: the overlay backdrop uses the same
   rgba(0,0,0,0.6-0.85) range as the audience-feedback widget, so
   it reads correctly on both the dark and light surfaces. The
   image itself doesn't need a theme variant — it's whatever the
   uploader created. The close button uses the same `--hp-surface`
   + `--hp-border` + `--hp-primary` (focus ring) tokens as the
   audience-feedback dismiss button, so the two modals feel like
   siblings.

   Mobile (the primary use case the operator reported): the
   trigger is `width: 100%` so the tap target covers the entire
   figure — the image is the tap target, not a small icon overlay.
   The lightbox image fills the viewport with a small inset so
   the close button has room at the top-right. Desktop: the
   trigger inherits the same width (the figure is already full-
   column-width) and the lightbox caps the image at ~95vw / ~92vh
   so a wide image doesn't push the close button off-screen.

   prefers-reduced-motion: the open/close transition is short
   (120ms fade) and the scale-pop is suppressed. Without the
   override, the pop animation can trigger vestibular issues on a
   small subset of users.
   ───────────────────────────────────────────────────────────────────── */

/* The trigger button. Sits inside the .pitch-section-media--still
   figure so it wraps the image; CSS resets the native button
   chrome (border, padding, background, font) and lets the inner
   <img> own the visible surface. position: static so the existing
   figure layout is unchanged. width: 100% so the tap target
   covers the whole image (mobile-first — see the operator's
   report "particularly on mobile").

   Cursor: zoom-in signals "click to enlarge" on hover (desktop
   only by convention; on touch devices the cursor never shows).
   The cursor reverts to the system default on devices that don't
   support it. */
.pitch-page .pitch-section-media--still__zoom {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: zoom-in;
  position: relative;
  -webkit-tap-highlight-color: transparent;
  line-height: 0;
  text-align: left;
}

/* The button itself is the focus ring owner. A 2px outline with
   the project's primary token makes the focus state readable on
   both the dark and light theme surfaces. outline-offset: 2px
   so the outline doesn't sit on top of the image edge. */
.pitch-page .pitch-section-media--still__zoom:focus-visible {
  outline: 2px solid var(--hp-primary, #e51923);
  outline-offset: 2px;
  border-radius: 2px;
}

/* The image inside the trigger keeps the existing
   .pitch-section-media--still img rules (width: 100%; height:
   auto; display: block). No overrides here — the image IS the
   trigger's content. */

/* The "tap to expand" hint. Sits at the bottom-right of the
   figure on hover (desktop) and is always-visible on touch
   devices (where there's no hover state). The hint is a small
   pill with a magnifier icon + a short label. The pill is
   positioned absolutely inside the trigger so it doesn't shift
   the image. */

.pitch-page .pitch-section-media--still__zoom-hint {
  position: absolute;
  right: 0.5rem;
  bottom: 0.5rem;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.55rem;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.65);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1;
  opacity: 0;
  transition: opacity 0.15s ease-out;
  pointer-events: none;
}

.pitch-page .pitch-section-media--still__zoom-hint svg {
  display: block;
}

/* Hover (desktop): fade the hint in. Focus-visible: also show
   the hint so keyboard users see the affordance when they tab
   to the trigger. */
.pitch-page .pitch-section-media--still__zoom:hover .pitch-section-media--still__zoom-hint,
.pitch-page .pitch-section-media--still__zoom:focus-visible .pitch-section-media--still__zoom-hint {
  opacity: 1;
}

/* Touch devices: always show the hint so the affordance is
   visible without a hover. The (hover: none) media query is the
   canonical "this device has no hover" signal — touch phones,
   tablets, kiosks. The (pointer: coarse) media query is the
   "primary input is imprecise" signal; combined, they cover
   every mobile-class device. */
@media (hover: none) and (pointer: coarse) {
  .pitch-page .pitch-section-media--still__zoom-hint {
    opacity: 1;
  }
}

/* The lightbox overlay. Fixed inset:0 + flex centering + dim
   backdrop. The close button sits at the top-right of the
   viewport (NOT the panel — there is no panel; the image is the
   panel).

   2026-06-29 (the fourth post-deploy fix): the rules in this
   block are CLASS SELECTORS, not descendant selectors. They
   match the lightbox root, image, and close button wherever
   they live in the DOM. pitch-cues.js appends the lightbox root
   to `document.body` (so `position: fixed` covers the viewport
   without being trapped by any ancestor with `transform`,
   `filter`, `perspective`, `will-change`, or `contain`). The
   pre-fix shape used `.pitch-page .pitch-zoom-lightbox`
   descendant selectors, which never matched because
   `document.body` is OUTSIDE the `.pitch-page` wrapper; the
   lightbox rendered inline at the bottom of the body with no
   positioning, no z-index, no dim backdrop, no overlay. That
   shape shipped in 2026-06-28; the visual symptom of the bug
   was "image appears at the bottom of the page, not as an
   overlay/popup". See
   `CHANGELOG.d/2026-06-28-pitch-section-image-zoom.md`
   "Fourth post-deploy fix" section for the full triage.

   z-index 10000 sits above every other modal on the pitch page:
   CTA bar z:5, drawer scrim z:24, drawer panels z:26,
   review-feedback modal z:60, audience-feedback widget z:9999.
   The 2026-06-28 first cut used z-index 70 — which sat below the
   audience-feedback widget — and the live UX bug was exactly
   that: a visitor who clicked the section hero image while the
   audience-feedback prompt was open saw the prompt cover the
   lightbox (including the close button). The visitor could not
   close the lightbox or even see the image. z-index 10000 puts
   the lightbox on top of every other modal; closing the
   lightbox returns the visitor to whatever was underneath. The
   dim backdrop is darker than the audience-feedback widget's so
   the image stands out.

   Body scroll lock: pitch-cues.js sets the
   `data-lightbox-open` attribute on body while the overlay is
   open. The `body[data-lightbox-open]` selector below is a
   BODY-ATTRIBUTE selector (not a descendant selector), so it
   matches regardless of where the lightbox DOM root lives.
   Same pattern the drawer scrim (data-drawer-open) and the
   audience feedback modal (data-audience-feedback-open) use. */
.pitch-zoom-lightbox {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  background: rgba(0, 0, 0, 0.82);
  animation: pitch-zoom-lightbox-fade-in 120ms ease-out;
}
@keyframes pitch-zoom-lightbox-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
/* 2026-06-29 (dead-selector purge): the previous
   ".pitch-page html[data-pitch-theme="light"] .pitch-zoom-lightbox"
   selector was structurally impossible — `html` cannot be a
   descendant of `.pitch-page` because `.pitch-page` IS a
   descendant of `<html>`. The selector matched nothing from
   day 1. We drop the `.pitch-page` prefix and use the same flat
   selector pattern as the base .pitch-zoom-lightbox rule
   (which has the same fix). Now: light-mode lightboxes get the
   slightly heavier backdrop, dark-mode gets the lighter one. */
html[data-pitch-theme="light"] .pitch-zoom-lightbox {
  background: rgba(0, 0, 0, 0.88);
}

/* The image inside the lightbox.

   2026-06-29 (operator-reported "the image should expand to fill
   all available space"): the previous cap of max-width: 95vw +
   max-height: 88vh left dead bands on a viewport-bound image
   (top + bottom gaps on a wide image, left + right gaps on a tall
   image). The operator wants the image to fill ALL available
   viewport. We now use width: 100vw + height: 100vh +
   max-width: 100vw + max-height: 100vh (so the image element
   itself fills the entire viewport) + object-fit: contain (so
   the image is scaled to FIT inside the viewport box without
   cropping or distortion). The close button's z-index: 1 (set in
   .pitch-zoom-lightbox__close below) sits on top of the image,
   so the close target is still always reachable.

   The image gets its own rounded corners + subtle shadow for
   visual definition against the dim backdrop. The shadow is
   heavier on dark theme (the black-on-black needs separation)
   and lighter on light theme (already a strong contrast). */
.pitch-zoom-lightbox__img {
  display: block;
  width: 100vw;
  height: 100vh;
  max-width: 100vw;
  max-height: 100vh;
  object-fit: contain;
  border-radius: 8px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.55);
}
/* 2026-06-29 (dead-selector purge, sibling of the rule above):
   same impossible `.pitch-page html[...]` prefix dropped for the
   image shadow in light theme. */
html[data-pitch-theme="light"] .pitch-zoom-lightbox__img {
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.35);
}

/* The close button. Fixed-position at the top-right of the
   viewport (NOT the image) so the close target is always
   reachable regardless of the image's dimensions. Same shape
   as the audience-feedback dismiss button — circular pill, ~2.75rem
   (44 px, the iOS HIG / WCAG 2.5.5 minimum touch target), border
   + transparent background, focus ring.

   2026-06-29 (operator-reported "the close button does not work
   reliably"): the previous 2.5rem circle was slightly below the
   44 px minimum touch target on dense mobile browsers and could
   miss on a poorly-aimed tap (the user perceives the click as a
   miss and the close doesn't fire). We bumped to 2.75rem (44 px
   at 16 px root font-size) AND added pointer-events: auto +
   touch-action: manipulation. The auto is defensive against any
   ancestor (Vue transition, future wrapper) accidentally setting
   pointer-events: none on its children — without it a stroke of
   bad luck on a parent wrapper would make the button unclickable
   even though it looks live. touch-action: manipulation
   suppresses the 350 ms double-tap-to-zoom delay on mobile
   browsers (the button should close in ~50 ms, not after a
   delay). Slightly higher z-index (1) than the image so the
   close target sits on top of the image. */
.pitch-zoom-lightbox__close {
  position: fixed;
  top: 0.75rem;
  right: 0.75rem;
  width: 2.75rem;
  height: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.65);
  color: #fff;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  pointer-events: auto;
  touch-action: manipulation;
  z-index: 1;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.45);
}
.pitch-zoom-lightbox__close:hover {
  background: rgba(0, 0, 0, 0.75);
  border-color: #fff;
}
.pitch-zoom-lightbox__close:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

/* Body scroll lock while the lightbox is open. The
   `data-lightbox-open` attribute is set by pitch-cues.js's
   Lightbox module on open and removed on close. Same pattern
   as the drawer scrim and the audience feedback modal. */
body[data-lightbox-open] {
  overflow: hidden;
}

/* prefers-reduced-motion: kill the fade-in. The transform
   property (none) is belt-and-suspenders — we don't use a
   transform animation today, but if a future contributor adds
   a scale-pop, the rule catches it. */
@media (prefers-reduced-motion: reduce) {
  .pitch-zoom-lightbox {
    animation: none;
  }
}


/* === Per-section video (v1.1 plan §3.4) =================================
 * Rendered by pitchSectionVideo in
 * _includes/_macros/pitch-sections.njk. The wrapper carries the
 * existing .pitch-section-media class so the inactive-section
 * hiding rule ([data-pitch-active="false"] .pitch-section-media)
 * applies without changes.
 *
 * The plan called this file ideo-poster-region.scss; the
 * project's convention is one pitch-stage.css, so the rules live
 * here. The class names + attribute hooks are the contract.
 */
.pitch-page .pitch-section-media--per-section-video {
  margin: 0 0 1.25rem;
}

.pitch-page .pitch-section-media--per-section-video .pitch-section-media__wrapper {
  position: relative;
}

.pitch-page .pitch-section-media--per-section-video .pitch-section-video-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 2;
}

.pitch-page .pitch-section-media--per-section-video[data-pitch-video-playing="true"] .pitch-section-video-poster {
  z-index: 0;
  pointer-events: none;
  transition: opacity 200ms ease-out, z-index 0s linear 200ms;
  opacity: 0;
}

.pitch-page .pitch-section-media--per-section-video .pitch-section-video-meta {
  margin: 0.25rem 0 0;
  font-size: 0.8125rem;
  color: var(--hp-text-muted, #555);
  display: flex;
  gap: 0.75rem;
}

.pitch-page .pitch-section-media--per-section-video .pitch-section-video-meta__resolution {
  font-weight: 600;
}

.pitch-page .pitch-section-media--per-section-video .pitch-section-video-meta__duration {
  font-variant-numeric: tabular-nums;
}

.pitch-page .pitch-section-media--per-section-video .pitch-section-video-pending {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background: var(--hp-surface-alt, #f5f5f5);
  border: 1px dashed var(--hp-border, #ddd);
  border-radius: var(--hp-radius, 4px);
  min-height: 200px;
}

.pitch-page .pitch-section-media--per-section-video .pitch-section-video-pending__msg {
  margin: 0;
  font-size: 0.9375rem;
  color: var(--hp-text-muted, #555);
  text-align: center;
  padding: 1rem;
}
/* === end per-section video ============================================ */
