/* ═══════════════════════════════════════════════════════════════
   REPEATERS.CSS — Repeater Readiness module
   New selectors only. Layout/typography tokens still come from
   setu_styles.css (--space-*, --ds-radius-*, --sage). Colour is this
   module's own — a distinct violet/indigo, not MannSetu's gold, not
   Admission Intelligence's green, not Exam Readiness's blue — applied
   uniformly from the ENTRY button through every screen. --sage stays
   as the one shared colour, reserved only for "done/complete" signals
   (a universal convention, not a brand colour). #stage/#footer/#header
   are reused unedited from the main stylesheet (sticky footer, safe-area
   padding, stage bottom-padding compensation all inherited for free).
═══════════════════════════════════════════════════════════════ */

:root {
  --rep-primary:      #6D4CE0;
  --rep-primary-dark:  #4B2FBF;
  --rep-primary-pale:  #EFE9FC;
  --rep-primary-12:    rgba(109, 76, 224, 0.12);
  --rep-primary-08:    rgba(109, 76, 224, 0.08);

  /* A warm "dusk" undertone — soft rose/amber-adjacent, deliberately never
     actual red/amber (this module's one hard law: no traffic-light judgement
     colour). Used sparingly: only the calmest moments (HERO, CONSENT, the
     crisis panel), never a wholesale repaint of the existing violet system. */
  --rep-dusk:      #F3A98C;
  --rep-dusk-soft: rgba(243, 169, 140, 0.12);

  /* Exclusive to the "For Parents" entry point — a warm rose, deliberately
     distinct from every other colour already claimed in this system (this
     module's own violet, --sage's done-green, --gold's MannSetu amber,
     Admission Intelligence's teal, Exam Readiness's blue, and --rep-dusk's
     peach). Never reused for anything else, so a parent's eye learns to
     find it instantly. */
  --rep-parent:      #D6336C;
  --rep-parent-dark: #A61E4D;
  --rep-parent-pale: #FDEEF3;
}

/* ══════════════════════════════════════════════════════════
   FIXED APP SHELL — this module always fits in exactly one screen:
   header and footer stay pinned, only the middle content scrolls.
   setu_styles.css only gives the main site this behaviour inside an
   @media(max-width:520px) block (its #stage there uses overflow:hidden,
   which works for that app because every screen is hand-fit to the
   viewport); this module applies the same fixed-shell shape at EVERY
   width instead of just mobile, and keeps overflow-y:auto on #stage
   (not hidden) since this module's longer copy (consent text, crisis
   panel, report paragraphs) genuinely needs to scroll rather than be
   clipped. Without min-height:0 here, #stage — a flex child — refuses
   to shrink below its content size, so overflow-y:auto never actually
   engages and the whole page grows past the viewport instead (the bug
   this fixes: footer pushed below the fold on any content taller than
   one screen). */
html, body { height: 100%; }
body { min-height: 100dvh; }

#app {
  height: 100dvh;
  min-height: 100dvh;
  overflow: hidden;
}

#header { flex: 0 0 auto; }

#stage {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding-bottom: var(--s4);
  /* setu_styles.css's base #stage rule sets will-change: opacity,
     transform for the main site's .s-entering/.s-leaving slide
     animation — this module never applies those classes (repeaters.js
     only ever swaps innerHTML), so it's dead weight here. Worse than
     dead weight, actually: will-change:transform creates a new
     containing block for fixed-position descendants, which was
     silently trapping .repeater-popup-overlay's position:fixed;inset:0
     inside #stage's own (now correctly clipped) box instead of the
     real viewport, once #stage stopped growing to fit content — the
     popup rendered short and off-position, header/footer bleeding in
     around it. Dropping transform here is what lets fixed-position
     modals in this module actually cover the whole screen again. */
  will-change: opacity;
  /* #stage's own will-change:opacity still makes it a stacking-context
     root (opacity/will-change:opacity both trigger one, just not a new
     containing block the way transform does). #header/#footer are flex
     items with z-index:200 from setu_styles.css, and flex items honour
     z-index even without their own position — so at equal z-index they
     outrank #stage's z-index:auto regardless of DOM order, painting
     over any fixed-position descendant of #stage (this module's
     popup/modal overlays) instead of under it. Raising #stage's own
     z-index above 200 is what lets those overlays actually cover the
     whole screen, header and footer included, while staying invisible
     to normal (non-overlapping) layout the rest of the time. */
  z-index: 300;
}

