/* ===================================================== */
/* PROGRAMS PAGE STYLES                                  */
/* ----------------------------------------------------- */
/* Programs-only styling and composition rules.          */
/* This file loads after css/styles.css and should only  */
/* hold rules that describe html/programs.html.          */
/* ===================================================== */

/* ===================================================== */
/* PROGRAMS PAGE TOKENS                                  */
/* ----------------------------------------------------- */
/* Page-level control panel for the youth training       */
/* programs page. Shared site tokens stay in styles.css. */
/* ===================================================== */

:root {
  /* ===================================================== */
  /* PROGRAMS LAYOUT TOKENS                                */
  /* ----------------------------------------------------- */
  /* Controls section width, spacing, surfaces, and        */
  /* scheduler framing for the Programs page.              */
  /* ===================================================== */
  --programs-page-max-width: 1200px;
  --programs-page-side-padding: 24px;
  --programs-section-space: 104px;
  --programs-surface-bg: #f7f7f5;
  --programs-surface-border: rgba(17, 17, 17, 0.12);
  --programs-title-size: 66px;
  --programs-title-line-height: 1.08;
  --programs-statement-size: 21px;
  --programs-statement-line-height: 1.42;
  --programs-section-title-size: 42px;
  --programs-section-title-line-height: 1.16;
  --programs-copy-size: 16px;
  --programs-copy-line-height: 1.55;
  --programs-label-size: 11px;
  --programs-action-height: 48px;
  --programs-action-padding-x: 22px;

  /* Book Frame scene scroll track (Scenes Three + Four). Mirrors index
     Scene Five's 128vh route scene: a one-viewport sticky stage held
     across a short scroll, so the Book Frame reads with white above and
     below it. */
  --programs-bookframe-scroll-height: 128vh;

  /* ===================================================== */
  /* PROGRAMS — BOOK FRAME ROUTER TOKENS                   */
  /* ----------------------------------------------------- */
  /* Describes the 1200×776 Book Frame at the active        */
  /* breakpoint. Scene One derives all dimensions from      */
  /* these tokens, not from hardcoded pixel values.         */
  /* ===================================================== */
  --programs-book-frame-open-spread-width: var(--book-frame-source-width);
  --programs-book-frame-open-spread-height: var(--book-frame-source-height);
  --programs-book-frame-page-stack-gap: 0px;
  --programs-book-frame-single-page-width: min(
    var(--book-frame-single-page-source-width),
    calc(100vw - 32px),
    calc((var(--app-viewport-height) - var(--header-clearance) - (var(--book-frame-viewport-clearance, 16px) * 2)) * var(--book-frame-single-page-width-from-height-ratio, 0.7732))
  );
  --programs-book-frame-single-page-height: calc(var(--programs-book-frame-single-page-width) * var(--book-frame-single-page-ratio, 1.2933));
  --programs-book-frame-single-page-gap: max(
    0px,
    calc(
      var(--app-viewport-height)
      - var(--header-clearance)
      - (var(--book-frame-viewport-clearance, 16px) * 2)
      - var(--programs-book-frame-single-page-height)
    )
  );
  --programs-book-frame-stacked-page-width: min(
    var(--book-frame-single-page-source-width),
    calc(100vw - 32px)
  );
  --programs-book-frame-stacked-page-height: calc(var(--programs-book-frame-stacked-page-width) * var(--book-frame-single-page-ratio, 1.2933));
  --programs-book-frame-open-spread-scale: calc(var(--programs-book-frame-open-spread-width) / var(--book-frame-source-width));
  --programs-book-frame-single-page-scale: calc(var(--programs-book-frame-single-page-width) / var(--book-frame-single-page-source-width));
  --programs-book-frame-stacked-page-scale: calc(var(--programs-book-frame-stacked-page-width) / var(--book-frame-single-page-source-width));
  --programs-book-frame-layout-width: var(--programs-book-frame-open-spread-width);
  --programs-book-frame-layout-height: var(--programs-book-frame-open-spread-height);
  --programs-book-frame-layout-scale: var(--programs-book-frame-open-spread-scale);

  /* Shared Book Frame router for Scene One.                      */
  /* These describe the same rectangle Scene One's .spread__book  */
  /* renders at the active breakpoint.                            */
  /*                                                              */
  /*   layout-top   viewport-y of the active book frame           */
  /*                (matches where Scene One's .spread__book      */
  /*                starts vertically)                            */
  --programs-book-frame-layout-top: var(--header-clearance);

  /* Scene One source measurements (documentation tokens).        */
  /* Record the 1440 source values so breakpoint math is          */
  /* traceable back to the original approved measurements.        */
  --programs-scene-one-source-page-inset-top: 104px;
  --programs-scene-one-source-page-inset-bottom: 144px;
  --programs-scene-one-source-page-inset-outer: 80px;
  --programs-scene-one-source-page-inset-gutter: 144px;
  --programs-scene-one-source-text-field-width: 430px;
  --programs-scene-one-source-text-offset-y: 96px;
  --programs-scene-one-source-headline-size: 66px;

  /* Firefox rejects custom-property chains that depend on         */
  /* length/length division. These ratios preserve the same 1440  */
  /* source measurements without routing Scene One text through an */
  /* invalid scale value.                                          */
  --programs-scene-one-active-page-width: calc(var(--programs-book-frame-layout-width) * 0.5);
  --programs-scene-one-active-headline-size: calc(var(--programs-scene-one-active-page-width) * 0.11);
  --programs-scene-one-active-page-inset-top: calc(var(--programs-book-frame-layout-height) * 0.1340206);
  --programs-scene-one-active-page-inset-bottom: calc(var(--programs-book-frame-layout-height) * 0.185567);
  --programs-scene-one-active-page-inset-outer: calc(var(--programs-scene-one-active-page-width) * 0.1333333);
  --programs-scene-one-active-page-inset-gutter: calc(var(--programs-scene-one-active-page-width) * 0.24);
  --programs-scene-one-active-text-field-width: calc(var(--programs-scene-one-active-page-width) * 0.7166667);
  --programs-scene-one-active-text-offset-y: calc(var(--programs-book-frame-layout-height) * 0.1237113);
  /* Vertical nudge for the centered text block. Source: -137px at the 776px
     source page height (negative = up, positive = down). Stored as a unitless
     ratio (-137 / 776) and applied as layout-height * ratio so it scales per
     breakpoint without a length/length scale -- which Firefox rejects as
     invalid, collapsing the offset to 0 (text drops to dead-center). */
  --programs-scene-one-text-nudge: -0.1765464;
}

