/* ─── Human Intelligence Learner Platform — Platform-specific styles ────────
   Milestone 18.4 (Human Intelligence Learner Platform, Phase 1).

   Loaded *in addition to* main.css (see platform.html) — every color,
   radius, border, and button style below reuses main.css's own existing
   custom properties and classes (--gold/--border/--text-*/--radius-*/
   .btn/.btn-gold/.btn-ghost/.btn-quiet/.loading-ring), consistent with
   this milestone's "no duplicated infrastructure" instruction. Only
   genuinely new layout — Programme cards, the Activity table, reserved-
   placeholder sections — gets a new `.plat-*` class here. Nothing in this
   file redefines a main.css custom property or class. */

/* ─── Experience Runtime — Milestone 18.5 ───────────────────────────────────
   The Experience Runtime (platform-experience-runtime.js) deliberately
   reuses admin-eb-preview.js's own visual language and class names verbatim
   (.eb-pw-*/.eb-preview-*/.eb-scale-*/.eb-slider-*/.eb-fb-*/.lc-preview-*/
   .eb-chip) — that file already proved this exact interactive design for
   the Interaction Library's 4 types. Those classes live in admin.css, which
   platform.html does not load (admin.css is the authoring-tool bundle, not
   the learner-facing one) — so the rules below are copied here verbatim
   from admin.css, unchanged, purely to make the SAME class names resolve
   inside the Platform's own CSS bundle. This is presentation duplication
   across two different page bundles, not logic duplication — the exact
   same pattern main.css/admin.css already both use for si-hero/
   si-canvas-wrap/editorial-canvas/sal-*/question-*/completion-*/
   reflection-* (all already defined in main.css, which both platform.html
   and index.html load, and duplicated again in admin.css for the Builder's
   own preview column). Every custom property referenced below
   (--gold/--gold-soft/--bg-card/--bg-input/--text-*/--radius-*/--border/
   --transition/--font-display) already exists in main.css, which
   platform.html loads immediately above this file — nothing new is
   introduced. */

.eb-chip { display: inline-flex; align-items: center; gap: 0.35rem; background: var(--gold-soft); color: var(--text-primary); font-size: 0.78rem; font-weight: 500; padding: 0.28rem 0.55rem 0.28rem 0.7rem; border-radius: 999px; }
.eb-chip--static { background: var(--bg-input); }

.lc-preview-characters { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 1.35rem; }
.lc-preview-context { font-size: 1rem; line-height: 1.75; color: var(--text-primary); max-width: 640px; margin-bottom: 1.5rem; white-space: pre-wrap; }
.lc-preview-reflection { background: var(--bg-card); border-left: 3px solid var(--gold); border-radius: 0 var(--radius-md) var(--radius-md) 0; padding: 1rem 1.25rem; }
.lc-preview-reflection-eyebrow { font-size: 0.66rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.12em; color: var(--gold); margin-bottom: 0.4rem; }
.lc-preview-reflection p { font-size: 0.92rem; line-height: 1.6; color: var(--text-secondary); font-style: italic; margin: 0; }

.eb-fade-in { animation: fadeSlideIn 0.22s ease both; }
@keyframes fadeSlideIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; } }

.eb-preview-empty-frame { font-size: 0.85rem; color: var(--text-muted); text-align: center; padding: 2rem 1rem; font-style: italic; }
.eb-preview-guidance { font-size: 0.9rem; font-style: italic; color: var(--text-secondary); margin-bottom: 1rem; }
.eb-preview-option-explain { font-size: 0.82rem; color: var(--text-muted); margin-top: 0.35rem; font-style: italic; }

.eb-preview-agreement { padding: 0.5rem 0 0.25rem; }
.eb-scale-row { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.9rem; }
.eb-scale-dot { flex: 1; height: 14px; border-radius: 999px; border: 1.5px solid var(--gold-soft); background: var(--bg-card); max-width: 32px; cursor: pointer; transition: var(--transition); padding: 0; appearance: none; outline: none; font: inherit; }
.eb-scale-dot:hover { background: var(--gold-soft); }
.eb-scale-dot--selected { background: var(--gold) !important; border-color: var(--gold) !important; }
.eb-scale-labels { display: flex; justify-content: space-between; font-size: 0.78rem; color: var(--text-muted); }

.eb-preview-slider { padding: 0.5rem 0 0.25rem; }
.eb-slider-input { width: 100%; accent-color: var(--gold); margin-bottom: 0.9rem; }
.eb-slider-labels { display: flex; justify-content: space-between; align-items: center; font-size: 0.78rem; color: var(--text-muted); }
.eb-slider-value { font-weight: 700; color: var(--gold); font-size: 0.9rem; }