#footer {
  flex: 0 0 auto;
  position: static;
  box-shadow: none;
}

.repeater-module-main,
.repeater-opt-main,
.repeater-q-main {
  display: block;
  font-weight: 600;
}

/* Every primary button in this module — reskinned from MannSetu's
   gold to this module's own violet. Scoped safely: repeaters.css only
   ever loads on this module's own pages. */
.btn.gold {
  background: linear-gradient(135deg, var(--rep-primary) 0%, var(--rep-primary-dark) 100%);
  box-shadow: 0 4px 14px rgba(75, 47, 191, .35);
}
.btn.gold:hover { box-shadow: 0 6px 18px rgba(75, 47, 191, .45); }

/* ── Header chrome — trust/privacy link, crisis-help trigger (left),
   language toggle (right). #header-left/#header-right already flex;
   this module just needs a little gap now that each side holds two
   elements instead of one — kept tight, and #brand-name's own
   letter-spacing trimmed slightly, so the centre brand text still has
   room and never clips (it did, at ~960px, before this pass). */
#header-left, #header-right { gap: var(--space-1, 4px); }
#brand-name { letter-spacing: 0.05em; }
.repeater-crisis-trigger { padding: 5px 8px; }
.repeater-trust-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  border-radius: 50%;
  color: inherit;
  text-decoration: none;
  opacity: 0.75;
  transition: background .15s, opacity .15s;
}
.repeater-trust-link:hover,
.repeater-trust-link:active {
  background: rgba(13, 27, 62, .12);
  opacity: 1;
}
.repeater-lang-toggle {
  display: flex;
  gap: 2px;
  border-radius: 999px;
  background: rgba(13,27,62,0.06);
  padding: 3px;
}
.repeater-lang-toggle a {
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.75em;
  font-weight: 600;
  text-decoration: none;
  color: inherit;
  opacity: 0.55;
}
.repeater-lang-toggle a.is-active {
  background: var(--rep-primary);
  color: #fff;
  opacity: 1;
}

/* #ulzan-bar (setu_styles.css's slim bar directly under the header) is
   the main program's slot for a single centered label on a dark navy
   background — this module now uses it for exactly that and nothing
   else, the current-module label, empty outside MODULE_Q. */