/* ===================================================== */
/* PROGRAMS PAGE FOUNDATION                              */
/* ----------------------------------------------------- */
/* Keeps the page in the shared site canvas while giving */
/* Programs its own operational editorial rhythm.        */
/* ===================================================== */

.programs-page {
  display: flex;
  flex-direction: column;
  gap: var(--programs-section-space);
  padding-bottom: var(--programs-section-space);
}

/* ===================================================== */
/* PROGRAMS TYPOGRAPHY                                   */
/* ----------------------------------------------------- */
/* Page-specific text roles for sections that sit        */
/* outside the generic spread text profiles.             */
/* ===================================================== */

.programs-kicker,
.programs-section-label {
  margin: 0;
  font-family: var(--font-secondary);
  font-size: var(--programs-label-size);
  line-height: 1.35;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.6);
}

.programs-title {
  margin: 0;
  font-family: var(--font-primary);
  font-size: var(--programs-title-size);
  line-height: var(--programs-title-line-height);
  font-weight: 400;
  letter-spacing: 0;
  color: var(--color-text);
}

.programs-section-title {
  margin: 0;
  font-family: var(--font-primary);
  font-size: var(--programs-section-title-size);
  line-height: var(--programs-section-title-line-height);
  font-weight: 400;
  letter-spacing: 0;
  color: var(--color-text);
}

.programs-copy {
  margin: 0;
  font-family: var(--font-primary);
  font-size: var(--programs-copy-size);
  line-height: var(--programs-copy-line-height);
  letter-spacing: 0.01em;
  color: var(--color-text);
}

/* ===================================================== */
/* PROGRAMS HERO                                         */
/* ----------------------------------------------------- */
/* Opening editorial spread. This section positions the  */
/* offer before moving into practical program details.   */
/* ===================================================== */

.programs-hero .spread__text {
  max-width: 430px;
}

.programs-hero__statement {
  margin: 0;
  font-family: var(--font-primary);
  font-size: var(--programs-statement-size);
  line-height: var(--programs-statement-line-height);
  letter-spacing: 0.01em;
  color: var(--color-text);
}

.programs-hero__media-frame {
  --spread-media-position: 18.8% 55%;
  --spread-media-scale: 1.3;
}

.programs-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.programs-action {
  min-height: var(--programs-action-height);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 var(--programs-action-padding-x);
  border: 1px solid var(--color-text);
  font-family: var(--font-secondary);
  font-size: 11px;
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
}

.programs-action--primary {
  background: var(--color-text);
  color: var(--color-bg);
}

.programs-action--secondary {
  background: transparent;
  color: var(--color-text);
}

.programs-action:hover,
.programs-action:focus-visible {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.programs-action:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 4px;
}

/* ===================================================== */
/* OVERVIEW SPREAD                                       */
/* ----------------------------------------------------- */
/* Concise positioning spread that explains the training */
/* offer before the program index appears.               */
/* ===================================================== */

.programs-overview .spread__text {
  max-width: 420px;
}

/* ===================================================== */
/* PROGRAM OFFERINGS                                     */
/* ----------------------------------------------------- */
/* Organized program index. This is intentionally more   */
/* sober than a course-card marketplace.                 */
/* ===================================================== */