.eb-fb-message { font-size: 1rem; line-height: 1.7; color: var(--text-secondary); margin: 0 0 1.25rem; }
.eb-fb-message--coaching { background: var(--gold-soft); border-left: 3px solid var(--gold); border-radius: var(--radius-sm); padding: 0.9rem 1.1rem; margin-bottom: 1.25rem; }
.eb-fb-message--coaching p { margin: 0; line-height: 1.65; color: var(--text-secondary); }
.eb-fb-message-label { display: block; font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: #8B6A12; margin-bottom: 0.4rem; }
.eb-fb-encouragement { font-family: var(--font-display); font-style: italic; font-size: 1.05rem; color: var(--text-primary); margin: 0 0 1.25rem; }
.eb-fb-movie-callback { display: flex; align-items: flex-start; gap: 0.65rem; background: var(--bg-input); border-radius: var(--radius-md); padding: 0.85rem 1rem; margin-bottom: 1.25rem; }
.eb-fb-movie-callback p { margin: 0; line-height: 1.6; color: var(--text-secondary); }
.eb-fb-movie-icon { font-size: 1rem; flex-shrink: 0; margin-top: 0.1rem; }
.eb-fb-quote { font-family: var(--font-display); font-size: 1.2rem; font-style: italic; line-height: 1.55; color: var(--text-primary); border-left: 2px solid var(--gold); padding-left: 1.1rem; margin: 1.5rem 0; }
.eb-fb-followup { margin-top: 1.75rem; }
.eb-fb-followup-prompt { font-size: 0.95rem; color: var(--text-primary); margin-bottom: 0.75rem; }

.eb-pw-toolbar { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; margin-bottom: 1.5rem; }
.eb-pw-toolbar-main { flex: 1; min-width: 0; }
.eb-pw-toolbar .assessment-progress-bar { margin-bottom: 0.9rem; }
/* Milestone 24.6 Issue 4: the Experience runtime previously had no
   "return to Programme" action at all until the Complete/Already-Completed
   screen — a learner exiting mid-Experience had nothing to click. This
   reuses the toolbar's own existing flex/space-between layout (see
   .eb-pw-toolbar above) as a second child alongside .eb-pw-toolbar-main, so
   it sits in the one piece of chrome present on every step, not a new band. */
.eb-pw-toolbar-back { flex-shrink: 0; color: var(--text-secondary); font-size: 0.85rem; text-decoration: none; white-space: nowrap; padding-top: 0.15rem; }
.eb-pw-toolbar-back:hover { color: var(--gold); }
.eb-pw-breadcrumb { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; }
.eb-pw-crumb { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; color: var(--text-muted); }
.eb-pw-crumb.done { color: var(--text-secondary); }
.eb-pw-crumb.active { color: var(--gold); }
.eb-pw-crumb-sep { font-size: 0.7rem; color: var(--border); }

.eb-pw-stage-wrap { margin-bottom: 1.5rem; }
.eb-pw-stage { min-height: 0; }
.eb-pw-stage .si-canvas-wrap { padding: 2rem 0 0; }
/* M24.4 Priority 1 fix: this used to be the unscoped `.eb-pw-stage
   .editorial-canvas { margin: 0; }`, which stripped the canvas's own
   `margin: 0 auto` centring (main.css's .editorial-canvas — see that
   file's own comment: "horizontal centring is the canvas's own job") on
   EVERY runtime step, not just the two-column Reference Panel layout it
   was written for. Most Activities have no Reference Panel at all (an
   Activity-level authoring choice, not every Activity's default), so in
   practice this made the canvas render flush against the left edge with a
   large dead void on the right on most Assessment/Experience steps —
   exactly the "left sticky reference margin ... no longer presenting as
   intended" regression this milestone exists to fix. Scoping the reset to
   `.eb-rt-with-refpanel` (the class only present when a Reference Panel is
   actually rendering beside the stage, see platform-reference-panel.js)
   restores centred Premium balance for the common no-panel case while
   keeping the flex-fill behavior the two-column case still needs. */
.eb-rt-with-refpanel .eb-pw-stage .editorial-canvas { margin: 0; }
/* Round 4 correction: Round 3's own comment here assumed the sticky_sidebar
   remaining column is always narrower than editorial-canvas's 960px cap —
   true only on compact screens. computeAssessmentReferenceBlocks()
   (platform-assessment-runtime.js) hardcodes displayMode: "sticky_sidebar"
   for every Assessment Reference Panel — Assessment never uses
   top_banner — so this is the ONLY rule that ever governs the Assessment
   stage's horizontal position when a Reference Panel is present; the
   :has(.eb-rt-refpanel--banner) override two rules below never reaches it.
   On any desktop-width screen, the remaining flex column (page width minus
   the 340px sidebar and 2rem gap) is comfortably wider than 960px, so
   margin: 0 pinned the canvas flush against the sidebar and dumped 100% of
   the leftover slack on the right — "correct width, but left-aligned" as
   reported live. margin: 0 auto restores centring within that remaining
   column whenever there's slack to distribute (below 960px it's a no-op,
   width:100% already fills the column edge-to-edge either way — mobile/
   tablet reflow, where the column becomes 100% of the page, is unaffected
   for the same reason). Left as its own rule (not merged into the
   .eb-pw-stage one above) deliberately: Experience's own sidebar-mode
   "hug the sidebar" presentation wasn't reported as a problem and this
   fix is scoped to the one runtime that was. */
.eb-rt-with-refpanel .qa-canvas-wrap .editorial-canvas { margin: 0 auto; }

.eb-pw-nav { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding-top: 1.25rem; border-top: 1px solid var(--border); margin-bottom: 1.5rem; }
.eb-pw-nav-center { display: flex; align-items: center; gap: 0.9rem; }
.eb-pw-nav-counter { font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); }

/* Milestone 19 Phase P6 — schemaVersion-2 Learner Runtime (Section/Block walk) */
/* .eb-option-btn copied verbatim from admin.css per this file's own established convention */
.eb-option-btn {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  width: 26px;
  height: 26px;
  cursor: pointer;
  font-size: 0.82rem;
  line-height: 1;
  transition: var(--transition);
}
.eb-option-btn:hover:not(:disabled) { border-color: var(--gold); color: var(--gold); }
.eb-option-btn:disabled { opacity: 0.35; cursor: default; }

.eb-rt-narrative { font-size: 1rem; line-height: 1.7; color: var(--text); margin-bottom: 1.25rem; }
.eb-rt-narrative-prompt { font-size: 0.95rem; line-height: 1.6; color: var(--text-muted); margin-top: 1rem; }

