/* Local Scheherazade New (SIL Open Font License — assets/fonts/OFL.txt),
   used for every Arabic-text rule across the site. Declared here so it
   always wins over the same-named family loaded from Google Fonts in
   includes/header.php's <link> — that link is earlier in every page's
   <head>, and this stylesheet's own <link> always comes after it, so
   these rules are later in source order and take precedence per the
   CSS spec's @font-face matching rules (harmless belt-and-suspenders
   on ordinary pages). worksheet-download-pdf.php's standalone
   PDF-source HTML goes further and omits the Google Fonts <link>
   entirely, so headless Chrome never makes that network call at all —
   confirmed via a minimal render using this exact stylesheet/
   @font-face setup through the same Chrome --print-to-pdf invocation:
   with fonts.googleapis.com/fonts.gstatic.com unreachable
   (--host-resolver-rules mapped to a dead address), the PDF still
   rendered Arabic correctly (ScheherazadeNew-Regular embedded, per
   `pdffonts`) — but a silently-dropped connection (vs. a fast
   connection-refused) was observed to stall the whole page load well
   past what's reasonable for an unattended PDF job, which is the
   actual reason the <link> is removed outright there rather than
   just outranked by source order. */
@font-face {
  font-family: 'Scheherazade New';
  src: url('../fonts/ScheherazadeNew-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Scheherazade New';
  src: url('../fonts/ScheherazadeNew-Medium.ttf') format('truetype');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Scheherazade New';
  src: url('../fonts/ScheherazadeNew-SemiBold.ttf') format('truetype');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Scheherazade New';
  src: url('../fonts/ScheherazadeNew-Bold.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* Local Vazirmatn (SIL Open Font License — assets/fonts/Vazirmatn-OFL.txt),
   used ONLY by the Trace It / Color It word-art renderer
   (includes/WorksheetCreativeRenderer.php) — a deliberately different font
   from Scheherazade New above, which stays the site's font for every other
   Arabic rule (ayah text, word banks, etc.). Vazirmatn's geometric,
   even-stroke letterforms suit a thick-outline coloring/tracing treatment;
   Scheherazade New's calligraphic Naskh forms don't reproduce the same way
   at a heavy stroke width. font-display:swap matches the Scheherazade New
   rule above, not because a fallback is expected here (this file is
   loaded the same guaranteed-local way, no Google Fonts dependency in the
   PDF-render path), just for consistency. */
@font-face {
  font-family: 'Vazirmatn';
  src: url('../fonts/Vazirmatn-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Vazirmatn';
  src: url('../fonts/Vazirmatn-Bold.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* Local Noto Emoji, monochrome outline variant (SIL Open Font License —
   assets/fonts/NotoEmoji-OFL.txt), for the same reason as Scheherazade
   New above: headless Chrome's PDF export has no color-emoji font
   available in this environment, so any raw emoji character (e.g.
   ayah_words.emoji — free-text per-word authoring, Rootcovery/Matching's
   .worksheet-word-emoji) rendered as an empty tofu box in the actual
   PDF. Deliberately the monochrome "Noto Emoji" family, not "Noto Color
   Emoji" — color emoji fonts use bitmap/COLR table formats with
   inconsistent support in Chromium's print/PDF path specifically (the
   very reason the panel header icons were replaced with hand-drawn SVGs
   instead of trusting any emoji font, color or not); a plain outline
   glyph font behaves exactly like any other text font, so it doesn't
   carry that same risk, and its stroke-only look already matches the
   rest of this template's SVG icon aesthetic. */
@font-face {
  font-family: 'Noto Emoji';
  src: url('../fonts/NotoEmoji-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  --teal: #159DAA;
  --teal-dark: #087C8B;
  --navy: #123A66;
  --orange: #FFB12B;
  --orange-dark: #F28A22;
  --peach: #FFE2C7;
  --cream: #FFF8D9;
  --butter: #FFF3B8;
  --sky: #DDF8FF;
  --sky-2: #BFEFFF;
  --cloud: #FFFFFF;
  --mint: #BDE5BE;
  --sage: #DDF0D5;
  --pink: #FF8BAD;
  --text: #25364A;
  --muted: #52677A;
  --border: rgba(18, 58, 102, .12);
  --shadow: 0 18px 45px rgba(18, 58, 102, .13);
  --soft-shadow: 0 10px 25px rgba(18, 58, 102, .10);
  --radius: 28px;
  --max: 1180px;
}

/* Semantic theme tokens — additive layer over the primitives above.
   Phase 0 of docs/WEBSITE-LIGHT-DARK-THEME-PLAN.md: resolves to the
   exact same values as today, so nothing renders differently yet.
   Dark-mode overrides for these are added in Phase 2. */
:root {
  --site-bg-page: var(--sky);
  --site-bg-surface: var(--cloud);
  --site-bg-tint-peach: var(--peach);
  --site-bg-tint-mint: var(--mint);
  --site-bg-tint-sage: var(--sage);
  --site-bg-tint-pink: var(--pink);
  --site-bg-tint-butter: var(--butter);
  --site-bg-tint-cream: var(--cream);

  --site-text-primary: var(--text);
  --site-text-secondary: var(--muted);
  --site-text-heading: var(--navy);
  --site-text-link: var(--teal-dark);
  --site-text-inverse: var(--cloud);

  --site-border-default: var(--border);

  --site-action-primary: var(--teal);
  --site-action-primary-strong: var(--teal-dark);
  --site-action-secondary: var(--orange);
  --site-action-secondary-strong: var(--orange-dark);

  --site-state-success: var(--mint);
  --site-state-error: var(--pink);

  --site-shadow: var(--shadow);
  --site-shadow-soft: var(--soft-shadow);

  /* Public marketing header (.site-header) — semantic tokens per
     product-owner direction, so a future header re-theme is one edit
     here, not a hunt through hard-coded rules. Light values match the
     header's existing appearance exactly (zero visual change in light
     mode). */
  --site-header-bg: rgba(255, 255, 255, .94);
  --site-header-text: #10243d;
  --site-header-border: rgba(18, 58, 102, .08);
  --site-header-active-bg: #E9F9FC;
  --site-header-active-text: var(--teal-dark);
}

/* Dark theme — Phase 2A of docs/WEBSITE-LIGHT-DARK-THEME-PLAN.md.
   First-pass values, flagged for visual QA (see the plan doc).

   Deliberately redefines the shared PRIMITIVES (--navy/--text/--muted/
   --teal-dark/--border/--shadow/--soft-shadow) rather than only the
   --site-* semantic aliases: those primitives are referenced directly
   by hundreds of existing rules across style.css/app.css/student.css
   (headings, body text, links, borders, shadows) that predate the
   semantic layer and were never rewritten to use it. Redefining the
   primitive here lets every one of those existing rules pick up the
   dark value automatically through normal CSS custom-property
   cascading, with zero changes to the rules themselves.

   --cloud, --teal, --orange, --orange-dark and the pastel family
   (--peach/--cream/--butter/--sky/--sky-2/--mint/--sage/--pink) are
   deliberately NOT redefined here:
   - --cloud feeds both --site-bg-surface (needs to go dark) and
     --site-text-inverse (must stay light — it colors text/icons sitting
     on accent-colored buttons and badges, which keep the same
     brightness in both themes). Overriding --cloud itself would wrongly
     flip both. --site-bg-surface gets its own explicit override below
     instead.
   - --teal/--orange/--orange-dark are used mainly as flat accent fills
     (button/badge backgrounds, borders) whose own brightness doesn't
     need to change; the text/icons placed on them are handled by
     --site-text-inverse, which is unaffected by this block.
   - The pastel family is used throughout style.css/student.css paired
     with hardcoded second gradient stops (e.g.
     `linear-gradient(180deg, var(--peach), #FFE3C7)`). Redefining just
     the primitive would produce a dark-to-light gradient, which is
     worse than doing nothing. These need per-selector dark overrides,
     authored by hand — tracked as follow-up work, not done in this
     pass. Pastel cards will still render in their light colors under
     dark mode for now. */
[data-theme="dark"] {
  --navy: #E9F1F8;
  --text: #DCE6EF;
  --muted: #9FB2C4;
  --teal-dark: #55D6E0;
  --border: rgba(233, 241, 248, .14);
  --shadow: 0 18px 45px rgba(0, 0, 0, .5);
  --soft-shadow: 0 10px 25px rgba(0, 0, 0, .4);

  --site-bg-page: #0E1620;
  --site-bg-surface: #17222E;

  --site-header-bg: #111C24;
  --site-header-text: #F5F7F8;
  --site-header-border: #263640;
  --site-header-active-bg: #0E7C7B;
  --site-header-active-text: #F5F7F8;
}

@media (prefers-color-scheme: dark) {
  /* Only applies before an explicit choice is made — see the
     resolution order in includes/header.php. Once a visitor or logged
     -in user picks a theme, data-theme="light"/"dark" is set explicitly
     and this block no longer matters (the :not() guard keeps an
     explicit "light" choice from being overridden by the OS setting). */
  :root:not([data-theme="light"]) {
    --navy: #E9F1F8;
    --text: #DCE6EF;
    --muted: #9FB2C4;
    --teal-dark: #55D6E0;
    --border: rgba(233, 241, 248, .14);
    --shadow: 0 18px 45px rgba(0, 0, 0, .5);
    --soft-shadow: 0 10px 25px rgba(0, 0, 0, .4);

    --site-bg-page: #0E1620;
    --site-bg-surface: #17222E;

    --site-header-bg: #111C24;
    --site-header-text: #F5F7F8;
    --site-header-border: #263640;
    --site-header-active-bg: #0E7C7B;
    --site-header-active-text: #F5F7F8;
  }

  /* Must be mirrored here too, not just under [data-theme="dark"]:
     the variable overrides above already apply in System-dark mode via
     this same media query, but `body`'s background is an explicit
     gradient (not built from --site-bg-page, since it also carries the
     light theme's decorative pastel stops), so it needs its own
     System-dark copy or text goes light on a background that's still
     light too — found by testing with the OS in dark mode. */
  :root:not([data-theme="light"]) body {
    background:
      radial-gradient(circle at 8% 18%, rgba(255,255,255,.04) 0 34px, transparent 35px),
      radial-gradient(circle at 92% 24%, rgba(255,255,255,.035) 0 42px, transparent 43px),
      linear-gradient(180deg, #0E1620 0%, #101C28 38%, #0C141D 72%, #0A121A 100%);
  }
  :root:not([data-theme="light"]) .hero,
  :root:not([data-theme="light"]) .page-hero {
    background:
      radial-gradient(circle at 6% 27%, rgba(255,255,255,.06) 0 34px, transparent 35px),
      radial-gradient(circle at 58% 17%, rgba(255,255,255,.05) 0 24px, transparent 25px),
      radial-gradient(circle at 94% 30%, rgba(255,255,255,.06) 0 40px, transparent 41px),
      linear-gradient(180deg, #0F1924 0%, #101C28 100%);
    border-bottom-color: rgba(233, 241, 248, .1);
  }
}

[data-theme="dark"] body {
  background:
    radial-gradient(circle at 8% 18%, rgba(255,255,255,.04) 0 34px, transparent 35px),
    radial-gradient(circle at 92% 24%, rgba(255,255,255,.035) 0 42px, transparent 43px),
    linear-gradient(180deg, #0E1620 0%, #101C28 38%, #0C141D 72%, #0A121A 100%);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: 'Baloo 2', 'Nunito', system-ui, sans-serif;
  color: var(--text);
  background:
    radial-gradient(circle at 8% 18%, rgba(255,255,255,.8) 0 34px, transparent 35px),
    radial-gradient(circle at 92% 24%, rgba(255,255,255,.75) 0 42px, transparent 43px),
    linear-gradient(180deg, var(--sky) 0%, #F6FDFF 38%, var(--cream) 72%, #E7FAFF 100%);
  font-size: 17px;
  line-height: 1.65;
  min-height: 100vh;
}
body::before {
  content: "★  ✦     ♡      ★       ✦      ♡";
  position: fixed;
  inset: 130px 4vw auto 4vw;
  z-index: -1;
  color: rgba(255, 177, 43, .65);
  font-size: clamp(22px, 3vw, 42px);
  letter-spacing: clamp(20px, 8vw, 120px);
  white-space: nowrap;
  pointer-events: none;
}

img { max-width: 100%; display: block; }
a { color: var(--teal-dark); text-decoration: none; font-weight: 800; }
a:hover { color: var(--orange-dark); }
h1, h2, h3 { font-family: 'Baloo 2', 'Nunito', system-ui, sans-serif; line-height: 1.05; margin: 0 0 14px; color: var(--navy); }
h1 {
    font-size: clamp(2rem, 4vw, 3rem);
    line-height: 1.15;
}
/*h2 { font-size: clamp(2rem, 4vw, 3.2rem); }*/
h2 {
    font-size: clamp(1.6rem, 3vw, 2.4rem);
    line-height: 1.2;
}
/*h3 { font-size: 1.45rem; }*/
h3 {
    font-size: clamp(1.2rem, 2vw, 1.6rem);
    line-height: 1.3;
}
p { margin: 0 0 18px; color: var(--text); }
/*
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 18px clamp(20px, 5vw, 72px);
  background: rgba(255, 255, 255, .94);
  border-bottom: 1px solid rgba(18, 58, 102, .08);
  border-radius: 0 0 34px 34px;
  box-shadow: 0 10px 30px rgba(18, 58, 102, .08);
  backdrop-filter: blur(12px);
}*/
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  /* Fixed 76px to match the STUDENT header (.sdv2-header in
     student.css, same height, same logo clamp) — a signed-in student
     moving between the public site and their own pages should not see
     the bar change height. Was 12px padding + a 220px logo = 98px.
     2026-09-25. */
  height: 76px;
  padding: 0 clamp(20px, 5vw, 72px);
  background: var(--site-header-bg);
  border-bottom: 1px solid var(--site-header-border);
  border-radius: 0 0 34px 34px;
  box-shadow: 0 10px 30px rgba(18, 58, 102, .08);
  backdrop-filter: blur(12px);
}
/* Social row at the bottom of the drawer, and the footer's social links.
   Icons are inline SVG inheriting currentColor, so both themes work with
   no per-theme rules. */
.site-drawer-social { margin-top: auto; padding-top: 18px; border-top: 1px solid var(--site-border-default); }
.site-drawer-social-label { display: block; font-size: .78rem; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); margin-bottom: 10px; }
.site-drawer-social-row { display: flex; gap: 10px; flex-wrap: wrap; }
.site-drawer-social-row a {
  padding: 0; display: grid; place-items: center;
  background: none; border-radius: 12px;
  transition: transform .15s ease;
}
.site-drawer-social-row a:hover { transform: translateY(-2px); }
.site-drawer-social-row a:hover .social-ic { filter: brightness(1.08); }
/* Footer social rows. Three things needed fixing (2026-09-26):
   - .footer-grid a is `display:block` at a HIGHER specificity than a bare
     .footer-social class, so the flex gap never applied and icon+label
     were jammed together. Hence the .footer-grid prefix here.
   - .footer-grid a::before adds a ★ to every footer link, which on these
     rows meant a star AND an icon. Suppressed for socials only; Quick
     Links keep their stars.
   - The bare glyphs read as stray letters, so each sits in a brand-
     coloured chip, matching the tiles on contact.php. */
.footer-grid a.footer-social { display: inline-flex; align-items: center; gap: 10px; }
.footer-grid a.footer-social::before { content: none; }
.footer-grid a.footer-social .social-ic,
.site-drawer-social-row a .social-ic {
  width: 18px; height: 18px; padding: 6px;
  box-sizing: content-box; border-radius: 9px;
  color: #fff; flex-shrink: 0;
}
/* Brand colours so each mark is recognisable at a glance. */
.social-instagram .social-ic { background: linear-gradient(135deg, #FF6A7A, #F28A22); }
.social-facebook  .social-ic { background: #1877F2; }
.social-tpt       .social-ic { background: #2DB48F; }
.social-etsy      .social-ic { background: #F1641E; }
.social-email     .social-ic { background: var(--teal-dark); }

/* ---------- Public header drawer (2026-09-26) ----------
   A three-line button to the LEFT of the logo, visible at EVERY width,
   opening a panel with the complete public link set. It replaces this
   header's old .menu-toggle (which only collapsed .site-nav below
   1100px); the student and app headers keep theirs untouched.

   Everything here is scoped to .site-header / .site-drawer*, which only
   the public header branch renders — the shared .menu-toggle/.site-nav
   leak that once put a floating nav pill over the student activity bar
   is exactly what this avoids repeating. */
/* The header is a space-between flex row, so with three children the
   brand floated into the MIDDLE. Letting the brand absorb the slack
   keeps [menu][logo] together hard against the left edge and pushes the
   nav to the right, which is the intended reading order. */
.site-header .brand { margin-right: auto; flex-shrink: 0; }
.site-header .site-nav { flex-shrink: 0; }

.site-menu-btn {
  flex-shrink: 0;
  width: 42px; height: 42px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  padding: 0; cursor: pointer;
  background: var(--site-bg-surface);
  border: 1px solid var(--site-border-default);
  border-radius: 12px;
  box-shadow: var(--soft-shadow);
  transition: transform .15s ease, background .15s ease;
}
.site-menu-btn span {
  display: block; width: 18px; height: 2.5px; border-radius: 2px;
  background: var(--site-header-text, var(--navy));
}
.site-menu-btn:hover { transform: translateY(-1px); background: var(--sky); }
[data-theme="dark"] .site-menu-btn:hover { background: rgba(255, 255, 255, .10); }

.site-drawer-backdrop {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(18, 58, 102, .45);
  backdrop-filter: blur(2px);
}
.site-drawer[hidden], .site-drawer-backdrop[hidden] { display: none; }
.site-drawer {
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 91;
  width: min(310px, 84vw);
  display: flex; flex-direction: column; gap: 4px;
  padding: 18px 16px;
  background: var(--site-bg-surface);
  border-right: 1px solid var(--site-border-default);
  box-shadow: 14px 0 40px rgba(18, 58, 102, .18);
  overflow-y: auto;
  transform: translateX(-100%);
  transition: transform .22s ease;
}
.site-drawer.is-open { transform: translateX(0); }
.site-drawer-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.site-drawer-title { font-weight: 900; color: var(--navy); font-size: 1.05rem; }
.site-drawer-close {
  width: 34px; height: 34px; border: 0; border-radius: 10px; cursor: pointer;
  background: transparent; color: var(--navy); font-size: 1.5rem; line-height: 1;
}
.site-drawer-close:hover { background: var(--sky); }
[data-theme="dark"] .site-drawer-close:hover { background: rgba(255, 255, 255, .10); }
.site-drawer a {
  display: block; padding: 11px 13px; border-radius: 12px;
  font-weight: 800; color: var(--navy); text-decoration: none;
}
.site-drawer a:hover { background: var(--sky); color: var(--teal-dark); }
[data-theme="dark"] .site-drawer a:hover { background: rgba(255, 255, 255, .10); }
.site-drawer a.active { background: var(--site-header-active-bg, var(--sky)); color: var(--site-header-active-text, var(--teal-dark)); }
.site-drawer-action { margin-top: 12px; text-align: center; }
.site-drawer-action .btn { width: 100%; }
@media (prefers-reduced-motion: reduce) {
  .site-drawer { transition: none; }
  .site-menu-btn { transition: none; }
}

/* Homepage revamp (2026-09-23) — logo shrunk from clamp(210px,24vw,330px)
   for a compact ~80-90px header (was rendering noticeably taller);
   kept large enough that the Deenscovery wordmark/logotype stays
   legible, not shrunk to a bare icon. */
.brand img { width: clamp(150px, 12vw, 186px); height: auto; }  /* matches .sdv2-brand img */
.site-nav { display: flex; align-items: center; gap: 10px; }
.site-nav a { color: var(--site-header-text); padding: 10px 12px; border-radius: 999px; font-weight: 900; }
/* Six links plus Sign In is a lot of bar; a slightly smaller label keeps
   the whole set inline down to ~1250px before the drawer takes over. */
.site-header .site-nav a { font-size: .95rem; }
.site-nav a:hover, .site-nav a.active { background: var(--site-header-active-bg); color: var(--site-header-active-text); }
/* Superseded by --site-header-active-bg/-text above (the previous
   version only fixed the text color, leaving a pale cyan pill on a
   dark header — the product owner asked for a proper dark-teal pill
   with light text instead, which the tokens now provide directly). */
.site-nav a:last-child {
  background: linear-gradient(180deg, #24B8C7, var(--teal-dark));
  color: var(--site-text-inverse);
  padding: 12px 22px;
  box-shadow: 0 8px 18px rgba(21,157,170,.24);
}
.site-nav a:last-child::before { content: '✉ '; }
.menu-toggle { display: none; border: 0; background: var(--teal); color: var(--site-text-inverse); border-radius: 14px; padding: 9px 13px; font-size: 1.35rem; }

/* Site theme toggle (Phase 2A) — shown in every header shell (see
   includes/header.php); content/label are set by assets/js/theme-toggle.js
   after checking localStorage, so the button never shows an empty/
   incorrect icon even before JS runs (the CSS content below is the
   pre-JS fallback, overwritten immediately). */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border: 1px solid var(--site-border-default);
  border-radius: 50%;
  background: var(--site-bg-surface);
  color: var(--site-text-primary);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}
/* Inside the (now dark) marketing header specifically: --site-bg-surface
   is close in tone to --site-header-bg, so the toggle would blend into
   the header instead of reading as an elevated control. A dedicated,
   slightly lighter shade keeps it visually distinct there, per the
   "dark elevated circle" request. */
[data-theme="dark"] .site-header .theme-toggle { background: #1B2833; border-color: var(--site-header-border); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .site-header .theme-toggle { background: #1B2833; border-color: var(--site-header-border); }
}
.theme-toggle:empty::before { content: '\1F5A5\FE0F'; }
.theme-toggle:hover { border-color: var(--site-action-primary); }

.nav-level-badge { display: inline-flex; align-items: center; background: var(--butter); color: var(--orange-dark); font-weight: 900; font-size: .82rem; padding: 8px 16px; border-radius: 999px; }
.nav-avatar { width: 36px; height: 36px; border-radius: 50%; background: var(--peach); display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
.nav-avatar svg { width: 20px; height: 20px; }

.site-footer-light { padding: 24px 20px; text-align: center; }
.site-footer-light .copyright { color: var(--muted); font-weight: 700; }
.site-footer-light .copyright a { color: var(--muted); font-weight: 800; }
.site-footer-light .copyright a:hover { color: var(--teal-dark); }

main { overflow: hidden; }
/*.section { max-width: var(--max); margin: 0 auto; padding: 58px 24px; position: relative; }*/
.section { max-width: var(--max); margin: 0 auto; padding: 4px 2px; position: relative; }
/*.hero { max-width: var(--max); margin: 0 auto; padding: 70px 24px 50px; display: grid; grid-template-columns: 1.05fr .95fr; gap: 42px; align-items: center; }*/

.center { text-align: center; }

/*.hero, .page-hero {
  position: relative;
  isolation: isolate;
  background:
    radial-gradient(circle at 6% 27%, white 0 34px, transparent 35px),
    radial-gradient(circle at 58% 17%, white 0 24px, transparent 25px),
    radial-gradient(circle at 94% 30%, white 0 40px, transparent 41px),
    linear-gradient(180deg, #D9F7FF 0%, #EDFCFF 100%);
  border-bottom: 1px solid rgba(18,58,102,.08);
}*/
.hero, .page-hero {
  position: relative;
  isolation: isolate;
  background:
    radial-gradient(circle at 6% 27%, white 0 34px, transparent 35px),
    radial-gradient(circle at 58% 17%, white 0 24px, transparent 25px),
    radial-gradient(circle at 94% 30%, white 0 40px, transparent 41px),
    linear-gradient(180deg, #D9F7FF 0%, #EDFCFF 100%);
  border-bottom: 1px solid rgba(18,58,102,.08);
}
[data-theme="dark"] .hero, [data-theme="dark"] .page-hero {
  background:
    radial-gradient(circle at 6% 27%, rgba(255,255,255,.06) 0 34px, transparent 35px),
    radial-gradient(circle at 58% 17%, rgba(255,255,255,.05) 0 24px, transparent 25px),
    radial-gradient(circle at 94% 30%, rgba(255,255,255,.06) 0 40px, transparent 41px),
    linear-gradient(180deg, #0F1924 0%, #101C28 100%);
  border-bottom-color: rgba(233, 241, 248, .1);
}
.hero::before, .page-hero::before {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 54px;
  background: radial-gradient(circle at 30px 54px, var(--peach) 30px, transparent 31px) repeat-x;
  background-size: 72px 54px;
  z-index: 0;
}
.hero::after, .page-hero::after {
  content: '✦   ★        ♡      ✦     ★';
  position: absolute;
  left: 5%; right: 5%; top: 26%;
  color: rgba(255, 177, 43, .7);
  font-size: 30px;
  letter-spacing: 80px;
  overflow: hidden;
  z-index: 0;
  pointer-events: none;
}
/* Homepage revamp (2026-09-23) — .hero is full-bleed (background/
   ::before/::after already span it); padding is a flat clamp()
   gutter rather than the old formula that re-centered a 1180px
   (--max) column here, which is exactly what caused dead space on
   wide monitors. Grid layout now lives on .hero-inner (below),
   deliberately capped wider than --max — --max itself stays
   untouched for every other .section site-wide. */
.hero {
  max-width: none;
  margin: 0;
  /* Homepage revamp (2026-09-23) — tightened from 70px/86px, then to
     24px (review pass): the visitor should see the headline and
     product right below the header, not scroll past a dead band
     first, and the next section should peek into the first viewport. */
  padding: 24px clamp(32px, 4vw, 96px) 40px;
}
/* Review pass (2026-09-23) — the floating ✦ ★ ♡ glyph row is switched
   off on the homepage hero only (.page-hero keeps it): the real
   product screenshots are now the visual attraction and the glyphs
   read as clutter next to them. The soft white circles in the hero
   background stay — they're quiet enough. */
.hero::after { content: none; }
.hero > * { position: relative; z-index: 1; }
/* Homepage revamp (2026-09-23) — hero rebuilt around a supplied
   promotional image instead of a live LessonRenderer preview (product
   decision: the hero is explicitly a marketing visual, not a live
   lesson component, so the accuracy-drift concern that drove the
   earlier live version no longer applies — the image is checked for
   accuracy once before shipping instead). .hero-inner caps content
   width, deliberately wider than --max (which stays untouched for
   every other .section on the site). Placed here (not further down
   the file) deliberately — it must sit BEFORE the responsive
   @media blocks below so their .hero-inner overrides (e.g. the
   900px stacking rule) actually win the cascade. */
.hero-inner {
  max-width: 1600px;
  margin: 0 auto;
  display: grid;
  /* .85fr 1.15fr (~43/57) — review pass (2026-09-23): the carousel
     is now a wide landscape frame showing real product screenshots,
     and the product should dominate the right half. The earlier
     1fr 1fr split was tuned for a tall 4:3 tablet artwork that read
     as too dominant vertically; that concern no longer applies.
     minmax(0, …) so long unbroken strings can't blow the columns. */
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
  gap: clamp(32px, 4vw, 64px);
  align-items: center;
}
/* Hero product carousel (2026-09-23) — real screenshots of the
   logged-in product. Review pass: the frame was a fixed 4/3 card
   (inherited from the static tablet artwork it replaced), which left
   the wide, shallow activity screenshots sitting small between big
   empty bands. It is now a wide landscape frame (16/9 on desktop;
   4/3 again once the hero stacks, where the column is narrow and a
   16/9 frame would make the screenshot tiny), and each screenshot is
   cropped at capture time around the actual learning UI (no footer,
   no excess wallpaper) so it fills ~85-100% of the frame width. The
   frame is fixed-ratio so the carousel never resizes as slides
   change; slides crossfade in place (absolute). Each figure is a flex
   column so the caption sits directly beneath its own screenshot no
   matter how tall that screenshot is; the dots live in a compact
   band at the bottom of the frame. Images keep their intrinsic ratio
   via max-width/max-height (never cropped by CSS). Placed here,
   before the responsive @media blocks below, for the same
   cascade-order reason as .hero-inner above. */
.hero-carousel { position: relative; }
.hero-carousel-viewport {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: 20px;
  overflow: hidden;
  background: linear-gradient(180deg, #E6FAFF, var(--sky-2));
  box-shadow: var(--shadow);
}
.hero-carousel-slide {
  position: absolute;
  inset: 12px 12px 34px; /* bottom band = dots row */
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  opacity: 0;
  transition: opacity .6s ease;
  pointer-events: none;
}
.hero-carousel-slide.is-active { opacity: 1; pointer-events: auto; }
.hero-carousel-slide img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: calc(100% - 44px); /* leave room for the caption pill + gap */
  border-radius: 12px;
  box-shadow: 0 10px 26px rgba(18,58,102,.16);
}
.hero-carousel-slide figcaption {
  background: rgba(18,58,102,.82);
  color: #fff;
  font-weight: 800;
  font-size: .85rem;
  line-height: 1.2;
  padding: 7px 18px;
  border-radius: 999px;
  white-space: nowrap;
}
.hero-carousel-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 0;
  cursor: pointer;
  background: rgba(255,255,255,.92);
  /* Literal navy, NOT var(--navy) — this is a white circle in every
     theme, and --navy flips to near-white under [data-theme="dark"],
     which made the arrow glyphs invisible in dark mode (found
     2026-09-25; the bug shipped with the carousel). */
  color: #123A66;
  font-weight: 900;
  font-size: 1.1rem;
  box-shadow: var(--soft-shadow);
  display: flex;
  align-items: center;
  justify-content: center;
}
.hero-carousel-prev { left: 12px; }
.hero-carousel-next { right: 12px; }
.hero-carousel-arrow:hover { background: #fff; }
.hero-carousel-dots { position: absolute; left: 0; right: 0; bottom: 12px; z-index: 2; display: flex; justify-content: center; gap: 8px; margin: 0; }
.hero-carousel-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 0;
  background: rgba(18,58,102,.25);
  cursor: pointer;
  padding: 0;
  transition: width .2s ease, border-radius .2s ease, background .2s ease;
}
.hero-carousel-dot.is-active { background: var(--teal-dark); width: 22px; border-radius: 5px; }
/* Frame ratio per breakpoint — chosen by measuring how much of the
   frame width the real screenshots occupy (target 85%+ for the
   least-wide slide, the 1.88:1 ayah page):
   - two columns, wide desktop: 16/9 (base rule above)
   - two columns, narrow (≤1100, the column is ~500px): 3/2, otherwise
     the ayah slide shrank to ~75% of the frame width
   - stacked (≤900): back to 16/9 — the column is now the full
     viewport width, so a tall frame would leave the shallow activity
     slides floating in empty space
   - phones (≤560): 7/5 — at ~310px wide a 16/9 frame would make the
     screenshot ~120px tall, unreadable */
@media (max-width: 1100px) {
  .hero-carousel-viewport { aspect-ratio: 3 / 2; }
}
@media (max-width: 900px) {
  .hero-carousel-viewport { aspect-ratio: 16 / 9; }
}
@media (max-width: 560px) {
  .hero-carousel-viewport { aspect-ratio: 7 / 5; }
  .hero-carousel-slide { inset: 10px 10px 30px; gap: 8px; }
  .hero-carousel-slide img { max-height: calc(100% - 38px); border-radius: 8px; }
  .hero-carousel-slide figcaption { font-size: .78rem; padding: 6px 14px; }
  .hero-carousel-arrow { width: 34px; height: 34px; }
  .hero-carousel-dots { bottom: 10px; }
}

/* Refinement pass (2026-09-23) — replaces the shared .eyebrow pill
   (kept fully intact for its other users: about.php, downloads.php,
   our-approach.php, contact.php, etc.) with a quiet, non-clickable-
   looking label just for the homepage hero, so the primary button
   stays the only element that visually reads as a CTA. */
.hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-weight: 800;
  font-size: .92rem;
  letter-spacing: .03em;
  color: var(--teal-dark);
  margin-bottom: 12px;
}
.hero-eyebrow::before { content: '✦'; color: var(--orange); font-size: .9em; }
[data-theme="dark"] .hero-eyebrow { color: #6FD8E0; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hero-eyebrow { color: #6FD8E0; }
}
/* Headline line-break rhythm (2026-09-23) — a max-width on the hero
   h1 only, so "Every ayah has more" / "to discover." wraps after
   "more" at typical desktop widths, achieved by narrowing the
   available line rather than a hard-coded <br> (which would either
   look fine or awkward depending on viewport/font-size and break
   responsively). Narrower columns (tablet/mobile) already wrap on
   their own available width well before this cap matters. */
.hero-copy h1 { max-width: 480px; }
.hero p, .page-hero p { color: #183B63; font-size: clamp(1.05rem, 1.7vw, 1.28rem); max-width: 720px; }
/* Reverse-direction bug: .hero/.page-hero DO get an actual dark
   background in dark mode (see the [data-theme="dark"] .hero,
   .page-hero rule above), but this paragraph text is a fixed dark
   navy that was only ever correct against the old light hero — once
   the hero goes dark, this became dark-on-dark. Same fix shape as
   .footer-grid a below. */
[data-theme="dark"] .hero p, [data-theme="dark"] .page-hero p { color: #DCE6EF; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hero p,
  :root:not([data-theme="light"]) .page-hero p { color: #DCE6EF; }
}
.hero-card { background: rgba(255,255,255,.68); border: 2px solid rgba(255,255,255,.85); border-radius: 36px; padding: 26px; box-shadow: var(--shadow); }
.hero-characters { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; align-items: end; }
.hero-characters img { background: var(--site-bg-surface); border-radius: 32px; padding: 12px; box-shadow: var(--soft-shadow); }

.page-hero .section {
  /* Was min-height 250 / 62px top / 74px bottom, which left a large dead
     band between the sticky header and the page's own heading on every
     .page-hero page (contact, our-approach, sources, login). Tightened
     2026-09-26 — the heading should start just below the bar. */
  min-height: 0;
  padding-top: 26px;
  padding-bottom: 34px;
  display: grid;
  grid-template-columns: 1.3fr .7fr;
  align-items: center;
  gap: 24px;
  z-index: 1;
}
.page-hero-art { display: flex; justify-content: center; align-items: end; min-height: 180px; }
.page-hero-art img { max-height: 240px; width: auto; filter: drop-shadow(0 12px 18px rgba(18,58,102,.15)); }
.page-hero-art.two img { max-height: 215px; margin-left: 0px; }

.eyebrow { display: inline-flex; align-items:center; gap: 8px; background: linear-gradient(180deg, #FFC94D, var(--orange)); color: var(--site-text-inverse); font-weight: 900; border-radius: 999px; padding: 9px 17px; margin-bottom: 16px; box-shadow: 0 8px 18px rgba(255,177,43,.24); }
.eyebrow::before { content: '★'; font-size: .82em; }
.btn-row { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 24px; }
.btn { display: inline-flex; align-items: center; justify-content: center; min-height: 50px; padding: 13px 24px; border-radius: 999px; border: 0; cursor: pointer; font-weight: 900; font-family: 'Baloo 2', 'Nunito', system-ui, sans-serif; transition: transform .15s ease, box-shadow .15s ease; }
/* .btn's own display:inline-flex ties in specificity with the
   browser's [hidden]{display:none} default and wins on source order
   — pre-existing bug (predates this change) that left every
   hidden .btn (e.g. guessword.php's "Show Choices" fallback, meant
   to stay hidden until 2 wrong attempts) visibly rendered from page
   load regardless of the hidden attribute. Discovered while verifying
   Guess the Word in this pass; fixed here since it directly broke a
   feature this pass is responsible for checking. */
.btn[hidden] { display: none; }
/* Same bug, same fix, one level up: .btn-row's own display:flex (line
   299) ties in specificity with [hidden]{display:none} too — hit when
   Milestone 3B.1's duplicate-navigation fix started toggling a
   .btn-row's hidden attribute via JS (activity-completion.js /
   matching.php's #pageNavRow) for the first time; previously no
   .btn-row was ever dynamically hidden, only present-or-absent in the
   server-rendered markup. */
.btn-row[hidden] { display: none; }
.btn:hover { transform: translateY(-2px); }
.btn-primary { background: linear-gradient(180deg, #21B8C8, var(--teal-dark)); color: var(--site-text-inverse); box-shadow: 0 10px 22px rgba(21,157,170,.22); }
.btn-primary:hover { color: var(--site-text-inverse); }
.btn-secondary { background: linear-gradient(180deg, #FFC247, var(--orange-dark)); color: var(--site-text-inverse); box-shadow: 0 10px 22px rgba(242,138,34,.22); }
.btn-secondary:hover { color: var(--site-text-inverse); }
.wbr-new-badge { display: inline-flex; align-items: center; margin-left: 8px; padding: 2px 7px; border-radius: 999px; background: rgba(255,255,255,.92); color: var(--orange-dark); font: 800 .68rem/1 'Nunito', system-ui, sans-serif; letter-spacing: .03em; text-transform: uppercase; }

/*.grid { display: grid; gap: 24px; }*/
.grid { display: grid; gap: 12px; }

.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.card {
  position: relative;
  background: rgba(255,255,255,.92);
  border: 2px solid rgba(255,255,255,.9);
  border-radius: var(--radius);
  padding: 30px;
  box-shadow: var(--shadow);
  overflow: hidden;
}
[data-theme="dark"] .card { background: rgba(23, 34, 46, .92); border-color: rgba(233, 241, 248, .12); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .card { background: rgba(23, 34, 46, .92); border-color: rgba(233, 241, 248, .12); }
}
.card::after { content: ''; position: absolute; right: 22px; top: 18px; width: 46px; height: 46px; background: radial-gradient(circle, rgba(255,177,43,.35) 0 38%, transparent 40%); border-radius: 50%; pointer-events: none; }
.card.sky, .contact-card { background: linear-gradient(180deg, #E6FAFF, #CFF3FB); }
.card.peach { background: linear-gradient(180deg, #FFF6E4, #FFE3C7); }
.card.sage { background: linear-gradient(180deg, #F0F9EA, #D9EFCF); }
.card.soft { background: linear-gradient(180deg, #FFFDF0, #FFF4BC); }
.card.pink { background: linear-gradient(180deg, #feeffd, #f9d1f7); }

/* PROVISIONAL dark values, not the final design. This whole pastel
   .card family was flagged from the start of the theme rollout as
   needing hand-picked dark colors reviewed by whoever owns the visual
   design (docs/WEBSITE-LIGHT-DARK-THEME-PLAN.md, Phase 2 open
   decisions) — auto-darkening a pastel gradient tends to produce muddy,
   characterless colors. These values exist only so high-traffic pages
   using .card.sky (e.g. login.php) aren't left with illegible light-on
   -light text while that design review is pending; expect them to be
   replaced. */
[data-theme="dark"] .card.sky, [data-theme="dark"] .contact-card { background: linear-gradient(180deg, #123038, #0B1F27); }
[data-theme="dark"] .card.peach { background: linear-gradient(180deg, #332619, #241A10); }
[data-theme="dark"] .card.sage { background: linear-gradient(180deg, #1E2B1A, #131F11); }
[data-theme="dark"] .card.soft { background: linear-gradient(180deg, #332D14, #241F0A); }
[data-theme="dark"] .card.pink { background: linear-gradient(180deg, #2E1E2C, #21131F); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .card.sky,
  :root:not([data-theme="light"]) .contact-card { background: linear-gradient(180deg, #123038, #0B1F27); }
  :root:not([data-theme="light"]) .card.peach { background: linear-gradient(180deg, #332619, #241A10); }
  :root:not([data-theme="light"]) .card.sage { background: linear-gradient(180deg, #1E2B1A, #131F11); }
  :root:not([data-theme="light"]) .card.soft { background: linear-gradient(180deg, #332D14, #241F0A); }
  :root:not([data-theme="light"]) .card.pink { background: linear-gradient(180deg, #2E1E2C, #21131F); }
}
.resource-card { display: grid; grid-template-columns: 310px 1fr; gap: 34px; align-items: center; }
.resource-cover { border-radius: 22px; box-shadow: var(--shadow); border: 8px solid var(--site-bg-surface); }
.pill-list { display: flex; flex-wrap: wrap; gap: 10px; margin: 18px 0; padding: 0; list-style: none; }
.pill-list li { background: #EAFBFF; color: var(--navy); border-radius: 999px; padding: 8px 13px; font-weight: 900; }
.pill-list li a { text-decoration: underline; text-underline-offset: 3px; }
.pill-list li a:hover { color: var(--orange-dark); }

/* .pill-list li's own background (#EAFBFF) is a one-off, untouched by
   the theme — but its text (color: var(--navy)) does flip light in
   dark mode, which broke the light-bg/dark-text pairing (see the
   standing rule in docs/architecture/SITE-THEME-ARCHITECTURE.md §5).
   Pin the text dark to match the background, same fix as the form
   fields. */
[data-theme="dark"] .pill-list li { color: #123A66; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pill-list li { color: #123A66; }
}

.form { display: grid; gap: 15px; }
.form label { font-weight: 900; color: var(--text); }
.form input, .form textarea, .form select { width: 100%; padding: 15px 16px; border: 2px solid rgba(18,58,102,.10); border-radius: 18px; font: inherit; background: var(--site-bg-surface); outline: none; }
.form input:focus, .form textarea:focus, .form select:focus { border-color: var(--teal); box-shadow: 0 0 0 4px rgba(21,157,170,.12); }
.form textarea { min-height: 160px; resize: vertical; }
.form select:disabled { opacity: .5; cursor: not-allowed; }

/* Standing rule (product-owner direction, 2026-09-12): a text-entry
   field's background stays light regardless of site theme, with dark
   text to match — never follow the page into dark mode. More generally:
   a light background always pairs with dark text and a dark background
   always pairs with light text, never dark-on-dark or light-on-light.
   This intentionally overrides --site-bg-surface (which does go dark)
   for form fields specifically. */
[data-theme="dark"] .form input,
[data-theme="dark"] .form textarea,
[data-theme="dark"] .form select {
  background: #FFFFFF;
  color: #1A2634;
}
[data-theme="dark"] .form input::placeholder,
[data-theme="dark"] .form textarea::placeholder {
  color: #6B7B8C;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .form input,
  :root:not([data-theme="light"]) .form textarea,
  :root:not([data-theme="light"]) .form select {
    background: #FFFFFF;
    color: #1A2634;
  }
  :root:not([data-theme="light"]) .form input::placeholder,
  :root:not([data-theme="light"]) .form textarea::placeholder {
    color: #6B7B8C;
  }
}
.notice { padding: 16px 18px; border-radius: 18px; margin-bottom: 20px; font-weight: 900; }
.notice.success { background: #e9f8e3; color: #376d2b; }
.notice.error { background: #fdeeee; color: #9a3030; }
.notice.warning { background: #fff4dc; color: #7a4f00; }

/* Setup Surah only — a routine confirmation (e.g. "Safeguards marked
   clear") shouldn't be as tall as a page-level alert; scoped here
   rather than shrinking .notice everywhere it's used sitewide. */
.setup-notice-compact { padding: 6px 14px; margin-bottom: 10px; font-size: .85rem; font-weight: 700; border-radius: 999px; display: inline-block; }
.feature-list { list-style: none; padding: 0; margin: 0; }
.feature-list li { margin: 10px 0; padding-left: 30px; position: relative; }
.feature-list li::before { content: '★'; position: absolute; left: 0; color: var(--orange); font-weight: 900; }

.contact-grid { align-items: stretch; margin-top: -50px; z-index: 2; }
.contact-email-box, .social-tile {
  display: flex; align-items: center; gap: 14px; padding: 16px; border-radius: 22px;
  background: rgba(255,255,255,.92); border: 2px solid rgba(18, 58, 102, 0.08); color: var(--text); margin-top: 14px;
  transition: transform .2s ease, box-shadow .2s ease;
}
.contact-email-box:hover, .social-tile:hover { transform: translateY(-3px); box-shadow: var(--soft-shadow); }
.contact-icon, .social-icon { width: 52px; height: 52px; border-radius: 18px; display: grid; place-items: center; flex-shrink: 0; color: var(--site-text-inverse); background: var(--teal); font-weight: 900; }
.contact-email-box strong, .social-tile strong { display: block; font-size: 1.05rem; }
.contact-email-box small, .social-tile small { display: block; color: var(--muted); margin-top: 2px; }
/* Same light-bg/dark-text pairing bug as .pill-list — .contact-email-box/
   .social-tile keep a fixed translucent-white background, so pin their
   text dark too instead of following --text/--muted light in dark mode. */
[data-theme="dark"] .contact-email-box,
[data-theme="dark"] .social-tile { color: #25364A; }
[data-theme="dark"] .contact-email-box small,
[data-theme="dark"] .social-tile small { color: #52677A; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .contact-email-box,
  :root:not([data-theme="light"]) .social-tile { color: #25364A; }
  :root:not([data-theme="light"]) .contact-email-box small,
  :root:not([data-theme="light"]) .social-tile small { color: #52677A; }
}
.social-heading { margin-top: 28px; }
.social-links { display: grid; gap: 12px; }
.instagram .social-icon { background: linear-gradient(135deg, #FF6A7A, #F28A22); }
.facebook .social-icon { background: #1877F2; }
.tpt .social-icon { background: #2DB48F; }
.etsy .social-icon { background: #F28A22; }
.tpt-text { font-size: .9rem; }
.etsy-text { font-size: 1.5rem; }
.hp-field { display: none; }

.site-footer {
  position: relative;
  background: linear-gradient(180deg, #DDF8FF, #BEEFFF);
  padding: 86px 24px 0;
  margin-top: 34px;
  overflow: hidden;
}
.site-footer::before {
  content: '';
  position: absolute; left: 0; right: 0; top: 0; height: 58px;
  background: radial-gradient(circle at 34px 0px, transparent 34px, #DDF8FF 35px) repeat-x;
  background-size: 74px 58px;
}
/* A page-level surface like .hero, not a small chip — gets an actual
   dark background rather than just pinned text (see the .pill-list
   fix's comment for the small-chip approach used elsewhere). --muted
   -based copyright text and the fixed-dark .footer-grid links already
   read correctly once the background itself goes dark. */
[data-theme="dark"] .site-footer { background: linear-gradient(180deg, #0F1924, #0C1620); }
[data-theme="dark"] .site-footer::before { background: radial-gradient(circle at 34px 0px, transparent 34px, #0F1924 35px) repeat-x; background-size: 74px 58px; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .site-footer { background: linear-gradient(180deg, #0F1924, #0C1620); }
  :root:not([data-theme="light"]) .site-footer::before { background: radial-gradient(circle at 34px 0px, transparent 34px, #0F1924 35px) repeat-x; background-size: 74px 58px; }
}
.footer-grid { max-width: var(--max); margin: 0 auto; display: grid; grid-template-columns: 1.5fr 1fr 1.2fr 1fr; gap: 30px; align-items: start; }
.footer-logo { width: 210px; }
.footer-grid a { display: block; margin: 7px 0; color: #10243d; font-weight: 900; }
[data-theme="dark"] .footer-grid a { color: #E9F1F8; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .footer-grid a { color: #E9F1F8; }
}
.footer-grid a::before { content: '★ '; color: var(--orange); }
.footer-characters { display:flex; align-items:end; justify-content:center; gap: 0; }
.footer-characters img { max-height: 165px; width: auto; margin-left: -22px; filter: drop-shadow(0 10px 14px var(--site-border-default)); }
.copyright { margin: 34px -24px 0; padding: 14px 24px; text-align: center; background: linear-gradient(180deg, #16AAB8, #087C8B); color: var(--site-text-inverse); font-weight: 800; }
.copyright::before, .copyright::after { content: ' 💗 '; }

/* Nav/header hamburger breakpoint — deliberately wider than the
   900px content breakpoint below (2026-09-22). The public nav (Home /
   Qur'an Learning / Resources / Our Story / Sign In pill) plus the
   clamp(210px,24vw,330px) logo don't comfortably fit single-line
   below ~1150px; 1024px specifically was wrapping to two lines.
   Rather than squeeze nav item padding/gaps to chase a lower number,
   the hamburger just takes over earlier — a clean compact nav beats
   a cramped desktop one. Kept separate from the 900px block below on
   purpose: that one governs hero/grid/footer content reflow used
   across every public page and must not shift just because the nav
   needed a different threshold.

   BUG FIX (2026-09-23): .menu-toggle and .site-nav are deliberately
   shared base class names across the public header, the student
   header (.sdv2-header, student.css), and the app header (.app-header,
   app.css) — see header.php's own comment: "kept so assets/js/
   script.js's existing mobile collapse behavior works unchanged."
   That means an UNSCOPED rule here doesn't just affect the public
   header — it also matches .sdv2-header's and .app-header's own nav,
   which have their own independently-tuned breakpoints (900px for
   student). Between 901-1100px this rule's position:absolute/
   background/etc (properties student.css's own higher-specificity
   base rule never redeclares) were winning on student pages even
   though student.css's display:flex correctly stayed active for the
   `display` property — CSS cascades per property, not per rule, so
   the result was a display:flex element that was ALSO position:
   absolute, floating a white nav pill on top of the activity-page
   actbar. Scoped to .site-header specifically so this can never leak
   into another header variant again. */
/* Below 1100px the inline nav simply goes away — the drawer already
   carries every link, so the old absolutely-positioned collapse panel
   (and the second hamburger that drove it) is gone. The theme toggle is
   pulled back out of .site-nav so it stays reachable in the bar. */
/* 1250px, measured not guessed: the full bar (42px button + 186px logo
   + 944px nav + gaps + gutters) needs ~1364px at its widest, and ~1240px
   once the logo and gutters reach their own clamp floors. Below this the
   inline links go away entirely and the drawer — which carries the same
   six links — is the only navigation. Without this the brand was the
   only shrinkable item and collapsed to ZERO width. */
@media (max-width: 1250px) {
  .site-header { border-radius: 0 0 24px 24px; }
  /* Sign In stays — it is an ACTION, not a navigation item, and it is
     the primary conversion on every marketing page. Only the links
     collapse into the drawer. */
  .site-header .site-nav a:not(.nav-signin) { display: none; }
  .site-header .site-nav { gap: 8px; }
}

@media (max-width: 900px) {
  .hero-inner, .page-hero .section, .resource-card, .grid-2, .grid-3, .footer-grid { grid-template-columns: 1fr; }
  .hero { padding-top: 28px; }
  .section { padding: 44px 20px; }
  .contact-grid { margin-top: 0; }
  .page-hero-art { min-height: 120px; }
  .page-hero-art img { max-height: 180px; }
  .footer-characters { justify-content:flex-start; }
}

@media (max-width: 560px) {
  body { font-size: 16px; }
  /* 150px, not the old 190px — with the base logo clamp shrunk to
     clamp(160px,16vw,220px) (2026-09-23), 190px here would make the
     logo BIGGER on phones than at just-above-mobile widths (where the
     clamp floors at 160px). 150px keeps it shrinking monotonically as
     the viewport narrows. */
  .site-header { height: 72px; gap: 12px; }
  /* Phones: [menu][logo][Sign In][theme] does not fit in 375px and was
     causing horizontal page overflow. Sign In drops out of the BAR only
     — the drawer carries it as a full-width primary button, so the
     action is still one tap away. */
  .site-header .nav-signin { display: none; }
  .brand img { width: 150px; }
  .hero-characters { grid-template-columns: 1fr; }
  .card { padding: 22px; }
}

/* Decorative art files added for the kid-friendly theme */
.page-hero .section::before {
  content: '';
  position: absolute;
  right: 35%;
  top: 34px;
  width: 82px;
  height: 62px;
  background: url('../images/paper-plane.svg') center/contain no-repeat;
  opacity: .95;
  transform: rotate(-7deg);
}
.page-hero .section::after {
  content: '';
  position: absolute;
  right: 24px;
  bottom: 42px;
  width: 150px;
  height: 110px;
  background: url('../images/book-stack.svg') center/contain no-repeat;
  opacity: .85;
}
.contact .page-hero .section::after { background-image: url('../images/masjid.svg'); }

/* Compact header for admin/dashboard screens — no decorative
   overlays or the marketing pages' large padding. */
.dashboard-hero {
  background: linear-gradient(180deg, #D9F7FF, #EDFCFF);
  border-bottom: 1px solid rgba(18,58,102,.08);
}
.dashboard-hero .section { padding: 24px 20px; }
.dashboard-hero .eyebrow { margin-bottom: 8px; }
.dashboard-hero h1 { margin-bottom: 4px; }
.dashboard-hero p { margin-bottom: 0; color: #183B63; }

/* Activity pages (matching/ordering/word-search/MCQ) show an
   admin-authored activity title here, which can run much longer than
   the site's short, fixed hero copy elsewhere — scale it down so a
   long title doesn't dominate the page, and size the instructions
   line up so it's actually legible next to it. */
.dashboard-hero.activity-hero h1 { font-size: clamp(1.3rem, 2.6vw, 1.9rem); }
.dashboard-hero.activity-hero p { font-size: 1.05rem; }

/* Activity type identity — a small, consistent "what kind of activity
   is this" marker shared across every activity page (MCQ, Matching,
   and whatever comes after them), separate from the .eyebrow above it
   (which already carries the lesson context, e.g. "Al-Fatihah, Ayah
   3") so the two pieces of information don't compete for the same
   slot. Deliberately soft/secondary — a semi-white pill on the hero's
   sky gradient, same recipe as .level-tag elsewhere on the site. */
.activity-type-badge {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(255,255,255,.7); color: var(--teal-dark);
  font-weight: 900; font-size: .85rem;
  border-radius: 999px; padding: 6px 14px;
  margin: 2px 0 10px;
}
/* Same light-bg/dark-text pairing bug as .pill-list (see
   docs/architecture/SITE-THEME-ARCHITECTURE.md §5) — background stays
   a fixed translucent white, so pin the text dark too instead of
   letting it follow --teal-dark light in dark mode. Also fixes
   .level-tag below, explicitly called out in the comment above as
   "same recipe." */
[data-theme="dark"] .activity-type-badge,
[data-theme="dark"] .level-tag { color: #087C8B; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .activity-type-badge,
  :root:not([data-theme="light"]) .level-tag { color: #087C8B; }
}

/* Activity completion — the "you're done" moment, shared visual
   pattern across activity types with genuinely different completion
   data (MCQ: a real score; Matching: no numeric score, just real
   completion). Same mint gradient as quran.php's .mark-complete-card
   so finishing an activity visually rhymes with finishing a lesson,
   not a one-off color. */
.activity-complete-card {
  background: linear-gradient(180deg, var(--mint), #DFF5E0);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 24px clamp(20px, 4vw, 34px); text-align: center; margin-bottom: 24px;
}
.activity-complete-icon { font-size: 2.4rem; display: block; margin-bottom: 6px; }
.activity-complete-title { font-weight: 900; color: var(--navy); font-size: 1.3rem; margin: 0 0 6px; }
.activity-complete-text { color: var(--muted); font-weight: 700; margin: 0 0 16px; }
.activity-complete-card .btn-row { justify-content: center; margin-top: 0; }
/* .activity-complete-card's mint gradient is fixed pastel (never redefined
   for dark), but its title/text colors are theme-reactive --navy/--muted —
   pin both to their light-mode values so this shared completion panel
   (MCQ, Matching, Guess the Word, etc.) keeps dark text in dark mode. */
[data-theme="dark"] .activity-complete-title { color: #123A66; }
[data-theme="dark"] .activity-complete-text { color: #52677A; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .activity-complete-title { color: #123A66; }
  :root:not([data-theme="light"]) .activity-complete-text { color: #52677A; }
}

/* Final Quest runner (Milestone 4F) — the approved floating-islands
   artwork IS the visual structure of the page now, not a faded
   background behind UI cards. Checkpoints are pinned to the real
   portals painted into the art (see FINAL_QUEST_CHECKPOINT_COORDS in
   final-quest.php and assets/images/final-quest/APPROVED-ASSETS.md);
   no artificial route is drawn on top of it. */

.fq-hero-row { display: flex; align-items: center; gap: 18px; }
.fq-hero-compass { width: 120px; height: 120px; flex-shrink: 0; filter: drop-shadow(0 6px 14px rgba(18,58,102,.22)); }
/* Milestone 4G §6/§5: "FINAL QUEST" is a strong kicker above the real
   heading, not a small orange pill competing with the artwork below. */
.fq-hero-kicker { display: block; font-weight: 900; letter-spacing: .08em; color: var(--teal-dark); font-size: 1rem; margin-bottom: 2px; }
.fq-hero-row h1 { margin-bottom: 2px; }
.fq-hero-level { margin: 0; color: var(--muted); font-weight: 700; font-size: .92rem; }
@media (min-width: 900px) {
  .fq-hero-compass { width: 140px; height: 140px; }
  .fq-hero-kicker { font-size: 1.1rem; }
}

.fq-progress-lede { font-weight: 900; color: var(--navy); font-size: 1.15rem; margin: 0 0 6px; }
.fq-progress-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.fq-progress-stars { font-size: 1.5rem; color: var(--orange); line-height: 1; }
.fq-progress-text { font-weight: 900; color: var(--navy); }

/* Milestone 4G §1: the map is the star of the page — let its section
   run wider than the site's normal content column so it dominates
   more of the viewport (roughly +20%) instead of leaving unused
   margin either side. */
.fq-map-section { max-width: calc(var(--max) * 1.22); }

/* Milestone 4G §7: "Back to Qur'an" must not compete with the
   current checkpoint's Start/Continue CTA for attention. */
.fq-btn-row { justify-content: center; margin-top: 20px; }
.fq-link-quiet {
  color: var(--muted); font-weight: 800; text-decoration: underline; text-underline-offset: 3px;
  padding: 8px 4px; background: none; box-shadow: none;
}
.fq-link-quiet:hover { color: var(--teal-dark); }

.final-quest-final-banner {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  text-align: center; font-weight: 900; color: var(--orange-dark); background: var(--cream);
  border-radius: 16px; padding: 12px 16px; margin-bottom: 14px; box-shadow: var(--soft-shadow);
}
.final-quest-final-banner-star { width: 26px; height: 26px; flex-shrink: 0; }

/* The map itself — full visibility, the actual centerpiece. Text
   readability comes from the frosted checkpoint labels, not from
   fading the artwork. */
/* .fq-map is the positioning root for checkpoints and its own
   percentage coordinates map exactly onto the image, so it stays
   overflow:visible — a label near an edge portal (e.g. the
   bottom-left one) is never clipped. The rounded-corner crop is on
   the image itself, not a clipping wrapper. */
.fq-map { position: relative; margin-bottom: 56px; }
.fq-map-art { display: block; width: 100%; height: auto; border-radius: var(--radius); box-shadow: var(--shadow); }

/* Desktop: checkpoints pinned to real portal coordinates (percentage
   of the map's native canvas), shown only when the map has room for
   accurate positioning. */
.fq-checkpoint-list { display: none; list-style: none; margin: 0; padding: 0; position: absolute; inset: 0; }
.fq-mobile-list { list-style: none; margin: 0; padding: 16px; display: flex; flex-direction: column; gap: 12px; }
@media (min-width: 760px) {
  .fq-checkpoint-list { display: block; }
  .fq-mobile-list { display: none; }
}
.fq-checkpoint { position: absolute; width: 0; height: 0; }
.fq-portal-glow, .fq-portal-badge, .fq-checkpoint-label { position: absolute; top: 0; left: 0; transform: translate(-50%, -50%); }
.fq-portal-glow {
  width: 64px; height: 64px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(255,255,255,.7), rgba(255,255,255,0) 70%);
}
.fq-checkpoint--complete .fq-portal-glow { width: 46px; height: 46px; background: radial-gradient(circle, rgba(189,229,190,.7), transparent 70%); }
.fq-checkpoint--locked .fq-portal-glow { display: none; }
/* Milestone 4G §2: a stronger, more saturated glow so the eye goes
   to the current checkpoint immediately. */
.fq-checkpoint--next .fq-portal-glow, .fq-checkpoint--climax .fq-portal-glow {
  width: 132px; height: 132px;
  background: radial-gradient(circle, rgba(255,241,168,1) 0%, rgba(255,177,43,.55) 50%, transparent 76%);
}
.fq-checkpoint--climax .fq-portal-glow { width: 164px; height: 164px; }

/* Milestone 4G §4: Final Discovery gets its own warm glow, stronger
   still once the ending is near/reachable — the destination should
   read as more important than an ordinary checkpoint. */
.fq-checkpoint--gateway .fq-portal-glow {
  width: 140px; height: 140px;
  background: radial-gradient(circle, rgba(255,244,200,.85) 0%, rgba(255,177,43,.4) 55%, transparent 78%);
}
.fq-checkpoint--gateway-near .fq-portal-glow, .fq-checkpoint--gateway-unlocked .fq-portal-glow {
  width: 172px; height: 172px;
  background: radial-gradient(circle, rgba(255,244,200,1) 0%, rgba(255,177,43,.6) 50%, transparent 78%);
}

.fq-portal-badge {
  width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  font-size: 1rem; font-weight: 900; color: var(--site-text-inverse); box-shadow: 0 2px 8px rgba(0,0,0,.28); border: 2.5px solid var(--site-bg-surface);
  background: rgba(18,58,102,.55);
}
.fq-checkpoint--complete .fq-portal-badge { background: var(--teal-dark); }
.fq-checkpoint--locked .fq-portal-badge { background: rgba(37,54,74,.62); font-size: .85rem; }
.fq-checkpoint--next .fq-portal-badge, .fq-checkpoint--climax .fq-portal-badge { display: none; }

/* Milestone 4G §3: locked labels read easily against rich artwork —
   a touch more size/padding and a stronger frosted background,
   while staying compact (not a card). */
.fq-checkpoint-label {
  top: 28px; display: flex; flex-direction: column; gap: 3px; text-align: center;
  background: rgba(255,255,255,.97); border: 1px solid rgba(255,255,255,.9);
  border-radius: 13px; padding: 8px 13px; box-shadow: var(--shadow);
  min-width: 128px; max-width: 188px; font-size: .82rem;
}
.fq-checkpoint--anchor-start .fq-checkpoint-label { left: 32px; transform: translate(0, 0); text-align: left; }
.fq-checkpoint--anchor-end .fq-checkpoint-label { left: -32px; transform: translate(-100%, 0); text-align: right; }
.fq-checkpoint-tag { font-weight: 900; color: var(--navy); text-transform: uppercase; letter-spacing: .02em; }
.fq-checkpoint-tag--current { color: var(--orange-dark); display: inline-flex; align-items: center; gap: 4px; font-size: 1rem; }
.fq-current-star { width: 18px; height: 18px; flex-shrink: 0; }
.fq-checkpoint-name { font-weight: 800; color: var(--text); }
.fq-checkpoint-sub { color: var(--muted); font-weight: 700; font-size: .76rem; }
/* .fq-checkpoint-label (and the mobile-fallback .fq-mobile-row, which
   reuses these same tag/name/sub classes — see final-quest.php) keep
   a fixed near-opaque white/cream frosted background in dark mode
   (for legibility against the map/portal artwork), so pin the label
   text dark instead of letting --navy/--text/--muted go light — same
   light-bg/dark-text chip pattern as .pill-list. Restate
   --orange-dark for .fq-checkpoint-tag--current right after: it isn't
   redefined for dark mode and was already correct, but shares equal
   selector specificity with the pin below, so it needs restating to
   win by source order. */
[data-theme="dark"] .fq-checkpoint-tag,
[data-theme="dark"] .fq-checkpoint-name { color: #123A66; }
[data-theme="dark"] .fq-checkpoint-sub { color: #52677A; }
[data-theme="dark"] .fq-checkpoint-tag--current { color: var(--orange-dark); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .fq-checkpoint-tag,
  :root:not([data-theme="light"]) .fq-checkpoint-name { color: #123A66; }
  :root:not([data-theme="light"]) .fq-checkpoint-sub { color: #52677A; }
  :root:not([data-theme="light"]) .fq-checkpoint-tag--current { color: var(--orange-dark); }
}
.fq-checkpoint-cta { display: inline-block; margin-top: 6px; padding: 8px 18px; font-size: .88rem; }
/* Milestone 4G §2: the current checkpoint's label sits closer to its
   portal and reads noticeably larger/bolder than every other label —
   the eye should go there first. */
.fq-checkpoint--next .fq-checkpoint-label, .fq-checkpoint--climax .fq-checkpoint-label {
  top: 20px; background: rgba(255,248,217,.99); border-color: var(--orange);
  min-width: 168px; max-width: 230px; font-size: .92rem; padding: 10px 16px; box-shadow: 0 0 0 3px rgba(255,177,43,.35), var(--shadow);
}
.fq-checkpoint--next .fq-checkpoint-name, .fq-checkpoint--climax .fq-checkpoint-name { font-size: 1.02rem; }
/* Wider rather than taller — at this portal spacing, a taller climax
   label collides with a neighboring portal's label; a wider one with
   less text-wrapping stays clear both vertically and (via the anchor
   direction) horizontally. */
.fq-checkpoint--climax .fq-checkpoint-label { min-width: 190px; width: max-content; max-width: 300px; font-size: .98rem; }
.fq-checkpoint--climax .fq-checkpoint-name { white-space: nowrap; }
/* Milestone 4G §4: Final Discovery's own label — bigger and bolder
   than an ordinary checkpoint, intensifying as it becomes reachable. */
.fq-checkpoint--gateway .fq-checkpoint-label {
  background: rgba(18,58,102,.88); border-color: rgba(255,255,255,.25); min-width: 160px; font-size: .86rem; padding: 9px 15px;
}
.fq-checkpoint--gateway .fq-checkpoint-tag, .fq-checkpoint--gateway .fq-checkpoint-sub { color: var(--site-text-inverse); }
.fq-checkpoint--gateway-near .fq-checkpoint-label, .fq-checkpoint--gateway-unlocked .fq-checkpoint-label {
  background: linear-gradient(180deg, #FFC94D, var(--orange-dark)); min-width: 180px; font-size: .94rem;
  box-shadow: 0 0 0 3px rgba(255,177,43,.4), var(--shadow);
}
.fq-checkpoint--gateway-near .fq-checkpoint-tag, .fq-checkpoint--gateway-unlocked .fq-checkpoint-tag,
.fq-checkpoint--gateway-near .fq-checkpoint-sub, .fq-checkpoint--gateway-unlocked .fq-checkpoint-sub { color: var(--site-text-inverse); }

/* Mobile: a clean vertical journey. Cropped "peeks" of each real
   portal (a CSS crop of the same single map asset, never a new
   file) stand in for the coordinate-pinned layout. */
.fq-mobile-row { display: flex; align-items: center; gap: 12px; background: rgba(255,255,255,.9); border-radius: 16px; padding: 10px 14px; box-shadow: var(--soft-shadow); }
.fq-mobile-row--next, .fq-mobile-row--climax { background: rgba(255,248,217,.96); box-shadow: 0 0 0 3px var(--orange), var(--shadow); }
.fq-mobile-row--locked { opacity: .82; }
.fq-mobile-badge {
  width: 52px; height: 52px; border-radius: 50%; flex-shrink: 0; background-repeat: no-repeat;
  border: 3px solid var(--site-bg-surface); box-shadow: 0 2px 8px rgba(0,0,0,.22); display: flex; align-items: center; justify-content: center;
}
.fq-mobile-badge-mark {
  width: 22px; height: 22px; border-radius: 50%; background: rgba(18,58,102,.72); color: var(--site-text-inverse);
  font-size: .75rem; display: flex; align-items: center; justify-content: center; font-weight: 900;
}
.fq-mobile-body { display: flex; flex-direction: column; gap: 2px; }

@media (prefers-reduced-motion: reduce) {
  .fq-checkpoint, .fq-mobile-row { animation: none; transition: none; }
  .hero-carousel-slide { transition: none; }
}

/* Award Results — achievement ceremony (Milestone 4D; backgrounds
   finalized Milestone 4K). A SEPARATE visual identity from the Final
   Quest Trail runner above: no compass/map iconography here at all.
   All four tiers now use the project owner's approved background
   artwork (assets/images/awards/backgrounds/, see
   BACKGROUNDS-ASSETS.md) as a full-bleed ::before layer, with a
   tier-tuned dark ::after overlay for text contrast — no CSS-only
   gradients/sunbursts and no photography (the earlier Pexels trophy/
   confetti photos and the brief CSS-gradient/conic-sunburst/sparkle
   treatment are both fully superseded; nothing here references
   either anymore). Escalation Bronze (simplest/calmest) < Silver
   (cool/clean/refined) < Golden (warm/rich/celebratory) < Shining
   (most magical/prestigious) now comes from the background art
   itself plus the medal's own glow strength. */
.quest-ceremony {
  position: relative; overflow: hidden; border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 44px 24px 34px; text-align: center; color: var(--site-text-inverse);
}
.quest-ceremony::before { content: ''; position: absolute; inset: 0; z-index: 0; background-size: cover; background-position: center; }
.quest-ceremony::after { content: ''; position: absolute; inset: 0; z-index: 1; }
.quest-ceremony > * { position: relative; z-index: 2; }

.quest-ceremony--bronze::before { background-image: url('../images/awards/backgrounds/bronze.webp'); }
.quest-ceremony--bronze::after { background: linear-gradient(180deg, rgba(60,30,10,.18), rgba(40,18,4,.55)); }

.quest-ceremony--silver::before { background-image: url('../images/awards/backgrounds/silver.webp'); }
.quest-ceremony--silver::after { background: linear-gradient(180deg, rgba(20,35,50,.3), rgba(15,28,40,.62)); }

.quest-ceremony--golden::before { background-image: url('../images/awards/backgrounds/golden.webp'); }
.quest-ceremony--golden::after { background: linear-gradient(180deg, rgba(90,55,0,.22), rgba(70,40,0,.55)); }

.quest-ceremony--shining::before { background-image: url('../images/awards/backgrounds/shining.webp'); }
.quest-ceremony--shining::after { background: linear-gradient(180deg, rgba(50,30,70,.12), rgba(35,20,60,.32)); }

.quest-ceremony--none {
  background: linear-gradient(160deg, var(--mint), #7FBF8C); color: var(--navy); box-shadow: var(--soft-shadow);
}

.quest-ceremony-eyebrow {
  display: block; font-weight: 900; font-size: 1.05rem; letter-spacing: .02em; margin-bottom: 10px;
  text-shadow: 0 2px 8px rgba(0,0,0,.2);
}
.quest-ceremony--none .quest-ceremony-eyebrow { text-shadow: none; }
.quest-ceremony-lede { font-weight: 800; margin: 0 0 14px; text-shadow: none; }
.quest-ceremony-score {
  display: block; font-family: 'Baloo 2', 'Nunito', system-ui, sans-serif; font-weight: 900;
  font-size: clamp(2.1rem, 6vw, 3.1rem); line-height: 1; margin-bottom: 4px; text-shadow: 0 3px 10px rgba(0,0,0,.22);
}
.quest-ceremony--none .quest-ceremony-score { text-shadow: none; }
.quest-ceremony-score-label {
  display: block; font-weight: 800; font-size: .82rem; opacity: .92; margin-bottom: 16px;
  text-transform: uppercase; letter-spacing: .06em;
}
/* Milestone 4H: the four project-owner-provided star medals are the
   real Award artwork — large, central, the hero of the reveal. A
   soft radial glow behind the medal (not more decorative images)
   escalates by tier so the celebration intensity comes from light,
   not from stacking extra art on top of an already-detailed medal. */
.quest-ceremony-medal-wrap { position: relative; display: inline-block; margin: 0 auto 12px; }
.quest-ceremony-medal-glow {
  position: absolute; inset: -18%; z-index: 0; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(255,255,255,.22), transparent 72%);
}
.quest-ceremony-medal {
  position: relative; z-index: 1; display: block; width: 44vw; max-width: 190px; height: auto;
  aspect-ratio: 700 / 700; /* bronze's native ratio; overridden below for the other three */
  filter: drop-shadow(0 14px 26px rgba(0,0,0,.3));
}
.quest-ceremony--silver .quest-ceremony-medal,
.quest-ceremony--golden .quest-ceremony-medal,
.quest-ceremony--shining .quest-ceremony-medal { aspect-ratio: 700 / 640; }
.quest-ceremony--silver .quest-ceremony-medal-glow { background: radial-gradient(circle, rgba(226,244,255,.4), transparent 72%); }
.quest-ceremony--golden .quest-ceremony-medal-wrap { margin-bottom: 14px; }
.quest-ceremony--golden .quest-ceremony-medal { max-width: 215px; }
.quest-ceremony--golden .quest-ceremony-medal-glow { inset: -24%; background: radial-gradient(circle, rgba(255,244,200,.65), rgba(255,177,43,.15) 60%, transparent 78%); }
.quest-ceremony--shining .quest-ceremony-medal-wrap { margin-bottom: 14px; }
.quest-ceremony--shining .quest-ceremony-medal { max-width: 250px; }
.quest-ceremony--shining .quest-ceremony-medal-glow {
  inset: -30%;
  background: radial-gradient(circle, rgba(255,255,255,.85) 0%, rgba(210,225,255,.4) 55%, transparent 78%);
  animation: questMedalShimmer 1.8s ease-out 1;
}
@keyframes questMedalShimmer {
  0% { opacity: .35; transform: scale(.82); }
  45% { opacity: 1; transform: scale(1.1); }
  100% { opacity: .85; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .quest-ceremony--shining .quest-ceremony-medal-glow { animation: none; }
}

.quest-ceremony-tier {
  font-family: 'Baloo 2', 'Nunito', system-ui, sans-serif; font-weight: 900;
  font-size: clamp(1.6rem, 4.5vw, 2.35rem); margin: 0 0 4px; color: var(--site-text-inverse); text-shadow: 0 3px 10px rgba(0,0,0,.28);
}
.quest-ceremony-tier-sub { font-weight: 800; opacity: .94; margin: 0; font-size: .95rem; }

.quest-ceremony-note { text-align: center; font-weight: 800; color: var(--muted); margin: 16px 0 0; }

/* Next goal (below-50) — never framed as failure: score + a warm,
   concrete next step. */
.next-goal-card {
  display: inline-block; background: rgba(255,255,255,.85); border-radius: 18px; padding: 14px 24px;
  margin: 4px auto 0; box-shadow: var(--soft-shadow);
}
.next-goal-label { font-size: .76rem; font-weight: 900; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); margin: 0 0 4px; }
.next-goal-tier { font-weight: 900; color: var(--navy); font-size: 1.15rem; margin: 0 0 2px; }
.next-goal-points { color: var(--teal-dark); font-weight: 800; margin: 0; }
/* .next-goal-card keeps a fixed near-opaque white background in dark
   mode, so pin its text dark instead of letting --muted/--navy/
   --teal-dark go light — same light-bg/dark-text chip pattern as
   .pill-list. */
[data-theme="dark"] .next-goal-label { color: #52677A; }
[data-theme="dark"] .next-goal-tier { color: #123A66; }
[data-theme="dark"] .next-goal-points { color: #087C8B; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .next-goal-label { color: #52677A; }
  :root:not([data-theme="light"]) .next-goal-tier { color: #123A66; }
  :root:not([data-theme="light"]) .next-goal-points { color: #087C8B; }
}

/* Collectible discovery — its own large "scene" after the Award
   ceremony, never a small pill. */
.discovery-scene { text-align: center; }
.discovery-grid { display: flex; gap: 22px; justify-content: center; flex-wrap: wrap; margin-top: 10px; }
.discovery-item { flex: 1 1 240px; max-width: 280px; background: var(--site-bg-surface); border-radius: 20px; padding: 20px; box-shadow: var(--soft-shadow); }
/* Milestone 4J: the real gem art is the hero of the card — large,
   with a soft glow behind it, matching the medal-wrap treatment. */
/* Milestone 4L: a fixed square frame + object-fit:contain, rather
   than width-only sizing — a naturally wide/short gem (e.g. a
   brilliant-cut diamond viewed side-on) would otherwise render
   shorter than a tall gem at the same width. This keeps every gem's
   visual weight comparable regardless of its own artwork's aspect
   ratio, without ever branching on which gem it is. */
.discovery-art-wrap { position: relative; display: block; margin: 0 auto 10px; width: 100%; }
.discovery-art-glow {
  position: absolute; inset: -20%; z-index: 0; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(255,244,200,.5), transparent 72%);
}
.discovery-art {
  position: relative; z-index: 1; display: block; width: 100%; height: 100%;
  object-fit: contain; filter: drop-shadow(0 8px 16px rgba(18,58,102,.2));
}
/* Card/frame size scales with how many collectibles share the grid
   (never with which gem it is) — a single discovery gets the
   biggest treatment, a multi-discovery grid still fits several
   cards per row. */
.discovery-grid--single .discovery-item { max-width: 340px; }
.discovery-grid--single .discovery-art-wrap { max-width: 248px; aspect-ratio: 1 / 1; }
.discovery-grid--multi .discovery-item { max-width: 300px; }
.discovery-grid--multi .discovery-art-wrap { max-width: 232px; aspect-ratio: 1 / 1; }
.discovery-name { font-weight: 900; color: var(--navy); font-size: 1.1rem; margin: 0 0 2px; text-transform: uppercase; letter-spacing: .02em; }
.discovery-sub { color: var(--muted); font-weight: 700; margin: 0 0 8px; }
.discovery-check { color: var(--teal-dark); font-weight: 900; margin: 0; }

/* Phase 2B: My Gem Collection (my-gems.php) — reuses .card/.stats-strip/
   .discovery-* throughout (see assets/css/student.css's own philosophy:
   one visual language, not a competing system). New rules below are
   only for the shapes that page introduces: the "+1" toast, the single
   prominent goal hero, and the Quartz->Diamond grid's locked/discovered
   states. */
.gem-plus-one-toast { text-align: center; font-weight: 900; font-size: 1.2rem; color: var(--navy); padding: 18px; }

.gem-goal-hero { text-align: center; }
.gem-goal-message { font-weight: 800; color: var(--navy); margin: 0 0 12px; }
.gem-goal-complete { font-size: 1.1rem; }
.gem-goal-target { max-width: 260px; margin: 0 auto; }
.gem-goal-art-wrap { max-width: 180px; aspect-ratio: 1 / 1; margin: 0 auto 8px; }
.gem-goal-requirement { color: var(--muted); font-weight: 700; margin: 0 0 14px; }
.gem-combine-form .btn:disabled { opacity: .5; cursor: not-allowed; }

.gem-grid { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
.gem-card { text-align: center; padding: 18px; }
.gem-card-art-wrap { max-width: 100px; aspect-ratio: 1 / 1; margin: 0 auto 8px; }
.gem-card-locked-icon { display: block; font-size: 1.8rem; margin: 12px auto 20px; opacity: .55; }
.gem-card-name { font-weight: 900; color: var(--navy); margin: 0 0 2px; text-transform: uppercase; letter-spacing: .02em; font-size: .95rem; }
.gem-card-name--locked { color: var(--muted); letter-spacing: .1em; }
.gem-card-status { color: var(--muted); font-weight: 700; font-size: .82rem; margin: 0; }
.gem-card--discovered .gem-card-status { color: var(--teal-dark); }
.gem-card--locked { opacity: .7; }

/* Existing-better-Award: "This Quest" vs "Your Best Award" — always
   reassuring, never reads as a downgrade. */
.best-award-compare { display: flex; gap: 22px; justify-content: center; flex-wrap: wrap; align-items: flex-start; margin: 6px 0 14px; }
.best-award-col { flex: 1 1 190px; max-width: 210px; }
.best-award-col h3 { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin: 0 0 8px; }
.best-award-col img { display: block; width: 100%; max-width: 120px; height: auto; margin: 0 auto 8px; }
.best-award-value { font-weight: 900; color: var(--navy); font-size: 1.2rem; margin: 0; }
.best-award-safe { font-weight: 900; color: var(--teal-dark); margin: 0 0 4px; }

/* Mystery teaser (not-started page) and mystery Award destination
   (runner trail end) — build anticipation without ever revealing the
   tier/collectible identity before completion. */
.mystery-card { text-align: center; background: linear-gradient(180deg, var(--sky), var(--sky-2)); border-radius: var(--radius); padding: 20px; }
.mystery-lock-row { font-size: 1.7rem; letter-spacing: 8px; margin-bottom: 6px; }
.mystery-card p { margin: 0; font-weight: 800; color: var(--navy); }

/* Mascots flanking a prompt card — used on the student's learning
   menus (dashboard, Quran/Islamic Studies/Arabic sub-menus). */
.mascot-bar { display: flex; align-items: center; justify-content: center; gap: 16px; margin-bottom: 8px; flex-wrap: wrap; }
.mascot-img { width: clamp(70px, 7vw, 110px); height: auto; filter: drop-shadow(0 10px 16px rgba(18,58,102,.16)); flex-shrink: 0; }
.mascot-prompt {
  flex: 1; max-width: 640px;
  background: linear-gradient(180deg, var(--cream), var(--butter));
  border: 2px solid rgba(255,255,255,.9);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px 26px;
  text-align: center;
}
.mascot-prompt h1 { margin-bottom: 2px; }
.mascot-prompt p { margin-bottom: 0; }
@media (max-width: 700px) { .mascot-img { display: none; } }

.coming-soon-card { text-align: center; opacity: .85; }
.coming-soon-card .lock-icon { font-size: 1.6rem; display: block; margin-bottom: 6px; }
.coming-soon-card .coming-soon-desc { font-size: .82rem; font-weight: 700; color: var(--muted); margin: 4px 0 0; }
.coming-soon-card .coming-soon-tag,
.stage-tile .coming-soon-tag { display: inline-block; font-size: .68rem; font-weight: 900; text-transform: uppercase; letter-spacing: .03em; color: var(--muted); background: rgba(18,58,102,.06); padding: 3px 10px; border-radius: 999px; margin: 8px 0 0; }
.coming-soon-tile-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-top: 12px; }

/* Stacked full-width stage bands — used on student-quran.php, one
   band per learning stage (Read / Memorize / Understand) instead of
   a flat card grid, so a locked stage's sub-topics read as a group. */
.stage-card { border-radius: var(--radius); padding: clamp(20px, 4vw, 30px); margin-bottom: 20px; box-shadow: var(--shadow); }
.stage-card.stage-read { background: linear-gradient(180deg, #E6FAFF, #CFF3FB); }
.stage-card.stage-memorize { background: linear-gradient(180deg, #FFF6E4, #FFE3C7); }
.stage-card.stage-understand { background: linear-gradient(180deg, #F0F9EA, #D9EFCF); display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.stage-head { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.stage-head .stage-ic { font-size: 1.4rem; }
.stage-head h2 { font-size: 1.15rem; margin: 0; color: var(--navy); }
.stage-sub { font-size: .88rem; color: var(--muted); font-weight: 700; margin: 0 0 14px; }
.stage-tile-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; }
.stage-tile { background: var(--site-bg-surface); border-radius: 14px; padding: 14px 16px; display: flex; flex-direction: column; gap: 6px; min-height: 78px; justify-content: center; opacity: .85; }
.stage-tile .tile-name { font-weight: 800; font-size: .9rem; color: var(--navy); }
.stage-tile .tile-desc { font-size: .76rem; font-weight: 700; color: var(--muted); }
.stage-tile .tile-status { font-size: .76rem; font-weight: 800; color: var(--muted); margin-top: 2px; }

.understand-left { display: flex; align-items: center; gap: 14px; }
.understand-ic { width: 52px; height: 52px; border-radius: 16px; background: var(--site-bg-surface); display: flex; align-items: center; justify-content: center; font-size: 1.6rem; flex-shrink: 0; }
.understand-text h2 { font-size: 1.15rem; margin: 0; color: var(--navy); }
.understand-text p { font-size: .85rem; color: var(--muted); font-weight: 700; margin: 2px 0 0; }

@media (max-width: 560px) {
  .stage-card.stage-understand { flex-direction: column; align-items: stretch; text-align: center; }
  .understand-left { flex-direction: column; }
}

/* Child/student list rows — parent's My Children, teacher's Class
   Roster — a decorative avatar plus a real per-subject Level strip,
   read from student_subject_levels via get_student_subject_levels(). */
.student-card { background: var(--site-bg-surface); border-radius: 16px; padding: 14px 16px; margin-bottom: 10px; text-decoration: none; color: inherit; display: block; box-shadow: var(--soft-shadow); }
.student-card:last-child { margin-bottom: 0; }
.student-top { display: flex; align-items: center; gap: 11px; }
.student-avatar { width: 38px; height: 38px; border-radius: 50%; background: var(--peach); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.student-avatar svg { width: 22px; height: 22px; }
.student-info { flex: 1; min-width: 0; }
.student-name { font-weight: 900; font-size: .92rem; color: var(--navy); }
.student-meta { font-size: .74rem; color: var(--muted); font-weight: 700; }
.student-arrow { font-size: 1.1rem; color: var(--muted); flex-shrink: 0; }
.level-strip { display: flex; gap: 5px; margin-top: 8px; flex-wrap: wrap; }
.level-chip { display: inline-flex; align-items: center; gap: 3px; font-size: .64rem; font-weight: 800; color: var(--teal-dark); background: var(--sage); padding: 2px 7px; border-radius: 999px; }
.level-chip .lv-subject { color: var(--muted); }

.resume-tile { display: flex; align-items: center; justify-content: space-between; gap: 16px; background: var(--site-bg-surface); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px clamp(20px, 4vw, 30px); margin-bottom: 20px; flex-wrap: wrap; }
.resume-tile-left { display: flex; align-items: center; gap: 14px; }
.resume-tile-icon { width: 48px; height: 48px; border-radius: 14px; background: var(--sage); display: flex; align-items: center; justify-content: center; font-size: 1.4rem; flex-shrink: 0; }
.resume-tile-label { font-size: .78rem; font-weight: 900; color: var(--muted); text-transform: uppercase; letter-spacing: .03em; }
.resume-tile-title { font-weight: 900; color: var(--navy); font-size: 1.05rem; margin-top: 2px; }

.stats-strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 14px; background: linear-gradient(180deg, var(--cream), var(--butter)); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px clamp(20px, 4vw, 30px); margin-bottom: 20px; }
.stats-strip .stat { text-align: center; }
.stats-strip .stat-num { font-size: 1.6rem; font-weight: 900; color: var(--navy); }
.stats-strip .stat-label { font-size: .8rem; font-weight: 800; color: var(--muted); margin-top: 2px; }

.admin .dashboard-hero { position: relative; overflow: hidden; }
.admin .dashboard-hero::before {
  content: '';
  position: absolute;
  right: 35%;
  top: 46px;
  width: 60px;
  height: 45px;
  background: url('../images/paper-plane.svg') center/contain no-repeat;
  opacity: .95;
  transform: rotate(-7deg);
}
.admin .dashboard-hero::after {
  content: '';
  position: absolute;
  right: 24px;
  bottom: 18px;
  width: 100px;
  height: 74px;
  background: url('../images/book-stack.svg') center/contain no-repeat;
  opacity: .85;
}

/* ------------------------------------------------------------
   Quran Explorer — surah/ayah picker + kid-friendly ayah viewer
   ------------------------------------------------------------ */
.quran-explorer { max-width: var(--max); margin: 0 auto; padding: 8px 20px 40px; display: grid; gap: 6px; }

.quran-back-link { margin: 0 0 6px; }
.quran-back-link a { color: var(--muted); font-weight: 800; font-size: .9rem; }
.quran-back-link a:hover { color: var(--navy); }

.level-tag { display: inline-block; font-size: .68rem; font-weight: 900; color: var(--teal-dark); background: rgba(255,255,255,.65); padding: 2px 9px; border-radius: 999px; margin-left: 6px; vertical-align: middle; }

.quran-picker-bar { display: flex; align-items: center; justify-content: center; gap: 6px; }
.quran-mascot { width: clamp(76px, 8vw, 128px); height: auto; filter: drop-shadow(0 10px 16px rgba(18,58,102,.16)); flex-shrink: 0; }

.quran-picker-card {
  flex: 1; max-width: 720px;
  background: linear-gradient(180deg, var(--cream), var(--butter));
  border: 2px solid rgba(255,255,255,.9);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px clamp(20px, 4vw, 34px);
}
/* Page-level surface, not a small chip (same reasoning as .site-footer
   above) — --navy-based title/label text already reads correctly once
   this goes dark. */
[data-theme="dark"] .quran-picker-card { background: linear-gradient(180deg, #332B14, #241D0A); border-color: rgba(233, 241, 248, .15); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .quran-picker-card { background: linear-gradient(180deg, #332B14, #241D0A); border-color: rgba(233, 241, 248, .15); }
}
.quran-picker-title { display: flex; align-items: center; gap: 10px; justify-content: center; font-weight: 900; color: var(--navy); font-size: 1.25rem; margin-bottom: 12px; }
.quran-picker-row { display: flex; align-items: flex-end; gap: 16px; }
.quran-picker-field { flex: 1; display: grid; gap: 6px; }
.quran-picker-field label { font-weight: 900; color: var(--navy); font-size: 1.05rem; }
.quran-picker-field select {
  margin: 0;
  font-family: 'Baloo 2', 'Nunito', system-ui, sans-serif;
  font-size: 1.15rem;
  font-weight: 700;
}
.quran-picker-badge {
  flex-shrink: 0; width: 46px; height: 46px; border-radius: 50%;
  background: linear-gradient(180deg, #FFC94D, var(--orange));
  color: var(--site-text-inverse); font-weight: 900; font-size: 1.15rem;
  display: grid; place-items: center; box-shadow: 0 8px 16px rgba(255,177,43,.3);
}

.ayah-display-card {
  position: relative;
  background: var(--site-bg-surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px clamp(20px, 6vw, 60px) 6px;
  text-align: center;
}
.ayah-display-header { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 14px; margin-bottom: 16px; }
.ayah-display-pill {
  display: inline-flex; align-items: center; gap: 6px;
  background: linear-gradient(180deg, #E6FAFF, var(--sky-2));
  color: var(--navy); font-weight: 900; font-size: 1.05rem; border-radius: 999px;
  padding: 8px 20px;
  /* Now a real <h2> (was a div) for heading-hierarchy accessibility —
     explicit margin:0 overrides the global h1/h2/h3 rule's own
     margin so promoting it to a heading doesn't add space that
     wasn't here before and throw off .ayah-display-header's
     flex-centered alignment with the font-select next to it. */
  margin: 0;
}
.ayah-font-select {
  padding: 8px 16px;
  border-radius: 999px;
  border: 2px solid rgba(18,58,102,.15);
  background: var(--site-bg-surface);
  font-family: 'Baloo 2', 'Nunito', system-ui, sans-serif;
  font-weight: 700;
  color: var(--navy);
  font-size: 1.05rem;
  cursor: pointer;
}
.ayah-audio-btn {
  position: absolute; top: 20px; right: clamp(20px, 6vw, 60px);
  width: 46px; height: 46px; border-radius: 50%; border: 0; cursor: pointer;
  background: linear-gradient(180deg, #FFC94D, var(--orange));
  color: var(--site-text-inverse); font-size: 1.2rem; box-shadow: 0 8px 16px rgba(255,177,43,.3);
}
/* Full ayah at reading size; the Word-to-Word words below it are
   larger. Both read --ayah-font, which the font picker sets on the
   card. */
.ayah-full-arabic,
.ayah-big-word {
  font-family: var(--ayah-font, 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif);
  color: var(--navy);
}
.ayah-full-arabic {
  font-size: clamp(24px, 2.8vw, 34px);
  line-height: 2.1;
  margin: 0;
  direction: rtl;
}
.ayah-display-divider { margin-top: 8px; color: var(--orange); letter-spacing: 10px; font-size: 1rem; }

/* Word-to-Word: each word sits in its own cell with its
   transliteration, meaning and root revealed directly beneath it.
   Slot backgrounds are transparent until revealed and then use the
   theme-reactive --site-bg-surface/--navy pair, so no dark-mode text
   pin is needed (the old separate boxes needed several). */
.wtw-title { display: flex; align-items: center; justify-content: center; gap: 10px; font-weight: 900; color: var(--navy); font-size: 1.15rem; margin: 14px 0 4px; }
.wtw-hint { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px; margin: 0 0 14px; font-size: .9rem; font-weight: 700; color: var(--muted); }
.wtw-key { border: 2px solid; border-radius: 999px; padding: 1px 10px; font-size: .8rem; font-weight: 800; color: var(--navy); }
.wtw-key-translit { border-color: var(--pink); }
.wtw-key-meaning { border-color: var(--teal); }
.wtw-key-root { border-color: #9C6ADE; }
.wtw-words {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  direction: rtl;
  padding-bottom: 16px;
}
.wtw-word {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  min-width: 112px;
  padding: 6px 8px 8px;
  border-radius: 18px;
  border: 1px solid color-mix(in srgb, var(--navy) 12%, transparent);
  background: color-mix(in srgb, var(--site-bg-surface) 50%, transparent);
}
.ayah-big-word {
  display: block;
  font-size: clamp(30px, 4vw, 46px);
  line-height: 1.8;
  padding: 0 12px;
  cursor: pointer;
  border-radius: 14px;
  transition: background .15s ease, transform .1s ease;
}
.ayah-big-word:hover { background: var(--sky-2); }
.ayah-big-word.active { background: var(--mint); transform: scale(1.04); }
.wtw-details { display: flex; flex-direction: column; gap: 6px; width: 100%; }
/* width:0 + min-width:100% keeps revealed text from widening the
   cell — the Arabic word alone sets each cell's width, so revealing
   never pushes the other words around; long meanings wrap instead. */
.wtw-slot {
  width: 0;
  min-width: 100%;
  min-height: 32px;
  box-sizing: border-box;
  display: grid;
  place-items: center;
  padding: 4px 6px;
  border: 2px dashed color-mix(in srgb, var(--navy) 22%, transparent);
  border-radius: 12px;
  text-align: center;
  font-weight: 800;
  color: var(--navy);
  line-height: 1.3;
  overflow-wrap: break-word;
  transition: background .2s ease, border-color .2s ease;
}
.wtw-translit { font-size: .9rem; }
.wtw-meaning { min-height: 52px; font-size: .95rem; }
.wtw-meaning-emoji { display: block; font-size: 1.4rem; line-height: 1.2; }
.wtw-root { font-size: 1.1rem; }
.wtw-slot.revealed { border-style: solid; background: var(--site-bg-surface); box-shadow: var(--soft-shadow); }
.wtw-translit.revealed { border-color: var(--pink); }
.wtw-meaning.revealed { border-color: var(--teal); }
.wtw-root.revealed { border-color: #9C6ADE; }
/* Phones: three equal cells per row (a long Arabic word still gets
   a wider cell), with slimmer slots so English meanings fit. */
@media (max-width: 600px) {
  .wtw-words { gap: 8px; }
  .wtw-word { min-width: calc((100% - 16px) / 3); box-sizing: border-box; padding: 4px 4px 6px; }
  .ayah-big-word { font-size: 28px; padding: 0 6px; }
  .wtw-slot { padding: 4px 2px; hyphens: auto; }
  .wtw-translit { font-size: .8rem; }
  .wtw-meaning { font-size: .85rem; }
}

.translation-title, .activities-title { display: flex; align-items: center; gap: 10px; font-weight: 900; color: var(--navy); font-size: 1.15rem; margin-bottom: 12px; }

.translation-card { background: linear-gradient(180deg, #E6FAFF, var(--sky-2)); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px clamp(20px, 4vw, 34px); text-align: center; }
.translation-title { justify-content: center; }
.translation-star { margin-left: 4px; }
.translation-text { font-family: 'Baloo 2', system-ui, sans-serif; font-size: clamp(1.2rem, 2.4vw, 1.7rem); font-weight: 700; color: var(--teal-dark); margin: 0; }

.simple-translation-card { background: linear-gradient(180deg, var(--pink), #FFC2D6); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px clamp(20px, 4vw, 34px); text-align: center; }
.simple-translation-title { display: flex; align-items: center; gap: 10px; justify-content: center; font-weight: 900; color: var(--site-text-inverse); font-size: 1.15rem; margin-bottom: 10px; }
.simple-translation-text { font-family: 'Baloo 2', system-ui, sans-serif; font-size: clamp(1.3rem, 2.6vw, 1.9rem); font-weight: 700; color: var(--site-text-inverse); margin: 0; }

.explanation-card { background: linear-gradient(180deg, var(--peach), #FFE3C7); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px clamp(20px, 4vw, 34px); }
.explanation-title { display: flex; align-items: center; gap: 10px; font-weight: 900; color: var(--navy); font-size: 1.15rem; margin-bottom: 10px; }
.explanation-text { margin: 0; font-size: 1.05rem; }

.story-card { background: linear-gradient(180deg, var(--butter), #FFE9A8); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px clamp(20px, 4vw, 34px); }
.story-title { display: flex; align-items: center; gap: 10px; font-weight: 900; color: var(--navy); font-size: 1.15rem; margin-bottom: 10px; }
.story-text { margin: 0; font-size: 1.05rem; color: var(--navy); }

.connection-card { background: linear-gradient(180deg, var(--mint), #A8DCAA); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px clamp(20px, 4vw, 34px); }
.connection-title { display: flex; align-items: center; gap: 10px; font-weight: 900; color: var(--navy); font-size: 1.15rem; margin-bottom: 12px; }
.connection-item { display: flex; align-items: flex-start; gap: 12px; background: rgba(255,255,255,.6); border-radius: 18px; padding: 12px 16px; margin-bottom: 10px; color: var(--navy); }
.connection-item:last-child { margin-bottom: 0; }
/* .story-text and .connection-item both held direct text content with
   NO color declared at all — silently inheriting. .story-text sits
   directly on .story-card (which the SDV2 dark pass above makes
   genuinely dark for students), so a plain `color: var(--navy)` is
   correct there in both themes. .connection-item is different: it's
   its own translucent-white CHIP (like the old word-reveal boxes
   had) that stays fixed-light in both themes, layered on top of
   the (now dark) .connection-card — so its --navy text needs to be
   pinned back dark for dark mode specifically, same chip pattern as
   its siblings, not left to flip with the token. */
[data-theme="dark"] .connection-item { color: #123A66; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .connection-item { color: #123A66; }
}
.connection-item p { margin: 0; font-size: 1rem; }
.connection-number {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%;
  background: var(--teal); color: var(--site-text-inverse); font-weight: 900;
  display: grid; place-items: center; font-size: .95rem;
}

.reflection-card { background: linear-gradient(180deg, #EAF0FF, #D6E4FF); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px clamp(20px, 4vw, 34px); text-align: center; }
.reflection-title { display: flex; align-items: center; gap: 10px; justify-content: center; font-weight: 900; color: var(--navy); font-size: 1.15rem; margin-bottom: 10px; }
.reflection-text { font-family: 'Baloo 2', system-ui, sans-serif; font-size: clamp(1.1rem, 2.2vw, 1.4rem); font-weight: 700; color: var(--navy); margin: 0 0 8px; }
.reflection-text:last-child { margin-bottom: 0; }
/* Each reflection question sits in its own speech bubble: an outlined
   oval with a curved tail, drawn as one closed SVG path so the outline
   is continuous. The SVG stretches with the text (non-scaling stroke
   keeps the line weight even), the oval holds the words, and the tail
   alternates: bottom-left on odd questions, bottom-right on even. */
.reflection-bubble {
  position: relative; max-width: 820px; margin: 14px auto 0; color: var(--navy);
  /* The box a text block can use inside an ellipse is about 66% of its
     width and height; the oval sits in the top 79% of the image, so the
     bottom padding also clears the tail. */
  padding: 36px 17% 78px;
  background: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 1000 560%22 preserveAspectRatio=%22none%22%3E%3Cpath d=%22M215 398 A468 205 0 1 1 352 429 C310 480 220 520 120 545 C190 500 220 450 215 398 Z%22 fill=%22%23fff%22 stroke=%22%23123A66%22 stroke-width=%224%22 stroke-linejoin=%22round%22 vector-effect=%22non-scaling-stroke%22/%3E%3C/svg%3E") no-repeat center / 100% 100%;
  filter: drop-shadow(0 8px 16px rgba(18, 58, 102, .12));
}
.reflection-bubble:first-of-type { margin-top: 6px; }
.reflection-bubble:nth-of-type(even) {
  background-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 1000 560%22 preserveAspectRatio=%22none%22%3E%3Cpath d=%22M785 398 A468 205 0 1 0 648 429 C690 480 780 520 880 545 C810 500 780 450 785 398 Z%22 fill=%22%23fff%22 stroke=%22%23123A66%22 stroke-width=%224%22 stroke-linejoin=%22round%22 vector-effect=%22non-scaling-stroke%22/%3E%3C/svg%3E");
}
.reflection-bubble .reflection-text { margin: 0; }
.reflection-bubble .reflection-image-link { margin-bottom: 12px; }
@media (max-width: 560px) {
  /* Phones stretch the oval tall, so the padding follows the width
     (22% / 45% of W ≈ 16% / 32% of the resulting height) and the
     text drops a size to keep long questions inside the outline. */
  .reflection-bubble { padding: 22% 17% 45%; }
  .reflection-bubble .reflection-text { font-size: 1rem; }
}
}
.reflection-image { display: block; max-width: 220px; max-height: 220px; border-radius: var(--radius); box-shadow: var(--shadow); margin: 0 auto; }
.reflection-image-link { display: block; width: fit-content; margin: 0 auto 10px; text-decoration: none; transition: transform 0.15s ease; }
.reflection-image-link:hover { transform: scale(1.03); }
.reflection-image-hint { display: block; text-align: center; font-size: 0.8rem; font-weight: 700; color: var(--muted); margin-top: 4px; }

.mark-complete-card { background: linear-gradient(180deg, var(--mint), #DFF5E0); border-radius: var(--radius); box-shadow: var(--shadow); padding: 16px clamp(20px, 4vw, 34px); text-align: center; margin-bottom: 24px; }
.mark-complete-done { margin: 0; font-weight: 900; color: var(--navy); font-size: 1.05rem; }
/* "I've read this ayah" couldn't be saved (lock timeout or deadlock): fixed light colours like .notice, readable in both themes. */
.mark-complete-retry { margin: 0 0 12px; padding: 10px 14px; border-radius: 14px; background: #fff4dc; color: #7a4f00; font-weight: 700; }

.activities-card { background: linear-gradient(180deg, var(--peach), #FFE3C7); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px clamp(20px, 4vw, 34px); text-align: center; }
.activities-card p { margin: 0 0 10px; }
.activities-placeholder {
  border: 2px dashed rgba(242,138,34,.4);
  border-radius: 20px;
  background: rgba(255,255,255,.55);
  padding: 26px 20px;
  font-weight: 900;
  color: var(--orange-dark);
  font-size: 1.05rem;
}
.activities-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 150px)); justify-content: center; gap: 14px; }
.activity-square {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  aspect-ratio: 1; background: var(--site-bg-surface); border-radius: 20px;
  box-shadow: var(--soft-shadow); font-weight: 900; color: var(--navy);
  padding: 10px; text-align: center; transition: transform .15s ease, box-shadow .15s ease;
}
.activity-square:hover { transform: translateY(-3px); box-shadow: var(--shadow); color: var(--orange-dark); }
.activity-square { position: relative; }
.activity-square.is-done { box-shadow: 0 0 0 3px #3cb371, var(--soft-shadow); }
.activity-square-check {
  position: absolute; top: 8px; right: 8px; width: 28px; height: 28px; border-radius: 50%;
  background: #3cb371; color: #fff; font-size: 1.05rem; font-weight: 900; line-height: 28px; text-align: center;
  box-shadow: 0 2px 6px rgba(0,0,0,.2);
}
.activity-square-icon { font-size: 2.6rem; }
.activity-square-label { font-size: 1.15rem; line-height: 1.2; }

/* MCQ quiz question cards (activity.php) — colorful, compact,
   horizontally-laid-out answer choices for kids. */
.mcq-card { padding: 20px clamp(18px, 3vw, 30px); }
.mcq-question { font-family: 'Baloo 2', system-ui, sans-serif; font-size: clamp(1.2rem, 2.4vw, 1.5rem); font-weight: 900; color: var(--navy); margin: 0 0 14px; }
.mcq-options { display: flex; flex-wrap: wrap; gap: 12px; }
.mcq-option {
  display: flex; align-items: center; gap: 10px;
  flex: 1 1 220px;
  background: var(--site-bg-surface); border-radius: 18px; border: 3px solid rgba(18,58,102,.10);
  padding: 14px 18px; cursor: pointer;
  font-family: 'Baloo 2', system-ui, sans-serif; font-weight: 800; font-size: 1.15rem; color: var(--navy);
  transition: transform .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.mcq-option:nth-child(4n+1) { background: linear-gradient(180deg, #FFF6E4, #FFF0CE); }
.mcq-option:nth-child(4n+2) { background: linear-gradient(180deg, #F0F9EA, #E3F4DA); }
.mcq-option:nth-child(4n+3) { background: linear-gradient(180deg, #feeffd, #fbe3fa); }
.mcq-option:nth-child(4n+4) { background: linear-gradient(180deg, #E6FAFF, #D8F5FC); }
.mcq-option:hover { transform: translateY(-2px); box-shadow: var(--soft-shadow); border-color: var(--teal); }
.mcq-option input[type="radio"] { width: 22px; height: 22px; flex-shrink: 0; accent-color: var(--teal-dark); margin: 0; }
.mcq-option.selected { border-color: var(--orange-dark); background: linear-gradient(180deg, #FFE7A8, #FFC94D); box-shadow: var(--shadow); }
/* Student Experience dark-mode contrast pass (2026-09-13): these 4
   answer-option colors plus .selected stayed fixed-light while
   .mcq-option's own `color: var(--navy)` correctly went light in dark
   mode — light-on-light on every MCQ answer. Reuses the exact dark
   equivalents already established for the .card.sky/.peach/.sage/.pink
   marketing-card family (same source hues), so this is the same
   palette everywhere, not a new one invented for activities. Text
   needs no separate fix: --navy already resolves correctly once the
   background is genuinely dark. */
[data-theme="dark"] .mcq-option:nth-child(4n+1) { background: linear-gradient(180deg, #332619, #241A10); }
[data-theme="dark"] .mcq-option:nth-child(4n+2) { background: linear-gradient(180deg, #1E2B1A, #131F11); }
[data-theme="dark"] .mcq-option:nth-child(4n+3) { background: linear-gradient(180deg, #2E1E2C, #21131F); }
[data-theme="dark"] .mcq-option:nth-child(4n+4) { background: linear-gradient(180deg, #123038, #0B1F27); }
[data-theme="dark"] .mcq-option.selected { background: linear-gradient(180deg, #332D14, #241F0A); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .mcq-option:nth-child(4n+1) { background: linear-gradient(180deg, #332619, #241A10); }
  :root:not([data-theme="light"]) .mcq-option:nth-child(4n+2) { background: linear-gradient(180deg, #1E2B1A, #131F11); }
  :root:not([data-theme="light"]) .mcq-option:nth-child(4n+3) { background: linear-gradient(180deg, #2E1E2C, #21131F); }
  :root:not([data-theme="light"]) .mcq-option:nth-child(4n+4) { background: linear-gradient(180deg, #123038, #0B1F27); }
  :root:not([data-theme="light"]) .mcq-option.selected { background: linear-gradient(180deg, #332D14, #241F0A); }
}
.rootcovery-word { font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 2rem; color: var(--navy); margin: 0 0 14px; text-align: center; }
.rootcovery-option-text { font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 1.3rem; letter-spacing: 4px; }
.rootcovery-result-card .rootcovery-word { margin-bottom: 8px; }

@media (max-width: 700px) {
  .quran-mascot { display: none; }
  .quran-picker-row { flex-direction: column; align-items: stretch; }
  .quran-picker-badge { justify-self: center; margin: 0 auto; }
}

/* ------------------------------------------------------------
   "Learn Meanings" matching activity (matching.php)
   ------------------------------------------------------------ */
.matching-card { padding: 26px clamp(20px, 4vw, 40px); }
.matching-status { text-align: center; font-weight: 900; font-size: 1.2rem; color: var(--navy); margin-bottom: 20px; }
.matching-status.all-done { color: var(--teal-dark); }
/* A single shared grid — word[i] and meaning[i] are placed by
   position (see matching.php), not by matching pair, so CSS Grid's
   own row-track sizing keeps each row's word/meaning pair the same
   height across both columns automatically, for any content length.
   Two independent per-column grids (the previous structure) never
   share a row track, so no min-height guess can align them. */
.matching-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 30px; align-items: stretch; }
.matching-word {
  font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 1.7rem;
  background: var(--sky); border: 3px dashed rgba(18,58,102,.25); border-radius: 18px;
  padding: 10px 16px; text-align: center; min-height: 60px; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  transition: background .2s ease, border-color .2s ease;
  color: var(--navy);
}
.matching-word-drop { font-family: 'Baloo 2', system-ui, sans-serif; font-size: .95rem; font-weight: 700; color: var(--muted); }
.matching-word.drag-over { background: var(--sky-2); border-color: var(--teal); }
.matching-word.correct { background: var(--mint); border: 3px solid var(--teal); cursor: default; }
.matching-word.correct .matching-word-drop { color: var(--teal-dark); font-weight: 900; }
.matching-word.shake { animation: matching-shake .4s; border-color: var(--pink); }
/* Student Experience dark-mode contrast pass (2026-09-13). The Arabic
   word is direct content of .matching-word itself, which never declared
   its own `color` — it silently inherited an ambient value, which is
   exactly the kind of gap that produced "Arabic text too pale" (the
   `color: var(--navy)` added above fixes this in both themes at once,
   value-identical to what dark-on-light inheritance already produced in
   light mode). The 3 backgrounds below (default/drag-over/correct) are
   fixed pastels — same flat-dark treatment as .order-tile's matching
   states, so "correct" reads the same dark-mint across every activity. */
[data-theme="dark"] .matching-word { background: #16303A; }
[data-theme="dark"] .matching-word.drag-over { background: #1C3A46; }
[data-theme="dark"] .matching-word.correct { background: #1B3323; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .matching-word { background: #16303A; }
  :root:not([data-theme="light"]) .matching-word.drag-over { background: #1C3A46; }
  :root:not([data-theme="light"]) .matching-word.correct { background: #1B3323; }
}
/* .matching-meaning sits on --butter, a fixed pastel that is never
   redefined for dark mode, but its `color: var(--navy)` IS theme-reactive
   (flips to a light navy for dark surfaces elsewhere) — pin it to the
   light-mode value so the pale-yellow chip keeps dark text in dark mode. */
[data-theme="dark"] .matching-meaning { color: #123A66; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .matching-meaning { color: #123A66; }
}
@keyframes matching-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-6px); }
  75% { transform: translateX(6px); }
}
.matching-meaning {
  cursor: grab; user-select: none;
  background: var(--butter); border: 2px solid rgba(255,177,43,.4); border-radius: 18px;
  padding: 10px 16px; text-align: center; font-weight: 800; font-size: 1.1rem; color: var(--navy);
  min-height: 60px; display: flex; align-items: center; justify-content: center;
  transition: transform .15s ease, box-shadow .15s ease;
}
.matching-meaning:hover { transform: translateY(-2px); box-shadow: var(--soft-shadow); }
.matching-meaning.selected { background: var(--orange); color: var(--site-text-inverse); }
.matching-meaning.matched { visibility: hidden; pointer-events: none; }
.matching-pagination { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 26px 0 10px; }
.matching-page-link { background: var(--site-bg-surface); border-radius: 999px; padding: 8px 16px; font-weight: 900; font-size: 1.05rem; color: var(--navy); box-shadow: var(--soft-shadow); }
.matching-page-link.active { background: var(--teal-dark); color: var(--site-text-inverse); }
@media (max-width: 700px) { .matching-columns { grid-template-columns: 1fr; } }

/* Arabic Word Search (wordsearch.php) */
.ws-layout { display: grid; grid-template-columns: 1.4fr 1fr; gap: 24px; align-items: start; }
.ws-grid-card, .ws-words-card { padding: 22px clamp(18px, 3vw, 30px); }
.ws-status { text-align: center; font-weight: 900; font-size: 1.2rem; color: var(--navy); margin-bottom: 20px; }
.ws-status.all-done { color: var(--teal-dark); }
/* Large puzzles (up to 15x15) on narrow phones: a strict 1fr grid
   would let cells shrink well under a usable touch target. minmax()
   holds each cell to a real minimum instead, and the card scrolls
   horizontally rather than compressing the grid into tiny cells. */
.ws-grid-card { overflow-x: auto; }
.ws-grid {
  display: grid;
  grid-template-columns: repeat(var(--ws-size), minmax(42px, 1fr));
  gap: 4px;
  max-width: 680px;
  margin: 0 auto;
}
.ws-cell {
  aspect-ratio: 1;
  display: flex; align-items: center; justify-content: center;
  background: var(--site-bg-surface); border-radius: 8px; border: 2px solid rgba(18,58,102,.10);
  font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif;
  font-size: var(--ws-font, 1.2rem); font-weight: 700; color: var(--navy);
  cursor: pointer; user-select: none;
  transition: background .15s ease, border-color .15s ease, transform .1s ease;
}
.ws-cell:hover { border-color: var(--teal); transform: translateY(-1px); }
.ws-cell.selected { background: var(--butter); border-color: var(--orange-dark); }
.ws-cell.found { background: var(--mint); border-color: var(--teal-dark); color: var(--teal-dark); }
.ws-cell.wrong { background: var(--pink); border-color: var(--pink); animation: matching-shake .4s; }
/* Student Experience dark-mode contrast pass (2026-09-13): same
   flat-dark palette as everywhere else (.order-tile, .matching-word).
   Covers both English and Arabic word search — they share this grid. */
[data-theme="dark"] .ws-cell.selected { background: #332B14; }
[data-theme="dark"] .ws-cell.found { background: #1B3323; }
[data-theme="dark"] .ws-cell.wrong { background: #34202E; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ws-cell.selected { background: #332B14; }
  :root:not([data-theme="light"]) .ws-cell.found { background: #1B3323; }
  :root:not([data-theme="light"]) .ws-cell.wrong { background: #34202E; }
}
.ws-cell-en { font-family: 'Baloo 2', system-ui, sans-serif; letter-spacing: 1px; }
.ws-words-title { font-weight: 900; color: var(--orange-dark); margin: 0 0 12px; font-size: 1.15rem; }
.ws-words { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.ws-word-item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: rgba(255,255,255,.75); border-radius: 14px; padding: 10px 14px;
  transition: background .2s ease, opacity .2s ease;
}
.ws-word-arabic { font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 1.3rem; color: var(--navy); }
.ws-word-en { font-family: 'Baloo 2', system-ui, sans-serif; font-weight: 900; letter-spacing: 1px; }
.ws-word-meaning { font-size: .95rem; color: var(--muted); font-weight: 700; }
/* .ws-word-item keeps a fixed near-opaque white background in dark
   mode, so pin its text dark instead of letting --navy/--muted go
   light — same light-bg/dark-text chip pattern as .pill-list. The
   .found variant below has higher specificity (two classes) so it
   still wins and keeps its own (separately tracked/deferred) pastel
   --mint background pairing untouched. */
[data-theme="dark"] .ws-word-arabic { color: #123A66; }
[data-theme="dark"] .ws-word-meaning { color: #52677A; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ws-word-arabic { color: #123A66; }
  :root:not([data-theme="light"]) .ws-word-meaning { color: #52677A; }
}
.ws-word-item.found { background: var(--mint); opacity: .7; }
.ws-word-item.found .ws-word-arabic, .ws-word-item.found .ws-word-meaning { text-decoration: line-through; color: var(--teal-dark); }
.ws-word-found-badge { font-size: 1.1rem; flex-shrink: 0; }
@media (max-width: 900px) { .ws-layout { grid-template-columns: 1fr; } }

/* Word Order (ordering.php) */
.order-card { padding: 22px clamp(18px, 3vw, 34px); }
.order-status { text-align: center; font-weight: 900; font-size: 1.2rem; color: var(--navy); margin-bottom: 20px; }
.order-status.all-done { color: var(--teal-dark); }
.order-slots, .order-bank { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; }
.order-slots { margin-bottom: 10px; }
.order-slot {
  min-width: 64px; min-height: 64px;
  border: 3px dashed rgba(18,58,102,.25); border-radius: 16px;
  background: rgba(255,255,255,.5);
  display: flex; align-items: center; justify-content: center;
  transition: background .2s ease, border-color .2s ease;
}
.order-slot.drag-over { background: var(--sky-2); border-color: var(--teal); }
.order-slot.wrong { animation: matching-shake .4s; border-color: var(--pink); }
.order-slot .order-tile { margin: 0; }
.order-bank-label { text-align: center; font-weight: 800; color: var(--muted); font-size: .95rem; margin: 18px 0 12px; }
.order-tile {
  font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 1.5rem;
  background: var(--butter); border: 2px solid rgba(255,177,43,.4); border-radius: 16px;
  padding: 12px 18px; min-height: 64px; min-width: 64px;
  display: flex; align-items: center; justify-content: center;
  cursor: grab; user-select: none; color: var(--navy);
  transition: transform .15s ease, box-shadow .15s ease, background .15s ease;
}
.order-tile:hover { transform: translateY(-2px); box-shadow: var(--soft-shadow); }
.order-tile.selected { background: var(--orange); color: var(--site-text-inverse); }
.order-tile.correct { background: var(--mint); border-color: var(--teal-dark); cursor: default; transform: none; }
.order-tile.correct:hover { transform: none; box-shadow: none; }
/* Student Experience dark-mode contrast pass (2026-09-13): default tile
   (--butter) and .correct (--mint, same dark value as everywhere else
   "correct" appears) were fixed-light under --navy text that goes
   light in dark mode — the default/most-common state of Word Order. */
[data-theme="dark"] .order-tile { background: #332B14; }
[data-theme="dark"] .order-tile.correct { background: #1B3323; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .order-tile { background: #332B14; }
  :root:not([data-theme="light"]) .order-tile.correct { background: #1B3323; }
}
.fillblank-sentences { display: grid; gap: 16px; margin-bottom: 10px; }
.fillblank-sentence { font-size: 1.1rem; font-weight: 700; color: var(--navy); line-height: 1.7; margin: 0; }
/* Combined with .order-slot (border/background/drag-over/wrong states
   inherited from there) — just overrides its block sizing to sit
   inline within a sentence instead of a standalone grid cell. */
.fillblank-inline-slot { display: inline-flex; vertical-align: middle; min-width: 90px; min-height: 34px; border-radius: 10px; margin: 0 4px; }
.fillblank-tile { font-family: inherit; font-size: 1rem; padding: 8px 16px; min-height: 40px; min-width: 40px; }

/* True or False (truefalse.php) / Guess the Word (guessword.php) */
.tf-statement, .gw-clue { padding: 18px 20px; margin-bottom: 14px; }
.tf-statement p, .gw-clue p { font-size: 1.1rem; font-weight: 700; color: var(--navy); line-height: 1.6; margin: 0 0 14px; }
.tf-statement.correct, .gw-clue.correct { background: var(--mint); }
/* The mint background above is reinforcement, not the signal itself
   — this text+icon line is what actually says "correct" without
   relying on color alone. */
.activity-item-feedback { margin: 8px 0 0; font-weight: 900; color: var(--teal-dark); font-size: .95rem; }
.tf-choice.wrong, .gw-input.wrong { animation: matching-shake .4s; border-color: var(--pink) !important; background: var(--pink) !important; }
.gw-input { font-family: inherit; font-size: 1rem; padding: 10px 14px; border-radius: 10px; border: 2px solid var(--border); min-width: 200px; background: #FFFFFF; color: #1A2634; }
.gw-input:disabled { opacity: .7; }
.gw-help-row { margin-top: 10px; }
.gw-choice-row { flex-wrap: wrap; }
.gw-choice-btn { font-family: inherit; font-size: 1rem; }
.gw-choice-btn.wrong { animation: matching-shake .4s; border-color: var(--pink) !important; background: var(--pink) !important; }
/* Student Experience dark-mode contrast pass (2026-09-13). "Correct"
   (mint) and "wrong" (pink) feedback states across True/False and
   Guess the Word: fixed pastel backgrounds paired with --navy text
   that goes light in dark mode. Unified to the same flat dark-mint/
   dark-pink pair used everywhere else "correct"/"wrong" appears
   (.matching-word, .order-tile below) so feedback reads consistently
   across every activity type, not just per-page.

   .gw-input.wrong is DELIBERATELY EXCLUDED from the dark-pink treatment
   below, unlike .tf-choice.wrong/.gw-choice-btn.wrong — caught by an
   objective contrast check, not by eye: .gw-input's own background/
   color (above) is unconditional #FFFFFF/#1A2634 in BOTH themes (it's
   a text-entry field, stays light always per the standing rule in
   docs/architecture/SITE-THEME-ARCHITECTURE.md §5). An earlier version
   of this comment claimed that made the dark-pink override redundant
   ("gets readable dark text for free") without checking the actual
   numbers — a dark-pink background (#34202E) with that SAME
   unconditional dark text (#1A2634) computes to 1.02:1 contrast,
   effectively invisible. .tf-choice/.gw-choice-btn are buttons/choices,
   not text-entry fields, so they don't have that unconditional-dark-text
   constraint and correctly get the shared dark-pink treatment. */
[data-theme="dark"] .tf-statement.correct,
[data-theme="dark"] .gw-clue.correct { background: #1B3323; }
[data-theme="dark"] .tf-choice.wrong,
[data-theme="dark"] .gw-choice-btn.wrong { background: #34202E !important; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tf-statement.correct,
  :root:not([data-theme="light"]) .gw-clue.correct { background: #1B3323; }
  :root:not([data-theme="light"]) .tf-choice.wrong,
  :root:not([data-theme="light"]) .gw-choice-btn.wrong { background: #34202E !important; }
}

/* Setup Surah (super-admin-setup-surah.php) */
.setup-picker { padding: 20px clamp(18px, 3vw, 30px); margin-bottom: 20px; }
.setup-picker-row { display: flex; flex-wrap: wrap; gap: 20px; }
.setup-picker-row > div { flex: 1 1 260px; display: flex; flex-direction: column; gap: 6px; }
.setup-picker-row label { font-weight: 900; color: var(--navy); font-size: .92rem; }
.setup-empty-note { color: var(--muted); font-weight: 700; margin: 12px 0 0; }
.setup-clipart-grid .setup-empty-note { grid-column: 1 / -1; }

.setup-stat-row { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 6px; }
.setup-stat { flex: 1 1 130px; display: flex; flex-direction: column; gap: 4px; }
.setup-stat span { font-weight: 900; color: var(--navy); font-size: .8rem; }
.setup-stat input {
  padding: 10px 12px; border: 2px solid rgba(18,58,102,.10); border-radius: 12px;
  font: inherit; font-weight: 700; background: rgba(18,58,102,.04); color: var(--muted);
  cursor: default;
}

.combo-wrap { position: relative; }
.combo-input {
  padding: 12px 14px; border: 2px solid rgba(18,58,102,.10); border-radius: 14px;
  font: inherit; background: var(--site-bg-surface); width: 100%;
}
.combo-input:disabled { background: rgba(18,58,102,.04); color: var(--muted); cursor: not-allowed; }
.combo-input:focus { border-color: var(--teal); outline: none; }
/* A searchable text field, same standing rule as .form input: stays
   light with dark text in both themes (see
   docs/architecture/SITE-THEME-ARCHITECTURE.md §5). It never had an
   explicit color at all, so it was falling back to dark regardless of
   background/theme — genuinely broken in dark mode, not just following
   --site-bg-surface's normal (correct) dark flip. */
[data-theme="dark"] .combo-input { background: #FFFFFF; color: #1A2634; }
[data-theme="dark"] .combo-input:disabled { background: rgba(255,255,255,.6); color: #52677A; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .combo-input { background: #FFFFFF; color: #1A2634; }
  :root:not([data-theme="light"]) .combo-input:disabled { background: rgba(255,255,255,.6); color: #52677A; }
}
.combo-dropdown {
  position: fixed; z-index: 60;
  background: var(--site-bg-surface); border-radius: 14px; box-shadow: var(--shadow);
  max-height: 280px; overflow-y: auto; padding: 6px;
}
.combo-dropdown[hidden] { display: none; }
.combo-option { padding: 10px 12px; border-radius: 10px; cursor: pointer; font-size: .92rem; color: var(--navy); }
.combo-option:hover, .combo-option.highlighted { background: var(--sky); }
.combo-empty { padding: 10px 12px; color: var(--muted); font-weight: 700; font-size: .88rem; }
.combo-option.tag-picker-add { color: var(--teal-dark); font-weight: 900; }
/* --sky stays fixed/light in dark mode (deliberately, it's part of the
   pastel family), but --navy/--teal-dark text lightens — pin both back
   to dark for this light highlight, same pattern as .pill-list. */
[data-theme="dark"] .combo-option:hover,
[data-theme="dark"] .combo-option.highlighted { color: #123A66; }
[data-theme="dark"] .combo-option.tag-picker-add:hover,
[data-theme="dark"] .combo-option.tag-picker-add.highlighted { color: #087C8B; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .combo-option:hover,
  :root:not([data-theme="light"]) .combo-option.highlighted { color: #123A66; }
  :root:not([data-theme="light"]) .combo-option.tag-picker-add:hover,
  :root:not([data-theme="light"]) .combo-option.tag-picker-add.highlighted { color: #087C8B; }
}

.tag-picker-group { margin-bottom: 22px; }
.tag-picker-group label { font-weight: 900; color: var(--navy); font-size: .92rem; display: block; margin-bottom: 8px; }
.tag-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
.tag-chips:empty { margin-bottom: 0; }
.tag-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--sky); color: var(--navy); font-weight: 700; font-size: .85rem;
  padding: 7px 10px 7px 14px; border-radius: 999px;
}
.tag-chip-remove {
  background: none; border: 0; color: var(--navy); font-size: 1.1rem; line-height: 1;
  cursor: pointer; opacity: .55; padding: 0;
}
.tag-chip-remove:hover { opacity: 1; }

.tag-pills { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.tag-pills:empty { margin-bottom: 0; }
.tag-pill {
  border: 2px solid var(--site-border-default); background: var(--site-bg-surface); color: var(--navy);
  font-weight: 700; font-size: .82rem; padding: 6px 12px; border-radius: 999px; cursor: pointer;
}
.tag-pill:hover { background: var(--sky); }
.tag-pill-suggested { border-color: var(--teal); color: var(--teal-dark); background: rgba(21,157,170,.06); }
.tag-bank-toggle {
  background: none; border: 0; color: var(--teal-dark); font-weight: 900; font-size: .82rem;
  cursor: pointer; padding: 4px 0; margin-bottom: 8px;
}

.setup-ai-prompt { background: rgba(18,58,102,.04); border-radius: 14px; padding: 14px; margin-bottom: 18px; }
.setup-ai-prompt-text {
  width: 100%; font-family: 'SFMono-Regular', Menlo, Consolas, monospace; font-size: .95rem; line-height: 1.6;
  padding: 12px 14px; border: 2px solid rgba(18,58,102,.10); border-radius: 10px;
  background: var(--site-bg-surface); color: var(--text); resize: vertical; margin: 8px 0; display: block;
}
.setup-ai-copy-btn { padding: 8px 16px; font-size: .85rem; min-height: auto; }

.tag-suggest-box { background: rgba(18,58,102,.04); border-radius: 14px; padding: 14px; margin-bottom: 20px; }
.tag-suggest-box label { font-weight: 900; color: var(--navy); font-size: .92rem; display: block; }
.tag-suggest-box textarea { width: 100%; margin: 8px 0; padding: 10px 12px; border: 2px solid rgba(18,58,102,.10); border-radius: 10px; font: inherit; }

.setup-ayah-header { text-align: center; margin: 12px 0 10px; }
.setup-arabic-preview {
  font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: clamp(1.6rem, 3vw, 2.2rem);
  color: var(--navy); margin: 8px 0 0;
}

/* Compact 3-column ayah context header (item 7) — content, arabic
   preview, and publish controls share one horizontal row instead of
   stacking across several hundred vertical pixels. .app-grid/.app-card
   are the shared "newer Superadmin dashboard" primitives (app.css);
   these rules only tighten padding/alignment for this specific use. */
/* margin: 0 — the shared .app-page flex gap (app.css) already spaces
   this from the titlebar above and the tabs below; adding our own
   margin on top of that gap was double-spacing the page. Column ratio
   (.app-grid.setup-compact-header, two classes, so it reliably beats
   .app-grid's own auto-fit columns regardless of stylesheet load
   order) favors the Arabic ayah while keeping status/controls compact. */
.app-grid.setup-compact-header { margin: 0; grid-template-columns: 0.8fr 1.4fr 1fr; align-items: stretch; }
.setup-compact-card { padding: 8px 14px; display: flex; flex-direction: column; gap: 4px; align-items: flex-start; justify-content: center; }
.setup-compact-card .eyebrow { margin-bottom: 0; }
.setup-compact-card-arabic { align-items: center; text-align: center; }
.setup-compact-card-arabic .setup-arabic-preview { margin: 0; }
.setup-compact-card-actions { align-items: stretch; justify-content: center; gap: 6px; }
.setup-compact-card-actions form { margin: 0; }
.setup-publish-requirements summary { cursor: pointer; font-weight: 800; color: #9A3B12; font-size: .82rem; list-style: none; }
.setup-publish-requirements summary::-webkit-details-marker { display: none; }
.setup-publish-requirements summary .setup-publish-view-link { color: var(--teal-dark, #0E7B87); text-decoration: underline; font-weight: 700; margin-inline-start: 4px; }
.setup-publish-requirements .setup-publish-missing { font-size: .78rem; color: var(--muted); margin: 6px 0 0; }
.setup-tabs-compact { margin: 0 0 8px; }
@media (max-width: 900px) {
  .app-grid.setup-compact-header { grid-template-columns: 1fr 1fr; }
  .setup-compact-card-arabic { grid-column: 1 / -1; }
}
@media (max-width: 600px) {
  .app-grid.setup-compact-header { grid-template-columns: 1fr; }
}

.status-badge { display: inline-flex; align-items: center; border-radius: 999px; padding: 2px 10px; font-size: .7rem; font-weight: 900; text-transform: uppercase; letter-spacing: .03em; vertical-align: middle; }
.status-badge.status-draft { background: rgba(82,103,122,.12); color: var(--muted); }
.status-badge.status-approved { background: var(--mint); color: #1D5C25; }
.status-badge.status-imported { background: var(--sky-2); color: var(--teal-dark); }
.status-badge.status-published { background: #DCEEFF; color: #14508C; }
.status-badge.status-archived { background: rgba(82,103,122,.12); color: var(--muted); text-decoration: line-through; }

.safeguard-badge { display: inline-flex; align-items: center; gap: 4px; border-radius: 999px; padding: 2px 10px; font-size: .68rem; font-weight: 800; vertical-align: middle; }
.safeguard-badge-not-reviewed { background: rgba(82,103,122,.12); color: var(--muted); }
.safeguard-badge-flagged { background: #FDE4D8; color: #9A3B12; }
.safeguard-badge-reviewed { background: var(--mint); color: #1D5C25; }
.setup-visual-idea-card-safeguard { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 2px 0 6px; }
.setup-hint-warning { color: #9A3B12; }
.setup-visual-idea-flag-form { display: flex; align-items: center; gap: 6px; padding: 4px 0; }
.setup-visual-idea-flag-form input[type="text"] { flex: 1; min-width: 0; font-size: .8rem; padding: 3px 6px; }

.setup-publish-status { display: flex; align-items: center; justify-content: center; gap: 12px; margin-top: 10px; flex-wrap: wrap; }
.setup-publish-status form { display: inline; }
.setup-publish-status .status-badge { font-size: .8rem; padding: 4px 14px; }
.setup-publish-missing { font-size: .82rem; color: var(--muted); font-weight: 700; max-width: 460px; }

.setup-tabs { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-bottom: 18px; }
.setup-tab {
  background: var(--site-bg-surface); border: 2px solid var(--site-border-default); border-radius: 999px;
  padding: 10px 18px; font-weight: 900; font-family: 'Baloo 2', system-ui, sans-serif;
  font-size: .92rem; color: var(--muted); cursor: pointer; transition: all .15s ease;
}
.setup-tab.active { background: var(--teal-dark); border-color: var(--teal-dark); color: var(--site-text-inverse); }
.setup-tab:hover:not(.active) { border-color: var(--teal); color: var(--teal-dark); }

.setup-section { padding: 22px clamp(18px, 3vw, 32px); margin-bottom: 18px; }
.setup-section h2 { margin: 0 0 6px; }
.setup-hint { color: var(--muted); font-weight: 700; font-size: .9rem; margin: 0 0 16px; }

.setup-word-table { display: grid; gap: 8px; margin-bottom: 16px; overflow-x: auto; }
.setup-word-row {
  display: grid; grid-template-columns: 100px 1.2fr 1fr 1.4fr 90px 90px 90px;
  gap: 10px; align-items: center; background: rgba(255,255,255,.7); border-radius: 12px; padding: 8px 10px;
}
.setup-word-row-head { background: none; font-weight: 900; color: var(--navy); font-size: .9rem; text-transform: uppercase; letter-spacing: .03em; padding: 0 10px; }
.setup-word-arabic { font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 1.3rem; text-align: center; color: var(--navy); }
/* .setup-word-row keeps a fixed near-opaque white background in dark
   mode, so pin its text dark instead of letting --navy go light —
   same light-bg/dark-text chip pattern as .pill-list. */
[data-theme="dark"] .setup-word-row-head,
[data-theme="dark"] .setup-word-arabic { color: #123A66; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .setup-word-row-head,
  :root:not([data-theme="light"]) .setup-word-arabic { color: #123A66; }
}
.setup-word-row input[type="text"] { padding: 9px 10px; border: 2px solid rgba(18,58,102,.10); border-radius: 10px; font: inherit; font-size: .95rem; width: 100%; }
.setup-word-row input[type="number"] { padding: 9px 10px; border: 2px solid rgba(18,58,102,.10); border-radius: 10px; font: inherit; font-size: .95rem; width: 100%; }
.setup-meaningblock-row { grid-template-columns: 1.4fr 110px 110px 2.2fr; }
.setup-keyword-row { grid-template-columns: 1fr 2.2fr; }
.setup-riddle-row { grid-template-columns: 1fr 140px; align-items: start; }
.setup-riddle-row textarea { width: 100%; box-sizing: border-box; padding: 9px 10px; border: 2px solid rgba(18,58,102,.10); border-radius: 10px; font: inherit; font-size: .95rem; resize: vertical; }
.setup-arabic-input { font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif !important; font-size: 1.1rem !important; }
.setup-emoji-field { display: flex; gap: 4px; align-items: center; }
.setup-emoji-input { width: 100%; text-align: center; font-size: 1.1rem !important; }
.btn-emoji-pick { border: none; background: var(--sky-2); border-radius: 10px; padding: 8px 9px; cursor: pointer; flex-shrink: 0; }
.setup-word-checkbox { display: flex; align-items: center; justify-content: center; }
.setup-word-checkbox input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--teal-dark); }

.setup-reference {
  background: rgba(255,255,255,.7); border-radius: 14px; padding: 14px 16px; margin-bottom: 16px; font-size: .9rem;
}
.setup-reference-arabic { display: block; font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 1.3rem; color: var(--navy); margin: 8px 0; }
.setup-reference-arabic span { margin-inline-start: 10px; cursor: help; border-bottom: 1px dashed var(--muted); }
.setup-reference-meanings { display: block; color: var(--muted); font-weight: 700; }

.setup-clipart-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; margin-bottom: 20px; }
.setup-clipart-grid-compact { grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); gap: 8px; margin-bottom: 10px; }
.setup-clipart-grid-compact .setup-clipart-item { padding: 8px 6px; }
.setup-clipart-grid-compact .setup-clipart-item img { max-height: 60px; }
.setup-clipart-item {
  position: relative; background: var(--site-bg-surface); border-radius: 14px; padding: 14px 10px; text-align: center;
  box-shadow: var(--soft-shadow); display: flex; flex-direction: column; align-items: center; gap: 6px;
}
.setup-clipart-emoji { font-size: 2.4rem; }
.setup-clipart-item img { max-width: 100%; max-height: 90px; border-radius: 8px; }
.setup-clipart-caption { font-size: .78rem; color: var(--muted); font-weight: 700; }
.setup-clipart-linked-note { font-size: .72rem; color: var(--muted); font-style: italic; }
/* The admin-written connection stored on an ayah link — the caption the
   student sees under this image on quran.php. */
.setup-clipart-connection { margin: 4px 0 0; font-size: .74rem; line-height: 1.3; color: var(--navy); font-style: italic; }
.setup-clipart-connection-input { width: 100%; box-sizing: border-box; font: inherit; font-size: .78rem; padding: 4px 6px; border: 1px solid rgba(0,0,0,.15); border-radius: 8px; margin-bottom: 4px; }
.setup-clipart-edit-connection { width: 100%; text-align: left; }
.setup-clipart-edit-connection > summary { cursor: pointer; font-size: .72rem; font-weight: 700; color: var(--teal-dark, #0E7B87); text-decoration: underline; list-style: none; text-align: center; }
.setup-clipart-edit-connection > summary::-webkit-details-marker { display: none; }
.setup-clipart-edit-connection form { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
.setup-clipart-edit-connection textarea { width: 100%; box-sizing: border-box; font: inherit; font-size: .78rem; padding: 4px 6px; border: 1px solid rgba(0,0,0,.15); border-radius: 8px; resize: vertical; }
.setup-clipart-item-actions { display: flex; align-items: center; justify-content: center; gap: 6px; flex-wrap: wrap; width: 100%; }
.setup-clipart-link-menu { position: relative; }
.setup-clipart-link-menu summary { list-style: none; cursor: pointer; font-size: .78rem; font-weight: 800; color: var(--teal-dark, #0E7B87); }
.setup-clipart-link-menu summary::-webkit-details-marker { display: none; }
.setup-clipart-link-menu form { display: inline; }
.setup-clipart-link-menu[open] { position: absolute; z-index: 5; background: var(--site-bg-surface); border-radius: 10px; box-shadow: var(--soft-shadow); padding: 8px; display: flex; flex-direction: column; gap: 4px; align-items: flex-start; }

/* Find Existing Clipart — compact horizontal toolbar instead of stacked full-width fields. */
.setup-clipart-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 14px; }
.setup-clipart-toolbar input[type="text"] { flex: 1; min-width: 140px; }
.setup-clipart-toolbar select { width: auto; }
.setup-clipart-toolbar-toggle { display: flex; align-items: center; gap: 5px; font-size: .82rem; font-weight: 700; color: var(--navy); white-space: nowrap; }

/* Create Clipart — two compact cards instead of three stacked full-width forms. */
.setup-create-clipart-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; align-items: start; }
.setup-create-clipart-card { background: var(--site-bg-surface); border-radius: 14px; box-shadow: var(--soft-shadow); padding: 16px 18px; }
.setup-create-clipart-card h4 { margin: 0 0 8px; font-size: 1rem; }
.setup-phase-c-note { margin-top: 10px; font-size: .78rem; }
.setup-clipart-remove {
  position: absolute; top: 4px; right: 4px; background: var(--pink); color: var(--site-text-inverse); border: none;
  width: 22px; height: 22px; border-radius: 50%; cursor: pointer; font-size: .75rem; line-height: 1;
}
.setup-clipart-purpose-badges { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; }
.setup-clipart-purpose-badge {
  font-size: .68rem; font-weight: 700; border-radius: 999px; padding: 3px 9px;
  border: 1px solid var(--navy); background: var(--navy); color: var(--site-text-inverse);
}
.setup-clipart-purpose-badge-none { background: var(--site-bg-surface); border-color: var(--muted); color: var(--muted); }
/* Accessibility warnings (Bulk Clipart Upload §9.7): fixed light colours like .notice, readable in both themes. */
.setup-clipart-a11y-badge { font-size: .68rem; font-weight: 800; border-radius: 999px; padding: 3px 9px; border: 1px solid #e0b25a; background: #fff4dc; color: #7a4f00; }
.setup-clipart-a11y-badge-neutral { background: var(--site-bg-surface); border-color: var(--muted); color: var(--muted); font-weight: 700; }
/* The inline correction (R6): shown above the panel after a refused link or purpose change. */
.setup-clipart-correction { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start; background: var(--site-bg-surface); border: 2px solid #e0b25a; border-radius: 14px; padding: 14px 16px; margin-bottom: 18px; box-shadow: var(--soft-shadow); }
.setup-clipart-correction > img { max-width: 120px; max-height: 120px; border-radius: 8px; }
.setup-clipart-correction > div { flex: 1 1 260px; min-width: 0; }
.setup-clipart-correction h4 { margin: 0 0 6px; font-size: 1rem; overflow-wrap: anywhere; }
.setup-clipart-purpose-editor { width: 100%; font-size: .78rem; }
.setup-clipart-purpose-editor summary { cursor: pointer; color: var(--teal-dark, #0E7B87); font-weight: 800; }
.setup-clipart-purpose-editor form { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; margin-top: 6px; }
.setup-clipart-purpose-checkbox { display: flex; align-items: flex-start; gap: 8px; font-size: .85rem; font-weight: 500; }
.setup-clipart-purpose-checkbox input { margin-top: 3px; }
.setup-clipart-purpose-save { font-size: .78rem; padding: 4px 10px; }
.setup-clipart-levels-radio { display: inline-flex; align-items: center; gap: 4px; font-weight: 700; font-size: .85rem; margin-inline-end: 12px; white-space: nowrap; }
.setup-clipart-secondary { margin: 16px 0; }
.setup-clipart-secondary summary { cursor: pointer; font-weight: 800; color: var(--teal-dark, #0E7B87); font-size: .9rem; margin-bottom: 8px; }
.setup-visual-idea-bulk { margin: 12px 0; }
.setup-visual-idea-bulk summary { cursor: pointer; font-weight: 800; color: var(--teal-dark, #0E7B87); font-size: .85rem; }
.setup-visual-idea-bulk form { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; max-width: 900px; }
.setup-visual-idea-bulk-textarea { width: 100%; min-height: 120px; font-size: .95rem; line-height: 1.5; padding: 12px; box-sizing: border-box; resize: vertical; }

.setup-archived-visual-ideas { margin: 14px 0; }
.setup-archived-visual-ideas summary { cursor: pointer; font-weight: 800; color: var(--muted); font-size: .85rem; list-style: none; }
.setup-archived-visual-ideas summary::-webkit-details-marker { display: none; }
.setup-archived-visual-ideas summary::before { content: '▸ '; }
.setup-archived-visual-ideas[open] summary::before { content: '▾ '; }
.setup-archived-visual-ideas .setup-hint { margin: 6px 0 10px; }
.setup-archived-visual-ideas .setup-visual-idea-card { opacity: .85; }
.setup-visual-ideas-secondary-actions { text-align: right; margin: 4px 0 8px; }
.setup-link-btn { background: none; border: none; padding: 2px 4px; font-size: .78rem; font-weight: 700; color: var(--teal-dark, #0E7B87); cursor: pointer; text-decoration: underline; }
.setup-link-btn:hover { color: var(--navy); }

/* Visual Idea cards — wide enough that ~3-4 fit a normal desktop row
   without recreating the skinny-card problem in the library grid below;
   see setup-visual-idea-card::after for why .card's own decorative
   corner dot is suppressed here specifically, not sitewide. */
.setup-visual-idea-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 14px; margin: 14px 0; }
.setup-visual-idea-card { display: flex; flex-direction: column; gap: 6px; padding: 14px 16px; overflow: visible; }
.setup-visual-idea-card::after { content: none; }
.setup-visual-idea-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.setup-visual-idea-card-head strong { font-size: .95rem; }
.setup-visual-idea-card-statuses { display: flex; flex-direction: column; gap: 2px; font-size: .78rem; }
.setup-status-line { display: flex; align-items: center; gap: 6px; }
.setup-status-line-label { color: var(--muted); font-weight: 700; min-width: 72px; }
.setup-visual-idea-card-desc, .setup-visual-idea-card-caption {
  margin: 0; font-size: .82rem; color: var(--navy); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.setup-visual-idea-card-caption { font-style: italic; color: var(--muted); }
.setup-visual-idea-card-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.setup-visual-idea-card-actions .setup-visual-idea-generate { flex: 1 1 auto; min-width: 120px; }
.setup-visual-idea-safeguard-btn { white-space: nowrap; }
.setup-visual-idea-more { position: relative; }
.setup-visual-idea-more summary { list-style: none; cursor: pointer; padding: 6px 10px; border-radius: 999px; border: 1px solid var(--muted); font-weight: 900; }
.setup-visual-idea-more summary::-webkit-details-marker { display: none; }
.setup-visual-idea-more[open] summary { background: var(--sky-2); }
.setup-visual-idea-more form { position: absolute; right: 0; top: 100%; z-index: 5; background: var(--site-bg-surface); border-radius: 10px; box-shadow: var(--soft-shadow); padding: 6px 10px; margin-top: 4px; white-space: nowrap; }

.setup-safeguard-modal-inner { max-width: 480px; }
.setup-safeguard-modal-ai { border: 1px dashed var(--muted); border-radius: 10px; padding: 10px 12px; margin: 10px 0; display: flex; flex-direction: column; gap: 6px; }
#setupSafeguardModalClearForm, #setupSafeguardModalFlagForm { margin-top: 10px; display: flex; flex-direction: column; gap: 6px; }
.setup-body-part-group { border: 1px solid var(--site-border-default); border-radius: 12px; padding: 10px 12px; margin: 4px 0; display: flex; flex-direction: column; gap: 6px; background: rgba(255,255,255,.6); }
.setup-body-part-subheading { margin: 0; font-weight: 900; font-size: .88rem; color: var(--navy); }
.setup-body-part-checkbox { display: flex; align-items: flex-start; gap: 8px; font-weight: 700; font-size: .85rem; }
.setup-body-part-checkbox input { margin-top: 3px; }
.setup-body-part-required { font-weight: 700; color: var(--muted); text-transform: none; }
/* .setup-body-part-group keeps a fixed near-opaque white background
   in dark mode, so pin its text dark instead of letting --navy/
   --muted go light — same light-bg/dark-text chip pattern as
   .pill-list. */
[data-theme="dark"] .setup-body-part-subheading { color: #123A66; }
[data-theme="dark"] .setup-body-part-required { color: #52677A; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .setup-body-part-subheading { color: #123A66; }
  :root:not([data-theme="light"]) .setup-body-part-required { color: #52677A; }
}
#setupSafeguardModalBodyPartFields { display: flex; flex-direction: column; gap: 6px; padding: 8px 10px; background: rgba(18,58,102,.04); border-radius: 10px; }

/* Visual Idea add/edit modal — compact, content-sized inputs, not a
   full-width multi-screen form. */
.setup-visual-idea-modal-inner { max-width: 480px; }
.setup-visual-idea-modal-form { display: flex; flex-direction: column; gap: 8px; }
.setup-visual-idea-modal-form input, .setup-visual-idea-modal-form textarea { width: 100%; box-sizing: border-box; }
.setup-visual-idea-modal-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
@media (max-width: 520px) { .setup-visual-idea-modal-grid2 { grid-template-columns: 1fr; } }

/* PENDING candidates only — a real staging bug (2026-09-08) showed why
   resolved (accepted/matched_existing/dismissed) candidates must never
   sit in this same grid: this container's default grid align-items is
   stretch, so a lightweight resolved row next to a tall editable card
   was being stretched to match it; align-items:start opts every card
   here out of that stretching regardless of what else is ever added. */
.setup-ai-visual-ideas-results { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; margin: 16px 0; align-items: start; }
.setup-ai-visual-idea-card { position: relative; }
.setup-ai-visual-idea-card::after { content: none; }
.setup-ai-visual-idea-form { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.setup-ai-visual-idea-form label { font-weight: 700; }
.setup-ai-visual-idea-form input, .setup-ai-visual-idea-form textarea { width: 100%; box-sizing: border-box; }
.setup-vi-dup-exists { background: var(--site-bg-surface); border-color: var(--muted); color: var(--muted); }
.setup-vi-dup-archived { background: var(--site-bg-surface); border-color: var(--muted); color: var(--muted); text-decoration: line-through; }
.setup-vi-dup-possible { background: var(--orange); border-color: var(--orange-dark); color: var(--site-text-inverse); }
.setup-vi-dup-new { background: var(--teal-dark, #0E7B87); border-color: var(--teal-dark, #0E7B87); color: var(--site-text-inverse); }
.setup-candidate-batch-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
.setup-ai-visual-idea-dismiss-form { margin-top: 6px; }

/* Resolved (accepted/matched_existing/dismissed) candidates — deliberately
   plain flow list items, never grid cards, so they can never again be
   stretched to match a pending card's height (see the comment above and
   on renderVisualIdeaCandidateBatch() in super-admin-setup-surah.php). */
.setup-resolved-candidates { margin: 4px 0 16px; }
.setup-resolved-candidates summary { cursor: pointer; font-weight: 800; color: var(--teal-dark, #0E7B87); }
.setup-resolved-candidate-list { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.setup-resolved-candidate-row { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; font-size: .85rem; padding: 5px 10px; border-radius: 8px; background: rgba(255,255,255,.55); }
.setup-resolved-candidate-icon { font-weight: 900; width: 1.1em; text-align: center; }
.setup-resolved-candidate-rank { font-weight: 700; color: var(--muted); }
.setup-resolved-candidate-status { color: var(--muted); }
.setup-resolved-candidate-accepted .setup-resolved-candidate-icon { color: var(--teal-dark, #0E7B87); }
.setup-resolved-candidate-matched_existing .setup-resolved-candidate-icon { color: var(--muted); }
.setup-resolved-candidate-dismissed { opacity: .65; }
.setup-resolved-candidate-dismissed .setup-resolved-candidate-icon { color: var(--muted); }
/* .setup-resolved-candidate-row keeps a fixed near-opaque white
   background in dark mode, so pin its text dark instead of letting
   --muted/--teal-dark go light — same light-bg/dark-text chip
   pattern as .pill-list. */
[data-theme="dark"] .setup-resolved-candidate-rank,
[data-theme="dark"] .setup-resolved-candidate-status,
[data-theme="dark"] .setup-resolved-candidate-matched_existing .setup-resolved-candidate-icon,
[data-theme="dark"] .setup-resolved-candidate-dismissed .setup-resolved-candidate-icon { color: #52677A; }
[data-theme="dark"] .setup-resolved-candidate-accepted .setup-resolved-candidate-icon { color: #087C8B; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .setup-resolved-candidate-rank,
  :root:not([data-theme="light"]) .setup-resolved-candidate-status,
  :root:not([data-theme="light"]) .setup-resolved-candidate-matched_existing .setup-resolved-candidate-icon,
  :root:not([data-theme="light"]) .setup-resolved-candidate-dismissed .setup-resolved-candidate-icon { color: #52677A; }
  :root:not([data-theme="light"]) .setup-resolved-candidate-accepted .setup-resolved-candidate-icon { color: #087C8B; }
}
.setup-clipart-add { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; }
.worksheet-clipart-picker-item { cursor: pointer; }
.worksheet-clipart-picker-item input[type="checkbox"] { align-self: flex-end; margin: -6px -2px 0 0; }
.setup-clipart-library h3 { margin: 20px 0 8px; }

.clipart-picker { background: var(--site-bg-surface); border-radius: 14px; padding: 14px; box-shadow: var(--soft-shadow); }
.clipart-picker-label { font-weight: 900; color: var(--navy); margin: 0 0 8px; font-size: .88rem; }
.clipart-picker-preview { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.clipart-picker-preview img { max-width: 64px; max-height: 64px; border-radius: 8px; }
.clipart-picker-preview span { font-size: .8rem; font-weight: 700; color: var(--muted); }
.clipart-picker-empty { font-size: .8rem; color: var(--muted); font-style: italic; }
.clipart-picker-chooser summary { cursor: pointer; font-weight: 800; color: var(--teal-dark); font-size: .85rem; margin-bottom: 10px; }
.clipart-picker-search { display: flex; gap: 8px; margin-bottom: 10px; }
.clipart-picker-search-input { flex: 1; }
.clipart-picker-results { display: grid; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); gap: 10px; margin-bottom: 12px; }
.clipart-picker-result { background: #F7FBFF; border-radius: 10px; padding: 8px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.clipart-picker-result img { max-width: 100%; max-height: 60px; border-radius: 6px; }
.clipart-picker-result span { font-size: .7rem; color: var(--muted); font-weight: 700; }
/* .clipart-picker-result is a fixed pale-blue swatch in both themes,
   so pin its caption text dark instead of letting --muted go light —
   same light-bg/dark-text chip pattern as .pill-list. */
[data-theme="dark"] .clipart-picker-result span { color: #52677A; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .clipart-picker-result span { color: #52677A; }
}
.clipart-picker-upload { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.clipart-picker-status { font-size: .8rem; font-weight: 700; color: var(--muted); margin-top: 8px; }
.clipart-picker-status-error { color: var(--pink-dark, #B3315C); }
.setup-clipart-link-form { display: flex; flex-direction: column; gap: 6px; width: 100%; }
.setup-clipart-upload-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; background: rgba(255,255,255,.7); border-radius: 14px; padding: 16px; }
.setup-clipart-upload-form label { display: flex; flex-direction: column; gap: 4px; font-weight: 900; color: var(--navy); font-size: .88rem; }
/* .setup-clipart-upload-form keeps a fixed near-opaque white
   background in dark mode, so pin its label text dark instead of
   letting --navy go light — same light-bg/dark-text chip pattern as
   .pill-list. */
[data-theme="dark"] .setup-clipart-upload-form label { color: #123A66; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .setup-clipart-upload-form label { color: #123A66; }
}
.setup-clipart-upload-form label[hidden] { display: none; }
.setup-clipart-level-fieldset { border: 2px solid rgba(18,58,102,.10); border-radius: 10px; padding: 8px 12px; grid-column: 1 / -1; }
.setup-clipart-upload-form button.btn { grid-column: 1 / -1; align-self: start; justify-self: start; }
.setup-clipart-level-fieldset legend { font-weight: 900; color: var(--navy); font-size: .82rem; padding: 0 6px; }
.setup-clipart-upload-form label.setup-clipart-level-checkbox { display: inline-flex; flex-direction: row; align-items: center; gap: 4px; font-weight: 700; font-size: .85rem; margin-inline-end: 12px; white-space: nowrap; }

/* Advanced full prompt builder: the heavier fieldsets here (curriculum
   context, learning suitability) need the full row, not just one
   auto-fit column, to stay readable — the plainer Upload form's own
   fieldsets are simple enough to not need this. */
.setup-prompt-builder-form fieldset,
.setup-prompt-builder-form p.setup-hint,
.setup-prompt-builder-form label:has(textarea) { grid-column: 1 / -1; }

.perm-fieldset { border: 2px solid rgba(18,58,102,.10); border-radius: 10px; padding: 8px 12px; grid-column: 1 / -1; }
.perm-fieldset legend { font-weight: 900; color: var(--navy); font-size: .82rem; padding: 0 6px; }
.perm-checkbox { display: inline-flex; align-items: center; gap: 4px; font-weight: 700; font-size: .85rem; margin-inline-end: 12px; white-space: nowrap; }
.setup-inline-form { background: rgba(255,255,255,.7); border-radius: 14px; padding: 14px 16px; gap: 10px; }
.setup-inline-form label { display: flex; flex-direction: column; gap: 4px; font-weight: 900; color: var(--navy); font-size: .88rem; }
/* .setup-inline-form keeps a fixed near-opaque white background in
   dark mode, so pin its label text dark instead of letting --navy go
   light — same light-bg/dark-text chip pattern as .pill-list. */
[data-theme="dark"] .setup-inline-form label { color: #123A66; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .setup-inline-form label { color: #123A66; }
}
.setup-inline-form input[type="text"], .setup-inline-form input[type="file"] {
  padding: 9px 10px; border: 2px solid rgba(18,58,102,.10); border-radius: 10px; font: inherit;
}

.setup-emoji-modal {
  position: fixed; inset: 0; background: rgba(18,58,102,.45); z-index: 100;
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.setup-emoji-modal[hidden] { display: none; }
.setup-emoji-modal-inner { background: var(--site-bg-surface); border-radius: 20px; box-shadow: var(--shadow); width: min(520px, 100%); max-height: 80vh; display: flex; flex-direction: column; overflow: hidden; }
.setup-emoji-modal-head { display: flex; gap: 10px; padding: 16px; border-bottom: 1px solid rgba(18,58,102,.10); }
.setup-emoji-modal-head input { flex: 1; padding: 10px 14px; border: 2px solid rgba(18,58,102,.10); border-radius: 12px; font: inherit; background: #FFFFFF; color: #1A2634; }
.setup-emoji-modal-head button { border: none; background: var(--peach); color: #123A66; border-radius: 10px; padding: 0 14px; cursor: pointer; font-size: .95rem; }
.setup-emoji-modal-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(46px, 1fr)); gap: 6px; padding: 14px; overflow-y: auto; }

.setup-prompt-modal-inner { width: min(700px, 100%); }
.setup-prompt-modal-text { flex: 1; margin: 16px; padding: 12px 14px; border: 2px solid rgba(18,58,102,.10); border-radius: 12px; font: inherit; font-size: .88rem; line-height: 1.5; resize: vertical; background: var(--sky); color: #1A2634; }
.setup-prompt-modal-actions { display: flex; justify-content: flex-end; padding: 0 16px 16px; }

.setup-level-tabs-wrapper { margin-top: 10px; }
.setup-level-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.setup-level-tab { border: 2px solid var(--site-border-default); background: var(--site-bg-surface); border-radius: 999px; padding: 8px 16px; font-weight: 800; font-size: .85rem; color: var(--muted); cursor: pointer; }
.setup-level-tab.active { background: var(--navy); border-color: var(--navy); color: var(--site-text-inverse); }
.setup-level-panel[hidden] { display: none; }
.setup-emoji-option { background: var(--sky); border: none; border-radius: 10px; font-size: 1.4rem; padding: 8px 0; cursor: pointer; transition: transform .1s ease; }
.setup-emoji-option:hover { transform: scale(1.15); background: var(--sky-2); }

@media (max-width: 760px) {
  .setup-word-row { grid-template-columns: 1fr; text-align: left; }
  .setup-word-row-head { display: none; }
}

.setup-ai-btn { background: linear-gradient(180deg, #B98CE8, #8B5FD1); color: var(--site-text-inverse); box-shadow: 0 10px 22px rgba(139,95,209,.28); }
.setup-ai-btn:hover { color: var(--site-text-inverse); }
.setup-ai-btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }
.setup-ai-note { color: var(--muted); font-size: .82rem; font-weight: 700; margin: 0 0 12px; }
.setup-ai-note code { background: rgba(18,58,102,.06); padding: 1px 6px; border-radius: 6px; }
.setup-divider { border: none; border-top: 2px dashed var(--site-border-default); margin: 22px 0; }
.setup-hint-inline { font-weight: 500; color: var(--muted); font-size: 1rem; line-height: 1.5; }
.setup-cost-note { font-size: .8rem; color: var(--orange-dark); font-weight: 700; margin: 4px 0 0; }
.setup-select-all-row { margin: 0 0 8px; }
.setup-select-all-link {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--teal-dark); font-weight: 700; font-size: 0.9rem; text-decoration: underline;
}
.setup-select-all-link:hover { color: var(--teal); }
.setup-activity-list { display: grid; gap: 10px; margin-bottom: 18px; }
.setup-activity-row { display: flex; align-items: center; justify-content: space-between; gap: 14px; background: rgba(255,255,255,.7); border-radius: 14px; padding: 12px 16px; flex-wrap: wrap; }
/* .setup-activity-row keeps a fixed near-opaque white background in
   dark mode. Its title (a plain <strong>, no class of its own) just
   inherits color, so pinning it dark on the row fixes that; the
   reused .setup-hint-inline utility class sets its own color
   directly (inheritance can't override that), so it needs its own
   override too — scoped to this row so it doesn't leak into
   .setup-hint-inline's many other (correctly-themed) uses elsewhere
   on the page. Same light-bg/dark-text chip pattern as .pill-list. */
[data-theme="dark"] .setup-activity-row { color: #123A66; }
[data-theme="dark"] .setup-activity-info .setup-hint-inline { color: #52677A; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .setup-activity-row { color: #123A66; }
  :root:not([data-theme="light"]) .setup-activity-info .setup-hint-inline { color: #52677A; }
}
.setup-activity-info { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.setup-activity-actions { display: flex; gap: 8px; }
.setup-activity-actions form { margin: 0; }
.setup-mcq-level-counts { display: flex; gap: 14px; flex-wrap: wrap; margin: 0 0 16px; }
.setup-mcq-question-list { display: grid; gap: 14px; margin-bottom: 18px; }
.setup-mcq-question { padding: 16px; display: grid; gap: 10px; }
.setup-mcq-question .form { gap: 10px; }
.setup-mcq-question-list + h4, .setup-mcq-question .btn-row + form { margin-top: 0; }
.setup-mcq-option-row { display: flex; align-items: center; gap: 10px; }
.setup-mcq-option-row input[type="radio"] { width: auto; flex-shrink: 0; accent-color: var(--teal-dark); }
.setup-mcq-option-row input[type="text"] { flex: 1; }
.setup-ai-clipart { display: flex; flex-direction: column; gap: 10px; }
.setup-ai-clipart label { display: flex; flex-direction: column; gap: 4px; font-weight: 900; color: var(--navy); font-size: .88rem; }
.setup-ai-clipart input[type="text"], .setup-ai-clipart textarea, .setup-ai-clipart select {
  width: 100%; padding: 9px 10px; border: 2px solid rgba(18,58,102,.10); border-radius: 10px; font: inherit; box-sizing: border-box;
}
.setup-ai-clipart textarea { resize: vertical; min-height: 72px; }
.setup-ai-clipart-results { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
.setup-ai-clipart-option {
  background: var(--site-bg-surface); border-radius: 12px; padding: 10px; text-align: center;
  box-shadow: var(--soft-shadow); display: flex; flex-direction: column; gap: 8px; align-items: center;
}
.setup-ai-clipart-option img { width: 100%; border-radius: 8px; }
.setup-ai-clipart-option input[type="text"] { width: 100%; }
.setup-ai-clipart-checklist { display: flex; flex-direction: column; gap: 8px; text-align: left; width: 100%; margin: 4px 0; }
.setup-ai-clipart-checklist label { display: flex; flex-direction: row; align-items: flex-start; gap: 8px; font-weight: 700; font-size: .82rem; color: var(--navy); line-height: 1.35; white-space: normal; margin: 0; }
.setup-ai-clipart-checklist label input[type="checkbox"] { margin-top: 2px; flex-shrink: 0; }
.setup-ai-clipart-checklist-selectall {
  align-self: flex-start; border: none; background: none; color: var(--teal-dark, #0E7B87);
  font-weight: 800; font-size: .8rem; text-decoration: underline; cursor: pointer; padding: 0;
}

.reflection-journal-page { max-width: 720px; margin: 0 auto; }
.reflection-journal-cover { text-align: center; margin-bottom: 28px; }
.reflection-journal-cover h1 { margin-bottom: 6px; }
.reflection-journal-reference { color: var(--muted); font-weight: 700; margin-bottom: 18px; }
.reflection-journal-nametag { display: flex; justify-content: center; gap: 32px; font-weight: 700; color: var(--navy); }
.reflection-journal-clipart { display: flex; justify-content: center; gap: 16px; margin-bottom: 24px; flex-wrap: wrap; }
.reflection-journal-clipart img { max-width: 160px; max-height: 160px; }
.reflection-journal-question { margin-bottom: 30px; }
.reflection-journal-question-text { font-weight: 800; color: var(--navy); font-size: 1.1rem; margin-bottom: 10px; }
.reflection-journal-question-image { display: block; max-width: 200px; max-height: 200px; margin: 0 auto 12px; border-radius: var(--radius); }
.reflection-worksheet-image { display: block; width: 100%; height: auto; margin: 0 auto; border-radius: var(--radius); box-shadow: var(--shadow); }
.reflection-journal-lines { display: grid; gap: 48px; }
.reflection-journal-lines span { display: block; border-bottom: 2px solid rgba(18,58,102,.2); height: 1px; }

/* Worksheet Generator — a fixed-size, paper-shaped page (not a fluid
   webpage section) built from reusable components: worksheet-page,
   worksheet-header, worksheet-panel (= "activity panel"),
   worksheet-question-card, worksheet-answer-choice(-list),
   worksheet-answer-bubble. Every content type reuses the same pieces
   so worksheets stay visually consistent instead of being formatted
   one-off per activity type. Colour lives in panel headers, badges
   and borders only — the page itself stays white to keep this
   printer-ink-friendly. */
.worksheet-page-backdrop { background: #E7EAEE; padding: 36px 16px; margin: 0 -4vw; }
/* worksheet-print.php's PDF.js canvas preview — same visual language as
   .worksheet-page-backdrop above (grey tray, white page, drop shadow)
   but for <canvas> pages rather than the raw HTML template. Screen-only
   sizing; @media print overrides live inline in worksheet-print.php
   itself (page-specific @page rule, not shared across every page that
   loads this stylesheet — see that file's own comment). */
#worksheet-pdf-viewer { background: #E7EAEE; padding: 36px 16px; margin: 0 -4vw; }
.worksheet-pdf-page-canvas {
  display: block; width: 8.5in; max-width: 100%; height: auto;
  margin: 0 auto 24px; border-radius: 6px; box-shadow: 0 12px 34px rgba(18,58,102,.18);
}
.worksheet-page {
  width: 8.5in; max-width: 100%; min-height: 11in; margin: 0 auto; box-sizing: border-box;
  background: white; border-radius: 6px; box-shadow: 0 12px 34px rgba(18,58,102,.18);
  padding: 0.55in 0.5in; font-size: 15pt; line-height: 1.5;
  /* Containing block + stacking context for .worksheet-page-cover-img
     below (position:relative + an explicit z-index, so its negative
     z-index child stays contained here instead of escaping to affect
     unrelated page-level siblings like the border frame). */
  position: relative; z-index: 0;
}
/* Cover-page frame — the branded template PNG, printed only once at
   the top of the document. A real <img> element, NOT a CSS
   background-image on .worksheet-page itself: .worksheet-page uses
   box-decoration-break:clone in print (see below) so its OWN padding
   applies to every physical page it spans, but that property clones
   EVERYTHING about a box's decoration together — background included
   — so a background-image here would have started repeating on every
   page right along with the padding. An absolutely-positioned child
   image is a separate, independent paint: it renders once, sized to
   exactly one page, positioned wherever .worksheet-page's own top-left
   falls (page 1) — negative z-index tucks it behind the header/panels
   painted after it in the DOM. */
.worksheet-page-cover-img {
  position: absolute; top: 0; left: 0; z-index: -1;
  /* Matches .worksheet-page's own screen-mode box (8.5in wide, padding
     0.55in/0.5in) edge to edge. Print uses a different box entirely
     (@page's own 0.25in margin already insets the page, then
     .worksheet-page's print padding is only 0.3in) — sized separately
     below. Without this split, the screen-mode panel's own right edge
     (8.5in - 0.5in padding = 8in) landed exactly on top of this
     image's right edge when it was sized for print's narrower box,
     visibly colliding with the colorful border in the on-screen
     preview specifically (never in the actual PDF, which was already
     correctly using the print-only sizing). */
  width: 8.5in; height: 11in;
  pointer-events: none;
}
/* padding-top: screen-mode preview only (the real PDF always renders via
   headless Chrome's print media, so @media print's own .worksheet-header
   override below is what actually matters) — kept in the same ballpark
   as that print value rather than pixel-measured separately. */
.worksheet-header { text-align: center; margin-bottom: 10px; padding-top: 0.85in; }
/* Portrait's repeating pages-2+ background — same "position:fixed has no
   page boundaries on screen" reasoning as landscape's own version below,
   hidden here and shown only in @media print. Replaced the older
   border-frame + footer-band + page1-footer-restore 3-image system (a
   colorful border cropped to a repeating frame, a separate repeating
   footer strip, and a page-1-only patch to swap the footer strip for
   page 1's own distinct footer) now that the supplied background PNGs
   are complete, single full-bleed page designs with their own border and
   footer baked in — see .worksheet-page-landscape-bg's own comment for
   the full z-index mechanism this mirrors. */
.worksheet-page-portrait-bg { display: none; }
/* Landscape's repeating pages-2+ background — same "position:fixed has
   no page boundaries on screen" reasoning as .worksheet-page-portrait-bg
   above, hidden here and shown only in @media print (see there for the
   full mechanism and why the .worksheet-page-backdrop--landscape/
   .worksheet-page--landscape z-index promotion below it is needed). */
.worksheet-page-landscape-bg { display: none; }
/* One size down from the original 26pt — now that the title folds the
   surah name + ayah range in directly (e.g. "Surah Al-Fatihah Ayahs
   1-7 Worksheet"), 26pt wrapped a realistic title to a second line.
   white-space:nowrap makes that a hard guarantee rather than a
   size-dependent hope, since a title this long has no good second-line
   break point anyway. */
.worksheet-header h1 { font-size: 20pt; margin-bottom: 14px; white-space: nowrap; }

.worksheet-panel {
  border: 3px solid var(--navy); border-radius: 18px; overflow: hidden;
  margin: 0 0 16px; background: white; box-sizing: border-box;
  /* When a panel's content DOES span a page break (by design for panels
     with many items, or an oversized single grid even after the print
     break-inside:avoid rules above), each page's fragment gets its own
     complete, closed border/background instead of an open-ended one —
     the box visually "closes" at the bottom of one page and "reopens"
     fresh at the top of the next, rather than looking cut off. */
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
}
/* align-items:center, not baseline — the h2 here is itself a flex
   container (icon + text), and a flex container's own baseline
   (needed to align it against the plain instruction paragraph
   alongside it) doesn't reliably match its text's visual baseline,
   which showed up as "Trace It" sitting visibly lower than its own
   instruction text. center reliably matches both to the row's
   vertical middle regardless of internal layout. */
.worksheet-panel-header { padding: 7px 16px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.worksheet-panel-header h2 { margin: 0; font-size: 18pt; color: var(--navy); display: flex; align-items: center; gap: 8px; }
.worksheet-panel-icon { width: 20pt; height: 20pt; flex-shrink: 0; }
.worksheet-panel-hint { margin: 0; font-size: 13pt; font-weight: 700; color: var(--navy); opacity: .8; font-family: 'Nunito', 'Baloo 2', system-ui, sans-serif; }
.worksheet-panel-body { padding: 10px 16px 12px; }
/* Panel header colors — tinted (light-to-mid, not the fully saturated
   brand hex) versions of the four colors in the Deenscovery wordmark
   and cover template's border (teal, red-orange, green, gold), so
   navy header text/icons stay legible against every one, matching
   the existing pastel-not-saturated design intent. 'pink' had no
   logo counterpart at all and is now a gold tint instead; 'soft' (no
   real logo color left over) is a paler, distinct teal tint so all 5
   panel slots stay in the same brand family instead of introducing an
   unrelated hue. Item-number circles below pick up the same accent,
   one shade darker, per panel type — see .worksheet-panel-sky
   .worksheet-item-number etc. */
.worksheet-panel-sky .worksheet-panel-header { background: linear-gradient(180deg, #CDEEF2, #7FC8D2); }
.worksheet-panel-peach .worksheet-panel-header { background: linear-gradient(180deg, #FFDECB, #FFA97A); }
.worksheet-panel-sage .worksheet-panel-header { background: linear-gradient(180deg, #E1EFCB, #B4DC86); }
.worksheet-panel-pink .worksheet-panel-header { background: linear-gradient(180deg, #FFEAC0, #FFC968); }
.worksheet-panel-soft .worksheet-panel-header { background: linear-gradient(180deg, #E7F6F4, #BFE6E1); }
.worksheet-panel-sky .worksheet-item-number { background: #0D7589; }
.worksheet-panel-peach .worksheet-item-number { background: #E14F0E; }
.worksheet-panel-sage .worksheet-item-number { background: #3A7A10; }
.worksheet-panel-pink .worksheet-item-number { background: #C9820A; }
.worksheet-panel-soft .worksheet-item-number { background: #127C8C; }
.worksheet-panel-key { border-color: var(--muted); border-style: dashed; }
.worksheet-panel-key .worksheet-panel-header { background: #F2F4F7; }
.worksheet-panel-key h3 { color: var(--navy); margin: 14px 0 6px; font-size: 14pt; }
.worksheet-panel-key ol { padding-left: 22px; columns: 2; font-size: 14pt; }
.worksheet-panel-key bdi { font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 14pt; }

/* A self-contained question: prompt + its own answers never split
   across a page/column boundary — the whole point being fixed here. */
.worksheet-question-card {
  border: 2px solid rgba(18,58,102,.18); border-radius: 14px; background: var(--cream);
  padding: 10px 14px; margin: 0 0 10px; box-sizing: border-box;
}
.worksheet-question-card:last-child { margin-bottom: 0; }
/* minmax(0, 1fr), not plain 1fr — grid tracks default to a min size
   based on their content (same root cause as flexbox's min-width:auto)
   unless overridden, which let a wide Arabic-word card force its own
   column wider than intended in a narrow container (found via
   Milestone 2's archetype Renderer, where this same class now also
   nests inside a much narrower paired-column context). */
.worksheet-question-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; }
.worksheet-item-text {
  display: flex; align-items: baseline; gap: 10px; font-weight: 800; color: var(--navy); font-size: 16pt; margin: 0 0 8px;
  font-family: 'Nunito', 'Baloo 2', system-ui, sans-serif;
}
.worksheet-fillblank-line { border: 2px solid rgba(18,58,102,.18); border-radius: 14px; background: var(--cream); padding: 10px 14px; box-sizing: border-box; margin: 0 0 10px; }
.worksheet-fillblank-line:last-child { margin-bottom: 0; }
.worksheet-item-number {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 30px; height: 30px; border-radius: 50%; background: var(--navy); color: white;
  font-size: 13pt; font-weight: 900;
}
.worksheet-arabic-word { justify-content: center; text-align: center; }
.worksheet-arabic-prompt, .worksheet-arabic-word bdi {
  font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif;
  font-size: 30pt; line-height: 1.3;
}
.worksheet-word-emoji { font-family: 'Noto Emoji', sans-serif; font-size: 16pt; display: inline-block; vertical-align: middle; }

/* Answer choices: worksheet-template.php picks -row (3-across) vs the
   default stacked (full-width) layout per question based on the
   longest option's text length — short answers read fine in columns,
   long ones become unreadable narrow towers in a fixed-width column,
   so they get a full-width row each instead. Rootcovery's narrow
   two-column cards always use the stacked default regardless of
   length, since a 3-across row wouldn't fit a half-width card anyway.
   Never justify-content:space-between here — that pushes prompt/
   answers apart instead of keeping them grouped. */
.worksheet-answer-choice-list { display: flex; flex-direction: column; gap: 8px; }
.worksheet-answer-choice-list-row { flex-direction: row; flex-wrap: wrap; gap: 10px; }
.worksheet-answer-choice {
  display: flex; align-items: flex-start; gap: 8px; border: 2px solid rgba(18,58,102,.3);
  border-radius: 12px; padding: 6px 12px; background: white; box-sizing: border-box;
}
.worksheet-answer-choice-list-row .worksheet-answer-choice { flex: 1 1 190px; }
.worksheet-answer-bubble { width: 20px; height: 20px; margin-top: 2px; border: 2.5px solid var(--navy); border-radius: 50%; background: white; flex-shrink: 0; }
.worksheet-choice-label { font-weight: 900; color: var(--navy); font-size: 15pt; }
.worksheet-choice-text {
  font-weight: 700; color: var(--navy); font-size: 15pt; text-align: left;
  font-family: 'Nunito', 'Baloo 2', system-ui, sans-serif;
}
/* Long (stacked, full-width) English answers read better un-bolded — Arabic (bdi) stays bold regardless. */
.worksheet-answer-choice-list:not(.worksheet-answer-choice-list-row) .worksheet-choice-text:not(bdi) { font-weight: 500; }
bdi.worksheet-choice-text { font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 17pt; }

.worksheet-blank-line { display: inline-block; width: 140px; height: 3px; background: var(--navy); border-radius: 2px; margin: 0 6px; vertical-align: middle; }

/* grid-auto-flow:column + an explicit row count (set inline per group,
   since group size varies 5-10 — see worksheet-template.php) fills the
   word column top-to-bottom first, then the meaning column — so word
   #3 and meaning-slot #3 land in the SAME grid row. Grid's default
   align-items:stretch then makes both cells in that row match the
   taller one automatically (e.g. a 2-line meaning stretches its
   same-row word tile to match) — this is what actually solves "tile
   heights should match," not a fixed height, since any fixed value
   would either clip long meanings or add dead space around short
   ones. Before this, the word/meaning lists were two independent
   block-flow columns with no shared row tracks at all — any wrapped
   meaning line silently drifted the two columns out of alignment for
   every row below it, not just its own. */
.worksheet-matching-grid { display: grid; grid-template-columns: 1fr 1fr; grid-auto-flow: column; gap: 12px 30px; }
.worksheet-matching-row {
  display: flex; align-items: center; gap: 10px; border: 2px solid rgba(18,58,102,.25);
  border-radius: 12px; padding: 8px 14px; font-weight: 800; color: var(--navy); font-size: 15pt; background: white;
  box-sizing: border-box; height: 100%;
}
.worksheet-matching-row bdi { font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 17pt; }
.worksheet-blank-box { width: 26px; height: 26px; border: 2.5px solid var(--navy); border-radius: 8px; flex-shrink: 0; }
.worksheet-matching-badge {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 24px; height: 24px; border-radius: 50%; color: white; font-weight: 900; font-size: 12pt;
}
.worksheet-matching-badge-number { background: #0D7589; }
.worksheet-matching-badge-letter { background: #C9820A; }

.worksheet-matching-group + .worksheet-matching-group { margin-top: 20px; }
/* Only applied when there's more than one group (25+ words split into
   chunks of ~5-10, see WorksheetGenerator::chunkMatchingGroups()) — a
   dashed box makes each chunk read as one self-contained matching set
   instead of a continuation of the list above it, since a match can
   only ever be found within its own group. */
.worksheet-matching-group-boxed {
  border: 2.5px dashed rgba(18,58,102,.35); border-radius: 16px; padding: 14px 16px 4px;
}
.worksheet-matching-group-label {
  margin: 0 0 10px; font-size: 11pt; font-weight: 800; color: var(--navy);
  text-transform: uppercase; letter-spacing: .04em;
}
.worksheet-answer-key-group-label { margin: 10px 0 2px; font-size: 10pt; font-weight: 800; color: var(--navy); }

/* Word Search (Arabic + English) — one puzzle per ayah, grid sized by
   the frozen puzzle's own --ws-size custom property (see
   includes/ActivityEngine.php's BaseWordSearchEngine::buildPuzzle()). */
.worksheet-wordsearch-item { margin: 0 0 10px; }
.worksheet-wordsearch-item:last-child { margin-bottom: 0; }
.worksheet-wordsearch-ayah { font-weight: 800; color: var(--navy); font-size: 14pt; margin: 0 0 4px; font-family: 'Nunito', 'Baloo 2', system-ui, sans-serif; }
.worksheet-wordsearch-grid {
  display: grid; grid-template-columns: repeat(var(--ws-size), 1fr); gap: 3px;
  max-width: 5.2in; margin: 0 auto 10px;
}
.worksheet-wordsearch-cell {
  aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
  border: 1.5px solid rgba(18,58,102,.3); border-radius: 4px; font-weight: 700; color: var(--navy);
  font-size: clamp(8pt, calc(160pt / var(--ws-size)), 16pt);
}
.worksheet-wordsearch-cell-ar { font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; }
.worksheet-wordsearch-cell-en { font-family: 'Nunito', 'Baloo 2', system-ui, sans-serif; letter-spacing: 1px; }
.worksheet-wordsearch-words { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 10px 18px; justify-content: center; font-weight: 700; color: var(--navy); font-size: 13pt; }
.worksheet-wordsearch-words bdi { font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 16pt; }

/* Answer Key "solved" word search — see includes/worksheet-wordsearch-key-item.php.
   Reuses the student-facing grid/cell/word-list classes above for identical sizing
   and typography, plus an SVG overlay drawing one highlighter-style stroke per
   found word straight through its cells (coordinates computed server-side from
   BaseWordSearchEngine::buildGrid()'s own placement data — see that file). */
.worksheet-wordsearch-key-item { margin: 0 0 16px; }
.worksheet-wordsearch-key-item:last-child { margin-bottom: 0; }
.worksheet-wordsearch-grid-solved { position: relative; }
.worksheet-wordsearch-solved-overlay { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.worksheet-wordsearch-solved-overlay line { stroke: #F2A93B; stroke-width: .55; stroke-linecap: round; opacity: .6; }
.worksheet-wordsearch-words-solved .worksheet-wordsearch-word-found { text-decoration: line-through; text-decoration-color: #E14F0E; text-decoration-thickness: 2px; opacity: .65; }

/* Crossword — blank numbered grid (never the filled letters — that's
   the answer key's job, see .worksheet-panel-key). Sized by the
   frozen puzzle's own --cw-width; height is implicit from row count. */
.worksheet-crossword-grid {
  display: grid; grid-template-columns: repeat(var(--cw-width), 1fr); gap: 0;
  max-width: 6in; margin: 0 auto 18px; border: 2px solid var(--navy);
}
.worksheet-crossword-cell { aspect-ratio: 1; position: relative; border: 0.75px solid rgba(18,58,102,.35); background: white; }
.worksheet-crossword-cell-blocked { background: var(--navy); border-color: var(--navy); }
.worksheet-crossword-number { position: absolute; top: 1px; left: 2px; font-size: 6pt; font-weight: 800; color: var(--navy); line-height: 1; }
.worksheet-crossword-clues { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 24px; }
.worksheet-crossword-clues h3 { color: var(--navy); font-size: 13pt; margin: 0 0 8px; }
.worksheet-crossword-clues ol { padding-left: 20px; font-size: 12pt; font-weight: 700; color: var(--navy); margin: 0; }
.worksheet-crossword-clues li { margin-bottom: 6px; }
.worksheet-crossword-unplaced-note { margin: 0 20px 12px; padding: 8px 14px; background: var(--butter); border-radius: 10px; font-size: .85rem; font-weight: 700; color: var(--navy); }

/* Word Order — shuffled tiles with a blank box (.worksheet-blank-box,
   shared with Matchcovery) under each for the student to write the
   correct position number. */
.worksheet-ordering-item { margin: 0 0 22px; }
.worksheet-ordering-item:last-child { margin-bottom: 0; }
.worksheet-ordering-bank { display: flex; flex-wrap: wrap; gap: 16px; justify-content: center; }
.worksheet-ordering-tile { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.worksheet-ordering-tile bdi { font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif; font-size: 20pt; color: var(--navy); font-weight: 700; }

/* True or False — a pill per choice for the student to circle. */
.worksheet-truefalse-choices { display: flex; gap: 20px; margin-top: 4px; }
.worksheet-truefalse-choice { border: 2.5px solid var(--navy); border-radius: 999px; padding: 6px 22px; font-weight: 800; color: var(--navy); font-size: 14pt; }

/* Worksheet Generator picker — rough size estimate before printing. */
.worksheet-size-estimate { grid-column: 1 / -1; padding: 10px 16px; border-radius: 12px; background: var(--sky); color: var(--navy); font-weight: 700; font-size: .88rem; }
.worksheet-size-estimate-warning { background: #fdeeee; color: #9a3030; }

/* Illustrations (ayah_explainer clipart) — inline images, not their own
   page, grouped near the ayah they explain. These are line-art clipart
   meant to be colored in (a coloring-sheet use case), so a single image
   should genuinely fill most of the panel, not just grow part way —
   raised twice already (180px -> 420px -> 600px) after real renders
   kept showing significant unused space below the image; 7in height /
   90% width is close to the actual printable column, leaving just
   enough margin for the panel's own padding and the caption below. A
   real multi-image render still settles each one back down via
   max-width + flex-wrap once there's more than one to share the row. */
.worksheet-clipart-inline-grid { display: flex; flex-wrap: wrap; gap: 18px; justify-content: center; }
.worksheet-clipart-inline-item { margin: 0; text-align: center; flex: 1 1 320px; max-width: 90%; }
.worksheet-clipart-inline-item img { width: 100%; height: auto; max-height: 7in; object-fit: contain; border-radius: 12px; box-shadow: 0 4px 10px rgba(18,58,102,.12); }
.worksheet-clipart-inline-item figcaption { font-size: 11pt; font-weight: 700; color: var(--muted); margin-top: 6px; }
/* 7in above was only ever checked against portrait (11in-tall pages) —
   landscape pages are 8.5in tall TOTAL, so that same cap overflowed
   past the title/panel-header already sharing the page, pushing the
   whole image onto its own extra page. Confirmed via a real generated
   PDF (crown Illustration landing alone on page 3 of 4, panel left
   empty on page 2). Scoped down here for landscape specifically. */
.worksheet-page--landscape .worksheet-clipart-inline-item img { max-height: 4in; }

/* worksheet_page / reflection_page clipart — a complete pre-composed
   page, printed alone with no panel chrome around it (see @media
   print below for the page-break itself). Fixed-height box +
   object-fit:contain rather than max-width/max-height on the <img>
   alone — max-* only ever shrinks an oversized image, so a portrait
   AI-generated card (commonly 1024x1536, smaller than a Letter page
   at print resolution) rendered tiny in the middle of an otherwise
   blank page instead of filling it; this scales the image up or down
   as needed to fill the box while keeping its aspect ratio.
   Deliberately not display:flex — Chromium's print pagination
   (break-inside/break-before) interacts unpredictably with flex
   containers and was observed to split unrelated preceding content
   (the page header) once this box's height pushed the total past one
   page; object-fit:contain already centers the image within a block
   box on its own, so flex was never actually needed here. */
/* height was 9.3in before the repeating page-border frame (see
   .worksheet-page-border-frame) added a permanent top+bottom content
   inset to every page — reduced so this plus its own 24px margin
   still comfortably fits the new, slightly smaller ~9.9in-tall usable
   page budget. */
.worksheet-clipart-page { position: relative; text-align: center; margin: 0 0 24px; }
/* Ayah/type badges used to sit absolutely-positioned over the image's
   top corners, which emphasized the empty side gutters a portrait
   image leaves in this landscape-ish slot (see .worksheet-clipart-art-stage
   below). Moved into one plain row above the artwork instead — same
   pill styling, just no longer floating over image content. */
.worksheet-clipart-page-tags { display: flex; justify-content: center; gap: 12px; margin: 0 0 10px; }
.worksheet-clipart-page-ayah, .worksheet-clipart-page-label {
  display: inline-block; background: white; border: 2px solid var(--navy); border-radius: 999px;
  padding: 3px 14px; font-size: 11pt; font-weight: 800; color: var(--navy);
  font-family: 'Nunito', 'Baloo 2', system-ui, sans-serif;
}
/* A portrait (taller-than-wide) image inside this landscape-shaped slot
   can never fill the full width without either cropping or distorting
   it — object-fit:contain alone left bare white gutters on the sides
   (and nothing behind them to suggest that was intentional). Rendering
   the SAME image a second time as a blurred, barely-visible backdrop
   that covers the full slot fills those gutters with a soft echo of
   the artwork's own colors instead of stark white — the foreground
   image is untouched: still 100% visible, uncropped, undistorted. This
   degrades gracefully for a well-matched image too — if the picture
   already fills the slot, the backdrop is simply hidden behind it. */
.worksheet-clipart-art-stage { position: relative; overflow: hidden; border-radius: 6px; height: 8.3in; }
/* Real reflection/illustration art is pale/cream to begin with, so its
   own blurred average sits close to white already — at only 14%
   opacity the result was nearly indistinguishable from plain white
   (confirmed by sampling a real rendered PDF: ~4-9 RGB units off
   white, not visible on a printed page). .45 is close to the practical
   ceiling for this technique: even at 100% opacity the backdrop can
   never look more different from white than the source's own blurred
   average does, since that average IS the color being laid over white
   — so if this still reads too faint on a given asset, opacity alone
   can't fix it (a genuinely bold/saturated source is needed instead of
   more tuning here). */
.worksheet-clipart-backdrop {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; filter: blur(32px); opacity: .45; transform: scale(1.1);
}
.worksheet-clipart-main { position: relative; display: block; width: 100%; height: 100%; margin: 0 auto; object-fit: contain; }
/* The one right after the header (no Illustrations panel before it —
   see the break-before override below) gets a shorter box so it can
   actually fit on the same page as the header instead of forcing a
   break that strands the header alone; every later one starts fresh
   at the top of its own page and can use the full height above.
   6.7in (not the full 8.3in a header-less page gets) — measured via a
   real print render: the header (padding-top clearing the cover
   banner + the title, now 20pt after the earlier size-down) actually
   uses about 1.43in above this box, leaving ~7.27in before the
   footer-band clearance zone before the tags row's own ~0.4in; kept
   at 6.7in rather than the exact max as a small safety margin. A
   portrait image (the common case for a reflection/illustration page)
   is height-bound under object-fit:contain, so every inch reclaimed
   here scales it up directly instead of sitting unused below it. */
.worksheet-header + .worksheet-clipart-page .worksheet-clipart-art-stage { height: 6.7in; }

/* Trace It / Color It / Draw It — see includes/WorksheetCreativeRenderer.php.
   Every SVG it emits carries stroke/fill="currentColor", so color comes
   from here (matching .worksheet-panel-icon's own currentColor pattern),
   never hardcoded in PHP. overflow:visible is the sizing safety net
   described in that file's docblock — the viewBox width is a real but
   imperfect estimate, and content is allowed to extend slightly past it
   rather than ever clip.
   width:100% is Color It ONLY (word art SHOULD stretch to fill its box —
   see renderSvgText()'s word_art branch). Trace It's repeated small text
   uses --intrinsic instead: explicit width/height attributes (set in PHP,
   1 viewBox unit == 1px) render it at its own natural font-size on every
   repetition, never stretched to the panel's full width — found the hard
   way, width:100% on a small font-size in a ~7in-wide panel blew the text
   up far past its intended size and clipped into the panel border. */
.worksheet-trace-block { color: var(--navy); margin: 0 0 20px; }
.worksheet-trace-item { margin: 0 0 6px; }
.worksheet-trace-item--baseline { border-bottom: 2px solid rgba(18,58,102,.35); padding-bottom: 2px; }
.worksheet-trace-svg { display: block; width: 100%; height: auto; overflow: visible; }
.worksheet-trace-svg--intrinsic { width: auto; max-width: 100%; height: auto; margin: 0 auto; }
.worksheet-trace-entry + .worksheet-trace-entry { margin-top: 22px; padding-top: 18px; border-top: 1px dashed rgba(18,58,102,.25); }

.worksheet-wordart-grid { display: flex; flex-direction: column; gap: 28px; }
.worksheet-wordart-figure { margin: 0; color: var(--navy); text-align: center; }
/* max-height guards against a pathologically tall render (e.g. a very
   narrow print column), not a normal one — a correctly-sized word-art
   SVG's aspect ratio got noticeably less wide once its viewBox width was
   fixed to match real glyph measurement (WorksheetCreativeRenderer.php),
   so this cap must stay generous or it becomes the binding constraint
   and shrinks the word right back down. */
.worksheet-wordart-figure .worksheet-trace-svg { margin: 0 auto; }
/* Large vs Extra Large has to be a container-size difference, not a
   font-size one: the SVG's own viewBox is rewritten at render time
   (renderMeasurementScript()) to fit its real glyph bounds exactly, so
   both sizes end up with nearly the same aspect ratio and, at
   width:100% of an unconstrained container, rendered identically
   regardless of the font-size WorksheetCreativeRenderer::renderWordArtText()
   used to draw the glyphs — confirmed via a real render where "Large"
   and "Extra Large" produced pixel-identical output. These caps are
   what actually make the two sizes look different on the page. */
.worksheet-wordart-figure--large .worksheet-trace-svg { max-width: 68%; max-height: 3.2in; }
.worksheet-wordart-figure--xlarge .worksheet-trace-svg { max-width: 100%; max-height: 4.5in; }
.worksheet-wordart-instruction { margin: 10px 0 0; font-weight: 800; font-size: 13pt; color: var(--navy); font-family: 'Nunito', 'Baloo 2', system-ui, sans-serif; }

.worksheet-draw-entry { margin: 0 0 24px; }
.worksheet-draw-prompt { font-weight: 800; color: var(--navy); font-size: 1.1rem; margin: 0 0 10px; }
/* Same recipe as .reflection-journal-lines — deliberately a separate,
   new component rather than reusing that class directly, so nothing here
   risks touching Reflection Journal's own print-pagination-hardened
   markup (see the approved plan for why). */
.worksheet-response-lines { display: grid; gap: 48px; }
.worksheet-response-lines span { display: block; border-bottom: 2px solid rgba(18,58,102,.2); height: 1px; }
/* Trace It's "practice it yourself" lines sit directly under an already-tall
   repeated-tracing block, so they use a tighter gap than a full-page
   response area (Draw It, or reflection's own lines) needs. */
.worksheet-response-lines--sm { gap: 28px; }
.worksheet-response-box { border: 3px solid var(--navy); border-radius: 12px; box-sizing: border-box; }
.worksheet-response-box--sm { min-height: 1.6in; }
.worksheet-response-box--md { min-height: 2.6in; }
.worksheet-response-box--lg { min-height: 4in; }
.worksheet-response-box--grid {
  /* background-size is NOT optional here — found via a real print-to-pdf
     render during verification: without an explicit tile size, headless
     Chrome's print rasterizer silently dropped the second (90deg,
     vertical-line) gradient layer while still painting the first
     (0deg, horizontal) one, even though both rendered correctly on
     screen and even with !important forcing this exact rule to apply.
     Declaring the tile size explicitly (matching the gradients' own
     28px repeat period) made both layers rasterize identically. */
  background-image:
    repeating-linear-gradient(0deg, rgba(18,58,102,.12) 0, rgba(18,58,102,.12) 1px, transparent 1px, transparent 28px),
    repeating-linear-gradient(90deg, rgba(18,58,102,.12) 0, rgba(18,58,102,.12) 1px, transparent 1px, transparent 28px);
  background-size: 28px 28px;
}

/* Picker-only (worksheet-generator.php Step 2) — the fixed-3-row Trace
   It/Color It/Draw It entry fields, rows 2/3 collapsed behind <details>
   so the section doesn't present three large blank forms at once. */
.worksheet-creative-row { border: 1px solid rgba(18,58,102,.2); border-radius: 10px; padding: 12px 14px; margin: 0 0 12px; display: grid; gap: 8px; }
.worksheet-creative-more { margin: 0 0 12px; }
.worksheet-creative-more summary { cursor: pointer; font-weight: 700; color: var(--navy); margin-bottom: 8px; }
.worksheet-creative-more .worksheet-creative-row { margin: 0; }

/* Trace It/Color It word-chip picker — clickable real ayah words that
   populate the word/phrase field above, so a super_admin author isn't
   forced to hand-type Arabic. See renderAyahWordChips() in
   worksheet-generator.php and the click handler in its <script>. */
.worksheet-word-chip-picker { margin: 0 0 14px; padding: 10px 14px; background: var(--sky); border: 1px solid var(--border); border-radius: 14px; }
.worksheet-word-chip-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 6px 0; }
.worksheet-word-chip-ayah-label { font-size: 0.78rem; font-weight: 700; color: var(--muted); min-width: 56px; }
.worksheet-word-chip {
  font-family: 'Scheherazade New', 'Amiri Quran', 'Traditional Arabic', serif;
  font-size: 1.1rem;
  direction: rtl;
  background: var(--teal);
  color: #fff;
  border: none;
  border-radius: 999px;
  padding: 4px 14px;
  cursor: pointer;
  transition: background-color .15s ease;
}
.worksheet-word-chip:hover,
.worksheet-word-chip:focus-visible { background: var(--teal-dark); }

/* Page orientation segmented control — see worksheet-generator.php's
   "2. Title & Options" form and orientation handling in
   includes/worksheet-template.php. */
.worksheet-orientation-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: 999px; padding: 3px; background: var(--sky); width: fit-content; }
.worksheet-orientation-option { display: flex; align-items: center; gap: 6px; padding: 6px 16px; border-radius: 999px; font-weight: 700; color: var(--navy); cursor: pointer; }
.worksheet-orientation-option:has(input:checked) { background: var(--teal); color: #fff; }
.worksheet-orientation-option input[type="radio"] { accent-color: var(--teal-dark); }

@media print {
  /* Shared print reset for every printable page (worksheet + reflection).
     body::before is the site's fixed decorative star row — fixed
     elements repeat on every printed page, so it must be hidden or it
     stamps stars across the middle of each sheet. */
  .no-print, header, footer, nav { display: none !important; }
  body::before, body::after { content: none !important; display: none !important; }
  body { background: white !important; }
  main { padding: 0 !important; margin: 0 !important; overflow: visible !important; }
  .section { padding: 0 !important; margin: 0 !important; max-width: none !important; }
  /* Deliberately NOT break-inside:avoid on the whole question (text+lines)
     anymore — that forced every line to move together, so a question that
     ran out of room after only 2-3 lines pushed ALL 6 lines to a fresh
     page, leaving the rest of the current page blank. Glue only the
     question text to its first line (same header/first-child pattern used
     elsewhere) and let the remaining lines flow naturally — they'll fill
     whatever room is actually left on the current page, then continue
     seamlessly at the top of the next one. */
  .reflection-journal-question-text { break-after: avoid-page; }
  .reflection-journal-lines > *:first-child { break-before: avoid-page; }

  /* 0.25in — close to the safe minimum most printers can actually
     print to; keeping the physical page-edge-to-border gap tight is
     the whole point of the border existing at all. */
  @page {
    size: letter portrait; margin: 0.25in;
    /* Page numbers — a genuine, well-supported subset of CSS Paged
       Media in Chromium's print engine (confirmed via an isolated
       repro), unlike the arbitrary-image @page margin-box content
       tried and abandoned elsewhere in this file. counter(page)/
       counter(pages) aren't available to ordinary position:fixed
       content (that trick is how the repeating border/footer work
       instead) — this is the only mechanism that actually knows which
       physical page it's on. Applies to every printed document sharing
       this stylesheet, not just worksheets — a reasonable shared
       default, not a worksheet-only overlay. */
    @bottom-right {
      content: "Page " counter(page) " of " counter(pages);
      font-family: 'Nunito', 'Baloo 2', system-ui, sans-serif;
      font-size: 9pt; font-weight: 700; color: #123A66;
    }
  }
  /* transparent + z-index promoted so the full-bleed background image
     below (.worksheet-page-portrait-bg) shows through wherever real
     content doesn't paint over it — same mechanism as landscape's own
     .worksheet-page-backdrop--landscape, see its comment for the full
     reasoning. position:relative (no stacking-context z-index of its
     own) so .worksheet-page's negative-z-index cover-img still gets a
     real containing block here rather than falling through to
     .worksheet-page's own z:0-trapped stacking context. */
  .worksheet-page-backdrop { background: transparent !important; padding: 0 !important; margin: 0 !important; position: relative; z-index: 2; }
  .worksheet-page {
    width: auto; min-height: 0; max-width: none; margin: 0;
    background: transparent !important;
    /* Reasonable initial safe-area padding — the background PNG bakes in
       its own decorative border, this just keeps real content off it.
       Same values as landscape's own first-pass safe-area padding
       (.worksheet-page--landscape below); tune visually against the
       actual portrait template if a real render shows it's too tight
       or too generous. */
    padding: 0.35in 0.35in 0.85in;
    box-shadow: none; border-radius: 0;
    /* Without this, padding (like border/background) only applies to
       a fragmented box's very first and very last physical-page slice
       by default (box-decoration-break: slice) — every page in
       between starts flush with zero top inset. clone makes every one
       of .worksheet-page's page-fragments get its own full padding,
       top and bottom, matching .worksheet-panel's existing use of the
       same property for the same reason. */
    box-decoration-break: clone; -webkit-box-decoration-break: clone;
  }
  /* Page 1 only (the header is the first element in the flow, never
     repeats) — clears the cover template's baked-in Name/Grade/Date
     band. Not pixel-measured against the new template; tune visually
     if a real render shows content starting too high/low. */
  .worksheet-header { padding-top: 0.5in; }
  .worksheet-page-cover-img { width: 8.5in; height: 11in; }
  /* Portrait pages 2+ background — same "real <img> child, not a
     background-image" + position:fixed per-physical-page repeat as
     landscape's own .worksheet-page-landscape-bg below (Chromium only
     repeats a fixed element's own rendered DOM content across physical
     pages, confirmed empirically there). z-index:1 so it beats
     .worksheet-page-backdrop's default stacking and is actually
     visible, sitting below the backdrop (z:2, see above) so real
     content still paints on top of it. Width/height come from
     $pageDimensions inline in worksheet-template.php. */
  .worksheet-page-portrait-bg {
    display: block; position: fixed; top: 0; left: 0;
    pointer-events: none; z-index: 1;
  }
  .worksheet-page-portrait-bg img { width: 100%; height: 100%; display: block; }
  /* Landscape pages 2+ background — same mechanism as
     .worksheet-page-portrait-bg above, own $pageDimensions sizing. */
  .worksheet-page-landscape-bg {
    display: block; position: fixed; top: 0; left: 0;
    pointer-events: none; z-index: 1;
  }
  .worksheet-page-landscape-bg img { width: 100%; height: 100%; display: block; }
  /* Both orientations' backgrounds are genuine full-bleed images real
     content sits ON TOP of everywhere on the page, not just at the
     edges — so the whole backdrop+page subtree is promoted above the
     background image's z-index (see .worksheet-page-backdrop above)
     and both go transparent so the image actually shows through
     wherever real content doesn't paint over it. Landscape needs its
     own copy of this promotion since .worksheet-page--landscape uses a
     different selector than the bare .worksheet-page rule above. */
  .worksheet-page-backdrop--landscape { background: transparent !important; z-index: 2; }
  /* Reasonable initial safe-area padding — the background PNGs bake in
     their own decorative border, this just keeps real content off it.
     Tune visually against the actual templates if needed; not
     re-derived from pixel measurement. */
  .worksheet-page--landscape {
    background: transparent !important;
    padding: 0.35in 0.35in 0.85in;
  }
  /* Page 1 only (the header is the first element in the flow, never
     repeats) — clears the landscape template's Name/Grade/Date band.
     2in was calibrated against an earlier version of the page-1
     template that had a tall logo block above the band; the current
     template's divider sits close to the top, so a real render with
     2in left most of page 1 empty and pushed all real content to page
     2. Cut down to a modest gap below the divider instead. */
  .worksheet-page--landscape .worksheet-header { padding-top: 0.5in; }
  .worksheet-panel, .worksheet-panel-header, .worksheet-question-card, .worksheet-fillblank-line,
  .worksheet-answer-choice, .worksheet-answer-bubble, .worksheet-matching-row, .worksheet-matching-badge,
  .worksheet-item-number {
    print-color-adjust: exact; -webkit-print-color-adjust: exact;
  }
  /* Deliberately NOT break-inside:avoid on .worksheet-panel itself —
     panels routinely run taller than one page (e.g. 12 MCQ
     questions), and a browser asked to avoid splitting a box that
     can't possibly fit on the current OR the next page pushes the
     whole thing to a fresh page anyway, wasting all the remaining
     space on the page before it (this is exactly what produced an
     almost-empty first page). Question-cards are the right atomic
     unit to protect instead — small enough to always fit within one
     page, so avoid-page on them actually holds. */
  /* break-after:avoid alone wasn't strong enough — Chromium happily
     printed a header alone at the bottom of a page (trivially
     satisfying "don't break right after me" when nothing follows on
     that page at all), stranding it away from its own body on the
     next page. Gluing both sides of the boundary with the fuller
     avoid-page value forces the header AND the body's first child to
     move together — if they can't both fit, the whole pairing moves
     to the next page instead, which is what "keep a heading with its
     content" actually requires. */
  /* break-after alone doesn't stop a break happening INSIDE the header
     itself — with a hint line under the title (every panel has one),
     the print engine could fit just the <h2> on the current page and
     push the hint paragraph down with the body's first child, stranding
     the title alone above a mostly-empty panel shell (confirmed via a
     real render: a Matchcovery panel whose first group didn't fit left
     "Matchcovery" sitting on its own atop a big empty gradient box, with
     the hint text and Group 1 both starting fresh on the next page).
     break-inside:avoid keeps the whole header atomic, so it can only
     ever move as a unit — combined with break-after below, the header
     and the body's first child are forced to move together as one. */
  .worksheet-panel-header { break-after: avoid-page; break-inside: avoid; }
  .worksheet-panel-body > *:first-child { break-before: avoid-page; }
  .worksheet-question-card { break-inside: avoid; }
  .worksheet-fillblank-line { break-inside: avoid; }
  .worksheet-matching-row { break-inside: avoid; }
  .worksheet-matching-group { break-inside: avoid; }
  .worksheet-wordsearch-item { break-inside: avoid; }
  .worksheet-trace-entry { break-inside: avoid; }
  .worksheet-wordart-figure { break-inside: avoid; }
  .worksheet-draw-entry { break-inside: avoid; }
  /* Word search's header+first-child glue above isn't enough on its own:
     .worksheet-wordsearch-item is tall (a big grid can run 6+ inches),
     and per the .worksheet-panel comment above, a browser asked to avoid
     splitting a box that doesn't fit the CURRENT remaining space pushes
     just that box to a fresh page — leaving the header it was "glued" to
     behind, since the header itself already fit where it was and had no
     independent reason to move. Confirmed on a real generated PDF: header
     stranded with a near-empty box, grid alone atop the next page.
     Word search panels are safe to treat as one atomic break-avoid unit
     (unlike MCQ/Fill-blank/etc.) because buildWordSearchPrintPuzzles()/
     buildWordSearchEnPrintPuzzles() always freeze to exactly ONE combined
     puzzle per panel now — never the many-items case the general panel
     comment is protecting against. */
  .worksheet-panel:has(.worksheet-wordsearch-item) { break-inside: avoid; }
  /* Deliberately its own class, not .worksheet-wordsearch-item — the Answer Key
     panel mixes many item types together (MCQ, Fill-blank, ..., solved word
     search grids), unlike a dedicated word-search panel's one-puzzle-only
     assumption above, so it must NOT also trip the :has() rule just above and
     make the whole mixed panel a single unbreakable unit. */
  .worksheet-wordsearch-key-item { break-inside: avoid; }
  .worksheet-clipart-inline-item { break-inside: avoid; }
  .worksheet-crossword-grid { break-inside: avoid; }
  .worksheet-crossword-clues h3 { break-after: avoid; }
  .worksheet-crossword-clues li { break-inside: avoid; }
  .worksheet-ordering-item { break-inside: avoid; }
  .worksheet-panel-key { break-before: page; }
  /* Answer Key runs in two CSS columns (see .worksheet-panel-key ol
     above) — without this, a list item can split mid-entry across
     the column break the same way it could across a page break, and
     a sub-heading ("Multiple Choice", "Matchcovery", ...) can end up
     alone at the bottom of a column separated from its own list. */
  .worksheet-panel-key li { break-inside: avoid; }
  .worksheet-panel-key h3 { break-after: avoid; }
  .worksheet-clipart-page { break-before: page; break-inside: avoid; margin: 0; }
  /* ...unless it's the very first thing after the header (no
     Illustrations panel rendered before it, e.g. only worksheet_page/
     reflection_page clipart was picked, no ayah_explainer) — forcing
     a break there stranded the header alone on an otherwise-blank
     first page instead of starting content immediately under it. */
  .worksheet-header + .worksheet-clipart-page { break-before: avoid; }

  /* A complete worksheet image (is_worksheet) must never orphan onto
     a page by itself leaving the previous page nearly empty — cap it
     so a compact cover + the image share one Letter page. */
  .reflection-worksheet-image { max-height: 7.4in; width: auto; max-width: 100%; box-shadow: none; margin: 0 auto; }
  .reflection-journal-question + .reflection-journal-question .reflection-worksheet-image { max-height: 9in; }
  .reflection-journal-question:has(.reflection-worksheet-image) + .reflection-journal-question:has(.reflection-worksheet-image) { page-break-before: always; }
}

.nav-link-button {
  appearance: none;
  background: none;
  border: 0;
  color: inherit;
  cursor: pointer;
  font: inherit;
  padding: 0;
}
.site-nav .nav-link-button {
  color: var(--site-header-text);
  padding: 11px 16px;
  border-radius: 999px;
  font-weight: 900;
}
.site-nav .nav-link-button:hover,
.site-nav .nav-link-button:focus-visible {
  background: var(--site-header-active-bg);
  color: var(--site-header-active-text);
}

/* Homepage revamp (2026-09) — Sign In as a distinct right-hand CTA
   pill. NOTE: .site-nav a:last-child (below) does NOT match here —
   the .theme-toggle <button> is the true last DOM child of .site-nav
   (confirmed by testing), so that selector never applies to any
   anchor in the logged-out header. Styled directly instead. */
.site-nav a.nav-signin {
  background: linear-gradient(180deg, #24B8C7, var(--teal-dark));
  color: var(--site-text-inverse);
  padding: 12px 22px;
  box-shadow: 0 8px 18px rgba(21,157,170,.24);
}
.site-nav a.nav-signin:hover { color: var(--site-text-inverse); }

/* Homepage revamp (2026-09) — "One ayah. More ways to understand it."
   concept row: one row on desktop, a compact 2x2 grid on mobile
   instead of four tall stacked rows. */
.home-concepts { padding-top: 30px; padding-bottom: 30px; }
.home-concepts-grid { display: flex; justify-content: center; gap: 18px; margin-top: 18px; flex-wrap: wrap; }
.home-concept {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  background: var(--site-bg-surface); border-radius: 18px; padding: 16px 26px;
  box-shadow: var(--soft-shadow); font-weight: 900; color: var(--navy); min-width: 110px;
}
.home-concept-icon { font-size: 1.8rem; }
@media (max-width: 560px) {
  .home-concepts-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
  .home-concept { min-width: 0; }
}

/* Ayah explainer illustrations inside the Simple Explanation card:
   a horizontal row of cards (wrapping on narrow screens), each image
   with its caption overlaid bottom-centre on a navy band so it reads
   on any artwork, in either theme. */
.explanation-clipart-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 14px; margin: 0 0 16px; }
.explanation-clipart-card {
  position: relative; flex: 1 1 220px; max-width: 320px; margin: 0;
  border-radius: 16px; overflow: hidden; background: var(--site-bg-surface, #fff);
  box-shadow: 0 8px 22px rgba(18, 58, 102, .14);
}
.explanation-clipart-card .explanation-clipart { display: block; width: 100%; height: 240px; object-fit: cover; margin: 0; border-radius: 0; }
.explanation-clipart-caption {
  position: absolute; left: 0; right: 0; bottom: 0; margin: 0;
  padding: 26px 12px 10px; text-align: center;
  font-size: .95rem; font-weight: 800; line-height: 1.3; color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .45);
  background: linear-gradient(180deg, rgba(18, 58, 102, 0), rgba(18, 58, 102, .88) 45%);
}
@media (max-width: 560px) {
  .explanation-clipart-card { flex-basis: 100%; max-width: 100%; }
  .explanation-clipart-card .explanation-clipart { height: 200px; }
}
/* Legacy single-image rule, still used where no card wraps the image. */
.explanation-clipart { display: block; max-width: 100%; max-height: 360px; height: auto; margin: 0 auto 14px; border-radius: 16px; }

/* Rich-text editor (admin) + rendered rich text (student). */
.re-wrap { border: 2px solid rgba(0,0,0,.08); border-radius: 16px; background: #fff; overflow: hidden; }
.re-toolbar { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px; background: rgba(0,0,0,.04); border-bottom: 1px solid rgba(0,0,0,.08); }
.re-btn { border: 0; border-radius: 10px; background: #fff; color: var(--navy); font: inherit; font-weight: 900; padding: 6px 12px; cursor: pointer; box-shadow: 0 1px 3px rgba(0,0,0,.12); }
.re-btn:hover { background: var(--orange-dark, #f7931e); color: #fff; }
.re-b { font-weight: 900; } .re-i { font-style: italic; } .re-u { text-decoration: underline; }
.re-area { min-height: 180px; padding: 14px 18px; line-height: 1.8; font-size: 1.05rem; outline: none; }
.re-area:focus { box-shadow: inset 0 0 0 2px var(--orange-dark, #f7931e); }
.re-area p, .explanation-rich p { margin: 0 0 .8em; }
.re-area ul, .re-area ol, .explanation-rich ul, .explanation-rich ol { margin: 0 0 .8em 1.4em; padding: 0; }
.re-area h3, .explanation-rich h3 { margin: .6em 0 .3em; }
.explanation-rich > :last-child { margin-bottom: 0; }
.explanation-rich li { margin-bottom: .35em; }
/* Level 4 extras on quran.php: Tafsir Summary under the explanation and
   the original (Pickthall) translation under the leveled translation. */
.tafsir-summary, .original-translation { margin-top: 16px; padding-top: 14px; border-top: 1px dashed rgba(31, 45, 77, .25); }
/* No divider when the leveled text above it isn't approved yet. */
.explanation-title + .tafsir-summary, .translation-title + .original-translation { margin-top: 0; padding-top: 0; border-top: 0; }
.tafsir-summary-title { margin: 0 0 6px; font-size: 1.05rem; color: inherit; }
.original-translation-title { margin: 0 0 6px; font-size: 1.05rem; font-weight: 900; color: var(--navy); }
.original-translation-source { margin-left: 6px; font-size: .8rem; font-weight: 700; opacity: .75; }
.original-translation-text { margin: 0; font-size: 1.05rem; font-weight: 600; line-height: 1.6; color: var(--teal-dark); }

/* Keyword colours for important words in tafsir (RICH_TEXT_KEYWORD_CLASSES).
   Dark shades by default: the editor and the student explanation card stay
   light in every theme. Only the app-shell explanation card turns dark, so
   it gets the light shades. All pairs are at least 4.5:1. */
:root { --kw-red: #B42318; --kw-green: #176B2C; --kw-blue: #1D4ED8; --kw-purple: #6D28D9; --kw-brown: #8A4B12; }
.kw-red { color: var(--kw-red); font-weight: 800; }
.kw-green { color: var(--kw-green); font-weight: 800; }
.kw-blue { color: var(--kw-blue); font-weight: 800; }
.kw-purple { color: var(--kw-purple); font-weight: 800; }
.kw-brown { color: var(--kw-brown); font-weight: 800; }
[data-theme="dark"] .app-shell .explanation-rich { --kw-red: #FF9B8F; --kw-green: #7EDC9B; --kw-blue: #9DC2FF; --kw-purple: #CDB6FF; --kw-brown: #E8B98A; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .app-shell .explanation-rich { --kw-red: #FF9B8F; --kw-green: #7EDC9B; --kw-blue: #9DC2FF; --kw-purple: #CDB6FF; --kw-brown: #E8B98A; }
}

.re-s { text-decoration: line-through; }
.re-group { display: inline-flex; align-items: center; gap: 4px; padding: 0 6px; border-left: 1px solid rgba(0,0,0,.12); }
.re-glabel { font-weight: 900; color: var(--navy); padding-right: 2px; }
.re-swatch { width: 22px; height: 22px; padding: 0; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0,0,0,.25); cursor: pointer; }
.re-swatch-none { background: #fff; color: #555; font-weight: 900; line-height: 1; font-size: .95rem; }

/* Surah/Ayah pickers on Setup Surah: centred, near full-height list over a light dim. */
.combo-backdrop { position: fixed; inset: 0; z-index: 59; background: rgba(18,58,102,.28); }
.combo-backdrop[hidden] { display: none; }
.combo-wrap:focus-within { z-index: 61; }