/* ----------------------------------------------------- */
/* Book Frame scene tokens (Scenes Three + Four)         */
/* ----------------------------------------------------- */
/* Self-contained mirror of the homepage Disciplines      */
/* scene, built on the Programs Book Frame router so no    */
/* cross-page tokens are referenced. Source map is the     */
/* 1440 Book Frame (1200×776); the active layout reads     */
/* ratios against --programs-book-frame-layout-* so the    */
/* whole field scales like the homepage at every band.     */
/* Shared by Scene Three (offerings accordion) and Scene   */
/* Four (scheduler embed) so both stay the same family —   */
/* identical kicker, statement, and field box at every     */
/* breakpoint and viewport logic.                          */
/* ----------------------------------------------------- */
.programs-bookframe-scene {
  /* --- Active Book Frame (Programs router) --- */
  --po-frame-width: var(--programs-book-frame-layout-width);
  --po-frame-height: var(--programs-book-frame-layout-height);
  --po-frame-top: var(--programs-book-frame-layout-top);
  --po-content-width: calc(var(--po-frame-width) * 0.8666667);

  /* --- Source ratios (y / 776, x / 1200, type / 1040) --- */
  --po-content-y-ratio: 0.1391753;        /* 108 / 776  */
  --po-statement-y-ratio: 0.1881443;      /* 146 / 776  */
  --po-statement-space-ratio: 0.1095361;  /*  85 / 776  */
  --po-accordion-height-ratio: 0.5360825; /* 416 / 776  */
  --po-row-open-height-ratio: 0.3350515;  /* 260 / 776  */
  --po-side-padding-ratio: 0.02;          /*  24 / 1200 */
  --po-row-padding-x-ratio: 0.02;         /*  24 / 1200 */
  --po-body-x-ratio: 0.2692308;           /* 280 / 1040 */
  --po-body-width-ratio: 0.5461538;       /* 568 / 1040 */
  --po-kicker-size-ratio: 0.0115384615;   /*  12 / 1040 */
  --po-statement-size-ratio: 0.025;       /*  26 / 1040 */
  --po-row-label-size-ratio: 0.0240384615;/*  25 / 1040 */
  --po-body-size-ratio: 0.0163461538;     /*  17 / 1040 */

  /* --- Active geometry (viewport y + field sizes) --- */
  --po-content-top: calc(var(--po-frame-top) + (var(--po-frame-height) * var(--po-content-y-ratio)));
  --po-statement-offset: calc(var(--po-frame-height) * (var(--po-statement-y-ratio) - var(--po-content-y-ratio)));
  --po-statement-space: calc(var(--po-frame-height) * var(--po-statement-space-ratio));
  --po-accordion-height: calc(var(--po-frame-height) * var(--po-accordion-height-ratio));
  --po-side-padding: calc(var(--po-frame-width) * var(--po-side-padding-ratio));
  --po-row-padding-x: calc(var(--po-frame-width) * var(--po-row-padding-x-ratio));
  --po-row-open-cap: calc(var(--po-frame-height) * var(--po-row-open-height-ratio));
  --po-row-open-height: var(--po-row-open-cap); /* JS overrides per row */
  --po-body-x: calc(var(--po-content-width) * var(--po-body-x-ratio));
  --po-body-width: calc(var(--po-content-width) * var(--po-body-width-ratio));

  /* --- Row metrics --- */
  --po-row-count: 3;
  --po-row-slot-height: calc(var(--po-accordion-height) / var(--po-row-count));
  --po-body-edge-padding: calc(
    (var(--po-row-slot-height) - (var(--po-row-label-size) * var(--po-row-label-line-height))) / 2
  );
  /* Closed rows never collapse below a legible height (portrait). */
  --po-row-closed-min: 0px;

  /* --- Portrait composition (single tall page) --- */
  /* Source ratios mirrored from the homepage portrait scene. */
  --po-portrait-statement-y-ratio: 0.0568862;
  --po-portrait-accordion-y-ratio: 0.1497006;
  --po-portrait-body-x-ratio: 0.24;
  --po-portrait-body-width-ratio: 0.6267;
  --po-kicker-line-box-height: calc(var(--po-kicker-size) * var(--po-kicker-line-height));
  /* Symmetric top/bottom breathing space around the portrait page. */
  --po-portrait-frame-edge-gap: max(
    0px,
    calc(var(--po-frame-top) - var(--header-logo-line-y))
  );
  /* Accordion fills from its top to the bottom of the page. */
  --po-accordion-page-fill-height: max(0px, calc(
    var(--po-frame-top)
    + var(--po-frame-height)
    - var(--po-content-top)
    - var(--po-kicker-line-box-height)
    - var(--po-statement-space)
  ));

  /* --- Label stack (inline when closed, stacked when open) --- */
  --po-label-collapsed-gap: 0.55em;
  --po-label-open-gap: 0.45em;

  /* --- Surfaces --- */
  --po-accordion-bg: #eeeeec;
  --po-row-bg: #eeeeec;
  --po-row-bg-open: #000000;
  --po-row-fg: #111111;
  --po-row-fg-open: #ffffff;
  --po-accordion-radius: 10px;
  --po-row-radius: 12px;
  --po-row-divider: rgba(17, 17, 17, 0.06);

  /* --- Type --- */
  --po-kicker-size: max(11px, calc(var(--po-content-width) * var(--po-kicker-size-ratio)));
  --po-kicker-line-height: 1.25;
  --po-statement-size: max(15px, calc(var(--po-content-width) * var(--po-statement-size-ratio)));
  --po-statement-line-height: 1.2;
  --po-row-label-size: max(16px, calc(var(--po-content-width) * var(--po-row-label-size-ratio)));
  --po-row-label-line-height: 1.2;
  --po-body-size: max(13px, calc(var(--po-content-width) * var(--po-body-size-ratio)));
  --po-body-line-height: 1.42;

  /* --- Motion --- */
  --po-row-duration: 520ms;
  --po-row-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ----------------------------------------------------- */
/* Scene + sticky stage (shared: Scenes Three + Four)    */
/* ----------------------------------------------------- */
/* Section is a short scroll track; the stage locks one   */
/* viewport of white into place (same sticky lock as the  */
/* homepage scene) while the field reads, then releases.  */
/* Scene Three holds the offerings accordion; Scene Four   */
/* holds the scheduler embed — both sit on the same Book   */
/* Frame composition.                                      */
.programs-offerings,
.programs-scheduler {
  position: relative;
  height: var(--programs-bookframe-scroll-height);
  background: #ffffff;
}

/* Scene Four sits directly on Scene Three — cancel the page flex gap
   before the scheduler so the two book-frame scenes stack with no extra
   gap, and the transition line pins to their seam (top: 0). (Scene
   Three's own leading gap is already cancelled by the article spread's
   negative margin-bottom, so only the scheduler needs this.) */
.programs-scheduler {
  margin-top: calc(-1 * var(--programs-section-space));
}

.programs-offerings__stage,
.programs-scheduler__stage {
  position: sticky;
  top: 0;
  height: var(--app-viewport-height);
  overflow: hidden;
  background: #ffffff;
}

/* Content frame: kicker / statement space / field box,    */
/* anchored inside the Book Frame and centered.            */
.programs-offerings__inner,
.programs-scheduler__inner {
  position: absolute;
  top: var(--po-content-top);
  left: 50%;
  width: var(--po-content-width);
  max-width: calc(100% - (var(--po-side-padding) * 2));
  transform: translateX(-50%);
  display: grid;
  grid-template-rows: auto var(--po-statement-space) auto;
  row-gap: 0;
  box-sizing: border-box;
}

/* Kicker ("Offerings:" / "Schedule:") mirrors the homepage kicker. */
.programs-offerings__kicker,
.programs-scheduler__kicker {
  margin: 0;
  font-family: var(--font-secondary);
  font-size: var(--po-kicker-size);
  font-weight: 400;
  letter-spacing: 0.08em;
  line-height: var(--po-kicker-line-height);
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.6);
}

/* Statement: placement + size mirror the homepage statement. */
/* Absolutely placed inside the content frame so it floats in  */
/* the statement space without disturbing the field box's y.   */
.programs-offerings__statement,
.programs-scheduler__statement {
  position: absolute;
  top: var(--po-statement-offset);
  left: 0;
  width: 100%;
  margin: 0;
  font-family: var(--font-primary);
  font-size: var(--po-statement-size);
  font-weight: 700;
  line-height: var(--po-statement-line-height);
  color: var(--color-text);
  pointer-events: none;
}

.programs-offerings__statement-space,
.programs-scheduler__statement-space {
  min-height: var(--po-statement-space);
}

.programs-details__inner {
  width: 100%;
  max-width: var(--programs-page-max-width);
  margin-left: auto;
  margin-right: auto;
}

/* ----------------------------------------------------- */
/* Accordion field                                       */
/* ----------------------------------------------------- */
/* One gray field holds the three offering rows. Only one */
/* row opens at a time (click); the open row turns into a */
/* dark panel that reveals the schedule + description.    */
.programs-offering-list {
  width: 100%;
  max-width: 100%;
  height: var(--po-accordion-height);
  display: flex;
  flex-direction: column;
  background: var(--po-accordion-bg);
  border-radius: var(--po-accordion-radius);
  overflow: hidden;
}

.programs-offering {
  position: relative;
  flex: 1 1 var(--po-row-slot-height);
  min-height: var(--po-row-closed-min, 0px);
  display: flex;
  flex-direction: column;
  background: var(--po-row-bg);
  color: var(--po-row-fg);
  border-top: 1px solid var(--po-row-divider);
  overflow: hidden;
  transition:
    flex-basis var(--po-row-duration) var(--po-row-ease),
    background-color var(--po-row-duration) var(--po-row-ease),
    border-radius var(--po-row-duration) var(--po-row-ease),
    color var(--po-row-duration) var(--po-row-ease);
}

.programs-offering:first-child {
  border-top: 0;
}

.programs-offering__heading {
  margin: 0;
  flex: 0 0 auto;
  height: 100%;
}