.eb-rt-summary-title { font-family: var(--font-serif, serif); font-size: 1.3rem; color: var(--text); margin-bottom: 0.75rem; }
.eb-rt-summary-body { font-size: 0.98rem; line-height: 1.7; color: var(--text-muted); }

.eb-rt-ranking-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.eb-rt-ranking-item { display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem 1rem; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-card); }
.eb-rt-ranking-text { flex: 1; font-size: 0.95rem; color: var(--text); }
.eb-rt-ranking-actions { display: flex; gap: 0.4rem; }

.eb-rt-checkbox { display: flex; align-items: center; gap: 0.6rem; padding: 0.65rem 0; cursor: pointer; }

.eb-rt-with-refpanel { display: flex; gap: 2rem; align-items: flex-start; }
.eb-rt-with-refpanel .eb-pw-stage { flex: 1; min-width: 0; }
/* Round 3 root-cause fix: the Experience runtime's stage wrapper is
   .eb-pw-stage (rule above), but the Assessment runtime
   (platform-assessment-runtime.js) wraps its own stage in .qa-canvas-wrap
   instead — a pre-existing class-name mismatch from when this two-column
   Reference Panel treatment was extended from Experience to Assessment
   (M24 Step D). Every flex-fill rule keyed to .eb-pw-stage above silently
   never matched a real Assessment element, so the Assessment stage was
   never a proper flex: 1 item at all: it fell back to default flex
   (0 1 auto), sizing itself to its own content's preferred width instead
   of filling the row/column — exactly the "assessment becomes much
   narrower whenever Reference Material exists" symptom. This is a pure
   CSS addition (no markup/JS change, no rename of the existing class) so
   the Assessment stage now gets the identical flex-fill treatment
   Experience already had. */
.eb-rt-with-refpanel .qa-canvas-wrap { flex: 1; min-width: 0; }

/* UX fix (Video Reference Material follow-up): top_banner is meant to
   render as a full-width strip ABOVE the stage — but .eb-rt-with-refpanel
   above is a flex ROW, built for the sticky_sidebar case. A banner-mode
   panel (`.eb-rt-refpanel--banner`, width: 100%) dropped into that row
   fights the stage for horizontal space instead of stacking, squeezing the
   question card narrower than its normal reading width until the existing
   900px breakpoint kicks in. Force column layout whenever a banner panel is
   present, at every viewport width, so the stage always keeps its normal
   width and the reference content (video or otherwise) simply sits above
   it, full width, as the "banner" name always implied. :has() is supported
   by every evergreen browser this platform targets; a browser without it
   just keeps the pre-existing row behaviour above 900px for banner mode
   only — no worse than before this fix, not a new risk. */
/* Round 2: align-items: flex-start (base rule above) is a sidebar-mode
   concern — it keeps the sticky sidebar from stretching to the stage's full
   height. In the banner case forced to column layout here, that same
   flex-start also applies to the CROSS axis, which in a column flex
   container is width: neither the banner nor the stage stretch to fill the
   row, so the stage — and the editorial-canvas/question card inside it —
   shrinks to its content's own preferred width instead of the full
   available width. That's the "split-stage width constraint" that outlived
   its purpose once banner mode stacks: restore full-width stretch for both
   children so the stage returns to exactly the width it used to fill
   before Reference Material existed. */
.eb-rt-with-refpanel:has(.eb-rt-refpanel--banner) { flex-direction: column; align-items: stretch; }

/* Round 3: banner mode's stage is now the full page width again (fixes
   above), matching the no-Reference-Panel case exactly — so it should also
   look like that case: the canvas centred within that full width via
   main.css's own `.editorial-canvas { margin: 0 auto }`, not pinned to the
   left edge. The two `margin: 0` rules above exist specifically for the
   sticky_sidebar case (a genuinely narrower column, where flush-left
   filling is the intended look) — this override restores centring only
   for banner mode, leaving sidebar mode's own margin: 0 untouched. */
.eb-rt-with-refpanel:has(.eb-rt-refpanel--banner) .eb-pw-stage .editorial-canvas,
.eb-rt-with-refpanel:has(.eb-rt-refpanel--banner) .qa-canvas-wrap .editorial-canvas { margin: 0 auto; }

/* Milestone 24 Part 7: was `background: var(--surface, transparent)` —
   --surface was never actually defined anywhere in main.css, so this
   silently rendered transparent on every page, not a real card. Fixed to
   `var(--bg-card)`, which made the panel a real card — but --bg-card is
   pure #FFFFFF, and Milestone 24.6 live testing flagged that a solid white
   box reads as a foreign "dashboard card" against the ivory/gold Premium
   canvas (same failure mode .results-chart-card/.feedback-card in main.css
   already document and fixed: "these panels no longer read as white
   dashboard cards sitting on ivory"). Reusing that exact established
   pattern here — var(--premium-ivory) (== --bg-deep, the page's own
   background) plus a faint gold hairline border — so the Reference Panel
   (and every reference asset inside it, which has no background of its
   own and simply inherits this container) reads as part of the Premium
   page instead of a white box breaking the design. */
.eb-rt-refpanel { border: 1px solid rgba(201, 162, 75, 0.25); border-radius: var(--radius-md); background: var(--premium-ivory); }
/* Milestone 24.6 Issue 2: was a fixed 280px — live testing on desktop found
   this read as cramped/narrow next to the ~960px stage, not using the
   available desktop width the Premium two-column layout was meant to give
   it. 340px is still deliberately far short of the stage's own width (this
   is a supporting sidebar, not a second stage), but gives real reference
   assets (images, PDF cards, longer quotes) enough room to read as
   intentional rather than an afterthought. Sticky/scroll/responsive
   behaviour below is unchanged. */