#ulzan-bar.repeater-ulzan-bar {
  justify-content: center;
}
.repeater-module-label {
  flex: 1;
  min-width: 0;
  text-align: center;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--gold, #d4a63a);
  letter-spacing: 0.02em;
  line-height: 1.4;
  opacity: 0;
  transition: opacity 0.2s ease;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.repeater-module-label:not(:empty) { opacity: 1; }

/* ── Crisis-support chrome — universal, every screen, zero JS required.
   A native <details>/<summary> disclosure (core/repeater_screens.php's
   crisisChrome()), not a JS-driven modal, so the helpline numbers are
   reachable even if repeaters.js fails to load entirely. Lives in
   #header-left, a sibling of #stage/#footer — see mannsetu-repeaters.php's
   rep_render_page() — so it is structurally untouched by every AJAX stage
   swap, on every screen, with no re-injection logic needed. Its own
   default colours (below) already suit the light header background it
   sits in, no dark-bg override needed here anymore. */
.repeater-crisis { position: relative; }
.repeater-crisis-trigger {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  font-size: 0.72em;
  font-weight: 700;
  opacity: 0.75;
  padding: 6px 10px;
  border-radius: 999px;
  background: var(--rep-dusk-soft);
  color: inherit;
  white-space: nowrap;
  list-style: none;
}
.repeater-crisis-trigger::-webkit-details-marker { display: none; }
.repeater-crisis-trigger::marker { content: ''; }
.repeater-crisis[open] .repeater-crisis-trigger { opacity: 1; }
.repeater-crisis-panel {
  position: fixed;
  inset: auto 12px 12px 12px;
  max-width: 380px;
  margin: 0 auto;
  background: #fff;
  border-radius: var(--ds-radius-card, 16px);
  box-shadow: 0 20px 60px rgba(28,16,64,0.35);
  padding: var(--space-4, 16px);
  z-index: 300;
}
.repeater-crisis-title { font-weight: 700; margin: 0 0 6px; }
.repeater-crisis-intro { margin: 0 0 var(--space-3, 12px); line-height: 1.5; font-size: 0.92em; }
.repeater-crisis-lines {
  display: flex;
  flex-direction: column;
  gap: var(--space-2, 8px);
  margin-bottom: var(--space-3, 12px);
}
.repeater-crisis-line {
  display: flex;
  flex-direction: column;
  padding: var(--space-2, 10px) var(--space-3, 12px);
  border-radius: var(--ds-radius-control, 13px);
  border: 1px solid var(--ds-navy-08, rgba(13,27,62,0.08));
  text-decoration: none;
  color: inherit;
}
.repeater-crisis-name { font-weight: 600; font-size: 0.9em; }
.repeater-crisis-phone { font-weight: 700; font-size: 1.05em; color: var(--rep-primary-dark); }
.repeater-crisis-note { font-size: 0.75em; opacity: 0.6; }
.repeater-crisis-footer { font-size: 0.72em; opacity: 0.6; line-height: 1.45; margin: 0; }

/* ── Ambient dusk gradient — HERO and CONSENT only (the two calmest,
   highest-stakes onboarding moments). A slow, near-imperceptible drift, not
   a distraction — never applied to MODULE_Q, where a student is actively
   reading/answering and motion would compete for attention instead of
   soothing. Respects prefers-reduced-motion. */
.checkpoint-stage:has(.repeater-hero),
.checkpoint-stage:has(.repeater-consent-screen) {
  background: linear-gradient(120deg, var(--rep-primary-08) 0%, var(--rep-dusk-soft) 50%, var(--rep-primary-08) 100%);
  background-size: 200% 200%;
  animation: repeaterDuskDrift 18s ease-in-out infinite;
}
@keyframes repeaterDuskDrift {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}
@media (prefers-reduced-motion: reduce) {
  .checkpoint-stage:has(.repeater-hero),
  .checkpoint-stage:has(.repeater-consent-screen) {
    animation: none;
  }
}

/* ── Onboarding 1/3 — HERO ── */
.repeater-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3, 12px);
  padding: 15vh 0 0;
}
.repeater-hero-headline {
  font-size: 1.6em;
  font-weight: 800;
  color: var(--rep-primary-dark);
  margin: 0;
}
.repeater-hero-sub { opacity: 0.65; margin: 0; max-width: 30ch; }
.repeater-hero-ack {
  opacity: 0.85;
  margin: 0;
  max-width: 28ch;
  font-weight: 600;
  color: var(--rep-primary-dark);
}
/* Prompt requirement 2: "have you checked colleges yet" nudge toward
   Admission Intelligence, right on the module's very first screen. Dashed
   border reads as a signpost/aside, not a competing primary CTA against
   the Begin button in the footer. */
.repeater-college-check {
  margin-top: var(--space-3, 12px);
  padding: var(--space-3, 12px) var(--space-4, 16px);
  border-radius: var(--ds-radius-card, 16px);
  border: 1px dashed var(--rep-primary-12);
  background: var(--rep-primary-08);
  max-width: 30ch;
}
.repeater-college-check-q { margin: 0 0 6px; font-size: 0.85em; opacity: 0.8; }
.repeater-college-check-link {
  display: inline-block;
  font-weight: 700;
  font-size: 0.88em;
  color: var(--rep-primary-dark);
  text-decoration: none;
}

/* ── Onboarding 2/3 — LANGUAGE ── */
.repeater-onboard-sub { opacity: 0.6; font-size: 0.88em; margin: -4px 0 var(--space-4, 16px); }
.repeater-lang-choice {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3, 12px);
}
.repeater-lang-choice-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5, 22px) 0;
  border-radius: var(--ds-radius-card, 16px);
  border: 2px solid var(--rep-primary-12);
  background: #fff;
  color: inherit;
  text-decoration: none;
  font-weight: 700;
  font-size: 1.1em;
}
.repeater-lang-choice-btn:active { background: var(--rep-primary-pale); }