.programs-offering__button {
  all: unset;
  /* `all: unset` does not reset custom properties, but re-bridge the
     label gap tokens here so the inner spans resolve them reliably. */
  --po-label-collapsed-gap: inherit;
  --po-label-open-gap: inherit;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 100%;
  height: 100%;
  padding: 0 var(--po-row-padding-x);
  cursor: pointer;
  font-family: var(--font-secondary);
  font-size: var(--po-row-label-size);
  font-weight: 300;
  letter-spacing: 0.02em;
  line-height: var(--po-row-label-line-height);
  color: inherit;
  transition: color var(--po-row-duration) var(--po-row-ease);
}

.programs-offering__button:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: -4px;
}

/* Label: collapsed reads inline ("Photography Workshop"); open stacks
   the suffix onto a second line so the heading stays clear of the
   description column — the same move as the homepage rows. */
.programs-offering__label {
  display: inline-block;
}

.programs-offering__label-stack {
  display: inline;
}

.programs-offering__label-word,
.programs-offering__label-gap,
.programs-offering__label-suffix {
  display: inline;
}

.programs-offering:not(.is-open) .programs-offering__label-suffix {
  margin-left: var(--po-label-collapsed-gap);
}

.programs-offering.is-open .programs-offering__label-stack {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 0.8;
}

.programs-offering.is-open .programs-offering__label-suffix {
  display: block;
  margin-top: var(--po-label-open-gap);
  margin-left: 0;
}

.programs-offering.is-open .programs-offering__label-gap {
  display: none;
}

.programs-offering__number {
  flex: 0 0 auto;
}

/* Closed hover: dark spotlight, mirrors the homepage row. */
.programs-offering:not(.is-open):hover {
  background: var(--po-row-bg-open);
  border-radius: var(--po-row-radius);
  color: var(--po-row-fg-open);
}

/* Panel (collapsing body) */
.programs-offering__panel {
  display: none;
}

.programs-offering__body {
  width: var(--po-body-width);
  max-width: var(--po-body-width);
  padding: var(--po-body-edge-padding) 0;
  font-family: var(--font-secondary);
  font-size: var(--po-body-size);
  font-weight: 300;
  line-height: var(--po-body-line-height);
  color: inherit;
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity var(--po-row-duration) var(--po-row-ease),
    transform var(--po-row-duration) var(--po-row-ease);
}

.programs-offering__body-meta {
  margin: 0 0 0.6em;
  font-size: 0.82em;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.72;
}

.programs-offering__body-copy {
  margin: 0;
}

/* Open state: row grows to the measured body height (capped), turns
   dark, heading pins to the top slot, body fades in beside it. */
.programs-offering.is-open {
  flex: 0 0 min(var(--po-row-open-height), var(--po-row-open-cap));
  background: var(--po-row-bg-open);
  border-radius: var(--po-row-radius);
  color: var(--po-row-fg-open);
  z-index: 2;
}

.programs-offering.is-open .programs-offering__heading,
.programs-offering.is-open .programs-offering__button {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--po-row-slot-height);
}

.programs-offering.is-open .programs-offering__heading {
  z-index: 2;
}

.programs-offering.is-open .programs-offering__button {
  align-items: center;
  pointer-events: auto;
}

.programs-offering.is-open .programs-offering__panel {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: flex-start;
  box-sizing: border-box;
  padding-left: var(--po-body-x);
  pointer-events: none;
}

.programs-offering.is-open .programs-offering__body {
  opacity: 1;
  transform: translateY(0);
}

/* ----------------------------------------------------- */
/* Reduced motion                                        */
/* ----------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .programs-offering,
  .programs-offering__body {
    transition: none !important;
  }
}

/* ----------------------------------------------------- */
/* Portrait / phone composition                          */
/* ----------------------------------------------------- */
/* Mirrors the homepage Scene Three portrait logic: the   */
/* Book Frame becomes one tall single page whose HEIGHT   */
/* is taken from the viewport, the kicker rebases to the  */
/* frame top, and the accordion fills the page. The scene */
/* stays locked (sticky) — the same behavior as the       */
/* homepage, not a static reflow.                         */
@media (min-width: 768px) and (max-width: 1300px) and (max-aspect-ratio: 6/5),
       (max-width: 767px) {
  .programs-bookframe-scene {
    /* Full single-page width; viewport-driven frame height. */
    --po-content-width: var(--po-frame-width);
    --po-frame-height: max(
      0px,
      calc(var(--app-viewport-height) - var(--po-frame-top) - var(--po-portrait-frame-edge-gap))
    );
    /* Kicker at the frame top; statement + field box rebased. */
    --po-content-top: var(--po-frame-top);
    --po-statement-offset: calc(var(--po-frame-height) * var(--po-portrait-statement-y-ratio));
    --po-statement-space: max(
      0px,
      calc((var(--po-frame-height) * var(--po-portrait-accordion-y-ratio)) - var(--po-kicker-line-box-height))
    );
    --po-accordion-height: var(--po-accordion-page-fill-height);
    /* Keep the hierarchy size but allow the (longer) Programs
       statement to wrap rather than clipping to one line. */
    --po-statement-size: max(
      calc(var(--po-kicker-size) * 1.85),
      calc(var(--po-content-width) * var(--po-statement-size-ratio))
    );
    /* Rows hold a legible closed height; the open row takes the rest. */
    --po-row-closed-min: max(
      44px,
      calc((var(--po-row-label-size) * var(--po-row-label-line-height)) + 24px)
    );
    --po-row-open-cap: max(
      var(--po-row-closed-min),
      calc(var(--po-accordion-height) - (var(--po-row-closed-min) * 2))
    );
    /* Description as a right-hand column inside the page. */
    --po-body-x: calc(var(--po-frame-width) * var(--po-portrait-body-x-ratio));
    --po-body-width: calc(var(--po-frame-width) * var(--po-portrait-body-width-ratio));
    /* Body box vertically fills its slot so the open row clears the
       heading and the copy centers against it. */
    --po-body-edge-padding: calc(
      (var(--po-row-slot-height) - (var(--po-body-size) * var(--po-body-line-height))) / 2
    );
  }

  /* Statement may wrap here; let it breathe within the page. */
  .programs-offerings__statement,
  .programs-scheduler__statement {
    white-space: normal;
  }

  /* Open row: top-align the stacked label within its slot. */
  .programs-offering.is-open .programs-offering__button {
    align-items: flex-start;
  }
}

/* Phone: the row is too narrow for a side-by-side body, so push the
   description below the heading slot and run it the page width. */