.eb-rt-refpanel--sidebar { width: 340px; flex-shrink: 0; padding: 1.25rem; position: sticky; top: 1.5rem; align-self: flex-start; max-height: calc(100vh - 3rem); overflow-y: auto; }
.eb-rt-refpanel--banner { width: 100%; padding: 1rem 1.25rem; margin-bottom: 1.5rem; }
.eb-rt-refpanel--drawer { position: fixed; right: 0; top: 0; bottom: 0; width: 320px; padding: 1.25rem; transform: translateX(100%); transition: transform var(--transition, 0.2s ease); z-index: 40; overflow-y: auto; box-shadow: -8px 0 24px rgba(0, 0, 0, 0.12); }
.eb-rt-refpanel--drawer.eb-rt-refpanel--open { transform: translateX(0); }
.eb-rt-refpanel-drawer-toggle { position: fixed; right: 1.5rem; bottom: 1.5rem; z-index: 41; border-radius: 999px; padding: 0.65rem 1.1rem; background: var(--gold); color: var(--bg, #fff); border: none; cursor: pointer; font-size: 0.8rem; letter-spacing: 0.04em; text-transform: uppercase; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18); }

.eb-rt-refblock { margin-bottom: 1.25rem; }
.eb-rt-refblock:last-child { margin-bottom: 0; }
.eb-rt-refasset { margin-bottom: 0.9rem; }
.eb-rt-refasset img { max-width: 100%; border-radius: var(--radius-sm); }
.eb-rt-refasset-caption { font-size: 0.78rem; color: var(--text-muted); margin-top: 0.35rem; line-height: 1.5; }
/* Milestone: Video Reference Material (V1) — responsive width, matches the
   image treatment above (max-width: 100%, same radius). display: block
   avoids the few stray pixels of inline-element whitespace under <video>.
   UX fix (follow-up): a full-width Reference video with no height cap could
   render very tall (16:9 at ~700px wide is ~390px, and wider still on a
   sidebar-stacked tablet view), pushing the question card below out of the
   viewport and reading as "compressed." Capping max-height keeps the video
   available above the stage without letting it dominate the page.
   Round 2: the fix above unintentionally left the player stretching to the
   full panel width even after the height was capped, distorting playback
   dimensions the wrong way. Switched width: 100% to width: auto — the
   video now sizes itself from its own intrinsic aspect ratio (height still
   governed by max-height, unchanged from Round 1), never stretches
   horizontally, and margin: 0 auto centres the resulting (narrower) box
   inside the Reference Panel. max-width: 100% is kept only as a safety net
   on very narrow panels/screens. */
.eb-rt-refasset-video-player { display: block; width: auto; max-width: 100%; height: auto; max-height: min(46vh, 420px); margin: 0 auto; border-radius: var(--radius-sm); background: #000; }

/* Milestone 24.5 Part 3 — uploaded PDF Document "open" card (no in-browser
   PDF viewer in this codebase; opens the file in a new tab). */
.eb-rt-refasset-pdf-link { display: flex; align-items: center; gap: 0.5rem; padding: 0.7rem 0.9rem; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-input); color: var(--text); text-decoration: none; font-size: 0.85rem; font-weight: 600; transition: border-color var(--transition, 0.2s ease); }
.eb-rt-refasset-pdf-link:hover { border-color: var(--gold); }

/* Milestone: Reference Material — Text Block Asset (V1) — a clean
   information panel for explanations/notes/instructions. Deliberately
   plain, per the brief's own words: "no quotation marks, no oversized
   typography, no decorative styling" — a smaller, quieter type scale than
   .eb-fb-quote's display-serif treatment above, closer to
   .eb-rt-refasset-caption's own restrained sizing. Title is optional and
   never rendered larger than the body — a label, not a heading. */
.eb-rt-refasset-textblock-title { font-size: 0.92rem; font-weight: 700; color: var(--text-primary); margin-bottom: 0.5rem; line-height: 1.4; }
.eb-rt-refasset-textblock p { font-size: 0.9rem; line-height: 1.65; color: var(--text-secondary); margin: 0 0 0.85rem; }
.eb-rt-refasset-textblock ul, .eb-rt-refasset-textblock ol { margin: 0 0 0.85rem; padding-left: 1.25rem; font-size: 0.9rem; line-height: 1.6; color: var(--text-secondary); }
.eb-rt-refasset-textblock li { margin-bottom: 0.3rem; }
.eb-rt-refasset-textblock p:last-child, .eb-rt-refasset-textblock ul:last-child, .eb-rt-refasset-textblock ol:last-child { margin-bottom: 0; }
.eb-rt-refasset-textblock li:last-child { margin-bottom: 0; }
.eb-rt-refasset-textblock strong { color: var(--text-primary); font-weight: 700; }
.eb-rt-refasset-textblock a { color: var(--accent); text-decoration: underline; }
.eb-rt-refasset-textblock a:hover { color: var(--gold); }

/* ─── Responsive — Milestone 23 Step 5 (Phase 3) ────────────────────────────
   Revision 4's §5 finding, restated from Revision 1: platform.css had zero
   `@media` rules anywhere, and the Reference Panel's two-column layout
   (`.eb-rt-with-refpanel`: a 280px sticky sidebar beside the stage) simply
   does not reflow on a tablet or phone — the brief's own instruction is to
   "improve and complete," not redesign, so this is a breakpoint fix only:
   no new imagery, no video support, no change to what author-chosen
   displayMode means (those remain real gaps, logged as a follow-on
   enhancement per §5's own priority call, not a launch blocker).
   Breakpoint (900px) matches this project's existing convention in
   main.css (`@media (max-width: 640px/480px)`) of using the minimum
   max-width needed for the specific element misbehaving, rather than a
   fixed device-size grid — 900px is roughly where a 280px sidebar + 2rem
   gap + a comfortably-readable stage (~500px) stops fitting side by side,
   which covers tablet portrait (iPad-class ~768-834px) as well as phones. */
@media (max-width: 900px) {
  .eb-rt-with-refpanel { flex-direction: column; gap: 1.5rem; }
  .eb-rt-refpanel--sidebar {
    width: 100%;
    position: static;   /* the 280px sticky column has no room to sit beside the stage once stacked — becomes a normal, non-sticky block instead of clipping/overlapping content below it */
    max-height: none;
    overflow-y: visible;
    order: -1;           /* Reference content reads before the stage, the same order sticky_sidebar/top_banner already imply on desktop (reference material informs the question, not the reverse) */
  }
  .eb-rt-refpanel--drawer { width: min(320px, 88vw); } /* a fixed 320px drawer would overflow (and on some phones, exceed) the viewport width itself */
}

@media (max-width: 480px) {
  .eb-rt-refpanel-drawer-toggle { right: 1rem; bottom: 1rem; padding: 0.55rem 0.9rem; font-size: 0.75rem; }
}

.plat-eyebrow {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--gold);
  font-weight: 600;
  margin-bottom: 0.4rem;
}

/* Milestone 24 Part 7: top margin removed — .plat-dash-section (the only
   caller in the learner runtime) already supplies its own top padding, so
   the previous 2rem top margin stacked on top of that padding and left a
   visibly oversized gap above every section heading (the exact
   "unnecessary whitespace" this Part asks to reduce). font-family added so
   this reads as the same display type as the rest of the runtime
   (.results-chart-card h3/.plat-my-learning-card-title), not the body font
   at a slightly larger size. */
.plat-section-title {
  font-size: 1.15rem;
  font-weight: 600;
  font-family: var(--font-display);
  color: var(--text-primary);
  margin: 1.5rem 0 1rem;
}
/* Programme Home's own .plat-dash-section already supplies top padding on
   every section (see above) — this is the one caller where a further 1.5rem
   title margin on top of that padding would still be the doubled-whitespace
   problem this Part is fixing. Programme Detail's own "Activities" heading
   (the section's only other caller) keeps the 1.5rem — it follows a
   progress line directly, with no wrapping padding of its own. */
.plat-dash-section .plat-section-title:first-child { margin-top: 0; }

.plat-badge {
  display: inline-block;
  font-size: 0.78rem;
  padding: 0.25rem 0.65rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  background: var(--bg-card);
}

.plat-badge--certificate {
  color: var(--gold);
  border-color: rgba(201,162,75,0.35);
}

.plat-empty-state {
  color: var(--text-secondary);
  text-align: center;
  padding: 3rem 1rem;
}
.plat-empty-state--error { color: #B91C1C; }

.plat-reserved-note {
  color: var(--text-muted);
  font-size: 0.9rem;
  font-style: italic;
}

.plat-card-progress-placeholder {
  color: var(--text-muted);
  font-size: 0.82rem;
  font-style: italic;
  margin-top: 0.5rem;
}

/* ── Consistent "back to Programme Home" navigation — Milestone 24
   follow-up. Reused identically on the Programme Catalogue and Programme
   Detail pages (the two "Programme pages" that had no way back except the
   browser Back button before this). Quiet by design, same treatment as
   .plat-dash-catalogue-link's own de-emphasised link — this is orientation,
   not a primary action. */
.plat-back-nav {
  padding: 1.25rem 2rem 0;
}
.plat-back-nav a {
  color: var(--text-secondary);
  font-size: 0.9rem;
  text-decoration: none;
}
.plat-back-nav a:hover { color: var(--gold); }
/* Inside .plat-detail-body (which already owns its own max-width/padding),
   the nav link needs none of its own — it should sit flush with the title
   below it, not add a second, mismatched width constraint. */
.plat-detail-body .plat-back-nav { padding: 0 0 1rem; }

/* ── Programme Catalogue ─────────────────────────────────────────────── */

.plat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.5rem;
  padding: 2rem;
  max-width: 1200px;
  margin: 0 auto;
}

/* Milestone 24.2: border/hover softened toward the Premium Report's own
   restraint (design-tokens.css: near-invisible shadow, gold hairline
   dividers, never a heavy generic drop shadow) while deliberately KEEPING
   the card as the browsing pattern — "refine, don't replace with a
   report-style layout," per the milestone's own explicit instruction. Was
   a plain neutral --border + a heavy 32px black-tinted hover shadow (the
   "app dashboard" language the M24.2 proposal flagged); now a faint gold
   hairline (matching .option/.results-chart-card's own border language)
   and a lighter, warm-toned hover lift instead of a generic black glow. */
.plat-card {
  display: block;
  border: 1px solid rgba(201,162,75,0.22);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--bg-card);
  text-decoration: none;
  color: inherit;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.plat-card:hover {
  transform: translateY(-2px);
  border-color: rgba(201,162,75,0.4);
  box-shadow: 0 10px 28px rgba(138,90,43,0.10);
}

.plat-card-hero {
  position: relative;
  aspect-ratio: 16 / 9;
  background: linear-gradient(135deg,#1A0A2E 0%,#2A1545 100%);
  display: flex;
  align-items: center;
  justify-content: center;
}
.plat-card-hero-img { width: 100%; height: 100%; object-fit: cover; }
/* Milestone 24.2: was a plain emoji glyph (🧭) sized via font-size — now the
   Premium icon() SVG (platform-icons.js), coloured gold so it reads clearly
   against this placeholder's dark cover gradient, same as every other
   gold-on-dark accent in this file. */
.plat-card-hero-icon { display: inline-flex; color: var(--gold); }

/* Milestone 24.2: the circular gold-bevel badge treatment the Premium
   Report wraps its own inline icons in (design-components.js's
   .dc-premium-meta-icon/.dc-premium-bar-icon) — reused here via
   platform-icons.js's iconBadge() for small inline markers (certificate/
   lock) so they read as the same design system, not a plain glyph. */
.plat-icon-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.7em;
  height: 1.7em;
  border-radius: 50%;
  flex: 0 0 auto;
  background: var(--bg-card);
  box-shadow: inset 0 0 0 1.5px currentColor;
  color: inherit;
}
.plat-card-brand-logo {
  position: absolute;
  bottom: 0.75rem;
  right: 0.75rem;
  height: 28px;
  border-radius: var(--radius-sm);
  background: rgba(255,255,255,0.9);
  padding: 0.2rem 0.4rem;
}

.plat-card-body { padding: 1.25rem; }
.plat-card-title { font-size: 1.1rem; margin: 0 0 0.4rem; color: var(--text-primary); }
.plat-card-description {
  font-size: 0.88rem;
  color: var(--text-secondary);
  margin: 0 0 0.75rem;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.plat-card-meta { display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* ── Programme Detail ────────────────────────────────────────────────── */

/* Milestone 24.2 follow-up: was a purely decorative 21:6 banner (image or
   dark-gradient placeholder) with title/progress rendered separately below
   it in plain text — "purposeful rather than decorative," per the Project
   Owner's own brief. Height cut roughly 65% (21:6 at typical viewport
   widths was 500-570px tall; clamp() below settles around 190-220px) and
   the Programme's own eyebrow/title/progress/Continue action now render
   directly on top of it, so the banner carries real information instead of
   empty space above a separate text block. */
.plat-detail-hero {
  position: relative;
  height: clamp(180px, 20vw, 230px);
  background: linear-gradient(135deg,#1A0A2E 0%,#2A1545 100%);
  overflow: hidden;
  display: flex;
  align-items: flex-end;
}
.plat-detail-hero-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* A dark-to-transparent scrim (bottom-anchored, since the overlay content
   sits at the bottom edge) guarantees the overlaid text stays legible
   whether the hero is the plain gradient placeholder or a real, possibly
   bright, cover image — the same "never assume an image is safe" principle
   .sal-card-hero::after already applies elsewhere in this codebase. The
   thin gold line at the very bottom is the "subtle gold accent" the brief
   asked for — the same hairline-divider language the Premium Report uses
   at its own header/footer, marking the hero/body seam. */
.plat-detail-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(15,8,24,0.82) 0%, rgba(15,8,24,0.35) 60%, rgba(15,8,24,0.05) 100%);
  pointer-events: none;
}
.plat-detail-hero::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--gold) 50%, transparent);
  opacity: 0.8;
}

