/* OrbitLab learning-portal layout: navbar, sidebar, hero, cards, topic detail,
   simulations. Loaded after theme.css and explore.css (reuses .viz, .search-*,
   .audio, .term-tip from explore.css). */

body[data-page] {
  background: var(--app-bg);
  font-size: var(--fs-body);
}

/* ---------------- deep-space field (parallax) ----------------
   Three star layers and a nebula wash, all fixed behind the content. portal.js
   writes the scroll offset to --scroll-y once per frame and each layer takes a
   different fraction of it, so the near stars drift while the far ones sit
   almost still - the same cue that makes a real sky look deep from a moving
   car. Everything here is decorative: markup is aria-hidden, the layers are
   pointer-events:none, and the whole field freezes under reduced motion. */
.starfield {
  position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
  contain: strict;
}
.star-layer {
  position: absolute; inset: -10% -10% -20%;
  display: block;
  background-repeat: repeat;
  transform: translate3d(0, calc(var(--scroll-y, 0px) * var(--rate, 0.04)), 0);
  will-change: transform;
}
/* Star tiles are hand-placed radial dots on a large tile so the repeat never
   reads as a pattern. Sizes differ per layer to suggest distance. */
.star-layer--far {
  --rate: 0.03;
  opacity: 0.5;
  background-image:
    radial-gradient(1px 1px at 12% 18%, #fff, transparent),
    radial-gradient(1px 1px at 63% 7%, #d9d5ff, transparent),
    radial-gradient(1px 1px at 84% 41%, #fff, transparent),
    radial-gradient(1px 1px at 27% 62%, #cfe9ff, transparent),
    radial-gradient(1px 1px at 47% 88%, #fff, transparent),
    radial-gradient(1px 1px at 92% 73%, #e4defd, transparent),
    radial-gradient(1px 1px at 8% 92%, #fff, transparent),
    radial-gradient(1px 1px at 71% 55%, #fff, transparent);
  background-size: 620px 620px;
}
.star-layer--mid {
  --rate: 0.07;
  opacity: 0.62;
  background-image:
    radial-gradient(1.4px 1.4px at 22% 31%, #fff, transparent),
    radial-gradient(1.4px 1.4px at 78% 12%, #ffd9e4, transparent),
    radial-gradient(1.4px 1.4px at 55% 71%, #fff, transparent),
    radial-gradient(1.4px 1.4px at 9% 66%, #c9fff6, transparent),
    radial-gradient(1.4px 1.4px at 88% 89%, #fff, transparent);
  background-size: 880px 880px;
}
.star-layer--near {
  --rate: 0.13;
  opacity: 0.75;
  background-image:
    radial-gradient(2px 2px at 34% 24%, #fff, transparent),
    radial-gradient(2px 2px at 81% 58%, #ffe3ec, transparent),
    radial-gradient(2px 2px at 14% 83%, #d5fff8, transparent);
  background-size: 1240px 1240px;
}
/* The two emission lines as a barely-there wash - the colour the palette is
   named after, at an alpha that never touches text contrast. The rgba pair is
   the below-baseline fallback for the color-mix() version that follows (C7). */
.starfield::after {
  content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(900px 520px at 82% -8%, rgba(255, 92, 134, 0.16), transparent 68%),
    radial-gradient(760px 480px at 6% 22%, rgba(70, 224, 213, 0.11), transparent 70%);
  background:
    radial-gradient(900px 520px at 82% -8%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 68%),
    radial-gradient(760px 480px at 6% 22%, color-mix(in srgb, var(--accent-2) 11%, transparent), transparent 70%);
}
/* Light theme: the field would be noise on paper, so only the faintest wash
   survives and the stars are dropped entirely. */
[data-theme="light"] .star-layer { display: none; }
[data-theme="light"] .starfield::after { opacity: 0.55; }

/* Content sits above the field. (The navbar and the offline banner set their
   own position/z-index below and already clear it.) */
.portal-shell, .portal-footer { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  .star-layer { transform: none; will-change: auto; }
}

/* ---------------- offline banner (Req 10.6) ---------------- */
/* Persistent indicator shown while the connection is lost. portal.js toggles
   the [hidden] attribute on the online/offline events. */
.offline-banner {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 10px 16px;
  font-size: 13.5px; font-weight: 600;
  color: #04121a;
  background: #ffc55c;
  border-top: 1px solid color-mix(in srgb, #ffc55c 70%, #000);
  box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.28);
}
.offline-banner[hidden] { display: none; }
.offline-banner-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: #b45309; flex-shrink: 0;
}

/* ---------------- navbar ----------------
   An instrument bar, not a marketing header: a hairline strip carrying the
   wordmark, the five ways into the material, and the reading controls. The nine
   topic destinations that used to live here moved to the sidebar index and the
   dashboard - a top bar is for choosing a mode of study, not for browsing a
   catalogue, and nine items never fitted on a phone anyway. */
.navbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 18px;
  padding: 9px 24px; border-bottom: 1px solid var(--border);
  background: var(--app-bg);
  background: color-mix(in srgb, var(--app-bg) 82%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
}
.nav-brand {
  display: flex; align-items: center; gap: 10px; text-decoration: none;
  color: var(--text); font-family: var(--font-display); font-size: 19px;
  font-weight: 600; letter-spacing: -0.015em; white-space: nowrap;
  font-variation-settings: "opsz" 48, "SOFT" 0, "WONK" 1;
}
.nav-brand .logo { display: inline-flex; }
/* The mark's orbit line traces on load, once - the site drawing its own logo. */
.nav-brand .logo .logo-orbit {
  stroke-dasharray: 92; stroke-dashoffset: 92;
  animation: traceOrbit 1.4s var(--ease-out) 0.15s forwards;
}
@keyframes traceOrbit { to { stroke-dashoffset: 0; } }
.nav-brand-text b { color: var(--accent); font-weight: 600; }
.nav-links { display: flex; gap: 2px; margin-inline-start: 14px; flex: 1; }
/* Navigation is prose, not instrumentation: these are the body face, sentence
   case. Setting them in tracked uppercase mono looked handsome and made
   "Arab & Islamic Astronomy" 200px wide, which is how a five-item bar turns
   into three wrapped rows. Mono stays where it earns its width - measurements
   and field labels. */
.nav-links a {
  position: relative; white-space: nowrap;
  color: var(--muted); text-decoration: none;
  font-size: 13.5px; font-weight: 500;
  padding: 8px 11px; border-radius: 7px;
  transition: color var(--t-med) ease, background var(--t-med) ease;
}
/* The spectral rule marks the current section - and only ever that. It wipes in
   from the inline start, so it reads as an underline being drawn under the word
   in both writing directions. */
.nav-links a::after {
  content: ""; position: absolute; inset-inline: 11px; bottom: 2px; height: 2px;
  border-radius: 2px; background: var(--spectral);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--t-med) var(--ease-out);
}
/* transform-origin takes no logical keyword, so RTL flips it explicitly. */
html[dir="rtl"] .nav-links a::after { transform-origin: right; }
.nav-links a:hover { color: var(--text-soft); background: var(--panel); background: color-mix(in srgb, var(--panel) 70%, transparent); }
.nav-links a.active { color: var(--text); }
.nav-links a.active::after, .nav-links a:hover::after { transform: scaleX(1); }

.nav-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; font-size: 15px; cursor: pointer;
  background: var(--panel-2);
  background: color-mix(in srgb, var(--panel-2) 70%, transparent);
  border: 1px solid var(--border); border-radius: 10px; color: var(--text-soft);
}
.icon-btn:hover { border-color: var(--accent-2); color: var(--text); }
.nav-sim {
  color: var(--accent-2); text-decoration: none;
  font-family: var(--font-mono); font-size: 11.5px; font-weight: 500;
  letter-spacing: 0.09em; text-transform: uppercase;
  white-space: nowrap; padding: 0 4px;
}
html[lang="ar"] .nav-sim { text-transform: none; letter-spacing: 0; font-size: 13px; }
.nav-toggle { display: none; flex-direction: column; gap: 4px; width: 38px; height: 36px; background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px; cursor: pointer; align-items: center; justify-content: center; }
.nav-toggle span { display: block; width: 16px; height: 2px; background: var(--text); border-radius: 2px; }

/* ---------------- shell + sidebar ---------------- */
.portal-shell { display: flex; max-width: 1340px; margin: 0 auto; }
.portal-sidebar {
  width: 236px; flex-shrink: 0; align-self: flex-start;
  /* Desktop sticky sidebar offset is derived from the rendered navbar height
     (H5/AC 5.3): portal.js measures .navbar and writes its px height to the
     --nav-h custom property, so the sidebar stays aligned when the navbar wraps
     on narrow-but-wide viewports. The 57px fallback keeps it correct before JS
     runs (and if the navbar is absent). */
  position: sticky; top: var(--nav-h, 57px); max-height: calc(100vh - var(--nav-h, 57px)); overflow-y: auto;
  padding: 22px 10px 40px; border-right: 1px solid var(--border);
}
/* The sidebar is the catalogue: group headings are instrument labels with a
   rule running out to the edge, entries are quiet until they are where you are. */
.portal-sidebar .side-grp {
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.16em; color: var(--muted);
  margin: 22px 0 8px; padding-inline-start: 12px;
  display: flex; align-items: center; gap: 10px;
}
.portal-sidebar .side-grp::after {
  content: ""; flex: 1; height: 1px; background: var(--rule);
}
html[lang="ar"] .portal-sidebar .side-grp { text-transform: none; letter-spacing: 0; font-size: 12px; }
.portal-sidebar ul { list-style: none; margin: 0; padding: 0; }
.portal-sidebar a {
  position: relative;
  display: block; padding: 7px 12px; margin: 1px 0; border-radius: 7px;
  color: var(--muted); text-decoration: none; font-size: 14px;
  transition: color var(--t-med) ease, background var(--t-med) ease;
}
/* A tick in the margin, filled only for the current page. */
.portal-sidebar a::before {
  content: ""; position: absolute; inset-inline-start: 2px; top: 50%;
  width: 2px; height: 0; margin-top: -1px; border-radius: 2px;
  background: var(--accent);
  transition: height var(--t-med) var(--ease-out), margin-top var(--t-med) var(--ease-out);
}
.portal-sidebar a:hover { color: var(--text-soft); background: var(--panel); background: color-mix(in srgb, var(--panel) 60%, transparent); }
.portal-sidebar a.active { color: var(--text); background: var(--panel); font-weight: 700; }
.portal-sidebar a.active::before { height: 18px; margin-top: -9px; }

.portal-main { flex: 1; min-width: 0; max-width: 1020px; padding: 30px 38px 84px; }
.portal-footer { border-top: 1px solid var(--rule); padding: 26px 34px 40px; color: var(--muted); font-size: 13px; text-align: center; }
.portal-footer p { max-width: 760px; margin: 0 auto; line-height: 1.7; }

/* ---------------- breadcrumbs + sections ---------------- */
.crumbs {
  font-family: var(--font-mono); font-size: 12px; color: var(--muted);
  margin: 0 0 22px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.crumbs a { color: var(--accent-2); text-decoration: none; }
.crumbs a:hover { text-decoration: underline; }

/* Section headings carry a short spectral rule above them: the same mark as the
   active nav item, so "where you are" always looks the same. */
.section-title {
  font-size: var(--fs-h2); margin: 52px 0 8px; padding-top: 14px;
  position: relative;
}
.section-title::before {
  content: ""; position: absolute; top: 0; inset-inline-start: 0;
  width: 44px; height: 2px; border-radius: 2px; background: var(--spectral);
}
.section-sub { color: var(--muted); font-size: var(--fs-sm); margin: 0 0 22px; max-width: 66ch; line-height: 1.6; }
.eyebrow {
  font-family: var(--font-mono); font-size: var(--fs-label); font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.16em;
  color: var(--accent-2); margin: 0 0 12px;
}
html[lang="ar"] .eyebrow { text-transform: none; letter-spacing: 0; font-size: 13px; font-weight: 600; }

/* ---------------- hero ---------------- */
.hero { margin-bottom: 14px; }
.hero h1 { font-size: var(--fs-h1); line-height: 1.08; margin: 0 0 14px; }
.hero .lead { font-size: 17.5px; color: var(--text-soft); max-width: 58ch; margin: 0 0 22px; line-height: 1.6; }
.hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }

/* ---------------- observation deck (dashboard hero) ----------------
   The homepage opens on the one thing only an astronomy site can open on: the
   sky that is actually overhead, right now, where the reader is. The headline
   sits over a slow orrery of orbit rings that drift with the scroll. */
.hero-dashboard {
  position: relative; overflow: hidden; isolation: isolate;
  padding: 64px 40px 52px; border-radius: var(--r-xl);
  border: 1px solid var(--border);
  /* Opaque fallback first: below-baseline browsers ignore the color-mix()
     background below and keep this solid gradient so the hero tint renders (C7). */
  background: linear-gradient(155deg, var(--panel), var(--app-bg));
  background:
    radial-gradient(760px 340px at 88% -30%, color-mix(in srgb, var(--accent) 26%, transparent), transparent 68%),
    radial-gradient(620px 320px at -10% 120%, color-mix(in srgb, var(--accent-2) 18%, transparent), transparent 70%),
    linear-gradient(155deg, var(--panel), var(--app-bg));
  margin-bottom: 12px;
}
.hero-dashboard .hero-body { position: relative; z-index: 2; max-width: 40ch; }
.hero-dashboard h1 {
  font-size: var(--fs-hero); line-height: 1.02; margin: 0 0 18px;
  font-variation-settings: "opsz" 144, "SOFT" 0, "WONK" 1;
}
.hero-dashboard .lead { max-width: 46ch; }

/* Orrery: concentric inclined rings with a lit body on each. Decorative, so the
   markup is aria-hidden; it drifts with --scroll-y and stops for reduced motion. */
.hero-orrery {
  position: absolute; z-index: 1; inset-block: -30% -30%; inset-inline-end: -14%;
  width: min(620px, 78%); pointer-events: none;
  display: grid; place-items: center;
  transform: translate3d(0, calc(var(--scroll-y, 0px) * -0.06), 0);
}
.orrery-ring {
  grid-area: 1 / 1; display: block;
  width: var(--d); height: var(--d); border-radius: 50%;
  border: 1px solid rgba(70, 224, 213, 0.34);
  border-color: color-mix(in srgb, var(--accent-2) 34%, transparent);
  transform: rotateX(74deg) rotateZ(var(--tilt, 0deg));
  animation: orreryTurn var(--period, 90s) linear infinite;
}
.orrery-ring::after {
  content: ""; position: absolute; top: -3px; left: calc(50% - 3px);
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--dot, var(--accent));
  box-shadow: 0 0 14px 2px var(--dot, var(--accent));
}
.orrery-ring { position: relative; }
.orrery-ring--1 { --d: 46%; --period: 42s; --tilt: 12deg; --dot: var(--accent); }
.orrery-ring--2 {
  --d: 70%; --period: 78s; --tilt: -8deg; --dot: var(--accent-2);
  border-color: rgba(255, 92, 134, 0.26);
  border-color: color-mix(in srgb, var(--accent) 26%, transparent);
}
.orrery-ring--3 {
  --d: 96%; --period: 140s; --tilt: 22deg; --dot: var(--history-accent-line);
  border-color: rgba(236, 234, 255, 0.12);
  border-color: color-mix(in srgb, var(--text) 12%, transparent);
}
@keyframes orreryTurn {
  from { transform: rotateX(74deg) rotateZ(var(--tilt, 0deg)); }
  to   { transform: rotateX(74deg) rotateZ(calc(var(--tilt, 0deg) + 360deg)); }
}

.hero-topic { display: grid; grid-template-columns: 1fr; gap: 22px; padding: 8px 0 18px; }
.hero-topic .eyebrow { color: var(--c, var(--accent)); }
.hero-sim .viz { aspect-ratio: 16 / 9; }

@media (prefers-reduced-motion: reduce) {
  .hero-orrery { transform: none; }
  .orrery-ring { animation: none; }
  .nav-brand .logo .logo-orbit { animation: none; stroke-dashoffset: 0; }
}

/* ---------------- dashboard grids ---------------- */
.domain-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 16px; }
.domain-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 22px 22px 20px; border-radius: var(--r-lg); text-decoration: none;
  background: var(--panel);
  border: 1px solid var(--border);
  border-top: 2px solid var(--c, var(--accent));
  transition: transform 0.15s ease, border-color 0.15s ease;
}
.domain-card:hover { transform: translateY(-3px); border-color: var(--c, var(--accent)); }
.domain-icon { font-size: 26px; display: block; color: var(--c, var(--accent)); }
.domain-card h3 { margin: 0; font-size: var(--fs-h3); color: var(--text); }
.domain-card p { margin: 0; font-size: var(--fs-sm); color: var(--muted); line-height: 1.62; flex: 1; }

/* ---------------- the distance ladder ----------------
   The four destination cards are not an arbitrary grid: they are rungs on one
   logarithmic distance axis, from eight light-minutes to two and a half million
   light-years. Each card carries its real distance and a marker showing where it
   falls on the shared scale, so the row teaches the single hardest idea in
   beginner astronomy - how much emptier space gets as you go out - before the
   reader has clicked anything. --pos is the card's log position, authored in the
   template alongside the figure it represents. */
.ladder { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }
.ladder .domain-card { padding-bottom: 16px; }
.domain-scale {
  display: block; position: relative; height: 1px; margin-top: 14px;
  background: var(--rule);
}
.domain-scale::before {
  content: ""; position: absolute; top: -3px; inset-inline-start: var(--pos, 0%);
  width: 7px; height: 7px; margin-inline-start: -3px; border-radius: 50%;
  background: var(--c, var(--accent));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--c, var(--accent)) 22%, transparent);
}
/* The travelled part of the axis, so the eye reads inline-start to inline-end as
   "further". The per-card --c means the fallback has to be the solid accent
   itself rather than an rgba literal (C7). */
.domain-scale::after {
  content: ""; position: absolute; inset-block: 0; inset-inline-start: 0;
  width: var(--pos, 0%);
  background: var(--c, var(--accent));
  background: color-mix(in srgb, var(--c, var(--accent)) 55%, transparent);
}
.domain-dist {
  font-family: var(--font-mono); font-size: 12px; font-weight: 500;
  font-variant-numeric: tabular-nums; color: var(--text-soft);
  margin-top: 10px; display: block; line-height: 1.4;
}
.ladder-axis {
  display: flex; justify-content: space-between; gap: 12px;
  margin: 10px 2px 0;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted);
}
html[lang="ar"] .ladder-axis { text-transform: none; letter-spacing: 0; font-size: 12px; }

/* learning paths */
.paths-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px; }
.path-card { padding: 18px; border-radius: 14px; background: var(--panel); border: 1px solid var(--border); border-inline-start: 4px solid var(--c, var(--accent)); }
.path-card h3 { margin: 0 0 7px; font-size: 16px; display: flex; align-items: center; gap: 8px; }
.path-card p { margin: 0 0 12px; font-size: 13px; color: var(--muted); }
.path-steps { list-style: none; margin: 0; padding: 0; }
.path-steps li { margin: 0; }
.path-steps a { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 7px; color: var(--text-soft); text-decoration: none; font-size: 13.5px; }
.path-steps a:hover { background: var(--panel-2); color: var(--text); }
.path-steps .step-dot { width: 18px; height: 18px; flex-shrink: 0; border-radius: 50%; border: 2px solid var(--c, var(--accent)); display: inline-flex; align-items: center; justify-content: center; font-size: 10px; color: var(--c, var(--accent)); }
.path-steps .step-dot .svg-icon { width: 12px; height: 12px; }
.path-steps a.done .step-dot { background: var(--c, var(--accent)); color: #04121a; }
.path-progress { height: 6px; border-radius: 3px; background: var(--panel-2); overflow: hidden; margin-bottom: 12px; }
.path-progress > span { display: block; height: 100%; background: var(--grad-accent); border-radius: 3px; transition: width 0.9s var(--ease-out); }

/* continue widget */
.continue { margin: 30px 0; }
.continue-body { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }

/* ---------------- link-card grid (planets / dwarfs) ---------------- */
.link-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; }
.link-card {
  display: flex; align-items: center; gap: 12px; padding: 14px; border-radius: 13px;
  text-decoration: none; background: var(--panel); border: 1px solid var(--border);
  transition: transform 0.15s ease, border-color 0.15s ease;
}
.link-card:hover { transform: translateY(-2px); border-color: var(--accent-2); }
.link-card .planet-dot { width: 34px; height: 34px; flex: none; }
/* The title and its subtitle are two bare <span>s inside a wrapper span, so
   without an explicit box they ran together as one word: "المريخصخري" for
   "Mars" + "rocky". Stacking them is the fix - the gap is what separates the
   name from what kind of thing it is. */
.link-card > span:not(.planet-dot) {
  display: flex; flex-direction: column; gap: 3px; min-width: 0;
}
.link-card .lc-title { display: block; font-size: 15px; font-weight: 700; line-height: 1.35; color: var(--text); }
.link-card .lc-sub { display: block; font-size: 12.5px; line-height: 1.5; color: var(--muted); }

/* ---------------- progress stats + achievements (dashboard) ---------------- */
.stats-panel { margin: 24px 0 30px; padding: 20px 22px; background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-lg); }
.stats-tiles { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 14px; }
.stat-tile { flex: 1; min-width: 110px; text-align: center; background: var(--panel-2); border-radius: var(--r-md); padding: 14px 10px; }
.stat-num {
  display: block; font-family: var(--font-mono); font-size: 30px; font-weight: 500;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
  color: var(--accent); line-height: 1.1;
}
.stat-label {
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.12em; color: var(--muted);
}
html[lang="ar"] .stat-label { text-transform: none; letter-spacing: 0; font-size: 12px; }
.stat-sub { display: block; margin-top: 4px; font-size: 11.5px; font-weight: 700; color: var(--accent-2); letter-spacing: 0.3px; }
.badges-block { margin-top: 4px; }
.badges-summary { margin: 0 0 8px; font-size: 12px; color: var(--muted); }
.badges-row { display: flex; flex-wrap: wrap; gap: 8px; }
.badge-chip {
  display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px;
  padding: 5px 11px; border-radius: 999px; border: 1px solid var(--border);
  background: var(--panel-2); color: var(--muted); opacity: 0.55; filter: grayscale(1);
}
.badge-chip.got { opacity: 1; filter: none; color: var(--text); border-color: var(--accent); background: var(--panel-2); background: color-mix(in srgb, var(--accent) 14%, var(--panel-2)); }

/* assessment scores list (Req 9.4) */
.assess-scores { margin-top: 16px; }
.assess-title { font-size: 13px; font-weight: 700; margin: 0 0 8px; color: var(--text); }
.assess-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.assess-item {
  display: flex; align-items: center; gap: 10px; padding: 7px 11px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 9px; font-size: 12.5px;
}
.assess-item .assess-id { flex: 1; color: var(--text); text-transform: capitalize; }
.assess-item .assess-score { color: var(--muted); font-variant-numeric: tabular-nums; }
.assess-item .assess-pct { font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums; min-width: 44px; text-align: end; }
.assess-item.passed { border-color: var(--accent); }
.assess-item.passed .assess-pct { color: var(--accent); }

/* ---------------- learning-path cards (extra states) ---------------- */
.path-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.path-level {
  flex-shrink: 0; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.6px;
  padding: 3px 8px; border-radius: 999px; background: var(--panel-2); color: var(--accent-2); border: 1px solid var(--border);
}
.path-card.complete { border-color: var(--c, var(--accent)); box-shadow: 0 0 0 1px var(--c, var(--accent)); }
.path-done { font-size: 13px; font-weight: 600; color: var(--c, var(--accent)); margin: 0 0 10px; }
.path-steps a.locked { opacity: 0.55; }
.path-steps a.locked .step-dot { border-color: var(--muted); color: var(--muted); }

/* ---------------- "Your guide" panel (Req 14.1/14.2/14.5/14.6) ---------------- */
/* A deterministic guidance card above the module grid: a progress summary, the
   next-best lesson CTA, "revisit" chips for failed-quiz lessons, and a learner-
   confirmed reading-band suggestion. Uses the brass/gold history accent. */
.guide-panel {
  margin: 0 0 22px; padding: 16px 18px; border-radius: 14px;
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--history-accent, #c9a227);
  background: color-mix(in srgb, var(--history-accent, #c9a227) 8%, var(--panel));
}
.guide-title {
  display: flex; align-items: center; gap: 8px; margin: 0 0 6px;
  font-size: 15px; color: var(--history-accent-line, #e6c25a);
}
.guide-title svg { width: 18px; height: 18px; }
.guide-summary { margin: 0 0 12px; font-size: 13.5px; color: var(--text-soft); }
.guide-next {
  display: inline-flex; flex-direction: column; align-items: flex-start; gap: 2px;
  color: var(--history-accent-ink, #1b1200); background: var(--history-accent, #c9a227);
  border: 1px solid transparent; text-decoration: none;
}
.guide-next-label { font-weight: 700; font-size: 14px; }
.guide-next-lesson { font-size: 12px; opacity: 0.85; }
.guide-done { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 13.5px; color: var(--good); }
.guide-done svg { width: 16px; height: 16px; }
.guide-gaps { margin-top: 14px; }
.guide-gaps-label { display: block; font-size: 11.5px; color: var(--muted); margin-bottom: 6px; }
.revisit-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.revisit-chip {
  display: inline-flex; align-items: center; gap: 5px; font-size: 12px;
  padding: 4px 10px; border-radius: 999px; border: 1px solid var(--border);
  background: var(--panel-2); color: var(--text-soft); text-decoration: none;
}
.revisit-chip svg { width: 13px; height: 13px; flex-shrink: 0; }
.revisit-chip:hover { border-color: var(--history-accent, #c9a227); }
.guide-band {
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--rule);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px;
}
.guide-band-msg { margin: 0; font-size: 13px; color: var(--text-soft); }
.guide-band-actions { display: flex; gap: 8px; }
.guide-band-actions .btn { font-size: 13px; padding: 7px 12px; }

/* ---------------- history course hub: module cards ---------------- */
/* The 10-module grid on /history. Cards mirror the .path-card idiom (panel +
   border + brass/gold inline-start accent) so the hub reads as a designed grid,
   not raw links. The whole card is a single link. */
.module-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px;
}
.module-card {
  border-radius: 14px; background: var(--panel); border: 1px solid var(--border);
  border-inline-start: 4px solid var(--c, var(--history-accent, #c9a227));
  transition: transform var(--t-fast) var(--ease-out), box-shadow var(--t-med) var(--ease-out),
              border-color var(--t-med) ease;
}
.module-card:hover { transform: translateY(-2px); box-shadow: 0 8px 26px var(--shadow); }
.module-card-link {
  display: block; padding: 16px 18px; color: inherit; text-decoration: none; height: 100%;
}
.module-card-head { display: flex; align-items: flex-start; gap: 12px; }
.module-ordinal {
  flex-shrink: 0; width: 34px; height: 34px; border-radius: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 16px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--history-accent-ink, #1b1200); background: var(--c, var(--history-accent, #c9a227));
}
.module-card-titles { flex: 1; min-width: 0; }
.module-card-titles h3 { margin: 0 0 6px; font-size: 16px; color: var(--text); line-height: 1.3; }
.module-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.module-count { font-size: 12px; color: var(--muted); }
.module-desc { margin: 12px 0 0; font-size: 13px; color: var(--text-soft); line-height: 1.62; }
.module-done { display: flex; align-items: center; gap: 6px; margin: 12px 0 0; font-size: 13px; font-weight: 600; color: var(--good); }
.module-done svg { width: 15px; height: 15px; }
/* Completion ring (shared .ring primitive), tinted to the module accent. */
.module-card .module-ring { flex-shrink: 0; }
.module-card .module-ring .ring-track { stroke: color-mix(in srgb, var(--c, var(--history-accent, #c9a227)) 20%, var(--panel-2)); }
.module-card .module-ring .ring-fill { stroke: var(--c, var(--history-accent, #c9a227)); }
.module-card .module-ring .ring-label { font-size: 12px; color: var(--history-accent-line, #e6c25a); }
.module-card.complete { border-color: var(--c, var(--history-accent, #c9a227)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c, var(--history-accent, #c9a227)) 40%, transparent); }
.module-card.complete .module-ring .ring-fill { stroke: var(--good); }
.module-card.complete .module-ring .ring-label { color: var(--good); }
/* Difficulty chip (levelChip() emits .module-level). */
.module-level {
  flex-shrink: 0; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.6px;
  padding: 3px 8px; border-radius: 999px; background: var(--panel-2); color: var(--history-accent-line, #e6c25a);
  border: 1px solid var(--border);
}

/* ---------------- history course hub: soft-locked modules (A.3.1) ---------------- */
/* A locked module card is greyed but still navigable (soft lock): the link stays
   active so direct lesson URLs keep working. */
.module-card.locked { opacity: 0.72; }
.module-card.locked .module-card-link { filter: grayscale(0.4); }
.module-lock {
  display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.5px; color: var(--muted);
  padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border); background: var(--panel-2);
}
.module-lock svg { width: 13px; height: 13px; }
.module-prereqs { margin: 10px 0 2px; }
.module-prereqs-label { display: block; font-size: 11.5px; color: var(--muted); margin-bottom: 6px; }
.prereq-chips { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.prereq-chip {
  display: inline-flex; align-items: center; gap: 5px; font-size: 12px;
  padding: 4px 10px; border-radius: 999px; border: 1px solid var(--border);
  background: var(--panel-2); color: var(--muted);
}
.prereq-chip svg { width: 13px; height: 13px; flex-shrink: 0; }

/* ---------------- history lesson soft-lock notice (Req 2.6 / A.3.1) ---------------- */
.lesson-lock-notice {
  display: flex; align-items: flex-start; gap: 12px; margin: 0 0 20px;
  padding: 13px 15px; border-radius: 12px; border: 1px solid var(--border);
  background: color-mix(in srgb, var(--accent) 8%, var(--panel));
  border-inline-start: 3px solid var(--accent);
}
.lesson-lock-icon { flex-shrink: 0; color: var(--accent); margin-top: 2px; }
.lesson-lock-icon svg { width: 20px; height: 20px; }
.lesson-lock-body { flex: 1; min-width: 0; }
.lesson-lock-body strong { display: block; font-size: 14.5px; color: var(--text); margin-bottom: 3px; }
.lesson-lock-body p { margin: 0; font-size: 13px; color: var(--muted); }
.lesson-lock-dismiss {
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0; border-radius: 8px; cursor: pointer;
  background: transparent; border: 1px solid transparent; color: var(--muted);
}
.lesson-lock-dismiss:hover { background: var(--panel-2); color: var(--text); }
.lesson-lock-dismiss svg { width: 16px; height: 16px; }

/* ---------------- observatory hotspot panorama (design A.3.4, Req 5.4/12.1) ---------------- */
/* A layered illustrated panorama with keyboard-tabbable dot buttons; each opens
   a caption card. The stage is position:relative so hotspots place by --x/--y
   (percentages of the image box). Interaction is progressive: the artwork and
   dots render without JS; course.js wires open/close. */
.observatory-panorama { margin: 0; }
.panorama-hint { margin: 0 0 10px; font-size: 13px; color: var(--muted); }
.panorama-stage {
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--panel-2);
  line-height: 0;
}
.panorama-img { display: block; width: 100%; height: auto; }
/* Themed fallback tile when the illustration is missing, so the stage is never
   empty and hotspots still have a surface to sit on. */
.panorama-img--fallback {
  aspect-ratio: 16 / 9;
  height: auto;
  background:
    radial-gradient(120% 120% at 50% 10%, color-mix(in srgb, var(--c, #c9a227) 45%, transparent), transparent 60%),
    linear-gradient(160deg, var(--panel-2), var(--panel));
}

/* A hotspot: a wrapper absolutely positioned at (--x, --y); the dot is centred
   on that point and its caption card floats above it. */
.hotspot {
  position: absolute;
  left: var(--x, 50%);
  top: var(--y, 50%);
  transform: translate(-50%, -50%);
  line-height: normal;
}
.hotspot-dot {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0;
  border-radius: 999px; cursor: pointer;
  color: var(--history-accent-ink, #1b1200); background: var(--history-accent, #c9a227);
  border: 2px solid #fff8e6;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
  font-size: 14px; font-weight: 700;
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.hotspot-dot:hover { transform: scale(1.12); }
/* Visible focus indicator on keyboard focus (Req 12.4/12.7). */
.hotspot-dot:focus-visible {
  outline: 3px solid var(--focus, #7c9cff);
  outline-offset: 2px;
}
.hotspot-num { pointer-events: none; }
.hotspot.is-open .hotspot-dot {
  transform: scale(1.12);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--history-accent, #c9a227) 45%, transparent);
}

/* The caption card: hidden until its dot is activated (native [hidden]). It sits
   above the dot and is width-constrained so long captions wrap. */
.hotspot-card {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 10px);
  transform: translateX(-50%);
  width: max-content;
  max-width: min(260px, 70vw);
  z-index: 3;
  padding: 11px 13px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--panel);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
  text-align: start;
}
.hotspot-card[hidden] { display: none; }
.hotspot-card-title { margin: 0 0 4px; font-size: 13.5px; font-weight: 700; color: var(--text); }
.hotspot-card-caption { margin: 0; font-size: 12.5px; line-height: 1.5; color: var(--muted); }
.panorama-credit { margin: 8px 2px 0; font-size: 11.5px; color: var(--muted); line-height: 1.4; }

/* Respect reduced motion: no dot scale/transition animations. */
@media (prefers-reduced-motion: reduce) {
  .hotspot-dot { transition: none; }
  .hotspot-dot:hover, .hotspot.is-open .hotspot-dot { transform: translate(0, 0); }
}

/* ---------------- quiz ("Check yourself") ---------------- */
.quiz-section { border-inline-start: 3px solid var(--accent); }
.quiz-intro { font-size: 13.5px; color: var(--muted); margin: 0 0 14px; }
.quiz-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 18px; }
.quiz-prompt { font-size: 15px; font-weight: 600; margin: 0 0 9px; }
.quiz-choices { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 8px; }
.quiz-choice {
  text-align: left; font-family: inherit; font-size: 14px; cursor: pointer;
  background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  border-radius: 9px; padding: 10px 13px; transition: border-color 0.12s ease, background 0.12s ease;
}
.quiz-choice:hover:not(:disabled) { border-color: var(--accent); }
.quiz-choice:disabled { cursor: default; }
.quiz-choice.correct { border-color: #5cf2a0; background: rgba(92, 242, 160, 0.16); color: #d6ffe8; }
.quiz-choice.incorrect { border-color: #ff6b6b; background: rgba(255, 107, 107, 0.16); color: #ffd9d9; }
.quiz-explain { font-size: 13.5px; margin: 9px 0 0; padding: 9px 12px; border-radius: 8px; background: var(--panel-2); color: var(--text-soft); }
.quiz-explain.ok { border-left: 3px solid #5cf2a0; }
.quiz-explain.no { border-left: 3px solid #ff6b6b; }
.quiz-result { margin-top: 16px; padding: 12px 16px; border-radius: 10px; background: var(--panel-2); display: flex; align-items: center; gap: 12px; flex-wrap: wrap; font-size: 14.5px; }
.quiz-result.passed { background: color-mix(in srgb, #5cf2a0 16%, var(--panel-2)); }
.quiz-result strong { font-size: 17px; color: var(--accent); }
.quiz-retry { margin-left: auto; padding: 7px 14px; }

/* ---------------- activities: order (timeline ordering) ---------------- */
/* Logical properties throughout; the list is vertical so move up/down is
   direction-agnostic and RTL-safe. */
.activity-section { border-inline-start: 3px solid var(--accent); }
.activity-prompt { font-size: 15px; font-weight: 600; margin: 0 0 6px; }
.activity-instr { font-size: 13px; color: var(--muted); margin: 0 0 14px; }
.order-list { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.order-chip {
  display: flex; align-items: center; gap: 10px;
  background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  border-radius: 10px; padding: 10px 12px; cursor: grab;
  transition: border-color 0.12s ease, background 0.12s ease, box-shadow 0.12s ease;
}
.order-chip:hover { border-color: var(--accent); }
.order-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.order-chip.is-grabbed { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent); background: color-mix(in srgb, var(--accent) 10%, var(--panel-2)); }
.order-chip.is-dragging { opacity: 0.6; cursor: grabbing; }
.order-chip.is-correct { border-color: #5cf2a0; background: rgba(92, 242, 160, 0.16); }
.order-chip.is-incorrect { border-color: #ff6b6b; background: rgba(255, 107, 107, 0.14); }
.order-chip-index { flex: 0 0 auto; min-width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; background: var(--panel); border: 1px solid var(--border); font-size: 12px; font-weight: 700; color: var(--accent); }
.order-chip-label { flex: 1 1 auto; font-size: 14px; }
.order-chip-controls { flex: 0 0 auto; display: inline-flex; gap: 4px; }
.order-move {
  width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 12px; cursor: pointer; color: var(--text);
  background: var(--panel); border: 1px solid var(--border); border-radius: 7px;
  transition: border-color 0.12s ease, background 0.12s ease;
}
.order-move:hover:not(:disabled) { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.order-move:disabled { opacity: 0.4; cursor: default; }
.order-move:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.activity-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.activity-feedback { margin: 12px 0 0; padding: 9px 12px; border-radius: 8px; background: var(--panel-2); color: var(--text-soft); font-size: 13.5px; }
.activity-feedback.ok { border-inline-start: 3px solid #5cf2a0; }
.activity-feedback.no { border-inline-start: 3px solid #ff6b6b; }
/* Visually hidden live region (announcements for assistive tech only). */
.activity-live { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }

/* `match` (pair) activity - "Make the matches". Each row pairs a fixed prompt on
   the start side with a <select> of shuffled options; grading paints the row
   green/correct or red/incorrect with a ✓/✗ mark. Mirrors the .order-chip
   language (panel-2 rows, accent focus, semantic pass/fail colours). */
.match-list { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.match-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1.1fr) 20px;
  align-items: center; gap: 10px;
  padding: 9px 12px; border-radius: 10px; background: var(--panel-2); border: 1px solid var(--border);
  transition: border-color var(--t-med) ease, background var(--t-med) ease;
}
.match-left { font-size: 14px; font-weight: 600; color: var(--text); min-width: 0; }
.match-connector { color: var(--muted); display: inline-flex; align-items: center; }
.match-connector svg { width: 16px; height: 16px; }
.match-select {
  font-family: inherit; font-size: 14px; color: var(--text); background: var(--panel);
  border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; width: 100%; min-width: 0; cursor: pointer;
  transition: border-color var(--t-med) ease;
}
.match-select:hover { border-color: var(--accent); }
.match-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.match-select:disabled { opacity: 0.75; cursor: default; }
.match-mark { justify-self: center; font-weight: 800; font-size: 15px; line-height: 1; }
.match-row.is-correct { border-color: #5cf2a0; background: rgba(92, 242, 160, 0.14); }
.match-row.is-correct .match-mark { color: #5cf2a0; }
.match-row.is-incorrect { border-color: #ff6b6b; background: rgba(255, 107, 107, 0.12); }
.match-row.is-incorrect .match-mark { color: #ff6b6b; }
/* RTL: flip the decorative connector arrow so it points across the pair. */
[dir="rtl"] .match-connector svg { transform: scaleX(-1); }
/* Narrow screens: stack the prompt above its menu so long text never crowds. */
@media (max-width: 560px) {
  .match-row {
    grid-template-columns: minmax(0, 1fr) 20px;
    grid-template-areas: "left mark" "select select";
    row-gap: 8px;
  }
  .match-left { grid-area: left; }
  .match-mark { grid-area: mark; }
  .match-connector { display: none; }
  .match-select { grid-area: select; }
}

@media (prefers-reduced-motion: reduce) {
  .order-chip { transition: none; }
  .order-move { transition: none; }
  .match-row, .match-select { transition: none; }
}

/* ---------------- simulations catalog ---------------- */
.sims-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 18px; }
.sim-card { background: var(--panel); border: 1px solid var(--border); border-radius: 14px; overflow: hidden; display: flex; flex-direction: column; }
.sim-card .viz { aspect-ratio: 16 / 10; border: 0; border-bottom: 1px solid var(--border); border-radius: 0; }
.sim-card-body { padding: 14px 16px; }
.sim-card-body h3 { margin: 0 0 8px; font-size: 16px; display: flex; align-items: center; gap: 8px; }
.sim-card-body p { margin: 0 0 12px; font-size: 13.5px; color: var(--muted); }

/* ---------------- topic detail ---------------- */
.topic-hero { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 26px; align-items: center; margin-bottom: 8px; }
.topic-hero.no-visual { grid-template-columns: 1fr; }
.topic-visual img { width: 100%; border-radius: 14px; border: 1px solid var(--border); display: block; }
/* H4 (AC 4.5): when the hero <img> ships no intrinsic width/height attributes
   (heroDimAttrs emits the pair only when both are valid), reserve layout space
   with a default aspect ratio matching the fallback tile so the box does not
   collapse to zero height before the image loads, keeping CLS ≤ 0.1. Scoped to
   :not([width]) so images that DO carry intrinsic dimensions keep the
   browser-derived aspect ratio and are never distorted; object-fit: cover keeps
   the reserved box undistorted if the loaded image differs from 16 / 10. */
.topic-visual img:not([width]) { aspect-ratio: 16 / 10; object-fit: cover; }
.topic-visual .planet-orb {
  position: relative;
  width: 100%; aspect-ratio: 1 / 1; max-width: 320px; margin: 0 auto; border-radius: 50%;
  background: radial-gradient(circle at 32% 30%, #fff6, transparent 42%), var(--orb, #888);
  box-shadow: 0 0 60px -10px var(--orb, #888);
}
/* Stylised, illustrative flair for the worlds shown as orbs (no photo yet).
   Jupiter/Mars/Saturn render real photos, so they don't need orb styling. */
.planet-orb[data-body="earth"] {
  background: radial-gradient(circle at 30% 28%, #fff7, transparent 40%),
    radial-gradient(circle at 65% 70%, #5cf2a0aa, transparent 30%),
    radial-gradient(circle at 35% 62%, #6fe0aaaa, transparent 26%), var(--orb);
}
.planet-orb[data-body="venus"] {
  background: radial-gradient(circle at 32% 30%, #fff8, transparent 44%),
    repeating-radial-gradient(circle at 50% 50%, rgba(255, 240, 200, 0.10) 0 6%, transparent 6% 12%), var(--orb);
}
.planet-orb[data-body="mercury"] {
  background: radial-gradient(circle at 30% 28%, #fff5, transparent 40%),
    radial-gradient(circle at 60% 65%, rgba(0, 0, 0, 0.22), transparent 22%),
    radial-gradient(circle at 72% 38%, rgba(0, 0, 0, 0.16), transparent 14%), var(--orb);
}
.planet-orb[data-body="uranus"], .planet-orb[data-body="neptune"] {
  box-shadow: 0 0 72px -8px var(--orb);
}
.planet-orb[data-body="neptune"]::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 58% 42%, rgba(0, 0, 0, 0.28), transparent 16%);
}
.topic-visual figcaption { font-size: 12px; color: var(--muted); margin-top: 8px; text-align: center; }
/* Gradient hero placeholder seeded by the record's colour, used for any type
   whose photo is missing or fails to load (galaxies, black holes, etc.). */
.topic-visual--fallback {
  width: 100%; aspect-ratio: 16 / 10; border-radius: 14px;
  border: 1px solid var(--border);
  background:
    radial-gradient(circle at 20% 22%, rgba(255, 255, 255, 0.22), transparent 36%),
    radial-gradient(circle at 80% 78%, rgba(0, 0, 0, 0.38), transparent 48%),
    radial-gradient(circle at 62% 30%, rgba(255, 255, 255, 0.10), transparent 28%),
    linear-gradient(135deg, var(--c, #7c9cff), #05070f);
  box-shadow: 0 0 60px -14px var(--c, #7c9cff);
}

/* Facts are readings, not chips: one hairline-divided strip, values in tabular
   mono so two planets compared in two tabs line up digit for digit.
   The dividers are grid GAPS showing the container colour through, not cell
   borders - a border on each cell leaves a hanging rule at the start of every
   wrapped row, and this strip wraps constantly (Mars has seven facts, phones
   are 375px). Gaps only ever appear between cells, in both writing directions
   and on every row. */
.fact-pills {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px; margin: 26px 0 0; background: var(--rule);
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
.fact-pill { padding: 13px 18px; background: var(--app-bg); }
.fact-pill dt {
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.13em; color: var(--muted);
}
html[lang="ar"] .fact-pill dt { text-transform: none; letter-spacing: 0; font-size: 12px; }
.fact-pill dd {
  margin: 5px 0 0; font-family: var(--font-mono); font-size: 15px; font-weight: 500;
  font-variant-numeric: tabular-nums; color: var(--text);
}

/* ---------------- reading-level toggle (Req 3) ---------------- */
/* The Reading_Level_Toggle is a segmented pill control in the topic hero
   offering exactly the three age bands; the active band is marked both by
   aria-pressed and this visual state (3.2, 3.8). */
.reading-level { display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap; margin: 18px 0 0; }
.reading-level-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 1px;
  color: var(--muted); font-weight: 600; white-space: nowrap;
}
.reading-level-options {
  display: inline-flex; gap: 3px; padding: 3px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 999px;
}
.reading-level-btn {
  padding: 5px 14px; min-height: 30px;
  font: inherit; font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--muted); background: transparent;
  border: 1px solid transparent; border-radius: 999px; cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease;
}
.reading-level-btn:hover { color: var(--text); background: var(--panel-2); }
.reading-level-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.reading-level-btn.is-active,
.reading-level-btn[aria-pressed="true"] {
  color: var(--app-bg); background: var(--accent); border-color: var(--accent);
}
@media (pointer: coarse) {
  .reading-level-btn { min-height: 44px; padding-inline: 16px; }
}

/* ---------------- the lesson: an observation log ----------------
   A lesson used to be a stack of identical grey cards, which made the objective,
   the story, the explanation and the experiment all look like the same kind of
   thing. Now one spectral spine runs down the page with a marker at every
   section, prose sits flush on the page at a comfortable measure, and a surface
   is reserved for the parts you DO rather than read - the experiment, the check,
   the takeaways. The shape of the page tells you how to spend your attention. */
.t-sections {
  position: relative; display: grid; gap: 0; margin-top: 44px;
  padding-inline-start: 40px;
}
.t-sections::before {
  content: ""; position: absolute; inset-block: 10px 16px; inset-inline-start: 11px;
  width: 2px; border-radius: 2px;
  background: linear-gradient(to bottom, var(--accent), var(--accent-2));
  opacity: 0.4;
}
.t-section {
  position: relative;
  background: transparent; border: 0; border-radius: 0;
  padding: 30px 0 32px; border-top: 1px solid var(--rule);
}
.t-section:first-child { border-top: 0; padding-top: 4px; }
.t-section > h2 {
  margin: 0 0 14px; font-size: var(--fs-h2);
  display: flex; align-items: center; gap: 9px;
}
/* The section's own icon becomes its marker on the spine. */
.t-section .sec-icon {
  position: absolute; inset-inline-start: -40px; top: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--app-bg); border: 1px solid var(--border);
  color: var(--accent-2); font-size: 12px;
}
.t-section .sec-icon .svg-icon { width: 13px; height: 13px; }
.t-section:first-child .sec-icon { top: 4px; }
.t-section p { margin: 0; max-width: 68ch; color: var(--text-soft); font-size: 16px; line-height: 1.72; }

/* Sections you act on keep a surface: the experiment, the takeaways, the
   objective and the story voice. Everything else is page. */
.t-section.t-tryit, .t-section.t-keypoints, .t-section.t-objective, .t-section.t-story {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 24px 26px; margin-block: 12px;
}
.t-section.t-tryit .sec-icon, .t-section.t-keypoints .sec-icon,
.t-section.t-objective .sec-icon, .t-section.t-story .sec-icon {
  inset-inline-start: -66px; top: 26px;
}
.t-tryit .viz { aspect-ratio: 16 / 9; margin-top: 14px; }
.t-tryit .tryit-instructions { margin-top: 12px !important; font-size: 13.5px; color: var(--muted); }

.dyk-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
.dyk-card { background: var(--panel-2); border-radius: var(--r-md); padding: 15px 17px; font-size: var(--fs-sm); line-height: 1.62; color: var(--text-soft); border-inline-start: 2px solid var(--accent-2); }

.related-chips { display: flex; flex-wrap: wrap; gap: 9px; }
.related-chips a {
  font-size: 13.5px; text-decoration: none; padding: 7px 14px; border-radius: 999px;
  background: var(--panel-2); color: var(--accent-2); border: 1px solid var(--border);
  transition: border-color var(--t-med) ease, color var(--t-med) ease;
}
.related-chips a:hover { border-color: var(--accent-2); color: var(--text); }

.ref-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 10px 18px; }
.ref-list a { color: var(--accent-2); font-size: 13.5px; text-decoration: none; }
.ref-list a:hover { text-decoration: underline; }

.topic-notfound { padding: 40px 0; text-align: center; color: var(--muted); }

/* ---------------- accuracy affordances (Req 3.4/3.5/10.1/10.2/10.4/10.5) ----
   Objective callout, narrative story hook, key-points summary, misconception
   callout, source disclosures, and interpretation labels. All use logical
   properties so they mirror correctly under RTL (design C.9). */

/* Learning-objective callout: a distinct accent-bordered note at the top. */
.t-objective.objective-callout { border-inline-start: 4px solid var(--accent); }
.t-objective.objective-callout p { color: var(--text); }

/* Narrative "story voice" hook: italic, quieter, visually distinct from claims. */
.story-block { background: var(--panel-2); border-inline-start: 4px solid var(--accent-2); }
.story-block p { font-style: italic; color: var(--text-soft); font-size: 15.5px; line-height: 1.7; }

/* End-of-lesson key-points summary. */
.key-points { margin: 0; padding-inline-start: 20px; display: grid; gap: 8px; }
.key-points li { color: var(--text-soft); font-size: 15px; line-height: 1.7; }

/* Misconception callout: a "myth vs. evidence" note, announced as role="note". */
.misconception {
  background: var(--panel); border: 1px solid var(--border); border-radius: 14px;
  border-inline-start: 4px solid var(--danger); padding: 18px 20px; display: grid; gap: 10px;
}
.misconception-head { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: 15px; margin-bottom: 2px; }
.misconception-icon { color: var(--danger); font-size: 19px; font-weight: 700; }
.misconception p { margin: 0; color: var(--text-soft); font-size: 14.5px; line-height: 1.7; }
.misconception-tag {
  display: inline-block; font-size: 11px; font-weight: 600; letter-spacing: 0.4px;
  text-transform: uppercase; margin-inline-end: 6px;
}
.misconception-belief .misconception-tag { color: var(--danger); }
.misconception-correction .misconception-tag { color: var(--good); }
.misconception-source { font-size: 12.5px; }

/* Source disclosures: native <details>/<summary> per section, plus a catch-all. */
.sources { margin-top: 14px; border-top: 1px solid var(--border); padding-top: 12px; }
.sources > summary {
  cursor: pointer; font-size: 13px; font-weight: 600; color: var(--accent);
  display: flex; align-items: center; gap: 7px; list-style: none;
}
.sources > summary::-webkit-details-marker { display: none; }
.source-list { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 8px; }
.source-list li { font-size: 13px; color: var(--text-soft); line-height: 1.6; }
.source-cite { font-style: normal; }
.source-link { color: var(--accent); text-decoration: none; display: inline-flex; align-items: baseline; gap: 5px; }
.source-link:hover { text-decoration: underline; }

/* Interpretation vs. fact: each interpretive claim carries a labelled chip. */
.claim-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.claim { display: grid; gap: 5px; }
.claim-interpretation {
  justify-self: start; display: inline-block; font-size: 11px; font-weight: 600;
  letter-spacing: 0.4px; text-transform: uppercase; padding: 3px 9px; border-radius: 999px;
  background: var(--panel-2); color: var(--accent-2); border: 1px solid var(--border);
}
.claim-text { color: var(--text-soft); font-size: 14.5px; line-height: 1.7; }
.claim-source { font-size: 12.5px; }
.claim-source .source-link, .misconception-source .source-link { color: var(--accent); }

/* ---------------- moon-phase widget ---------------- */
.viz.moonphase { display: flex; flex-direction: column; }
/* min-height:0 lets the canvas shrink in the flex column (overriding the
   replaced-element default of min-height:auto), so the controls below are
   never pushed past the clipped edge of the .viz box. */
.moonphase-canvas { flex: 1 1 auto; min-height: 0; width: 100%; display: block; }
.moonphase-controls { flex-shrink: 0; padding: 10px 14px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 6px; background: var(--panel); }
.moonphase-label { font-size: 13px; font-weight: 600; color: var(--accent); text-align: center; }
.moonphase-date { font-size: 12px; color: var(--muted); text-align: center; }
.moonphase-reset { align-self: center; font-size: 12px; font-weight: 600; color: var(--accent); background: transparent; border: 1px solid var(--border); border-radius: 999px; padding: 3px 12px; cursor: pointer; transition: background .15s, border-color .15s; }
.moonphase-reset:hover { background: var(--panel-2, rgba(255,255,255,0.06)); border-color: var(--accent); }
.moonphase-slider { width: 100%; height: 24px; margin: 0; accent-color: var(--accent); cursor: pointer; }

/* ---------------- astrolabe widget ---------------- */
/* The aria-hidden canvas is ordered above the controls (it is appended after
   them by the shared canvas host), and the controls stack below like the
   moon-phase widget. */
.viz.astrolabe { display: flex; flex-direction: column; touch-action: none; }
.viz.astrolabe canvas { order: -1; flex: 1 1 auto; min-height: 0; cursor: grab; }
.viz.astrolabe canvas:active { cursor: grabbing; }
.astrolabe-controls { flex-shrink: 0; padding: 10px 14px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 8px; background: var(--panel); }
.astrolabe-fields { display: flex; flex-wrap: wrap; gap: 10px; }
.astrolabe-field { display: flex; flex-direction: column; gap: 3px; font-size: 12px; color: var(--muted); flex: 1 1 120px; }
.astrolabe-readout { margin: 0; font-size: 13px; font-weight: 600; color: var(--accent); text-align: center; }
.astrolabe-hint { margin: 0; font-size: 12px; color: var(--muted); text-align: center; }
.astrolabe-knob { align-self: center; font-size: 12px; font-weight: 600; color: var(--accent); background: transparent; border: 1px solid var(--border); border-radius: 999px; padding: 4px 14px; cursor: ew-resize; }
.astrolabe-knob::before { content: "\21ba \21bb"; margin-inline-end: 6px; }
.astrolabe-knob:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.viz.qibla { display: flex; flex-direction: column; }
.viz.qibla canvas { order: -1; flex: 1 1 auto; min-height: 0; }
.qibla-controls { flex-shrink: 0; padding: 10px 14px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 8px; background: var(--panel); }
.qibla-field { display: flex; flex-direction: column; gap: 3px; font-size: 12px; color: var(--muted); }
.qibla-readout { margin: 0; font-size: 13px; font-weight: 600; color: var(--accent); text-align: center; }
.qibla-hint { margin: 0; font-size: 12px; color: var(--muted); text-align: center; }

/* ---------------- responsive ----------------
   The five primary links measure 616px; with the wordmark and the reading
   controls either side, the bar needs ~1235px to hold them on one row. Below
   that the top nav steps aside rather than wrapping into three ragged rows -
   the sidebar is still a permanent rail down to 980px and carries every one of
   those destinations, so nothing becomes unreachable. */
@media (max-width: 1240px) {
  .nav-links { display: none; }
  .nav-actions { margin-inline-start: auto; }
}

@media (max-width: 980px) {
  .nav-links { display: none; }
  .nav-toggle { display: flex; }
  .nav-sim { display: none; }
  .portal-sidebar {
    position: fixed; top: 0; left: 0; bottom: 0; width: 270px; z-index: 50;
    max-height: none; height: 100vh; height: 100dvh; overflow-y: auto; background: var(--app-bg);
    transform: translateX(-100%); transition: transform 0.2s ease; padding-top: 70px;
  }
  body.sidebar-open .portal-sidebar { transform: translateX(0); box-shadow: 0 0 50px var(--shadow); }
  body.sidebar-open::after { content: ""; position: fixed; inset: 0; z-index: 45; background: rgba(0,0,0,0.5); }
  .topic-hero { grid-template-columns: 1fr; }
  .portal-main { padding: 22px 18px 60px; }
  .lang-select { font-size: 16px; } /* avoid iOS focus auto-zoom */
}

@media (max-width: 560px) {
  /* The action cluster (search/theme/font/audio/language) has a fixed minimum
     width that exceeds narrow phones - wider still with the Arabic language
     label - so the row must be allowed to wrap instead of forcing a 40px+
     horizontal document overflow (Req 13.5, both LTR and RTL). The auto
     inline-start margin keeps the cluster at the inline end whether it shares
     the brand's row or wraps onto its own. */
  .navbar { gap: 10px; row-gap: 8px; padding: 9px 14px; flex-wrap: wrap; }
  .nav-actions { gap: 6px; flex-wrap: wrap; justify-content: flex-end; min-width: 0; margin-inline-start: auto; }
  .nav-actions .icon-btn { width: 34px; height: 34px; }
  .lang-select { padding-block: 4px; padding-inline: 4px; }
  .nav-brand { font-size: 16px; }
  .nav-brand-text { font-size: 15px; }
  .portal-main { padding: 18px 14px 56px; }
  .portal-footer { padding: 18px 16px 32px; }
  /* Single-column card grids on phones so nothing forces a horizontal scroll. */
  .domain-grid, .paths-grid, .continue-body, .sims-grid, .ladder { grid-template-columns: 1fr; }
  .hero-dashboard { padding: 38px 20px 32px; }
  /* The spine narrows on phones rather than disappearing: it is the reader's
     position indicator, and losing it mid-lesson is worse than losing 14px. */
  .t-sections { padding-inline-start: 26px; }
  .t-sections::before { inset-inline-start: 9px; }
  .t-section .sec-icon { inset-inline-start: -26px; width: 20px; height: 20px; }
  .t-section.t-tryit .sec-icon, .t-section.t-keypoints .sec-icon,
  .t-section.t-objective .sec-icon, .t-section.t-story .sec-icon { inset-inline-start: -44px; }
  .t-section.t-tryit, .t-section.t-keypoints,
  .t-section.t-objective, .t-section.t-story { padding: 18px 16px; }
  .fact-pills { grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); }
  .fact-pill { padding: 11px 13px; }
}

/* H1 - touch-target sizing for portal-only links on touch devices. Coarse
   pointers (touchscreens) get a >= 44x44 CSS-px hit area via min-height plus
   flex centring so the visible label stays centred; fine-pointer sizing above
   is intentionally left untouched. */
@media (pointer: coarse) {
  .path-steps a,
  .portal-sidebar a,
  .nav-links a {
    min-height: 44px;
    display: flex;
    align-items: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  .domain-card, .link-card, .portal-sidebar { transition: none; }
}

/* ---------------- premium polish (elevation + motion) ---------------- */
.domain-card, .path-card, .sim-card, .link-card {
  box-shadow: var(--elev-1);
  transition: transform var(--t-med) var(--ease-out), box-shadow var(--t-med) var(--ease-out), border-color var(--t-med) ease;
}
.domain-card:hover, .sim-card:hover, .link-card:hover { transform: translateY(-4px); box-shadow: var(--elev-3); }
.path-card:hover { box-shadow: var(--elev-2); }
.hero-dashboard { box-shadow: var(--elev-2); }
.stat-tile { transition: transform var(--t-med) var(--ease-out), background var(--t-med) ease; }
.stat-tile:hover { transform: translateY(-2px); }
.badge-chip { transition: opacity var(--t-med) ease, filter var(--t-med) ease, border-color var(--t-med) ease, transform var(--t-fast) var(--ease-out); }
.badge-chip.got { animation: pop var(--t-med) var(--ease-spring); }
.domain-icon .svg-icon { transition: transform var(--t-med) var(--ease-spring); }
.domain-card:hover .domain-icon .svg-icon { transform: scale(1.12) rotate(-4deg); }

/* Path completion gets a celebratory sheen on its accent bar. */
.path-card.complete .path-progress > span { background: var(--grad-accent); box-shadow: 0 0 12px -2px var(--accent); }

@media (prefers-reduced-motion: reduce) {
  .domain-card, .path-card, .sim-card, .link-card, .stat-tile { transition: none; }
  .domain-card:hover, .sim-card:hover, .link-card:hover, .stat-tile:hover { transform: none; }
  .domain-card:hover .domain-icon .svg-icon { transform: none; }
  .badge-chip.got { animation: none; }
}

/* ---------------- path progress ring ---------------- */
.path-head-main { min-width: 0; }
.path-head .path-ring { flex-shrink: 0; }
.path-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
.path-count { font-size: 11.5px; color: var(--muted); }
.path-ring .ring-track { stroke: color-mix(in srgb, var(--c, var(--accent)) 18%, var(--panel-2)); }
.path-card .ring-fill { stroke: var(--c, var(--accent)); }
.path-ring .ring-label { color: var(--c, var(--accent)); font-size: 12px; font-weight: 700; }
.path-card.complete .path-ring .ring-label { color: var(--good); }
.path-card.complete .ring-fill { stroke: var(--good); }

/* ---------------- onboarding (first-visit dashboard) ---------------- */
.stats-panel.onboarding { display: block;
  /* Opaque fallback first: below-baseline browsers ignore the color-mix()
     background below and keep this solid panel colour so the tint renders (C7). */
  background: var(--panel);
  background:
    radial-gradient(520px 200px at 90% -30%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 70%),
    var(--panel); }
.onboarding-head { display: flex; gap: 14px; align-items: flex-start; }
.onboarding-icon { font-size: 30px; color: var(--accent); flex-shrink: 0; line-height: 1; }
.onboarding-head h2 { margin: 0 0 4px; font-size: 19px; }
.onboarding-head p { margin: 0; color: var(--muted); font-size: 14px; max-width: 60ch; }
.onboarding-steps { list-style: none; margin: 16px 0; padding: 0; display: grid; gap: 9px; }
.onboarding-steps li { display: flex; align-items: center; gap: 10px; font-size: 14px; color: var(--text-soft); }
.onboarding-step-icon { color: var(--accent-2); display: inline-flex; }
.onboarding-goals { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--rule); }
.onboarding-goals-title { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--muted); margin: 0 0 9px; }

/* ---------------- empty / error states ---------------- */
.empty-state {
  grid-column: 1 / -1; text-align: center; padding: 44px 22px; color: var(--muted);
  background: var(--panel); border: 1px dashed var(--border); border-radius: var(--r-lg);
}
.empty-state .empty-icon { display: inline-flex; font-size: 34px; color: var(--accent); margin-bottom: 12px; }
.empty-state h3 { margin: 0 0 6px; color: var(--text); font-size: 17px; }
.empty-state p { margin: 0 auto 16px; font-size: 14px; max-width: 44ch; }

/* Nicer topic-not-found uses the shared empty-state look. */
.topic-notfound.empty-state { margin: 40px auto; max-width: 520px; }

/* ---------------- guided path step navigation (pathnav.js) ---------------- */
/* Appended to the end of main content when the page is a learning-path step:
   path name + "Step i of N", a slim progress bar, and Previous/Next cards.
   Directional spacing/alignment uses logical properties so RTL mirrors. */
.pathnav { margin-top: 40px; padding-top: 18px; border-top: 1px solid var(--rule, var(--border)); }
.pathnav-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.pathnav-title { font-weight: 600; font-size: 13.5px; color: var(--accent-2); }
.pathnav-count { font-size: 12px; color: var(--muted); }
.pathnav-track {
  height: 5px; border-radius: 3px; margin: 10px 0 14px; overflow: hidden;
  background: var(--panel-2);
}
.pathnav-fill {
  display: block; height: 100%; border-radius: 3px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: width 0.4s ease;
}
.pathnav-links { display: flex; justify-content: space-between; gap: 12px; }
.pathnav-link {
  display: flex; flex-direction: column; gap: 3px; flex: 1; max-width: 48%;
  min-height: 44px; padding: 10px 14px; text-decoration: none;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-md, 10px);
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.pathnav-link:hover { border-color: var(--accent); transform: translateY(-2px); }
.pathnav-link:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
.pathnav-link.placeholder { visibility: hidden; border: none; }
.pathnav-link.next { text-align: end; margin-inline-start: auto; }
.pathnav-link.prev { text-align: start; }
.pathnav-dir { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--muted); }
.pathnav-step { font-size: 14px; font-weight: 600; color: var(--accent); }
.pathnav-link.finish .pathnav-step { color: var(--good, var(--accent)); }
@media (max-width: 560px) {
  .pathnav-links { flex-direction: column; }
  .pathnav-link, .pathnav-link.next { max-width: none; margin-inline-start: 0; }
  .pathnav-link.placeholder { display: none; }
}
@media (pointer: coarse) {
  .pathnav-link { min-height: 44px; }
}
@media (prefers-reduced-motion: reduce) {
  .pathnav-fill, .pathnav-link { transition: none; }
  .pathnav-link:hover { transform: none; }
}

/* ---------------- Tonight's Sky panel + sky map (sky.js) ----------------
   On the dashboard this panel is the live half of the observation deck, so it is
   docked to the hero above it (square top corners, no gap) and its five values
   are set as instrument readings: mono, tabular, on a hairline-divided strip.
   These are real numbers computed for the reader's own city - they should look
   measured, not decorated. */
.tonight {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 20px 24px 22px; margin-bottom: 30px;
}
.hero-dashboard + .tonight {
  border-start-start-radius: 0; border-start-end-radius: 0;
  border-top: 0; margin-top: 0;
}
.sky-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.sky-head .section-title { margin: 0; padding-top: 0; font-size: var(--fs-h3); }
.sky-head .section-title::before { display: none; }
.sky-city { display: inline-flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--muted); }
/* Same hairline-gap technique as the lesson fact strip: dividers are the grid
   gap, so five readings wrapping to two rows never leave a stray leading rule. */
.sky-tiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(126px, 1fr));
  gap: 1px; margin: 18px 0; background: var(--rule);
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
.sky-tile {
  display: flex; flex-direction: column; gap: 4px; padding: 14px 16px;
  background: var(--panel);
}
.sky-tile-icon { color: var(--accent-2); display: inline-flex; }
.sky-tile-label {
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.12em; color: var(--muted);
}
html[lang="ar"] .sky-tile-label { text-transform: none; letter-spacing: 0; font-size: 12px; }
.sky-tile-value {
  font-family: var(--font-mono); font-size: 16px; font-weight: 500;
  font-variant-numeric: tabular-nums; color: var(--text);
}
.sky-planets { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.sky-planets-label {
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.12em; color: var(--muted);
}
html[lang="ar"] .sky-planets-label { text-transform: none; letter-spacing: 0; font-size: 12px; }
.sky-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 999px;
  font-size: 12.5px; min-height: 30px;
}
.sky-chip b { font-family: var(--font-mono); color: var(--accent-2); font-weight: 500; font-variant-numeric: tabular-nums; }
.sky-none { font-size: 12.5px; color: var(--muted); }
.sky-foot { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 14px 0 0; }
.sky-foot .hint { font-size: 11.5px; color: var(--muted); }

.skychart { max-width: 700px; }
.sky-controls { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 10px; }
.sky-time { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.sky-time span { font-size: 15px; font-weight: 600; color: var(--accent); min-width: 64px; }
.sky-time input[type="range"] { flex: 1; accent-color: var(--accent); min-height: 32px; }
.sky-canvas-wrap { position: relative; display: flex; justify-content: center; }
.sky-canvas-wrap canvas { display: block; }
.sky-day {
  position: absolute; inset-block-start: 12px; inset-inline-start: 50%;
  transform: translateX(-50%); margin: 0; padding: 6px 14px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 999px;
  font-size: 12px; color: var(--muted); white-space: nowrap;
}
[dir="rtl"] .sky-day { transform: translateX(50%); }

/* ---------------- Al-Sufi Arabic star-names layer (Req 6) ---------------- */
.sky-arabic { width: 100%; margin-bottom: 12px; }
.sky-arabic-toggle {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 13px; color: var(--text); cursor: pointer; min-height: 32px;
}
/* Modern custom checkbox: a rounded 20px tile that fills with the accent
   gradient when checked. Drawn with appearance:none + an inline-SVG check so
   it matches the theme in both modes; falls back to a native accent-colored
   box wherever appearance:none is unsupported. */
.sky-arabic-toggle input {
  accent-color: var(--accent-2); /* fallback path */
  appearance: none; -webkit-appearance: none;
  width: 20px; height: 20px; min-width: 20px; min-height: 20px;
  margin: 0; cursor: pointer;
  border: 2px solid var(--border); border-radius: 6px;
  background: var(--panel-2) center / 12px no-repeat;
  transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
}
.sky-arabic-toggle input:hover { border-color: var(--accent-2); }
.sky-arabic-toggle input:focus-visible { outline: none; box-shadow: var(--ring); }
.sky-arabic-toggle input:checked {
  border-color: var(--accent);
  background-color: var(--accent);
  background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23071018" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpath d="M5 12.6l4.5 4.5L19 7"/%3E%3C/svg%3E');
}
/* Light theme: the accent is a deep teal, so the check flips to white. */
[data-theme="light"] .sky-arabic-toggle input:checked {
  background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23ffffff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpath d="M5 12.6l4.5 4.5L19 7"/%3E%3C/svg%3E');
}
.sky-names {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px;
  max-height: 148px; overflow-y: auto; scrollbar-gutter: stable;
  padding: 10px; background: var(--panel);
  border: 1px solid var(--border); border-radius: var(--r-md, 10px);
}
.sky-name-btn {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 5px 10px; border: 1px solid var(--border); border-radius: 999px;
  background: var(--panel); color: var(--text); cursor: pointer; font: inherit;
}
.sky-name-btn:hover { border-color: var(--accent-2); }
.sky-name-ar { font-size: 14px; color: #ffd86b; }
.sky-name-modern { font-size: 11.5px; color: var(--muted); }

.sky-star-popover {
  position: absolute; z-index: 4; max-width: 220px;
  display: flex; flex-direction: column; gap: 3px;
  padding: 12px 14px; background: var(--panel);
  border: 1px solid var(--accent-2); border-radius: 12px;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.35);
  font-size: 12.5px; color: var(--text);
}
.sky-pop-close {
  position: absolute; inset-block-start: 4px; inset-inline-end: 6px;
  border: none; background: none; color: var(--muted);
  font-size: 18px; line-height: 1; cursor: pointer; padding: 2px 4px;
}
.sky-pop-arabic { font-size: 20px; font-weight: 700; color: #ffd86b; }
.sky-pop-translit { font-style: italic; color: var(--muted); }
.sky-pop-meaning { color: var(--text); }
.sky-pop-row { font-size: 12px; color: var(--muted); }

@media (pointer: coarse) {
  .sky-arabic-toggle { min-height: 44px; }
  .sky-name-btn { min-height: 44px; }
}

/* New Phase 12 directional icons point in the reading direction, so under RTL
   they mirror horizontally (11.4). The lesson-plan step chevron is a single
   `chevron-right` glyph reused for both directions via a transform mirror
   rather than a second icon. */
[dir="rtl"] .step-arrow,
[dir="rtl"] .step-arrow .svg-icon { transform: scaleX(-1); }

@media (pointer: coarse) {
  .sky-chip { min-height: 44px; }
  .sky-city select, .sky-city input, .sky-controls .btn { min-height: 44px; }
  .sky-time input[type="range"] { min-height: 44px; }
}
@media (max-width: 560px) {
  .sky-tiles { grid-template-columns: repeat(2, 1fr); }
  .sky-head { flex-direction: column; align-items: flex-start; }
}

/* ---------------- ISS passes + sky calendar + light pollution ---------------- */
.sky-bortle { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.sky-bortle > span:first-child { font-size: 12.5px; color: var(--muted); white-space: nowrap; }
.sky-bortle input[type="range"] { flex: 0 1 180px; accent-color: var(--accent-2); min-height: 32px; }
.sky-bortle-desc { font-size: 12px; color: var(--muted); flex: 1 1 220px; }

.sky-iss, .sky-events { margin-top: 34px; }
.iss-list { list-style: none; margin: 0 0 10px; padding: 0; display: grid; gap: 10px; }
.iss-pass {
  display: flex; align-items: baseline; gap: 8px 16px; flex-wrap: wrap;
  padding: 12px 16px; background: var(--panel);
  border: 1px solid var(--border); border-radius: var(--r-md, 10px);
  border-inline-start: 3px solid var(--border);
}
.iss-pass.watchable { border-inline-start-color: var(--good, var(--accent)); }
.iss-when { font-weight: 600; color: var(--accent); font-size: 14.5px; }
.iss-meta { color: var(--text); font-size: 13px; }
.iss-good { color: var(--good, var(--accent)); font-size: 12.5px; }
.iss-dim { color: var(--muted); font-size: 12.5px; }
.iss-stale { color: var(--danger); }

.sky-event-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.sky-event {
  display: flex; gap: 14px; padding: 14px 16px;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-md, 10px);
}
.sky-event.past { opacity: 0.55; }
.sky-event.next { border-color: var(--accent); }
.sky-event-icon { color: var(--accent-2); display: inline-flex; flex-shrink: 0; margin-top: 2px; }
.sky-event-body h3 { margin: 2px 0 4px; font-size: 15px; }
.sky-event-body p { margin: 0; font-size: 13px; color: var(--muted); line-height: 1.5; }
.sky-event-date { font-size: 12px; color: var(--accent); font-weight: 600; display: inline-flex; align-items: center; gap: 8px; }
.sky-event-next {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.6px;
  background: var(--accent); color: #06101f; padding: 2px 8px; border-radius: 999px;
}

@media (pointer: coarse) {
  .sky-bortle input[type="range"] { min-height: 44px; }
}

/* ---------------- constellation explorer (constellations.js) ---------------- */
.const-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px; margin-top: 18px;
}
.const-card {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 14px 10px; cursor: pointer; min-height: 44px;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--r-md, 10px);
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.const-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.const-card:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
.const-card.active { border-color: var(--accent); }
.const-card canvas { background: #0b1020; border-radius: 50%; }
.const-card-name { font-size: 13.5px; font-weight: 600; text-align: center; }
.const-latin { font-size: 11.5px; color: var(--muted); font-style: italic; }

.const-detail {
  background: var(--panel); border: 1px solid var(--accent);
  border-radius: var(--r-lg); padding: 18px 20px; outline: none;
}
.const-detail-grid { display: flex; gap: 22px; flex-wrap: wrap; align-items: flex-start; }
.const-canvas { background: #0b1020; border-radius: var(--r-md, 10px); flex-shrink: 0; }
.const-facts { flex: 1; min-width: 240px; }
.const-facts h2 { margin: 0 0 10px; font-size: 20px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.const-zodiac {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.6px;
  background: var(--accent-2); color: #06101f; padding: 2px 9px; border-radius: 999px;
}
.const-facts dl { margin: 0 0 12px; display: grid; gap: 6px; }
.const-facts dl > div { display: flex; gap: 8px; font-size: 13.5px; }
.const-facts dt { color: var(--muted); }
.const-facts dt::after { content: ":"; }
.const-facts dd { margin: 0; color: var(--accent); font-weight: 600; }
.const-story { font-size: 14px; line-height: 1.65; margin: 0 0 14px; }
.const-back { margin-bottom: 14px; }

@media (max-width: 560px) {
  .const-grid { grid-template-columns: repeat(2, 1fr); }
  .const-detail-grid { flex-direction: column; align-items: center; }
}

/* ---------------- worksheet / print CSS (teacher mode) ----------------
   Requirements 5.2, 5.3, 5.4, 5.5, 5.6. The printable Worksheet_View is the
   existing Topic_Page / Lesson_Plan_Page printed through pure print CSS - there
   is no separate render path to keep in sync. teacher.js adds `body.worksheet`
   before calling window.print(), but the print LAYOUT itself is declarative CSS
   and does not depend on JavaScript being enabled (5.6): the chrome-hiding and
   page geometry live in a plain `@media print` block so a no-JS Ctrl+P of the
   server-rendered <h1>/lead still prints clean, dark-on-white, and unclipped.
   Only the quiz answer-key withholding is scoped to `body.worksheet`, because a
   quiz only exists once JS has hydrated it. */

/* A4 and US Letter both print correctly in portrait with a comfortable margin;
   `size: portrait` lets each printer keep its own paper size (5.6). */
@page {
  size: portrait;
  margin: 16mm 15mm;
}

@media print {
  /* Dark text on a white background, body text >= 11pt, and nothing clipped
     beyond the printable page width (5.6). */
  :root { color-scheme: light; }
  html, body {
    background: #fff !important;
    color: #111 !important;
    font-size: 12pt;            /* body copy stays >= 11pt when printed (5.6) */
    line-height: 1.5;
  }

  /* Navigation chrome, the sidebar, and all interactive control clusters are
     excluded from the printout (5.2). */
  .navbar,
  .nav-actions,
  .nav-toggle,
  .portal-sidebar,
  .crumbs,
  .teacher-bar,
  .reading-level,
  .pathnav,
  .portal-footer,
  .site-footer,
  .skip-link { display: none !important; }

  /* Simulations and their reserved boxes are removed entirely so no empty
     placeholder space is left where a canvas/WebGL surface would sit (5.2).
     Hiding the whole `.t-tryit`/`.hero-sim` section (not just the `.viz`)
     avoids an orphaned "Try it" heading over blank space. */
  .viz,
  [data-scene],
  [data-moonphase],
  .hero-sim,
  .t-tryit { display: none !important; }

  /* Collapse the flex shell so lesson content flows full page width with no
     reserved sidebar gutter and no max-width clipping (5.2, 5.6). */
  .portal-shell { display: block !important; max-width: none !important; margin: 0 !important; }
  .portal-main {
    max-width: none !important; width: auto !important;
    padding: 0 !important; margin: 0 !important;
    overflow: visible !important;
  }

  /* Single-column hero and full-bleed media so images never overflow the page. */
  .topic-hero { display: block !important; }
  img { max-width: 100% !important; height: auto !important; }

  /* Lesson cards print as plain dark-on-white blocks and avoid breaking across
     pages mid-section where possible. */
  .t-section {
    background: #fff !important;
    border: 1px solid #999 !important;
    box-shadow: none !important;
    break-inside: avoid;
    page-break-inside: avoid;
  }
  h1, .lead,
  .t-section h2, .t-section p,
  .fact-pill dt, .fact-pill dd,
  .dyk-card, .related-chips a, .ref-list a { color: #111 !important; }

  /* The narration player is an interactive control; hide the player but leave
     the transcript text in place so the worksheet stays a full reading (5.2). */
  .audio audio,
  .audio video,
  audio, video { display: none !important; }

  /* The deep-space field and the lesson spine are screen furniture: on paper the
     gutter they reserve is wasted margin, so the log flattens back to a plain
     sequence of sections. */
  .starfield,
  .hero-orrery { display: none !important; }
  .t-sections { padding-inline-start: 0 !important; }
  .t-sections::before { display: none !important; }
  .t-section .sec-icon { position: static !important; border: 0 !important; background: none !important; }

  /* Print links as plain text (no URL noise), keeping them dark-on-white. */
  a { color: #111 !important; text-decoration: none !important; }
}

/* Worksheet-scoped answer withholding (5.3): the printed worksheet keeps every
   quiz PROMPT but drops the choice buttons, the revealed `answer` index, the
   `explain` text, the "correct answer" phrase, and the score/result region, so
   students receive questions without an answer key. Scoped to `body.worksheet`
   so a teacher's deliberate worksheet print is the only place the key is
   stripped. The now-empty containers are collapsed to leave no blank gap under
   each prompt (5.2). */
@media print {
  body.worksheet .quiz-choices,
  body.worksheet .quiz-explain,
  body.worksheet .quiz-result,
  body.worksheet .quiz-correct-answer,
  body.worksheet .quiz-outcome { display: none !important; }

  body.worksheet .quiz-q { margin: 0 0 12pt !important; }
  body.worksheet .quiz-prompt { color: #111 !important; margin: 0; }
}

/* ---------------- scientist profiles + compare (scientists.js) ----------------
   Two surfaces share this block: the /scientists index (card grid) and a
   /scientists/{id} profile (bilingual header, vertical CSS timeline, expand-in-
   place discovery cards, impact/legacy). All directional spacing/alignment uses
   logical properties so the Arabic RTL layout mirrors automatically. */

/* --- profile index --- */
.sci-index-head { margin-bottom: 22px; }
.sci-index-head h1 { margin: 0 0 8px; }
.sci-compare-hint {
  display: inline-flex; align-items: center; gap: 8px; margin: 10px 0 0;
  font-size: 12.5px; color: var(--muted);
}
.sci-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 16px; margin-top: 10px;
}
.sci-card {
  display: flex; flex-direction: column; gap: 10px;
  padding: 16px 18px; background: var(--panel);
  border: 1px solid var(--border); border-radius: var(--r-lg);
  border-inline-start: 3px solid var(--c, var(--accent));
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.sci-card:hover { transform: translateY(-2px); }
.sci-card-link {
  display: flex; flex-direction: column; gap: 4px; text-decoration: none; color: inherit;
}
.sci-card-link:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; border-radius: 6px; }
.sci-card-ar { font-size: 20px; color: var(--accent); line-height: 1.4; }
.sci-card-en { font-size: 16px; font-weight: 600; color: var(--text); }
.sci-card-dates { font-size: 12px; color: var(--muted); }
.sci-card-summary { font-size: 13px; color: var(--muted); line-height: 1.55; margin-top: 2px; }
.sci-card-actions { margin-top: auto; }

/* Small "chip" variant of a button used for the index compare toggles. */
.btn-chip {
  display: inline-flex; align-items: center; gap: 6px; min-height: 34px;
  padding: 6px 12px; font-size: 12.5px; border-radius: 999px;
  background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  cursor: pointer; transition: border-color 0.15s ease, background 0.15s ease;
}
.btn-chip:hover { border-color: var(--accent); }
.sci-compare-toggle[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
.sci-compare-toggle[disabled] { opacity: 0.5; cursor: not-allowed; }
.sci-compare-toggle:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }

/* --- profile header --- */
.sci-header { align-items: center; }
.sci-header-body { min-width: 0; }
.sci-name-ar {
  font-size: 30px; line-height: 1.4; margin: 0 0 2px; color: var(--accent);
  font-weight: 600;
}
.sci-name-en { margin: 0 0 4px; font-size: 26px; }
.sci-translit { margin: 0 0 8px; font-size: 14px; color: var(--muted); font-style: italic; }
.sci-dates { margin: 0 0 12px; font-size: 13.5px; }
.sci-dates-span { font-weight: 600; color: var(--accent); }
.sci-dates-places { color: var(--muted); margin-inline-start: 8px; }
.sci-tags { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 0; padding: 0; }
.sci-tags li {
  font-size: 11.5px; color: var(--muted); padding: 3px 10px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 999px;
}
.sci-header-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 16px; }

.sci-visual { margin: 0; }
.sci-visual img,
.sci-visual-fallback { width: 100%; border-radius: var(--r-lg); display: block; }
.sci-visual-fallback {
  aspect-ratio: 4 / 3;
  background: radial-gradient(120% 120% at 30% 20%, var(--c, var(--accent)) 0%, transparent 60%), var(--panel-2);
  border: 1px solid var(--border);
}
.sci-visual figcaption { font-size: 11px; color: var(--muted); margin-top: 6px; line-height: 1.5; }

/* --- vertical CSS timeline (Req 4.2, no library) --- */
.sci-timeline { list-style: none; margin: 6px 0 0; padding: 0; position: relative; }
.sci-timeline::before {
  content: ""; position: absolute; inset-block: 6px; inset-inline-start: 8px;
  width: 2px; background: var(--rule, var(--border));
}
.sci-tl-item { position: relative; padding-block: 0 20px; padding-inline-start: 34px; }
.sci-tl-item::before {
  content: ""; position: absolute; inset-inline-start: 2px; inset-block-start: 5px;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--bg); border: 3px solid var(--accent);
  box-shadow: 0 0 10px -1px var(--accent);
}
.sci-tl-year { display: block; font-weight: 600; color: var(--accent); font-size: 13.5px; }
.sci-tl-body p { margin: 2px 0 0; font-size: 14px; line-height: 1.6; }
.sci-tl-src { display: block; margin-top: 4px; font-size: 11.5px; }

/* --- expand-in-place discovery cards (Req 4.3) --- */
.sci-disc-list { display: grid; gap: 10px; }
.sci-disc {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-md, 10px); border-inline-start: 3px solid var(--accent-2, var(--accent));
}
.sci-disc > summary {
  cursor: pointer; list-style: none; padding: 12px 16px; min-height: 44px;
  display: flex; align-items: center; gap: 10px; font-weight: 600;
}
.sci-disc > summary::-webkit-details-marker { display: none; }
.sci-disc > summary::after {
  content: "+"; margin-inline-start: auto; color: var(--accent);
  font-size: 20px; line-height: 1; transition: transform 0.15s ease;
}
.sci-disc[open] > summary::after { content: "\2212"; }
.sci-disc > summary:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: 8px; }
.sci-disc-body { padding: 0 16px 14px; }
.sci-disc-body p { margin: 6px 0 0; font-size: 14px; line-height: 1.65; }
.sci-tag {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--accent-2, var(--accent)); font-weight: 700; margin-inline-end: 6px;
}
.sci-disc-legacy { color: var(--text); }
.sci-disc-src { font-size: 11.5px; }

/* --- compare tray (Req 4.4) --- */
.compare-tray {
  position: sticky; inset-block-end: 0; z-index: 5; margin-top: 30px;
  background: var(--panel); border: 1px solid var(--accent);
  border-radius: var(--r-lg); padding: 16px 18px;
  box-shadow: 0 -6px 24px -12px rgba(0, 0, 0, 0.5);
}
.compare-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.compare-head h2 { margin: 0; font-size: 16px; display: inline-flex; align-items: center; gap: 8px; }
.compare-count {
  font-size: 11.5px; color: var(--muted); background: var(--panel-2);
  border-radius: 999px; padding: 2px 9px;
}
.compare-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0; }
.compare-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 6px 5px 12px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 999px;
  font-size: 12.5px;
}
.compare-chip-x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; min-width: 24px; padding: 0; border-radius: 50%;
  background: transparent; border: none; color: var(--muted); cursor: pointer;
}
.compare-chip-x:hover { color: var(--danger, var(--accent)); }
.compare-chip-x:focus-visible { outline: 2px solid var(--ring); outline-offset: 1px; }
.compare-hint { font-size: 13px; color: var(--muted); margin: 4px 0 0; }

.compare-table-wrap { overflow-x: auto; margin-top: 6px; }
.compare-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.compare-table th, .compare-table td {
  padding: 9px 12px; text-align: start; vertical-align: top;
  border-block-end: 1px solid var(--border);
}
.compare-table thead th { color: var(--accent); font-weight: 600; }
.compare-table tbody th[scope="row"] { color: var(--muted); font-weight: 500; white-space: nowrap; }
.compare-table .compare-corner { color: var(--muted); font-weight: 500; }

@media (pointer: coarse) {
  .btn-chip, .compare-chip-x { min-height: 44px; }
  .sci-disc > summary { min-height: 44px; }
}
@media (max-width: 820px) {
  .sci-header { display: block; }
  .sci-visual { margin-top: 16px; max-width: 360px; }
}
@media (max-width: 560px) {
  .sci-grid { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .sci-card, .btn-chip, .sci-disc > summary::after { transition: none; }
  .sci-card:hover { transform: none; }
}

/* ---------------- completion certificate (Req 7.7, task 12.5) ----------------
   /history/certificate. certificate.js renders one of two states into
   [data-certificate]: an encouraging "keep going" panel until all ten modules
   are complete, or the issued certificate (a name field + print button above a
   printable certificate sheet). All directional spacing uses logical properties
   so the Arabic RTL layout mirrors automatically. The @media print block below
   strips the chrome so a Ctrl+P / the Print button yields just the sheet. */

.certificate-page { margin-top: 8px; }

/* --- pending (not yet earned) state --- */
.cert-pending { text-align: center; max-width: 560px; margin: 20px auto; }
.cert-pending h2 { margin: 6px 0 8px; font-size: 22px; }
.cert-pending p { color: var(--muted); font-size: 15px; }
.cert-progress {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  margin: 18px auto 20px; max-width: 340px;
}
.cert-progress-bar {
  width: 100%; height: 8px; border-radius: 999px;
  background: var(--panel-2); border: 1px solid var(--border); overflow: hidden;
}
.cert-progress-fill {
  display: block; height: 100%; border-radius: 999px;
  background: var(--grad-accent, var(--accent));
  transition: width 0.9s var(--ease-out, ease);
}
.cert-progress-label { font-size: 13px; color: var(--muted); font-weight: 600; }

/* --- issued: on-screen controls (hidden in print) --- */
.cert-controls {
  display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap;
  margin: 6px 0 22px;
}
.cert-name-field { display: flex; flex-direction: column; gap: 6px; flex: 1 1 260px; }
.cert-name-field span {
  font-size: 11px; text-transform: uppercase; letter-spacing: 1px;
  color: var(--muted); font-weight: 600;
}
.cert-name-field input {
  font: inherit; font-size: 15px; color: var(--text);
  padding: 10px 13px; border-radius: 9px;
  background: var(--panel-2); border: 1px solid var(--border);
}
.cert-name-field input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }

/* --- issued: the certificate sheet --- */
.certificate-sheet {
  position: relative; text-align: center;
  max-width: 720px; margin: 0 auto;
  padding: 44px 40px 38px;
  border-radius: 16px;
  border: 1px solid color-mix(in srgb, #c9a227 55%, var(--border));
  background:
    radial-gradient(120% 120% at 50% -10%, color-mix(in srgb, #c9a227 12%, transparent), transparent 60%),
    var(--panel);
  box-shadow: 0 0 0 1px color-mix(in srgb, #c9a227 40%, transparent), 0 18px 48px -22px rgba(0, 0, 0, 0.55);
}
.cert-seal {
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; margin: 0 auto 12px; border-radius: 50%;
  color: #1b1200; background: #c9a227;
  box-shadow: 0 0 0 5px color-mix(in srgb, #c9a227 30%, transparent);
}
.cert-seal svg { width: 30px; height: 30px; }
.cert-eyebrow {
  margin: 0 0 6px; font-size: 12px; text-transform: uppercase; letter-spacing: 2px;
  color: var(--accent-2); font-weight: 600;
}
.cert-heading { margin: 0 0 14px; font-size: clamp(24px, 4vw, 32px); }
.cert-intro { margin: 0 0 6px; color: var(--muted); font-size: 14.5px; }
.cert-name {
  margin: 4px 0 10px; font-size: clamp(26px, 5vw, 38px); font-weight: 700;
  color: var(--text); line-height: 1.15;
  border-bottom: 2px solid color-mix(in srgb, #c9a227 55%, var(--border));
  display: inline-block; padding: 0 18px 6px; min-width: 220px;
}
.cert-for { margin: 0 0 24px; color: var(--text-soft); font-size: 15px; }
.cert-for strong { color: var(--text); }
.cert-modules { margin: 0 auto 22px; max-width: 520px; text-align: start; }
.cert-modules h3 {
  margin: 0 0 10px; font-size: 13px; text-transform: uppercase; letter-spacing: 1px;
  color: var(--muted); text-align: center;
}
.cert-module-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.cert-module {
  display: flex; align-items: baseline; gap: 10px;
  padding: 8px 12px; border-radius: 9px;
  background: var(--panel-2); border: 1px solid var(--border);
}
.cert-module-ord {
  flex: 0 0 auto; font-size: 11.5px; font-weight: 700; letter-spacing: 0.4px;
  color: var(--accent-2); min-width: 76px;
}
.cert-module-title { flex: 1 1 auto; font-size: 14px; color: var(--text); }
.cert-date { margin: 0; color: var(--muted); font-size: 13.5px; }
.cert-date span { text-transform: uppercase; letter-spacing: 1px; font-size: 11px; font-weight: 600; }

/* Certificate print rules: on /history/certificate, strip the page hero and the
   on-screen controls so only the certificate sheet prints, and render the sheet
   as a clean dark-on-white bordered card that never breaks across pages. The
   global @media print block (above) already hides the navbar/sidebar/footer and
   forces the light colour scheme. */
@media print {
  body[data-page="certificate"] .hero-course,
  body[data-page="certificate"] .cert-controls { display: none !important; }

  body[data-page="certificate"] .certificate-sheet {
    max-width: none !important; margin: 0 !important;
    background: #fff !important; color: #111 !important;
    border: 2px solid #b8860b !important;
    box-shadow: none !important;
    break-inside: avoid; page-break-inside: avoid;
  }
  body[data-page="certificate"] .cert-eyebrow,
  body[data-page="certificate"] .cert-heading,
  body[data-page="certificate"] .cert-intro,
  body[data-page="certificate"] .cert-name,
  body[data-page="certificate"] .cert-for,
  body[data-page="certificate"] .cert-for strong,
  body[data-page="certificate"] .cert-modules h3,
  body[data-page="certificate"] .cert-module-title,
  body[data-page="certificate"] .cert-module-ord,
  body[data-page="certificate"] .cert-date { color: #111 !important; }

  body[data-page="certificate"] .cert-seal {
    color: #1b1200 !important; background: #d4af37 !important; box-shadow: none !important;
  }
  body[data-page="certificate"] .cert-module {
    background: #fff !important; border: 1px solid #999 !important;
  }
  body[data-page="certificate"] .cert-name { border-bottom-color: #b8860b !important; }
}

/* ---------------- collectible scientist cards (Req 7.6, task 12.3) ----------------
   A flip-card gallery on the dashboard ([data-cards]). Each card flips between a
   front face (rarity + bilingual name + collected/locked status) and a back face
   (what the astronomer is known for, or how to collect the card). cards.js
   toggles .is-flipped on the .card-collectible when its .card-flip button is
   activated (click or keyboard). The rotation is a pure CSS transform; the
   prefers-reduced-motion block below removes the animation so the faces still
   swap but do not spin (Req 12.6). All spacing uses logical properties for RTL. */

.cards-panel { margin: 8px 0 30px; padding: 18px 20px; background: var(--panel); border: 1px solid var(--border); border-radius: 14px; }
.cards-head h2 { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 4px; font-size: 18px; }
.cards-count { font-size: 13px; font-weight: 600; color: var(--accent); background: var(--panel-2); border-radius: 999px; padding: 2px 10px; }
.cards-sub { margin: 0 0 14px; font-size: 13.5px; color: var(--muted); }

.cards-gallery {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.card-cell { display: flex; flex-direction: column; gap: 6px; }

/* The flip container. A fixed aspect ratio keeps the two faces the same size so
   the back is a true mirror of the front. Perspective enables the 3D rotate. */
.card-collectible { display: flex; flex-direction: column; gap: 6px; }
.card-flip {
  display: block; width: 100%; aspect-ratio: 3 / 4; padding: 0; border: none;
  background: transparent; cursor: pointer; perspective: 900px;
}
.card-flip:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; border-radius: 12px; }

.card-inner {
  position: relative; display: block; width: 100%; height: 100%;
  transform-style: preserve-3d; transition: transform var(--t-slow, 520ms) var(--ease-out, ease);
}
.card-collectible.is-flipped .card-inner { transform: rotateY(180deg); }

.card-face {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 6px; text-align: center;
  padding: 12px; border-radius: 12px; border: 1px solid var(--border);
  background: var(--panel-2);
  -webkit-backface-visibility: hidden; backface-visibility: hidden;
  overflow: hidden;
}
.card-front {
  border-color: color-mix(in srgb, var(--c, var(--accent)) 45%, var(--border));
  background: var(--panel-2);
  background: linear-gradient(160deg, color-mix(in srgb, var(--c, var(--accent)) 22%, var(--panel-2)), var(--panel-2));
}
.card-back { transform: rotateY(180deg); }

/* Portrait medallion: a circular frame for the astronomer's illustration,
   echoing a trading-card portrait window. Illustrations are drawn at 4/3 and
   sized generously here, so `contain` (not `cover`) keeps the whole scene
   inside the circle instead of cropping it. */
.card-portrait {
  width: 30%; aspect-ratio: 1; border-radius: 50%; flex: none; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  border: 2px solid var(--c, var(--accent));
  background: radial-gradient(120% 120% at 32% 22%, var(--c, var(--accent)) 0%, transparent 65%), var(--panel);
  box-shadow: 0 4px 14px -8px var(--c, var(--accent)), inset 0 0 0 1px color-mix(in srgb, var(--c, var(--accent)) 35%, transparent);
}
.card-portrait img { width: 100%; height: 100%; object-fit: contain; padding: 12%; display: block; }
.card-portrait-fallback { opacity: 0.55; }
.card-collectible.is-collected .card-portrait { box-shadow: 0 0 0 1px var(--c, var(--accent)), 0 4px 16px -6px var(--c, var(--accent)); }

.card-rarity { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--c, var(--accent)); }
.card-ar { font-size: 17px; line-height: 1.3; }
.card-en { font-size: 14px; font-weight: 700; color: var(--text); line-height: 1.25; }
.card-dates { font-size: 11.5px; color: var(--muted); }
.card-status { margin-top: 4px; font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); }
.card-back-title { font-size: 12.5px; font-weight: 700; color: var(--accent); }
.card-known, .card-hint { font-size: 12.5px; color: var(--text); line-height: 1.4; }
.card-hint { color: var(--muted); }

/* Collected cards read full-colour; locked cards are muted + desaturated. */
.card-collectible.is-collected .card-front { box-shadow: 0 0 0 1px color-mix(in srgb, var(--c, var(--accent)) 30%, transparent), 0 6px 18px -10px var(--c, var(--accent)); }
.card-collectible.is-locked .card-front { filter: grayscale(0.85); opacity: 0.72; }
.card-collectible.is-collected .card-status { color: var(--good, var(--accent)); }

/* Rarity accents (fall back to the record's --c when unset). */
.card-collectible.rarity-gold { --c: #d4af37; }
.card-collectible.rarity-silver { --c: #c0c7d0; }
.card-collectible.rarity-bronze { --c: #cd7f32; }

.card-link { align-self: center; font-size: 12.5px; color: var(--accent); text-decoration: none; }
.card-link:hover { text-decoration: underline; }
.card-link:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: 4px; }

@media (pointer: coarse) {
  .card-link { min-height: 44px; display: inline-flex; align-items: center; }
}
@media (max-width: 560px) {
  .cards-gallery { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
}

/* Reduced motion: keep the flip functional (faces still swap) but drop the
   spinning transition so no non-essential animation plays (Req 12.6). */
@media (prefers-reduced-motion: reduce) {
  .card-inner { transition: none; }
}

/* ---------------- Daily challenge panel (paths.js, Req 7.3) ----------------
   A single date-keyed question shown beside Tonight's Sky. Options are real
   <button>s; the chosen/correct/wrong states reuse the quiz colour language.
   All spacing uses logical properties so the layout mirrors under RTL. */
.challenge-panel { margin-bottom: 26px; }
.challenge-card {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 18px 20px;
}
.challenge-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.challenge-head .section-title { margin: 0; display: inline-flex; align-items: center; gap: 8px; }
.challenge-status {
  display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700;
  color: var(--good, #5cf2a0); background: var(--panel-2);
  border: 1px solid var(--border); border-radius: 999px; padding: 4px 11px;
}
.challenge-sub { margin: 4px 0 12px; font-size: 13.5px; color: var(--muted); }
.challenge-q { margin: 0 0 12px; font-size: 15px; font-weight: 600; line-height: 1.4; }

.challenge-opts { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 8px; }
.challenge-opt {
  display: flex; align-items: center; gap: 9px; text-align: start; font-family: inherit;
  font-size: 14px; cursor: pointer; color: var(--text);
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 9px; padding: 10px 13px;
  transition: border-color 0.12s ease, background 0.12s ease;
}
.challenge-opt:hover:not(:disabled) { border-color: var(--accent); }
.challenge-opt:disabled { cursor: default; }
.challenge-opt:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
.challenge-opt-mark {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 999px; font-size: 12px; font-weight: 700;
  background: var(--panel); border: 1px solid var(--border); color: var(--muted);
}
.challenge-opt.correct { border-color: #5cf2a0; background: rgba(92, 242, 160, 0.16); color: #d6ffe8; }
.challenge-opt.wrong { border-color: #ff6b6b; background: rgba(255, 107, 107, 0.16); color: #ffd9d9; }

.challenge-feedback { margin-top: 12px; }
.challenge-result { margin: 0; display: inline-flex; align-items: center; gap: 8px; font-weight: 600; }
.challenge-reward {
  font-size: 12.5px; font-weight: 700; color: var(--accent);
  background: var(--panel-2); border-radius: 999px; padding: 2px 10px;
}
.challenge-explain { margin: 9px 0 0; font-size: 13.5px; color: var(--text-soft, var(--muted)); padding: 9px 12px; border-radius: 8px; background: var(--panel-2); border-inline-start: 3px solid #5cf2a0; }
.challenge-hint { margin: 10px 0 0; font-size: 12.5px; color: var(--muted); }

@media (pointer: coarse) {
  .challenge-opt { min-height: 44px; }
}

/* ---------------- simulation widget controls on touch ----------------
   The interactive sims are the point of the portal on a phone, and their
   controls were the last ones still sized for a mouse: the moon-phase track
   shipped at 24px tall and the H-R diagram's at 16px. A slider is a DRAG
   target, so the whole track has to be thumb-sized - not just the thumb - or
   the learner is asked to catch a hairline while their finger covers it.
   Placed last in the file so it wins over the authored heights above. */
@media (pointer: coarse) {
  .viz input[type="range"] { min-height: 44px; }
  .moonphase-slider { height: 44px; }
  /* The extra control height must not come out of the canvas: the widget gets
     taller instead. Left as-is, the Moon shrank from 195px to 97px on the one
     screen where the Moon IS the lesson. */
  .viz.moonphase { aspect-ratio: 5 / 4; }
  .moonphase-reset { min-height: 44px; padding-inline: 18px; }
  .astrolabe-knob { min-height: 44px; }
  .astrolabe-field input,
  .astrolabe-field select,
  .qibla-field input,
  .qibla-field select { min-height: 44px; }
  .match-select { min-height: 44px; }
}