@media (max-width: 767px) {
  .programs-bookframe-scene {
    --po-body-x: var(--po-row-padding-x);
    --po-body-width: calc(var(--po-frame-width) - (var(--po-row-padding-x) * 2));
    --po-body-edge-padding: calc(var(--po-row-slot-height) + 12px);
  }
}

/* Shared header clearance on phone portrait. The site header is the   */
/* same on every page, so the clearance below it must match the        */
/* homepage at these widths (the homepage reduces it in index.css).    */
/* This keeps the portrait Book Frame top — and therefore Scene Three's */
/* viewport-driven page height — identical to the homepage.            */
@media (min-width: 481px) and (max-width: 767px) and (orientation: portrait) {
  :root {
    --header-clearance: 113px;
  }
}

@media (max-width: 480px) and (orientation: portrait) {
  :root {
    --header-clearance: 96px;
  }
}

/* ===================================================== */
/* STUDENT GAINS AND FORMAT                              */
/* ----------------------------------------------------- */
/* Buyer-facing value and logistics in one controlled    */
/* field.                                                */
/* ===================================================== */

.programs-details {
  padding-left: var(--programs-page-side-padding);
  padding-right: var(--programs-page-side-padding);
}

.programs-details__inner {
  display: grid;
  gap: 36px;
}

.programs-details__intro {
  width: min(100%, 760px);
  display: grid;
  gap: 14px;
}

.programs-details__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--programs-surface-border);
}

.programs-detail-block {
  min-height: 330px;
  display: grid;
  align-content: start;
  gap: 24px;
  padding: 34px 32px;
  background: var(--programs-surface-bg);
}

.programs-detail-block__title {
  margin: 0;
  font-family: var(--font-primary);
  font-size: 30px;
  line-height: 1.18;
  font-weight: 400;
}

.programs-detail-list {
  display: grid;
  gap: 16px;
  margin: 0;
  padding-left: 18px;
  font-family: var(--font-primary);
  font-size: var(--programs-copy-size);
  line-height: var(--programs-copy-line-height);
}

.programs-logistics {
  display: grid;
  gap: 18px;
  margin: 0;
}

.programs-logistics__item {
  display: grid;
  gap: 6px;
  padding-top: 14px;
  border-top: 1px solid var(--programs-surface-border);
}

.programs-logistics dt {
  font-family: var(--font-secondary);
  font-size: 11px;
  line-height: 1.35;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.58);
}

.programs-logistics dd {
  margin: 0;
  font-family: var(--font-primary);
  font-size: var(--programs-copy-size);
  line-height: var(--programs-copy-line-height);
}

/* ===================================================== */
/* SCHEDULER SECTION                                     */
/* ----------------------------------------------------- */
/* Final action layer. The Brickhouse page frames Acuity */
/* but does not try to turn Acuity into the design system.*/
/* ===================================================== */

/* Scene Four shares the Book Frame composition with Scene Three (scene, */
/* stage, content frame, kicker, statement are grouped above). Only the   */
/* embed field box is scheduler-specific: it mirrors the offerings         */
/* accordion box — same width, height, and corner radius at every          */
/* breakpoint and viewport logic — but holds the Acuity embed instead of   */
/* the click rows.                                                         */
.programs-scheduler__frame {
  position: relative;
  width: 100%;
  max-width: 100%;
  height: var(--po-accordion-page-fill-height);
  background: var(--po-accordion-bg);
  border-radius: var(--po-accordion-radius);
  /* Scroll container: the box keeps its fixed height; the taller
     Acuity embed scrolls within it so every listing is reachable.
     border-radius still clips the iframe to the rounded box. */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

/* Small curtain: masks the very top edge of the upward-shifted
   iframe so the crop reads clean. pointer-events:none lets
   clicks pass through to the embed below. */
.programs-scheduler__frame::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 0px;
  background: var(--po-accordion-bg);
  border-radius: var(--po-accordion-radius) var(--po-accordion-radius) 0 0;
  z-index: 1;
  pointer-events: none;
}

.programs-scheduler__embed {
  display: block;
  width: 100%;
  /* Let Acuity's embed.js set the iframe to its FULL content height
     (no !important override) so nothing below is clipped — the frame
     above scrolls through it. min-height keeps the box filled even if
     the embed is short. margin-top crops the top chrome out of view;
     the negative margin sits above scroll origin so it stays hidden. */
  min-height: calc(100% + 138px);
  margin-top: -138px;
  border: 0;
  background: var(--po-accordion-bg);
}

/* ===================================================== */
/* PROGRAMS RESPONSIVE STATES                            */
/* ----------------------------------------------------- */
/* Keeps program information readable and the scheduler  */
/* usable across smaller screens.                        */
/* ===================================================== */

@media (max-width: 959px) {
  :root {
    --programs-section-space: 80px;
    --programs-title-size: 56px;
    --programs-section-title-size: 36px;
  }

  .programs-details__grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 767px) {
  :root {
    --programs-page-side-padding: 16px;
    --programs-section-space: 56px;
    --programs-title-size: 44px;
    --programs-statement-size: 18px;
    --programs-section-title-size: 30px;
    --programs-copy-size: 15px;
  }

  .programs-hero__actions {
    flex-direction: column;
    align-items: stretch;
  }

  .programs-action {
    width: 100%;
  }

  .programs-detail-block {
    min-height: auto;
    padding: 28px 20px;
  }
}

/* ===================================================== */
/* SCENE ONE — PROGRAMS HERO                             */
/* ----------------------------------------------------- */
/* .programs-hero is the CSS hook for Scene One.         */
/* Image is on the LEFT page, text on the RIGHT page.    */
/* Right page insets: outer on right edge, gutter on     */
/* left edge (facing the image page) — same layout as    */
/* case studies.                                         */
/* Vertical centering is handled by .spread__inner--center*/
/* already in styles.css — no justify-content needed here.*/
/* ===================================================== */

.programs-hero {
  display: flex;
  align-items: stretch;
}

/* Right page: text. Outer padding faces the viewport right
   edge; gutter padding faces the image page on the left.
   Top and bottom padding are zeroed so that justify-content:
   center (from .spread__inner--center in styles.css) operates
   over the full book-frame height. The explicit height gives
   flexbox a concrete pixel value at every breakpoint — the
   same cross-browser reliability pattern used in the case
   study spreads. */
.programs-hero .spread__page--right .spread__inner {
  padding-top: 0;
  padding-bottom: 0;
  height: var(--programs-book-frame-layout-height);
  padding-left: var(--programs-scene-one-active-page-inset-gutter);
  padding-right: var(--programs-scene-one-active-page-inset-outer);
}

/* Nudge: shifts the text block from its centered position.
   Expressed in source-space px, scaled by layout-scale so
   the offset is proportional at every breakpoint. */