.plat-detail-hero-overlay {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  padding: 1rem 2rem 1.35rem;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
}
.plat-detail-hero-overlay-main { min-width: 0; flex: 1; }
.plat-detail-hero-eyebrow {
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--gold);
  font-weight: 700;
  margin: 0 0 0.3rem;
}
.plat-detail-hero-title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 3.4vw, 2.1rem);
  font-weight: 400;
  color: #FBF6EC;
  margin: 0 0 0.65rem;
  line-height: 1.15;
  /* Keeps the title legible on its own even where the scrim above is
     thinnest (a bright cover image's top-right corner, say) — a small,
     genuinely subtle assist, not a heavy drop shadow. */
  text-shadow: 0 1px 6px rgba(0,0,0,0.35);
}
.plat-detail-hero-progress-track {
  width: min(320px, 60vw);
  height: 6px;
  border-radius: 3px;
  background: rgba(255,255,255,0.22);
  overflow: hidden;
}
.plat-detail-hero-progress-fill { height: 100%; background: var(--gold); border-radius: 3px; }
.plat-detail-hero-progress-label {
  font-size: 0.78rem;
  color: rgba(251,246,236,0.82);
  margin: 0.45rem 0 0;
}
.plat-detail-hero-cta { flex-shrink: 0; }

/* Back-navigation, moved into the hero itself (Project Owner feedback: the
   original .plat-back-nav sat in a thin, easy-to-miss bar above the hero —
   see the removed <nav class="plat-back-nav"> above the hero markup in
   platform-programme-detail.js). Grouped with the Continue CTA in one
   flex-end column so both live in the same, unmissable top-right corner of
   the hero image, whether or not Continue is present this visit. */