/* ── Onboarding 3/3 — CONSENT ── */
.repeater-consent-reassurance {
  font-size: 0.9em;
  opacity: 0.75;
  line-height: 1.5;
  margin: 0 0 var(--space-3, 12px);
  font-style: italic;
}
.repeater-consent-list { margin: var(--space-3, 12px) 0; padding-left: 1.2em; }
.repeater-consent-list li { margin-bottom: 10px; line-height: 1.5; }
.repeater-consent-agree {
  display: flex;
  align-items: center;
  gap: var(--space-3, 12px);
  padding: var(--space-3, 12px) var(--space-4, 16px);
  border-radius: var(--ds-radius-card, 16px);
  border: 2px solid var(--ds-navy-08, rgba(13,27,62,0.08));
  cursor: pointer;
  margin-top: var(--space-3, 12px);
}
/* Split into separate rules (not a joined selector list) — some browser
   builds fail to invalidate style on a plain classList mutation when the
   rule ALSO contains a :has() branch bundled into the same declaration
   block. .is-checked (toggled by assets/js/repeaters.js) is the
   guaranteed-reliable path; :has() is an independent, redundant one. */
.repeater-consent-agree:has(input:checked) {
  border-color: var(--sage, #2f9e6e);
  background: rgba(47,158,110,0.08);
}
.repeater-consent-agree.is-checked {
  border-color: var(--sage, #2f9e6e);
  background: rgba(47,158,110,0.08);
}
.repeater-consent-agree input { width: 18px; height: 18px; accent-color: var(--sage, #2f9e6e); }

/* ── HUB — 2-block module checklist (condensed for minimal scroll) ── */
.repeater-hub {
  display: flex;
  flex-direction: column;
  gap: var(--space-4, 16px);
  margin: var(--space-3, 12px) 0;
}
.repeater-block-title {
  font-size: 0.76em;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.6;
  margin-bottom: var(--space-2, 8px);
}
.repeater-block-grid {
  display: flex;
  flex-direction: column;
  gap: var(--space-2, 8px);
}

/* ── "For Parents" — dedicated entry, top of the HUB stack, exclusive
   rose theme (--rep-parent). Deliberately bolder than a module row: this
   is a full-bleed gradient card with its own icon chip, not a list item,
   so it reads as a distinct category, not a sixth module. */
.repeater-parent-cta {
  display: flex;
  align-items: center;
  gap: var(--space-3, 12px);
  padding: var(--space-4, 16px);
  margin-bottom: var(--space-1, 4px);
  border-radius: var(--ds-radius-card, 16px);
  background: linear-gradient(135deg, var(--rep-parent) 0%, var(--rep-parent-dark) 100%);
  color: #fff;
  text-decoration: none;
  box-shadow: 0 8px 22px rgba(166, 30, 77, 0.32);
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.repeater-parent-cta:active { box-shadow: 0 4px 12px rgba(166, 30, 77, 0.32); transform: scale(0.99); }
.repeater-parent-cta-icon {
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.2);
  font-size: 1.3em;
}
.repeater-parent-cta-text { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.repeater-parent-cta-title { font-weight: 800; font-size: 1.02em; }
.repeater-parent-cta-sub { font-size: 0.78em; opacity: 0.9; }
.repeater-parent-cta-arrow { font-size: 1.3em; opacity: 0.9; }

.repeater-module-btn {
  display: flex;
  align-items: center;
  gap: var(--space-3, 12px);
  padding: var(--space-3, 12px) var(--space-4, 16px);
  border-radius: var(--ds-radius-card, 16px);
  border: 1px solid var(--ds-navy-08, rgba(13,27,62,0.08));
  text-decoration: none;
  color: inherit;
  background: rgba(255,255,255,0.5);
  transition: border-color 0.15s ease, background 0.15s ease;
}
.repeater-module-btn.is-next {
  border-color: var(--rep-primary);
  background: var(--rep-primary-12);
}
/* Colourful completed state — vivid, not muted. --sage is the one
   shared "done" colour, deliberately not this module's own accent. */
.repeater-module-btn.is-done {
  border-color: var(--sage, #2f9e6e);
  background: linear-gradient(135deg, rgba(47,158,110,0.16), rgba(47,158,110,0.06));
}
.repeater-module-check {
  color: var(--sage, #2f9e6e);
  font-weight: 700;
  font-size: 1.2em;
}
.repeater-module-text { flex: 1; }
.repeater-module-arrow { opacity: 0.5; }

.repeater-next-btn.is-locked {
  display: block;
  text-align: center;
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Milestone popup — striking, self-closable, 2-action footer ── */
.repeater-popup-overlay {
  position: fixed;
  inset: 0;
  background: rgba(28,16,64,0.6);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
  padding: var(--space-4, 16px);
}
.repeater-popup-card {
  position: relative;
  background: linear-gradient(160deg, #fff, var(--rep-primary-pale) 160%);
  border-radius: 22px;
  padding: var(--space-6, 32px) var(--space-5, 22px) var(--space-5, 22px);
  max-width: 360px;
  width: 100%;
  text-align: center;
  box-shadow: 0 20px 60px rgba(28,16,64,0.35);
  animation: repeaterPopIn 0.22s cubic-bezier(.2,.8,.2,1);
}
@keyframes repeaterPopIn {
  from { opacity: 0; transform: scale(.92) translateY(8px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}
.repeater-popup-close {
  position: absolute;
  top: 12px; right: 12px;
  border: none;
  background: rgba(13,27,62,0.06);
  width: 28px; height: 28px;
  border-radius: 50%;
  font-size: 1em;
  cursor: pointer;
  opacity: 0.6;
  line-height: 1;
}
.repeater-popup-badge {
  width: 56px; height: 56px;
  margin: 0 auto var(--space-3, 12px);
  border-radius: 50%;
  background: var(--sage, #2f9e6e);
  color: #fff;
  font-size: 1.6em;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 20px rgba(47,158,110,0.4);
}
.repeater-popup-title { font-weight: 700; font-size: 1.15em; margin: 0 0 6px; }
.repeater-popup-progress { font-size: 0.85em; opacity: 0.6; margin: 0 0 var(--space-4, 18px); }
.repeater-popup-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3, 12px);
}
.repeater-popup-dismiss {
  font-size: 0.82em;
  opacity: 0.55;
  text-decoration: none;
  color: inherit;
  padding: 10px 4px;
}
.repeater-popup-nextbtn { flex: 1; }

/* ── Module significance modal — 90%x90% viewport, pre-entry (Task E).
   Reuses .repeater-popup-overlay for the backdrop + self-close button;
   its own card is much larger and scrolls internally if content is tall. */
.repeater-modal-card {
  position: relative;
  background: #fff;
  border-radius: 22px;
  padding: var(--space-6, 32px) var(--space-5, 22px) var(--space-5, 22px);
  width: 90vw;
  height: 90vh;
  max-width: 460px;
  display: flex;
  flex-direction: column;
  box-shadow: 0 20px 60px rgba(28,16,64,0.35);
  animation: repeaterPopIn 0.22s cubic-bezier(.2,.8,.2,1);
  overflow-y: auto;
}
.repeater-modal-title { font-weight: 800; font-size: 1.3em; margin: var(--space-2, 8px) 0 var(--space-4, 16px); }
.repeater-modal-list { flex: 1; margin: 0 0 var(--space-4, 16px); padding-left: 1.2em; }
.repeater-modal-list li { margin-bottom: var(--space-3, 12px); line-height: 1.55; }

/* ── Module question options — multiselect ──
   Reuses .opt/.opt-check/.opt-text as-is (defined in setu_styles.css
   for ROOTS). Native checkbox stays in the DOM for real, JS-free form
   submission; :has() gives it this module's own violet "selected"
   treatment, driven by :checked instead of a JS-toggled class. */
.repeater-opts-form { display: flex; flex-direction: column; gap: var(--space-2, 8px); }
.repeater-opt { position: relative; padding: var(--space-3, 12px); }
.repeater-opt-input {
  position: absolute;
  width: 20px; height: 20px;
  opacity: 0; /* .opt-check span is the visible indicator, matches ROOTS */
  margin: 0;
  cursor: pointer;
}
.repeater-opt:has(.repeater-opt-input:checked) { border-color: var(--rep-primary); background: var(--rep-primary-pale); box-shadow: 0 3px 12px rgba(75,47,191,.18); }
.repeater-opt.is-checked { border-color: var(--rep-primary); background: var(--rep-primary-pale); box-shadow: 0 3px 12px rgba(75,47,191,.18); }
.repeater-opt:has(.repeater-opt-input:checked) .opt-check { background: var(--rep-primary); border-color: var(--rep-primary); }
.repeater-opt.is-checked .opt-check { background: var(--rep-primary); border-color: var(--rep-primary); }
.repeater-opt:has(.repeater-opt-input:checked) .opt-check::after {
  content: '';
  position: absolute;
  left: 6px; top: 2px;
  width: 5px; height: 10px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.repeater-opt.is-checked .opt-check::after {
  content: '';
  position: absolute;
  left: 6px; top: 2px;
  width: 5px; height: 10px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.repeater-multiselect-hint {
  font-size: 0.76em;
  opacity: 0.55;
  text-align: center;
  margin: var(--space-2, 8px) 0 0;
}

/* Extra breathing room on the question-answering screens specifically — a
   tired or anxious reader benefits from more generous line-height than the
   rest of the module needs; scoped to reflection-stage only. */
.reflection-stage .qcard { line-height: 1.7; letter-spacing: 0.01em; }
.reflection-stage .repeater-opt-main { line-height: 1.6; }

/* ── Pay / Share choice cards — one stacked column, not a 2-up grid.
   Side-by-side presented this as a stark either/or at a raw emotional
   moment; stacked reads as sequential options, not a forced comparison. */
.repeater-choice-grid {
  display: flex;
  flex-direction: column;
  gap: var(--space-3, 12px);
  margin: var(--space-3, 12px) 0;
}
.repeater-choice-reassurance {
  text-align: center;
  font-size: 0.85em;
  opacity: 0.7;
  line-height: 1.5;
  margin: 0 0 var(--space-3, 12px);
}
.repeater-choice-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-2, 8px);
  padding: var(--space-3, 12px);
  border-radius: var(--ds-radius-card, 16px);
  border: 2px solid var(--ds-navy-08, rgba(13,27,62,0.08));
  cursor: pointer;
  position: relative;
}
.repeater-choice-card input[type="radio"] {
  position: absolute;
  top: 10px;
  left: 10px;
}
.repeater-choice-card:has(input:checked) {
  border-color: var(--rep-primary);
  background: var(--rep-primary-12);
}
.repeater-choice-card.is-checked {
  border-color: var(--rep-primary);
  background: var(--rep-primary-12);
}
.repeater-choice-badge {
  font-size: 0.7em;
  letter-spacing: 0.06em;
  font-weight: 700;
  opacity: 0.6;
}
.repeater-choice-title { font-weight: 600; }
.repeater-choice-qr { width: 96px; height: 96px; object-fit: contain; border-radius: 8px; }
.repeater-choice-upi { font-size: 0.72em; opacity: 0.65; }
.repeater-choice-note { font-size: 0.78em; opacity: 0.65; }
.repeater-trust-line { text-align: center; font-size: 0.78em; opacity: 0.6; margin: var(--space-2, 8px) 0; }

/* ── Report cards (REPORT_CARD, one screen per module) ── */
.repeater-report-para { margin: var(--space-3, 12px) 0 0; line-height: 1.55; }

/* Indicative graph — unlabelled fill only, no numbers, no band words.
   This module's own violet gradient, never red/amber "traffic-light"
   judgement colour. */
.repeater-graph {
  height: 8px;
  border-radius: 999px;
  background: var(--ds-navy-08, rgba(13,27,62,0.08));
  overflow: hidden;
  margin-top: var(--space-3, 12px);
}
.repeater-graph-fill {
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--rep-primary-pale), var(--rep-primary));
  transition: width 0.3s ease;
}

/* Counter-actions card (on REPORT_CARD) — kept in --sage (green), the
   shared "positive next step" convention, distinct from the module's
   own violet brand accent. */
.repeater-actions-card {
  margin: var(--space-4, 16px) 0 0;
  padding: var(--space-3, 12px) var(--space-4, 16px);
  border-radius: var(--ds-radius-card, 16px);
  background: rgba(47,158,110,0.08);
  border: 1px solid rgba(47,158,110,0.18);
}
.repeater-actions-title { font-weight: 600; margin: 0 0 6px; font-size: 0.85em; }
.repeater-actions-list { margin: 0; padding-left: 1.1em; }
.repeater-actions-list li { margin-bottom: 4px; line-height: 1.5; font-size: 0.92em; }
.repeater-actions-list li:last-child { margin-bottom: 0; }

/* Improvements summary (REPORT_SUMMARY) */
.repeater-improve-card {
  margin: var(--space-3, 12px) 0;
  padding: var(--space-4, 16px);
  border-radius: var(--ds-radius-card, 16px);
  background: var(--rep-primary-08);
  border: 1px solid var(--rep-primary-12);
}
.repeater-improve-title { font-weight: 600; margin: 0 0 var(--space-2, 8px); }
.repeater-improve-list { margin: 0; padding-left: 1.1em; }
.repeater-improve-list li { margin-bottom: 6px; line-height: 1.5; }
.repeater-improve-list li:last-child { margin-bottom: 0; }

/* Secondary CTA (REPORT_SUMMARY) — deliberately NOT .btn.gold: the parent-
   share option must read as an optional companion action, never compete
   with the primary "continue" button sitting right above it in the footer. */
.repeater-parent-share-btn {
  background: transparent;
  border: 2px solid var(--rep-primary-12);
  color: var(--rep-primary-dark);
  box-shadow: none;
  margin-top: var(--space-2, 8px);
}
.repeater-parent-share-btn:hover { background: var(--rep-primary-08); }

/* Physically-present-but-invisible form, per this file's own established
   pattern (footer button uses form="id" to submit a form living in the
   scrollable stage) — this one has no visible fields of its own. */
.repeater-hidden-form { display: none; }

/* ── Persistent counselling nudge (REPORT_SUMMARY + SHARE) ── */
.repeater-counselling-block {
  display: flex;
  gap: var(--space-3, 12px);
  align-items: flex-start;
  margin: var(--space-3, 12px) 0;
  padding: var(--space-3, 12px) var(--space-4, 16px);
  border-radius: var(--ds-radius-card, 16px);
  background: rgba(13,27,62,0.04);
  border: 1px solid var(--ds-navy-08, rgba(13,27,62,0.08));
}
.repeater-counselling-icon { font-size: 1.3em; line-height: 1; }
.repeater-counselling-block p { margin: 0; line-height: 1.5; font-size: 0.88em; }

/* ── Feedback checkboxes ── */
.repeater-feedback-list { display: flex; flex-direction: column; gap: var(--space-2, 8px); margin-bottom: var(--space-3, 12px); }
.repeater-feedback-option {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3, 12px);
  padding: var(--space-2, 10px) var(--space-3, 12px);
  border-radius: var(--ds-radius-control, 13px);
  border: 1px solid var(--ds-navy-08, rgba(13,27,62,0.08));
  cursor: pointer;
}
.repeater-feedback-option:has(input:checked) {
  border-color: var(--rep-primary);
  background: var(--rep-primary-12);
}
.repeater-feedback-option.is-checked {
  border-color: var(--rep-primary);
  background: var(--rep-primary-12);
}
.repeater-feedback-option input { margin-top: 3px; }

/* ── WhatsApp message preview ── */
.repeater-message-card {
  border-radius: var(--ds-radius-card, 16px);
  border: 1px solid var(--ds-navy-08, rgba(13,27,62,0.08));
  padding: var(--space-3, 12px);
  margin: var(--space-3, 12px) 0;
  background: rgba(37,211,102,0.06);
}
.repeater-message-text {
  width: 100%;
  border: none;
  background: transparent;
  font: inherit;
  resize: vertical;
  line-height: 1.5;
}
.repeater-message-text:focus { outline: none; }
.repeater-return-link { margin-top: var(--space-2, 8px); opacity: 0.7; }

/* ── AJAX navigation busy state (assets/js/repeaters.js RS.navigate) ──
   Deliberately subtle and brief — most navigations resolve in well under
   the transition duration, so this should read as a soft settle, not a
   loading spinner. */
#app.rs-loading #stage,
#app.rs-loading #footer {
  opacity: 0.55;
  pointer-events: none;
  transition: opacity 0.15s ease;
}

/* ── Mobile-first: tighten stage padding so screens fit with minimal scroll ── */
@media (max-width: 480px) {
  .mentor-headline { font-size: 1.15em; line-height: 1.35; }
  .repeater-choice-qr { width: 84px; height: 84px; }
  .repeater-hero { padding-top: 10vh; }
  .repeater-modal-card { width: 92vw; height: 88vh; }
}