.programs-hero .spread__page--right .spread__inner .spread__text {
  margin-top: calc(var(--programs-book-frame-layout-height) * var(--programs-scene-one-text-nudge));
}

/* Text field: wider than the standard case-study 376px.
   Source: 430px at 1440 = 0.7166667 × active page width. */
.programs-hero .spread__text {
  max-width: var(--programs-scene-one-active-text-field-width);
}

/* Headline: .programs-title uses --programs-title-size
   (66px at 1440). Book Frame scale replaces the hardcoded
   breakpoint overrides for this element.                  */
.programs-hero .programs-title {
  font-size: var(--programs-scene-one-active-headline-size);
}

/* ===================================================== */
/* SCENE ONE — PROPORTIONAL TEXT BLOCK SCALING           */
/* ----------------------------------------------------- */
/* The headline already scales via active-headline-size. */
/* The kicker, statement, action buttons, and all spacing */
/* are fixed in px — as the book frame shrinks they take */
/* up a growing proportion of the page, collapsing the   */
/* free space that centering + nudge needs to resolve.   */
/*                                                       */
/* These overrides express every fixed measurement as a  */
/* ratio of the active book frame so the entire text     */
/* block scales as a single unit at every breakpoint.    */
/*                                                       */
/* Source reference (1200×776 open spread):              */
/*   active-page-width = 600px  layout-height = 776px   */
/* ===================================================== */

/* Kicker: 11px font at source. */
.programs-hero .programs-kicker {
  font-size: calc(var(--programs-scene-one-active-page-width) * 0.01833);
}

/* Stack gap between all text block children: 24px at source. */
.programs-hero .spread__page--right .spread__text {
  gap: calc(var(--programs-book-frame-layout-height) * 0.031);
}

/* Statement: 21px font at source. */
.programs-hero .programs-hero__statement {
  font-size: calc(var(--programs-scene-one-active-page-width) * 0.035);
}

/* Action buttons: 48px height, 22px horizontal padding,
   11px font at source.                                  */
.programs-hero .programs-action {
  min-height: calc(var(--programs-book-frame-layout-height) * 0.0619);
  padding-left: calc(var(--programs-scene-one-active-page-width) * 0.0367);
  padding-right: calc(var(--programs-scene-one-active-page-width) * 0.0367);
  font-size: calc(var(--programs-scene-one-active-page-width) * 0.01833);
}

/* Gap between the two action buttons: 12px at source. */
.programs-hero .programs-hero__actions {
  gap: calc(var(--programs-book-frame-layout-height) * 0.0155);
}

/* ===================================================== */
/* SCENE ONE — RESPONSIVE BREAKPOINTS                    */
/* ----------------------------------------------------- */
/* This section is the Scene One responsive layer. It    */
/* does not invent a new layout system; it adjusts the   */
/* existing Book Frame tokens and only adds structural    */
/* overrides where the spread must change shape.          */
/*                                                        */
/* Current responsive states:                            */
/*   1. Desktop source          : 1301+ normal height    */
/*   2. Short-height desktop    : 1301+ / max-height 895 */
/*      Global spread scaling lives in css/styles.css;   */
/*      this file inherits that scaled spread.           */
/*   3. Narrow Desktop / Laptop : 1100–1300              */
/*   4. Fitted open spread      : 768–1099               */
/*   5. Phone                   : 0–767                  */
/*   6. Portrait stacking       : 768–1300 portrait      */
/* ===================================================== */

/* ====================================================== */
/* ACTIVE BOOK FRAME SYNC                                */
/* ------------------------------------------------------ */
/* The 1440 source band keeps the source 1200x776 frame.  */
/* Bands where the shared spread has already scaled in    */
/* css/styles.css read that rendered spread back into the */
/* Programs Book Frame tokens. Tablet widths below the    */
/* shared spread threshold opt Scene One into a fitted    */
/* two-page spread without changing global spread tokens. */
/* ====================================================== */
@media (min-width: 1301px) and (max-height: 895px),
       (min-width: 1100px) and (max-width: 1300px) {
  :root {
    --programs-book-frame-open-spread-width: var(--spread-max-width);
    --programs-book-frame-open-spread-height: var(--spread-height);
  }
}