.plat-detail-hero-actions {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.6rem;
}
/* Round 2 (Project Owner: "it has to be a button its not visible") — a
   plain text link on top of a busy photographic hero was too easy to miss
   regardless of position. Rebuilt as a real outline button: translucent
   fill + visible border so it reads as clickable at a glance, distinct from
   Continue's solid gold treatment (secondary vs. primary action) rather
   than competing with it. */
.plat-detail-hero-back {
  background: rgba(15,8,24,0.55);
  border: 1px solid rgba(251,246,236,0.55);
  color: #FBF6EC;
  text-decoration: none;
  backdrop-filter: blur(3px);
}
.plat-detail-hero-back:hover {
  background: rgba(15,8,24,0.75);
  border-color: var(--gold);
  color: var(--gold);
  transform: none;
}

.plat-detail-body { max-width: 900px; margin: 0 auto; padding: 2rem; }
.plat-detail-title { font-size: 1.8rem; color: var(--text-primary); margin: 0 0 0.5rem; }
.plat-detail-description { color: var(--text-secondary); margin: 0 0 1rem; }
.plat-detail-meta { display: flex; gap: 0.5rem; margin-bottom: 1.5rem; }

/* UI Polish (2026-07-28): two-column reorganisation of the Programme page
   body — no functional change, same data/markup building blocks as the
   single-column layout above (.plat-detail-description/.plat-detail-meta/
   .plat-activity-table are reused as-is inside .plat-detail-main). The hero
   above is untouched. Left column (~68%) stays the main focus (About +
   Activities); right column (~32%) holds secondary Programme Information /
   Your Progress / Programme Actions in clean cards, making better use of
   desktop width. Stacks to a single column below 900px. */
.plat-detail-layout {
  max-width: 1200px;
  margin: 0 auto;
  padding: 2rem;
  display: grid;
  grid-template-columns: minmax(0, 2.1fr) minmax(260px, 1fr);
  gap: 2rem;
  align-items: start;
}
.plat-detail-main { min-width: 0; }
.plat-detail-main .plat-detail-description { margin-bottom: 0.75rem; }
.plat-detail-main-cta { margin-top: 1.75rem; }

.plat-detail-sidebar {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  position: sticky;
  top: 1.5rem;
}

.plat-detail-card {
  border: 1px solid rgba(201,162,75,0.22);
  border-radius: var(--radius-lg);
  background: var(--bg-card);
  padding: 1.25rem;
}
.plat-detail-card-title {
  font-size: 0.95rem;
  font-weight: 600;
  font-family: var(--font-display);
  color: var(--text-primary);
  margin: 0 0 0.9rem;
}
.plat-detail-card-fact {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.88rem;
}
.plat-detail-card-fact:last-child { border-bottom: none; padding-bottom: 0; }
.plat-detail-card-fact-label { color: var(--text-muted); }
.plat-detail-card-fact-value { color: var(--text-primary); font-weight: 600; }

.plat-detail-card-progress-track {
  width: 100%;
  height: 6px;
  border-radius: 3px;
  background: var(--border);
  overflow: hidden;
}
.plat-detail-card-progress-fill { height: 100%; background: var(--gold); border-radius: 3px; }
.plat-detail-card-progress-label {
  font-size: 0.82rem;
  color: var(--text-secondary);
  margin: 0.6rem 0 0;
}

.plat-detail-card-action { width: 100%; justify-content: center; }

@media (max-width: 900px) {
  .plat-detail-layout { grid-template-columns: 1fr; padding: 1.5rem; gap: 1.5rem; }
  .plat-detail-sidebar { position: static; }
}

.plat-activity-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}
.plat-activity-table th {
  text-align: left;
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--border);
  color: var(--text-muted);
  font-weight: 600;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.plat-activity-table td {
  padding: 0.75rem;
  border-bottom: 1px solid var(--border);
  color: var(--text-primary);
  vertical-align: middle;
}

/* Milestone 23 Step 3: "restore the learner to the correct Activity
   location" — a brief highlight applied to the Activity row the learner
   just returned from (see platform-programme-detail.js's
   restoreActivityFocus()), then removed after a few seconds. Ephemeral,
   not a persisted state indicator. */
.plat-activity-row--focus {
  background: rgba(201,162,75,0.14);
  transition: background 2s ease;
}

/* Milestone 23 Step 4: a real, Progression-locked Activity row — quieted,
   not hidden (the learner should still see what's ahead of them, just not
   be able to open it yet). */
.plat-activity-row--locked { opacity: 0.6; }
.plat-btn-launch:disabled { opacity: 0.5; cursor: default; }
.plat-activity-refnum {
  display: block;
  font-size: 0.75rem;
  color: var(--text-muted);
  font-family: "JetBrains Mono", monospace;
}
.plat-activity-availability, .plat-activity-completion {
  color: var(--text-muted);
  font-size: 0.82rem;
  font-style: italic;
}

/* ── Learner Dashboard ───────────────────────────────────────────────── */

.plat-dash-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: 900px;
  margin: 0 auto;
  padding: 2rem 2rem 1rem;
}

/* Task #865 — the Dashboard topbar's one additive Sign In/Log Out entry
   point. No structural change to .plat-dash-topbar itself needed (it was
   already display:flex/justify-content:space-between — see this block's own
   header comment history); this just gives the link/button a size that
   doesn't compete with the "Programme Home" title next to it. */
.plat-dash-auth-link {
  font-size: 0.8rem;
  padding: 0.45rem 0.9rem;
  flex-shrink: 0;
}

/* Milestone 24 Part 7: consistent vertical rhythm between Programme Home's
   stacked sections (Current Programme/My Reports/My Certificates/Programme
   Summary) — was a flat 1rem top+bottom on every section regardless of
   what came before/after, which reads as slightly cramped between a
   section's own content and the next section's heading. A hairline divider
   between sections (not around the whole page) gives the eye a clear
   break without adding a boxed-card feel to every section. */
.plat-dash-section {
  max-width: 900px;
  margin: 0 auto;
  padding: 1.5rem 2rem;
  border-bottom: 1px solid var(--border);
}
.plat-dash-section:last-of-type { border-bottom: none; }

.plat-dash-summary { color: var(--text-secondary); margin-bottom: 0.75rem; }