/* ====================================================== */
/* FITTED OPEN SPREAD : 768–1099                          */
/* ------------------------------------------------------ */
/* The Programs hero intro can still hold its two-page    */
/* idea at tablet widths if the Book Frame is scaled by   */
/* width AND height. This keeps the spread from switching */
/* to a phone stack prematurely while leaving other       */
/* sections alone.                                        */
/* ====================================================== */
@media (min-width: 768px) and (max-width: 1099px) {
  :root {
    --programs-book-frame-open-spread-width: min(
      var(--book-frame-source-width),
      calc(100vw - 48px),
      calc((var(--app-viewport-height) - var(--header-clearance) - var(--book-frame-viewport-clearance, 16px)) * var(--book-frame-width-from-height-ratio, 1.5464))
    );
    --programs-book-frame-open-spread-height: calc(var(--programs-book-frame-open-spread-width) * var(--book-frame-source-ratio, 0.6467));
  }

  .programs-hero {
    min-height: var(--programs-book-frame-open-spread-height);
  }

  .programs-hero .spread__page--left,
  .programs-hero .spread__page--right {
    order: 0;
  }

  .programs-hero .spread__book {
    width: var(--programs-book-frame-open-spread-width);
    max-width: var(--programs-book-frame-open-spread-width);
    height: var(--programs-book-frame-open-spread-height);
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .programs-hero .spread__page,
  .programs-hero .spread__page--media-only {
    width: auto;
    height: var(--programs-book-frame-open-spread-height);
    min-height: var(--programs-book-frame-open-spread-height);
  }
}

/* ====================================================== */
/* SCENE ONE STACKED ORDER + PAGE MODEL : 0–767           */
/* ------------------------------------------------------ */
/* The Book Frame switches Scene One into a stacked       */
/* Single Page model at phone widths. Image leads on top, */
/* text follows below, preserving the original 600x776    */
/* page proportion instead of becoming loose full-width   */
/* content. Image leads here so the stack mirrors the     */
/* open-spread swap (image-left, text-right).             */
/* ====================================================== */
@media (max-width: 767px) {
  :root {
    --programs-book-frame-stacked-page-width: min(
      var(--book-frame-single-page-source-width),
      calc(100vw - 48px),
      calc((var(--app-viewport-height) - var(--header-clearance) - (var(--book-frame-viewport-clearance, 16px) * 2)) * var(--book-frame-single-page-width-from-height-ratio, 0.7732))
    );
    --programs-book-frame-stacked-page-height: calc(var(--programs-book-frame-stacked-page-width) * var(--book-frame-single-page-ratio, 1.2933));
    --programs-book-frame-page-stack-gap: 0px;
    --programs-book-frame-layout-width: var(--programs-book-frame-stacked-page-width);
    --programs-book-frame-layout-height: var(--programs-book-frame-stacked-page-height);
    --programs-book-frame-layout-scale: var(--programs-book-frame-stacked-page-scale);
    --programs-book-frame-layout-top: calc(var(--header-clearance) + var(--book-frame-viewport-clearance, 16px));
    --programs-scene-one-active-page-width: var(--programs-book-frame-layout-width);
  }

  .programs-hero {
    padding-top: var(--book-frame-viewport-clearance, 16px);
  }

  /* Image first, text second. Grid items accept the
     `order` property exactly like flex items. The image is
     the leading (left) page, so it leads the stack too. */
  .programs-hero .spread__page--left  { order: -1; }
  .programs-hero .spread__page--right { order: 0; }

  .programs-hero .spread__book {
    width: var(--programs-book-frame-stacked-page-width);
    max-width: var(--programs-book-frame-stacked-page-width);
    height: auto;
    grid-template-columns: 1fr;
    gap: var(--programs-book-frame-page-stack-gap);
    justify-items: stretch;
  }

  .programs-hero .spread__page {
    width: var(--programs-book-frame-stacked-page-width);
    height: var(--programs-book-frame-stacked-page-height);
    min-height: var(--programs-book-frame-stacked-page-height);
  }

  /* Image keeps the right-page crop field instead of expanding to
     a loose, oversized mobile image. */
  .programs-hero .spread__page--media-only {
    height: var(--programs-book-frame-stacked-page-height);
    min-height: var(--programs-book-frame-stacked-page-height);
  }

  .programs-hero .spread__page--media-only .spread__media,
  .programs-hero .spread__page--media-only .spread__media-frame {
    height: 100%;
    min-height: 100%;
  }
}

/* ====================================================== */
/* SCENE ONE PORTRAIT PAGE STACK : 768–1300               */
/* ------------------------------------------------------ */
/* Tablet, small-laptop, and narrow-desktop windows keep  */
/* the scaled Open Spread while they are landscape-ish.   */
/* Once the viewport leans portrait, this rule preserves  */
/* the Book Frame page logic as two stacked pages: Left   */
/* Page on top, Right Page below. The gap is leftover     */
/* viewport space, so page one clears as page two snaps   */
/* into place. The text page keeps its imaginary page     */
/* boundary and text-safe field.                         */
/* Each page snaps independently so the user lands on one */
/* fitted page before scrolling into the next page.       */
/* ====================================================== */
@media (min-width: 768px) and (max-width: 1300px) and (max-aspect-ratio: 6/5) {
  :root {
    --programs-book-frame-page-stack-gap: var(--programs-book-frame-single-page-gap);
    --programs-book-frame-layout-width: var(--programs-book-frame-single-page-width);
    --programs-book-frame-layout-height: var(--programs-book-frame-single-page-height);
    --programs-book-frame-layout-scale: var(--programs-book-frame-single-page-scale);
    --programs-book-frame-layout-top: calc(var(--header-clearance) + var(--book-frame-viewport-clearance, 16px));
    --programs-scene-one-active-page-width: var(--programs-book-frame-layout-width);
  }

  .programs-hero {
    padding-top: var(--book-frame-viewport-clearance, 16px);
  }

  .programs-hero .spread__page--left  { order: -1; }
  .programs-hero .spread__page--right { order: 0; }

  .programs-hero .spread__book {
    width: var(--programs-book-frame-single-page-width);
    max-width: var(--programs-book-frame-single-page-width);
    height: auto;
    grid-template-columns: 1fr;
    gap: var(--programs-book-frame-page-stack-gap);
  }

  .programs-hero .spread__page {
    width: var(--programs-book-frame-single-page-width);
    height: var(--programs-book-frame-single-page-height);
    min-height: var(--programs-book-frame-single-page-height);
  }

  .programs-hero .spread__page--media-only {
    height: var(--programs-book-frame-single-page-height);
    min-height: var(--programs-book-frame-single-page-height);
  }

  .programs-hero .spread__page--media-only .spread__media,
  .programs-hero .spread__page--media-only .spread__media-frame {
    height: 100%;
    min-height: 100%;
  }
}

/* ===================================================== */
/* SCENE TWO — ARTICLE SPREAD                            */
/* ----------------------------------------------------- */
/* A sticky two-page book spread on the same scroll-lock  */
/* system as Scenes Three and Four: the section is a 128vh */
/* scroll track; the stage locks one viewport into place;  */
/* the open book is absolutely positioned on the Book Frame */
/* — same coordinates as Scene One.                        */
/*                                                         */
/* The copy fills the LEFT page, then continues on the     */
/* RIGHT page. "Overview" lands at the same baseline as    */
/* "Offerings:" in Scene Three (0.1391753 of frame height).*/
/* Body copy matches Scene One's Baskerville statement     */
/* style exactly (same size ratio: 0.035 × page width).   */
/* "Program Format" / "What Students Gain" are kicker-    */
/* styled like "Offerings:", 16px above / 8px below.       */
/*                                                         */
/* Portrait/phone: the sticky lock is released and the     */
/* pages stack in normal flow (same as Scene One portrait).*/
/* ===================================================== */
.programs-article-spread {
  --pa-copy-size: max(15px, calc(var(--programs-scene-one-active-page-width) * 0.035));
  --pa-label-size: max(11px, calc(var(--programs-scene-one-active-page-width) * 0.02));
  /* Space above a heading is ~2.5× the space below so the heading
     reads as the opening of the next paragraph, not the close of
     the previous one. Both scale with the active page width. */
  --pa-heading-gap-top: calc(var(--pa-overview-gap) * 2.4);
  --pa-heading-gap-bottom: 8px;
  --pa-overview-gap: calc(var(--programs-scene-one-active-page-width) * 0.045);

  /* 128vh scroll track — same as Scenes Three + Four. */
  position: relative;
  height: var(--programs-bookframe-scroll-height);
  background: #ffffff;
  /* Cancel the page flex gap on BOTH sides in landscape so this book
     frame sits directly on the hero above and the offerings below — no
     extra gap between book-frame scenes. The sticky mechanics (128vh
     track vs 100vh stage) supply the breathing room. The transition
     line then pins to the hero/Scene Two seam (top: 0). */
  margin-top: calc(-1 * var(--programs-section-space));
  margin-bottom: calc(-1 * var(--programs-section-space));
}

/* Sticky stage: one viewport locks in place while the
   user scrolls through the 128vh track. Identical to the
   Scene Three / Four stage in every respect.              */
.programs-article-spread__stage {
  position: sticky;
  top: 0;
  height: var(--app-viewport-height);
  overflow: hidden;
  background: #ffffff;
}

/* Open book, absolutely placed on the Book Frame.
   top  = --programs-book-frame-layout-top (= header-clearance
          in landscape, clearance + viewport-clearance in portrait).
   The book fills the full frame width and height so both pages
   clip at the page bottom — text that doesn't fit is hidden,
   exactly as if the page had a physical bottom edge.          */
.programs-article-spread .spread__book {
  position: absolute;
  top: var(--programs-book-frame-layout-top);
  left: 50%;
  transform: translateX(-50%);
  width: var(--programs-book-frame-layout-width);
  max-width: var(--programs-book-frame-layout-width);
  height: var(--programs-book-frame-layout-height);
  margin: 0;
  /* Always two columns in landscape — overrides the global
     max-width:1099px rule that collapses to one column. */
  grid-template-columns: 1fr 1fr;
}

/* Spine crease: a hairline at the horizontal center of the frame,
   half the frame height tall and vertically centered.
   This sits above the page columns (z-index 2) but is pointer-events:none
   so it never blocks text selection or clicks.                        */
.programs-article-spread .spread__book::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 33.333%;
  transform: translateX(-50%);
  width: 1px;
  height: 33.333%;
  background: linear-gradient(
    to bottom,
    transparent,
    rgba(17, 17, 17, 0.18) 25%,
    rgba(17, 17, 17, 0.18) 75%,
    transparent
  );
  pointer-events: none;
  z-index: 2;
}