/* Milestone 24 Part 9: the Programme Catalogue link — deliberately NOT a
   .plat-dash-section with its own h2 title (that would make it compete with
   Current Programme/My Reports/My Certificates/Programme Summary for
   attention); a single quiet line, same column width, sits below all four
   real sections instead. */
.plat-dash-catalogue-link {
  max-width: 900px;
  margin: 0 auto;
  padding: 0.5rem 2rem 2rem;
  text-align: center;
  font-size: 0.875rem;
}
.plat-dash-catalogue-link a { color: var(--text-secondary); }
.plat-dash-catalogue-link a:hover { color: var(--gold); }

/* UI Polish (2026-07-28): two-column reorganisation of Programme Home, same
   treatment as the single-Programme page above — no functional change, the
   same section-building functions (renderCurrentProgrammeSection() etc.)
   are reused as-is. Current Programme stays the main focus in the left
   column (~68%); My Reports / My Certificates / Programme Summary move into
   .plat-detail-card sidebar cards on the right (~32%), reusing the exact
   card styling already defined above for the single-Programme page so both
   pages read as one consistent design language. The topbar, one-time
   registration prompt, and Catalogue link stay full-width above/below, same
   as before. */
.plat-dash-layout {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0.5rem 2rem 2rem;
  display: grid;
  grid-template-columns: minmax(0, 2.1fr) minmax(260px, 1fr);
  gap: 2rem;
  align-items: start;
}
.plat-dash-main { min-width: 0; }
.plat-dash-main .plat-dash-section,
.plat-detail-card .plat-dash-section {
  max-width: none;
  margin: 0;
  padding: 0;
  border-bottom: none;
}
.plat-dash-sidebar {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  position: sticky;
  top: 1.5rem;
}

@media (max-width: 900px) {
  .plat-dash-layout { grid-template-columns: 1fr; padding: 0.5rem 1.5rem 1.5rem; gap: 1.5rem; }
  .plat-dash-sidebar { position: static; }
}

/* ── My Learning (Milestone 23 Step 9) — Active/Completed Programmes,
   Assessment/Experience History. Reuses the Dashboard's own .plat-dash-
   section container/max-width, so these sections sit in the exact same
   column as everything above and below them. ─────────────────────────── */

.plat-my-learning-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 1rem;
}

/* Milestone 24 Part 7: border/background now read the platform's real
   design tokens (--border/--bg-card) instead of --border-color/--surface —
   neither was ever defined in main.css, so every one of these cards was
   silently rendering its hardcoded fallback colour (#e5e0d8/#fff) rather
   than the theme's own ivory/cream card treatment. Radius switched to
   --radius-lg to match .results-chart-card/.feedback-card's own rounding,
   padding widened slightly — one consistent card language across the whole
   learner runtime rather than two slightly different ones. */
/* Milestone 24.2: border recoloured from neutral --border to the same faint
   gold hairline .plat-card/.results-chart-card/.option already use — one
   consistent "card edge" language across the whole learner runtime rather
   than a plain grey border on this one card type. */
.plat-my-learning-card {
  border: 1px solid rgba(201,162,75,0.22);
  border-radius: var(--radius-lg);
  padding: 1.25rem 1.4rem;
  background: var(--bg-card);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.plat-my-learning-card-title { font-size: 1.1rem; color: var(--text-primary); margin: 0; font-family: var(--font-display); }

.plat-my-learning-progress {
  width: 100%;
  height: 6px;
  border-radius: 3px;
  background: rgba(31, 27, 20, 0.08);
  overflow: hidden;
}
.plat-my-learning-progress-fill { height: 100%; background: var(--gold, #c8932e); }
.plat-my-learning-progress-label { font-size: 0.78rem; color: var(--text-muted); margin: 0; }

.plat-my-learning-meta { font-size: 0.85rem; color: var(--text-secondary); margin: 0; }

.plat-my-learning-card .btn { align-self: flex-start; margin-top: 0.4rem; }

.plat-history-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }

.plat-history-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.9rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--border);
}
.plat-history-list .plat-history-row:last-child { border-bottom: none; }
.plat-history-row-title { font-weight: 600; color: var(--text-primary); }

/* ── Learner Auth (Task #865: Sign In / Create Account / Forgot Password /
   Reset Password) ───────────────────────────────────────────────────────
   Scoped override of the shared .auth-box/.auth-card/.auth-form/.field/
   .input family (main.css) — the exact same reuse pattern
   #view-learner-id .auth-card already established for a different
   learner-facing screen (see that block's own comment in main.css), applied
   here to a new .plat-auth-view wrapper instead. Purely additive: nothing
   in main.css's own #view-auth (admin login) or #view-learner-id rules is
   touched. */
.plat-auth-view {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 70vh;
  padding: 2rem 1rem;
}
.plat-auth-view .auth-card {
  background: var(--bg-deep);
  border: 1px solid rgba(201, 162, 75, 0.2);
  box-shadow: 0 10px 40px rgba(139, 106, 18, 0.04);
}
.plat-auth-view .input {
  border-color: rgba(201, 162, 75, 0.18);
}
.plat-auth-view .input:focus {
  border-color: var(--gold);
  box-shadow: 0 0 0 3px var(--gold-soft);
}
.plat-auth-view .auth-divider a { color: var(--gold, #c8932e); }

.plat-auth-remember {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
  color: var(--text-secondary);
  cursor: pointer;
}
.plat-auth-remember input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  accent-color: var(--gold, #c8932e);
  cursor: pointer;
}
.plat-history-row-meta { font-size: 0.85rem; color: var(--text-secondary); }
.plat-history-row .plat-reserved-note { flex-basis: 100%; margin: 0; }