/* Each page is one column of the fixed-height frame. */
.programs-article-spread .spread__page {
  height: var(--programs-book-frame-layout-height);
  min-height: 0;
  overflow: hidden;
}

/* Inner text-safe padding:
   top    = same ratio as "Offerings:" on Scene Three (108/776)
   bottom = Scene One's active inset bottom
   left/right mirror Scene One's outer + gutter insets,
   so the two pages face each other across the spine.     */
.programs-article-spread .spread__page--text-only .spread__inner {
  padding-top: calc(var(--programs-book-frame-layout-height) * 0.1391753);
  padding-bottom: var(--programs-scene-one-active-page-inset-bottom);
}

.programs-article-spread .spread__page--left .spread__inner {
  padding-left: var(--programs-scene-one-active-page-inset-outer);
  padding-right: var(--programs-scene-one-active-page-inset-gutter);
}

.programs-article-spread .spread__page--right .spread__inner {
  padding-left: var(--programs-scene-one-active-page-inset-gutter);
  padding-right: var(--programs-scene-one-active-page-inset-outer);
}

/* Text fills the inset box; override the default 376px / 96px-top
   that is tuned for the hero. */
.programs-article-spread .spread__text {
  max-width: 100%;
  padding-top: 0;
}

/* "Overview" + section headings: same mono kicker style as
   "Offerings:" and "Schedule:" on Scenes Three + Four. */
.programs-article__kicker,
.programs-article__subhead {
  margin: 0;
  font-family: var(--font-secondary);
  font-size: var(--pa-label-size);
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.6);
}

/* Body copy: matches Scene One's Baskerville statement exactly. */
.programs-article__copy {
  margin: 0;
  font-family: var(--font-primary);
  font-size: var(--pa-copy-size);
  line-height: var(--programs-statement-line-height);
  letter-spacing: 0.01em;
  color: var(--color-text);
}

.programs-article__kicker + .programs-article__copy {
  margin-top: var(--pa-overview-gap);
}

/* 16px above each heading; gap below matches the Overview → paragraph gap
   so all three label → copy transitions feel the same weight. */
.programs-article__subhead {
  margin-top: var(--pa-heading-gap-top);
  margin-bottom: var(--pa-overview-gap);
}

/* First child on each page pins to the page baseline. */
.programs-article-spread .spread__text > :first-child {
  margin-top: 0;
}

/* ----------------------------------------------------- */
/* Scene Two — portrait + phone (one continuous column)  */
/* ----------------------------------------------------- */
/* Portrait can't carry the two-page spine. Stacked, the   */
/* facing insets open a dead gap exactly where the copy     */
/* actually runs straight on, and the paragraph the spine   */
/* split across pages reads as two. So the sticky lock      */
/* releases and the spread collapses into ONE editorial     */
/* column: the page boxes, their inners, and text wrappers  */
/* dissolve (display:contents) so every block flows as a    */
/* single vertical article in DOM order (left page, then    */
/* right). The split paragraph ("…by session, not by        */
/* individual enrollment. / Sessions can be held…") rejoins */
/* inline so it reads as the one paragraph it really is.    */
@media (min-width: 768px) and (max-width: 1300px) and (max-aspect-ratio: 6/5),
       (max-width: 767px) {
  /* Release the sticky lock and restore the normal section gap on both
     sides — the column is normal flow here, not a locked stage. */
  .programs-article-spread {
    height: auto;
    margin-top: 0;
    margin-bottom: 0;
  }

  .programs-article-spread__stage {
    position: static;
    height: auto;
    overflow: visible;
  }

  /* The book becomes the single article column. Page insets apply
     once, around the whole block, instead of per facing page — so
     there is one top inset and one bottom inset, no middle gap. */
  .programs-article-spread .spread__book {
    position: static;
    transform: none;
    display: block;
    width: var(--programs-book-frame-layout-width);
    max-width: var(--programs-book-frame-layout-width);
    height: auto;
    margin-left: auto;
    margin-right: auto;
    padding: var(--programs-scene-one-active-page-inset-top)
             var(--programs-scene-one-active-page-inset-outer)
             var(--programs-scene-one-active-page-inset-bottom);
    box-sizing: border-box;
  }

  /* Dissolve the two pages, their inners, and text wrappers so all
     copy joins one flow. DOM order already reads left page → right. */
  .programs-article-spread .spread__page,
  .programs-article-spread .spread__inner,
  .programs-article-spread .spread__text {
    display: contents;
  }

  /* The split paragraph is one paragraph here: the two halves run
     inline so the sentence continues unbroken, with a single space
     where the spine used to divide them across pages. */
  .programs-article-spread .programs-article__copy--cont-a,
  .programs-article-spread .programs-article__copy--cont-b {
    display: inline;
  }

  .programs-article-spread .programs-article__copy--cont-a::after {
    content: " ";
  }

  /* No spine crease when the spread is one column. */
  .programs-article-spread .spread__book::after {
    display: none;
  }
}
