/* =================================================================
   Design tokens — shared with lesson.html (keep in sync).
   ================================================================= */
:root {
  --purple:       #7B4DFF;
  --purple-light: #AA8AFF;
  --purple-dark:  #5A2EE0;
  --orange:       #F5A623;
  --orange-light: #FFCC66;
  --blue:         #3B82F6;
  --magenta:      #9C2C6B;
  --coral:        #FF4B5C;
  --green:        #10B981;
  --green-light:  #34D399;

  --world-color:        #7B4DFF;
  --world-color-light:  #AA8AFF;
  --world-color-rgb:        123, 77, 255;
  --world-tint-strong: 0.20;
  --world-tint-soft:   0.10;

  --font-h: 'Nunito', 'MadikaArabic', sans-serif;
  --font-b: 'Space Grotesk', 'MadikaArabic', sans-serif;

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 14px;
  --radius-xl: 16px;
  --radius-2xl: 20px;

  --easing: cubic-bezier(.4, 0, .2, 1);
}

@font-face {
  font-family: 'MadikaArabic';
  src: url('../fonts/MadikaArabic-Regular.otf') format('opentype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

/* Dark theme tokens — only theme supported for now. */
/* -----------------------------------------------------------------
   Lucide icon placeholders
   -----------------------------------------------------------------
   `<i data-lucide="…">` is the placeholder swapped at runtime by
   either our same-origin sprite shim (see `app/templates/base.html`)
   or the legacy lucide UMD bundle (still used on the standalone
   `lesson.html`). Without a CSS hint the empty `<i>` collapses to
   `width: 0`, then the post-swap `<svg>` inflates to 1 em / 24 px
   and shifts every line of text to its right — a textbook CLS bug
   PageSpeed Insights consistently flags on list / breadcrumb pages.
   Sizing the placeholder (and ONLY the placeholder, not the rendered
   `<svg>`) keeps lucide's intrinsic 24×24 dimensions intact while
   still reserving the column up front. Specific icon classes that
   want a different size still win on specificity.
   ----------------------------------------------------------------- */
i[data-lucide] {
  display: inline-block;
  width: 1em;
  height: 1em;
  flex-shrink: 0;
  vertical-align: -0.125em;
  line-height: 0;
}

:root {
  --bg:           #0B0820;
  --bg-top:       #0D0826;
  --bg-bottom:    #07122E;
  --surface:      #120E2A;
  --surface-lift: #1A1440;

  --text:         #FFFFFF;
  --text-soft:    rgba(255,255,255,0.88);
  --text-muted:   #CEC9E3;
  /* Bumped from #B8B0D0 (≈ 5.2:1 vs --bg) to #CFC7E6 (≈ 6.4:1) so the
     dimmest body copy still passes WCAG AA on the dark background. */
  --text-dim:     #CFC7E6;

  --card-fill:        rgba(255,255,255,0.04);
  --card-fill-strong: rgba(255,255,255,0.08);
  --card-border:      rgba(255,255,255,0.10);
  --card-border-hover:rgba(255,255,255,0.22);
  --card-hover:       rgba(255,255,255,0.06);

  --nav-bg:   rgba(13,8,38,0.88);
  --nav-bg-2: rgba(13,8,38,0.95);
  --crumb:    rgba(255,255,255,0.60);
  --chip-bg:  rgba(123,77,255,0.18);

  --scrollbar:    rgba(255,255,255,0.10);

  --hero-gradient: linear-gradient(180deg, var(--bg-top) 0%, var(--bg) 50%, var(--bg-bottom) 100%);
  --world-tint-strong: 0.22;
  --world-tint-soft:   0.12;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html {
  background: var(--bg);
  scroll-behavior: smooth;
  max-width: 100%;
  overflow-x: clip;
  font-size: 17px;
}
body {
  font-family: var(--font-b);
  color: var(--text);
  font-size: 17px;
  background: transparent;
  background-image: var(--hero-gradient);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100vh;
  min-height: 100dvh;
}
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 90% 55% at 50% 0%,
      rgba(var(--world-color-rgb), var(--world-tint-strong)) 0%,
      transparent 60%),
    radial-gradient(ellipse 70% 45% at 50% 100%,
      rgba(var(--world-color-rgb), var(--world-tint-soft)) 0%,
      transparent 70%);
  transition: background 400ms var(--easing);
}

button { font-family: inherit; border: none; background: none; cursor: pointer; color: inherit; }
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--scrollbar); border-radius: 4px; }

/* =================================================================
   Cosmic starfield — global, fixed, viewport-sized canvas
   -----------------------------------------------------------------
   Rendered as a sibling of `.app` (see base.html). Sits at z-index:0
   in body's stacking context — above `body::before`'s world tint
   (also z-index:0, but earlier in DOM order) and below `.app`
   (z-index:2) so page content always reads on top. The animation
   logic lives in base.html so every page extending base.html shares
   the same "space theme" as the marketing site (getxplain.ai).
   ================================================================= */
#starfield {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  z-index: 0;
  pointer-events: none;
}

/* =================================================================
   Knowledge-fuel meter — global, fixed, viewport-pinned slider
   -----------------------------------------------------------------
   A tall vertical orange "fuel tube" pinned to the right gutter on
   every page so Xplore's mission progress is always in view as
   visitors navigate worlds/categories/lessons. Hidden below 1200 px
   where the gutter is too tight to host it without overlapping
   content. Pointer events are off — purely decorative.
   ================================================================= */
.fuel-rail {
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  display: none;
}
@media (min-width: 1200px) {
  .fuel-rail { display: block; }
}

.fuel-rail__side {
  position: fixed;
  top: 132px;             /* clears the sticky site-header + lang rail */
  bottom: 40px;
  inset-inline-end: 8px;
  width: 132px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  pointer-events: none;
}
@media (min-width: 1440px) {
  .fuel-rail__side { width: 148px; inset-inline-end: 12px; }
}

/* Charging cap — golden circular badge sitting above the pipe. */
.fuel-rail__cap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: linear-gradient(135deg, #F5A623, #FFD700);
  color: #2A1700;
  flex-shrink: 0;
  border: 2px solid rgba(255, 255, 255, 0.35);
  box-shadow:
    0 0 0 5px rgba(245, 166, 35, 0.10),
    0 0 28px rgba(245, 166, 35, 0.55),
    inset 0 -3px 8px rgba(0, 0, 0, 0.12);
}
.fuel-rail__cap i { width: 20px; height: 20px; }

.fuel-rail__label {
  font-family: var(--font-h);
  font-weight: 800;
  font-size: 11px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: center;
  line-height: 1.25;
  white-space: nowrap;
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.35);
}
.fuel-rail__label--top {
  color: #FFB74D;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.fuel-rail__label--bottom { color: var(--text-muted); }
.fuel-rail__pct {
  font-family: var(--font-h);
  font-weight: 800;
  font-size: 16px;
  letter-spacing: 0.04em;
  line-height: 1;
  color: #FFB74D;
}
.fuel-rail__count {
  font-family: var(--font-h);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.85);
  text-transform: none;
}

/* The pipe — a chunky vertical tube with a static orange fuel fill. */
.fuel-rail__pipe {
  position: relative;
  width: 30px;
  flex: 1 1 auto;
  min-height: 180px;
  border-radius: 999px;
  background:
    linear-gradient(180deg,
      rgba(12, 4, 30, 0.55) 0%,
      rgba(12, 4, 30, 0.35) 100%);
  border: 2px solid rgba(255, 255, 255, 0.10);
  overflow: hidden;
  box-shadow:
    inset 0 2px 10px rgba(0, 0, 0, 0.55),
    inset 0 -2px 8px rgba(255, 255, 255, 0.04),
    0 0 30px rgba(245, 166, 35, 0.12);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* Live fuel fill — warm orange whose height comes from the
   --fuel-pct custom property set on .fuel-rail__side. Inherits the
   percent up from the parent via CSS variables so the SSR template
   only has to set one value per render. Falls back to 0% if missing. */
.fuel-rail__pipe::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--fuel-pct, 0%);
  transition: height 0.6s ease-out;
  background:
    linear-gradient(180deg,
      rgba(245, 166, 35, 0.35) 0%,
      rgba(245, 166, 35, 0.85) 45%,
      rgba(255, 183, 77, 1)    100%);
  box-shadow:
    inset 0 0 24px rgba(245, 166, 35, 0.65),
    0 -6px 22px rgba(245, 166, 35, 0.55);
}

/* =================================================================
   Layout shell
   ================================================================= */
.app {
  position: relative;
  z-index: 2;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 32px 96px;
}

/* =================================================================
   Top header (site-header) — sticky chrome with navbar + lang rail.
   ================================================================= */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  margin: 0 -32px 8px;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: border-color .25s var(--easing), box-shadow .25s var(--easing);
  isolation: isolate;
}
.site-header::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 100vw;
  transform: translateX(-50%);
  z-index: -1;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--bg) 88%, transparent) 0%,
    color-mix(in srgb, var(--bg) 78%, transparent) 55%,
    color-mix(in srgb, var(--bg) 0%,  transparent) 100%
  );
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 60%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 60%, transparent 100%);
  pointer-events: none;
}
.site-header.is-stuck::before {
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--bg) 94%, transparent) 0%,
    color-mix(in srgb, var(--bg) 84%, transparent) 60%,
    color-mix(in srgb, var(--bg) 0%,  transparent) 100%
  );
}
.site-header.is-stuck {
  box-shadow: 0 8px 24px rgba(0,0,0,0.18);
}

.site-bar {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 18px 32px 10px;
  background: transparent;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-h);
  font-weight: 900;
  font-size: clamp(30px, 3.2vw, 40px);
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--text);
  text-decoration: none;
}
.brand .brand-icon {
  /* Logo source is 257×227 (≈ 1.132). Letting `height` derive from
     `aspect-ratio` keeps the rendered box matching the natural image
     ratio so PSI's "Displays images with incorrect aspect ratio"
     audit passes, while the responsive `clamp(...)` width still
     scales fluidly with the viewport. `object-fit` is no longer
     needed because the box is no longer square. */
  width: clamp(40px, 4.2vw, 52px);
  aspect-ratio: 257 / 227;
  height: auto;
  display: block;
}
.brand .brand-text { display: inline-flex; align-items: baseline; }
.brand .b-get, .brand .b-plain { color: var(--text); }
.brand .b-x {
  background: linear-gradient(180deg, #7B4DFF 0%, #AA8AFF 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  padding: 0 1px;
}
.brand .b-dot { color: #F5A623; }
.brand .b-ai {
  background: linear-gradient(180deg, #F5A623 0%, #FFD700 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.site-nav {
  margin-left: auto;
  display: none;
  align-items: center;
  gap: 4px;
  font-weight: 600;
  font-size: 16px;
  color: var(--text-muted);
}
@media (min-width: 900px) { .site-nav { display: inline-flex; } }
.site-nav a { padding: 10px 14px; border-radius: 999px; transition: color .15s, background .15s; }
@media (hover: hover) { .site-nav a:hover { color: var(--text); background: var(--card-hover); } }
.site-nav a.active { color: var(--text); background: var(--card-fill-strong); }

.site-bar-tail { display: inline-flex; align-items: center; gap: 10px; }
@media (min-width: 900px) { .site-bar-tail { margin-left: 8px; } }
@media (max-width: 899px) { .site-bar-tail { margin-left: auto; } }

.lang-switch-rail {
  display: flex;
  justify-content: flex-end;
  padding: 0 32px 14px;
}

.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.lang-switch__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
}
.lang-switch__icon i { width: 15px; height: 15px; }

.lang-switch__track {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  min-width: 84px;
  padding: 3px;
  border-radius: 999px;
  border: 1px solid var(--card-border);
  background: var(--card-fill);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.18);
}

.lang-switch__thumb {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  width: calc(50% - 3px);
  border-radius: 999px;
  background: linear-gradient(180deg, #ffffff 0%, #e8ecff 100%);
  box-shadow:
    0 1px 2px rgba(255, 255, 255, 0.35) inset,
    0 2px 8px rgba(0, 0, 0, 0.2);
  transition: transform .22s var(--easing);
  pointer-events: none;
}

.lang-switch[data-locale="ar-EG"] .lang-switch__thumb {
  transform: translateX(100%);
}

.lang-switch__opt {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  padding: 6px 10px;
  border-radius: 999px;
  border: 0;
  background: transparent;
  font-family: var(--font-h);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.08em;
  line-height: 1;
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: color .15s, background .15s;
}

.lang-switch__opt.is-active {
  color: #1a1033;
  cursor: default;
}

.lang-switch__opt:focus-visible {
  outline: 2px solid var(--purple-light);
  outline-offset: 2px;
}

@media (hover: hover) {
  .lang-switch__opt:not(.is-active):hover {
    color: var(--text);
    background: var(--card-hover);
  }
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  border: 1px solid var(--card-border);
  background: var(--card-fill);
  transition: background .15s, border-color .15s, transform .15s;
}
@media (hover: hover) { .icon-btn:hover { background: var(--card-hover); border-color: var(--card-border-hover); transform: translateY(-1px); } }
.icon-btn i { width: 18px; height: 18px; color: var(--text); }

/* =================================================================
   Buttons — shared CTA pills
   -----------------------------------------------------------------
   `base.css` is the only stylesheet the directory pages load, so the
   `.btn` markup they use (currently `404.html`) has to be styled
   here. Without it the anchors fall back to plain inline flow and
   the runtime-swapped `<svg>` icon sits on the text baseline instead
   of centred against its label.

   `lesson.css` re-declares `.btn` for the viewer's full-width
   controls and loads *after* this file, so the lesson player keeps
   its own sizing; every property below is one it already overrides.
   ================================================================= */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 52px;
  padding: 0 22px;
  border-radius: var(--radius-lg);
  font-family: var(--font-b);
  font-weight: 700;
  font-size: 16.5px;
  cursor: pointer;
  transition: transform .12s var(--easing), box-shadow .18s,
              background .18s, color .18s, border-color .18s;
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--purple-light); outline-offset: 3px; }

.btn-primary {
  background: linear-gradient(135deg, var(--orange), var(--orange-light));
  color: #2A1B02;
  box-shadow: 0 10px 28px rgba(245,166,35,0.35);
  font-weight: 800;
}
@media (hover: hover) { .btn-primary:hover { box-shadow: 0 14px 34px rgba(245,166,35,0.5); } }

.btn-secondary {
  background: var(--card-fill);
  border: 1px solid var(--card-border);
  color: var(--text);
}
@media (hover: hover) { .btn-secondary:hover { background: var(--card-hover); border-color: var(--card-border-hover); } }

/* Centred row of `.btn`s under a `.page-head` (404, empty states).
   The icon rule targets `svg` as well as the `<i>` placeholder:
   `_icon_sprite_shim.html` replaces the `<i>` node with a fresh
   `<svg width="24">`, so an `i`-only selector stops applying the
   moment the sprite renders. Scoped to this row so the lesson
   viewer's own buttons keep their sizing. */
.page-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  margin: 24px 0 64px;
}
.page-actions .btn i,
.page-actions .btn svg { width: 20px; height: 20px; flex-shrink: 0; }

/* =================================================================
   Breadcrumbs
   -----------------------------------------------------------------
   Markup is produced by `_breadcrumbs.html`'s `render_breadcrumbs`
   macro (and mirrored verbatim by the lesson viewer's JS), so the
   styling here is the single visual source of truth for every
   page's path trail:

     <nav class="crumbs">
       <a class="crumb" href="..."><i data-lucide="..."></i>
         <span class="crumb-label">…</span></a>
       <i class="crumb-sep" data-lucide="chevron-right"></i>
       <span class="crumb is-current" aria-current="page">…</span>
     </nav>
   ================================================================= */
.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  margin: 14px 0 36px;
  font-family: var(--font-h);
  line-height: 1.2;
  min-width: 0;
}
.crumb {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 2px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text-muted);
  text-decoration: none;
  background: transparent;
  border: 0;
  border-radius: 6px;
  max-width: 22ch;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color 0.18s ease;
}
@media (hover: hover) { .crumb:hover { color: var(--text); } }
@media (hover: hover) { .crumb:hover .crumb-label {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 1px;
} }
.crumb:focus-visible {
  outline: 2px solid var(--purple);
  outline-offset: 3px;
  color: var(--text);
}
.crumb i { width: 13px; height: 13px; flex: 0 0 auto; color: var(--purple-light); opacity: 0.85; }

/* The current page — gradient text + brighter icon. Keep both
   `.is-current` (canonical) and the legacy `.current` selector
   alive so older JS-generated markup still styles correctly. */
.crumb.is-current,
.crumb.current {
  color: var(--text);
  font-weight: 800;
  max-width: 60ch;
  background: linear-gradient(135deg, #7B4DFF 0%, #3B82F6 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
}
.crumb.is-current i,
.crumb.current i { color: #F5A623; opacity: 1; }
@media (hover: hover) { .crumb.is-current:hover .crumb-label,
.crumb.current:hover .crumb-label {
  background-image: linear-gradient(135deg, #7B4DFF 0%, #3B82F6 100%);
  background-size: 100% 1px;
} }

/* Separator chevron — lucide icon between crumbs. Falls back
   gracefully for any template that still emits a text "›" by
   sizing as a small inline glyph. */
.crumb-sep {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 12px;
  height: 12px;
  opacity: 0.4;
  color: var(--text-muted);
  flex: 0 0 auto;
  margin: 0 -1px;
  font-size: 12px;
  line-height: 1;
}

@media (max-width: 720px) {
  .crumbs {
    flex-wrap: nowrap;
    gap: 4px 6px;
    margin: 12px 0 22px;
  }
  .crumb {
    font-size: 12.5px;
    padding: 2px;
    max-width: none;
    min-width: 0;
    flex: 0 1 auto;
  }
  .crumb i { width: 12px; height: 12px; }
  .crumb-sep { width: 11px; height: 11px; }
}

/* =================================================================
   Section heads + titles
   ================================================================= */
.page-head { margin: 8px 0 28px; }
.page-title {
  font-family: var(--font-h);
  font-weight: 800;
  font-size: clamp(32px, 3.8vw, 48px);
  line-height: 1.1;
  margin: 0 0 10px;
  color: var(--text);
}
.page-subtitle {
  font-size: 17px;
  color: var(--text-muted);
  margin: 0;
  max-width: 720px;
}
.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 36px 0 16px;
}
.section-title {
  font-family: var(--font-h);
  font-weight: 800;
  font-size: clamp(22px, 2.4vw, 28px);
  line-height: 1.2;
  color: var(--text);
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.section-title i { width: 26px; height: 26px; color: var(--world-color, var(--purple)); }

/* =================================================================
   Card grids — categories, worlds, lessons
   ================================================================= */
.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
}
@media (min-width: 640px)  { .grid-2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px)  { .grid-3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1100px) { .grid-4 { grid-template-columns: repeat(4, 1fr); } }

.card {
  background: var(--card-fill);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-xl);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  text-decoration: none;
  color: inherit;
  transition: transform .15s var(--easing), border-color .2s, background .2s, box-shadow .2s;
  position: relative;
  overflow: hidden;
}
@media (hover: hover) { .card:hover {
  transform: translateY(-2px);
  border-color: var(--card-border-hover);
  background: var(--card-hover);
  box-shadow: 0 14px 36px rgba(123,77,255,.12);
} }
.card:focus-visible {
  outline: 2px solid var(--world-color, var(--purple));
  outline-offset: 3px;
}

/* Colored left-accent tied to the world/category colour */
.card.accent::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 4px;
  background: var(--world-color, var(--purple));
  border-radius: 4px 0 0 4px;
}

.card-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 12px;
  background: rgba(var(--world-color-rgb), 0.18);
  color: var(--world-color, var(--purple));
}
.card-icon i { width: 24px; height: 24px; }
.card-title {
  font-family: var(--font-h);
  font-weight: 800;
  font-size: 19px;
  line-height: 1.25;
  color: var(--text);
  margin: 4px 0 2px;
}
.card-meta {
  font-size: 14px;
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.card-meta .dot { opacity: 0.55; }
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--chip-bg);
  color: var(--world-color, var(--purple));
  font-weight: 600;
  font-size: 13px;
}
.pill i { width: 14px; height: 14px; }

/* =================================================================
   Category block (on /worlds index: category title with its worlds)
   ================================================================= */
.cat-block { margin: 0 0 48px; }
.cat-head {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  margin: 0 0 18px;
}
.cat-head-main {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
  flex: 1 1 auto;
}
.cat-head .cat-icon {
  width: 56px; height: 56px;
  border-radius: 14px;
  background: rgba(var(--world-color-rgb), 0.18);
  color: var(--world-color);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.cat-head .cat-icon i { width: 28px; height: 28px; }
.cat-head .cat-text { display: flex; flex-direction: column; gap: 4px; }
.cat-head .cat-text .cat-name {
  font-family: var(--font-h);
  font-weight: 800;
  font-size: 24px;
  color: var(--text);
}
.cat-head .cat-text .cat-sub {
  color: var(--text-muted);
  font-size: 14px;
}
.cat-head .cat-link {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px; border-radius: 999px;
  border: 1px solid var(--card-border);
  background: var(--card-fill);
  color: var(--text-muted);
  font-weight: 600;
  font-size: 14px;
  transition: background .15s, border-color .15s, color .15s;
  /* Trailing-edge pin: inline-start auto = right in LTR, left in RTL. */
  margin-inline-start: auto;
}
@media (hover: hover) { .cat-head .cat-link:hover { color: var(--text); background: var(--card-hover); border-color: var(--card-border-hover); } }
.cat-head .cat-link i { width: 14px; height: 14px; }
.cat-head .cat-link svg { width: 14px; height: 14px; }
html[dir="rtl"] .cat-head .cat-link i,
html[dir="rtl"] .cat-head .cat-link svg { transform: scaleX(-1); }

/* =================================================================
   World tile — subtle color-tinted card (matches mobile app)
   Used on /worlds and /worlds/<category>
   ================================================================= */
.world-grid {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
@media (min-width: 640px) {
  .world-grid { gap: 16px; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); }
}
@media (min-width: 1100px) {
  .world-grid { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
}

.world-tile {
  position: relative;
  aspect-ratio: 1 / 1;
  display: block;
  text-decoration: none;
  color: inherit;
  background: rgba(var(--world-color-rgb), 0.08);
  border: 1px solid rgba(var(--world-color-rgb), 0.18);
  border-radius: 14px;
  overflow: hidden;
  isolation: isolate;
  transition: transform .15s var(--easing), background .2s, border-color .2s;
}
@media (hover: hover) { .world-tile:hover {
  transform: translateY(-2px);
  border-color: rgba(var(--world-color-rgb), 0.42);
} }
.world-tile:focus-visible {
  outline: 2px solid var(--world-color);
  outline-offset: 2px;
}

/* Hero layer — random lesson image when available, color-tinted gradient
   otherwise. A bottom-anchored dark gradient keeps the body text readable
   regardless of the image. */
.world-tile-hero {
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    linear-gradient(
      to top,
      rgba(11, 8, 32, 0.92) 0%,
      rgba(11, 8, 32, 0.72) 35%,
      rgba(11, 8, 32, 0.30) 65%,
      rgba(11, 8, 32, 0.10) 100%
    ),
    radial-gradient(120% 80% at 50% 0%,
      rgba(var(--world-color-rgb), 0.30) 0%,
      rgba(var(--world-color-rgb), 0.05) 60%,
      transparent 100%
    );
  background-size: 100% 100%, 100% 100%;
  transition: transform .25s var(--easing), filter .25s;
}
.world-tile.has-hero .world-tile-hero {
  background:
    linear-gradient(
      to top,
      rgba(11, 8, 32, 0.30) 0%,
      rgba(11, 8, 32, 0.05) 50%,
      transparent 100%
    ),
    var(--world-hero) center / cover no-repeat;
}
@media (hover: hover) { .world-tile:hover .world-tile-hero {
  transform: scale(1.04);
} }

/* World icon chip overlaid on the hero, top-left */
.world-tile-icon {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: rgba(var(--world-color-rgb), 0.92);
  color: #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
  flex-shrink: 0;
}
.world-tile-icon i {
  width: 20px;
  height: 20px;
  stroke-width: 2;
}

/* Bottom-anchored content stack: name, count, peek title.
   Sits in a solid frosted band so the text is always readable, regardless
   of how busy the hero image behind it is. */
.world-tile-body {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 12px 12px;
  min-width: 0;
  background: linear-gradient(
    to bottom,
    rgba(11, 8, 32, 0.78) 0%,
    rgba(11, 8, 32, 0.94) 100%
  );
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-top: 1px solid rgba(var(--world-color-rgb), 0.35);
  box-shadow: 0 -8px 16px -8px rgba(0, 0, 0, 0.45);
}
.world-tile-name {
  font-family: var(--font-h);
  font-weight: 800;
  font-size: 15px;
  line-height: 1.15;
  color: #fff;
  letter-spacing: -0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.world-tile-meta {
  font-family: var(--font-h);
  font-weight: 700;
  font-size: 11px;
  line-height: 1.2;
  color: rgba(255, 255, 255, 0.82);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.world-tile-meta.is-empty {
  color: rgba(255, 255, 255, 0.55);
  text-transform: none;
  letter-spacing: 0;
  font-weight: 600;
}

.world-tile-peek {
  margin-top: 4px;
  display: flex;
  align-items: flex-start;
  gap: 6px;
  font-family: var(--font-h);
  font-weight: 600;
  font-size: 11px;
  line-height: 1.3;
  color: rgba(255, 255, 255, 0.92);
  min-width: 0;
}
.world-tile-peek i {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--world-color);
  stroke-width: 2.25;
  filter: drop-shadow(0 0 6px rgba(var(--world-color-rgb), 0.45));
}
.world-tile-peek-text {
  min-width: 0;
  flex: 1;
  white-space: normal;
  word-break: break-word;
  overflow-wrap: anywhere;
}

/* Empty-state tile — no lessons yet, no hero image. The icon takes over the
   whole tile so the empty card still looks intentional and inviting. */
.world-tile.is-empty .world-tile-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, calc(-50% - 22px));
  width: 96px;
  height: 96px;
  border-radius: 22px;
  background: rgba(var(--world-color-rgb), 0.18);
  color: var(--world-color);
  box-shadow:
    0 8px 30px rgba(var(--world-color-rgb), 0.30),
    inset 0 0 0 1px rgba(var(--world-color-rgb), 0.35);
  transition: transform .25s var(--easing), background .25s, box-shadow .25s;
}
@media (hover: hover) { .world-tile.is-empty:hover .world-tile-icon {
  transform: translate(-50%, calc(-50% - 22px)) scale(1.04);
  background: rgba(var(--world-color-rgb), 0.26);
} }
.world-tile.is-empty .world-tile-icon i {
  width: 56px;
  height: 56px;
  stroke-width: 1.6;
}
@media (min-width: 1100px) {
  .world-tile.is-empty .world-tile-icon {
    width: 112px;
    height: 112px;
    border-radius: 26px;
    transform: translate(-50%, calc(-50% - 24px));
  }
  @media (hover: hover) { .world-tile.is-empty:hover .world-tile-icon {
    transform: translate(-50%, calc(-50% - 24px)) scale(1.04);
  } }
  .world-tile.is-empty .world-tile-icon i {
    width: 64px;
    height: 64px;
  }
}

/* =================================================================
   Lesson card — image on top, meta below
   ================================================================= */
.lesson-card {
  background: var(--card-fill);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-xl);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  color: inherit;
  text-decoration: none;
  transition: transform .15s var(--easing), border-color .2s, background .2s, box-shadow .2s;
}
@media (hover: hover) { .lesson-card:hover {
  transform: translateY(-2px);
  border-color: var(--card-border-hover);
  background: var(--card-hover);
  box-shadow: 0 14px 36px rgba(123,77,255,.12);
} }
.lesson-card:focus-visible {
  outline: 2px solid var(--world-color, var(--purple));
  outline-offset: 3px;
}
.lesson-card .lc-image {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--card-hover);
  overflow: hidden;
}
.lesson-card .lc-image img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .35s var(--easing);
}
@media (hover: hover) { .lesson-card:hover .lc-image img { transform: scale(1.04); } }
.lesson-card .lc-image .lc-image-fallback {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-dim);
}
.lesson-card .lc-body { padding: 20px; display: flex; flex-direction: column; gap: 10px; flex: 1; }
.lesson-card .lc-world {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-h);
  font-weight: 700;
  font-size: 13px;
  padding: 4px 12px;
  border-radius: 999px;
  background: rgba(var(--world-color-rgb), 0.18);
  color: var(--world-color);
  align-self: flex-start;
}
.lesson-card .lc-world i { width: 14px; height: 14px; }
.lesson-card .lc-title {
  font-family: var(--font-h);
  font-weight: 800;
  font-size: 18px;
  line-height: 1.3;
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.lesson-card .lc-meta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  font-size: 13px;
  color: var(--text-muted);
  margin-top: auto;
}
.lesson-card .lc-meta i { width: 14px; height: 14px; }

/* =================================================================
   Pagination
   ================================================================= */
.pager {
  margin: 40px 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex-wrap: wrap;
}
.pager a, .pager span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  height: 40px;
  padding: 0 12px;
  border-radius: 10px;
  border: 1px solid var(--card-border);
  background: var(--card-fill);
  color: var(--text-muted);
  font-weight: 600;
  font-size: 15px;
  text-decoration: none;
  transition: background .15s, border-color .15s, color .15s;
}
@media (hover: hover) { .pager a:hover { color: var(--text); background: var(--card-hover); border-color: var(--card-border-hover); } }
.pager .current {
  color: var(--text);
  background: var(--world-color, var(--purple));
  border-color: var(--world-color, var(--purple));
  color: #fff;
}
.pager .disabled {
  opacity: 0.4;
  pointer-events: none;
}
.pager .ellipsis {
  border: 0;
  background: transparent;
  color: var(--text-dim);
}

/* =================================================================
   Empty state
   ================================================================= */
.empty {
  padding: 48px 20px;
  text-align: center;
  color: var(--text-muted);
  border: 1px dashed var(--card-border);
  border-radius: var(--radius-xl);
  background: var(--card-fill);
}
.empty i { width: 36px; height: 36px; color: var(--text-dim); margin: 0 auto 10px; display: block; }
.empty .empty-title {
  font-family: var(--font-h);
  font-weight: 700;
  font-size: 18px;
  color: var(--text);
  margin: 0 0 6px;
}

/* =================================================================
   Empty-world invitation modal — fired from .world-tile.is-empty
   ================================================================= */
html.modal-open,
body.modal-open { overflow: hidden; }

.modal-root {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.modal-root[hidden] { display: none; }

.modal-backdrop {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(60% 60% at 50% 30%, rgba(var(--world-color-rgb), 0.30) 0%, rgba(11, 8, 32, 0.10) 60%, transparent 100%),
    rgba(11, 8, 32, 0.78);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  animation: modal-backdrop-in .2s var(--easing) both;
}
@keyframes modal-backdrop-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.modal-card {
  position: relative;
  z-index: 1;
  width: min(480px, 100%);
  max-height: calc(100vh - 40px);
  overflow: auto;
  background:
    linear-gradient(180deg, rgba(26, 20, 64, 0.94) 0%, rgba(11, 8, 32, 0.98) 100%);
  border: 1px solid rgba(var(--world-color-rgb), 0.45);
  border-radius: 24px;
  box-shadow:
    0 30px 80px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(255, 255, 255, 0.04) inset,
    0 0 60px rgba(var(--world-color-rgb), 0.30);
  color: #fff;
  animation: modal-card-in .28s var(--easing) both;
}
@keyframes modal-card-in {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  color: rgba(255, 255, 255, 0.85);
  z-index: 2;
  transition: background .15s, color .15s, transform .15s var(--easing);
}
@media (hover: hover) { .modal-close:hover {
  background: rgba(var(--world-color-rgb), 0.30);
  color: #fff;
  transform: rotate(90deg);
} }
.modal-close i { width: 18px; height: 18px; stroke-width: 2.25; }

/* Hero strip — mascot + glowing world icon side-by-side */
.modal-hero {
  position: relative;
  padding: 32px 28px 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
}
.modal-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(60% 80% at 50% 0%, rgba(var(--world-color-rgb), 0.28) 0%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}
.modal-mascot {
  position: relative;
  z-index: 1;
  width: 110px;
  height: 110px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  filter: drop-shadow(0 10px 30px rgba(var(--world-color-rgb), 0.45));
  animation: modal-mascot-float 4s ease-in-out infinite;
}
.modal-mascot img {
  /* Mascot is 1414×2000 (≈ 0.707 portrait). Letting the IMG honour
     its natural ratio (height fills the parent, width derived) keeps
     PSI's aspect-ratio audit happy and prevents the squashed look
     `width:100%; height:100%` gave the modal hero. */
  width: auto;
  height: 100%;
  aspect-ratio: 1414 / 2000;
  object-fit: contain;
}
@keyframes modal-mascot-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}
.modal-world-icon {
  position: relative;
  z-index: 1;
  width: 72px;
  height: 72px;
  border-radius: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(var(--world-color-rgb), 0.20);
  color: var(--world-color);
  border: 1px solid rgba(var(--world-color-rgb), 0.45);
  box-shadow: 0 10px 30px rgba(var(--world-color-rgb), 0.30);
}
.modal-world-icon i {
  width: 38px;
  height: 38px;
  stroke-width: 1.75;
}

.modal-body {
  position: relative;
  z-index: 1;
  padding: 18px 28px 28px;
  text-align: center;
}

.modal-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 10px;
  padding: 5px 12px;
  border-radius: 999px;
  background: rgba(var(--world-color-rgb), 0.16);
  border: 1px solid rgba(var(--world-color-rgb), 0.32);
  color: var(--world-color);
  font-family: var(--font-h);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.modal-eyebrow i { width: 13px; height: 13px; stroke-width: 2.25; }

.modal-title {
  font-family: var(--font-h);
  font-weight: 900;
  font-size: clamp(22px, 4vw, 28px);
  line-height: 1.15;
  margin: 4px 0 12px;
  letter-spacing: -0.01em;
  color: #fff;
}
.modal-world-name {
  background: linear-gradient(135deg, var(--world-color), var(--orange));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 24px rgba(var(--world-color-rgb), 0.40));
}

.modal-desc {
  font-family: var(--font-b);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.82);
  margin: 0 0 22px;
}
.modal-desc strong {
  color: #fff;
  font-weight: 700;
}

.modal-stores {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: 0 0 18px;
}
.modal-store {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  padding: 4px;
  transition: transform .15s var(--easing), box-shadow .2s;
}
@media (hover: hover) { .modal-store:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 30px rgba(var(--world-color-rgb), 0.35);
} }
.modal-store:focus-visible {
  outline: 2px solid var(--world-color);
  outline-offset: 3px;
}
.modal-store img {
  display: block;
  height: 48px;
  width: auto;
}

.modal-microcopy {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 8px 14px;
  border-radius: 999px;
  background: rgba(16, 185, 129, 0.12);
  border: 1px solid rgba(16, 185, 129, 0.30);
  color: var(--green-light, #34D399);
  font-family: var(--font-b);
  font-weight: 600;
  font-size: 12px;
}
.modal-microcopy i { width: 14px; height: 14px; stroke-width: 2.25; }

/* Copy-to-clipboard variant of the microcopy pill — used by the
   challenge landing so the invite code can be tapped instead of
   hand-selected. It's a real <button>, so strip the UA chrome and
   restore the pill's own type ramp. `.is-copied` is toggled by the
   inline script in `challenge.html` for ~2 s after a successful copy. */
.invite-code-copy {
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
  font-family: var(--font-b);
  font-weight: 600;
  font-size: 12px;
  line-height: 1.2;
  cursor: pointer;
  /* iOS Safari paints a grey box over the pill on tap, which reads as
     a rendering glitch next to our own `.is-copied` feedback. */
  -webkit-tap-highlight-color: transparent;
  transition: background 0.18s ease, border-color 0.18s ease, transform 0.12s ease;
}
.invite-code-copy code { letter-spacing: 0.06em; }
@media (hover: hover) { .invite-code-copy:hover {
  background: rgba(16, 185, 129, 0.20);
  border-color: rgba(16, 185, 129, 0.55);
} }
.invite-code-copy:active { transform: scale(0.97); }
.invite-code-copy:focus-visible {
  outline: 2px solid var(--green-light, #34D399);
  outline-offset: 3px;
}
.invite-code-copy.is-copied {
  background: rgba(16, 185, 129, 0.24);
  border-color: rgba(16, 185, 129, 0.65);
}
@media (prefers-reduced-motion: reduce) {
  .invite-code-copy { transition: none; }
  .invite-code-copy:active { transform: none; }
}

/* Screen-reader-only live region (copy confirmation). Kept in the
   layout — `display:none` / `visibility:hidden` are ignored by
   assistive tech, so aria-live updates would never be announced. */
.sr-only {
  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;
}
@media (max-width: 480px) {
  .modal-hero { padding: 26px 20px 0; gap: 12px; }
  .modal-mascot { width: 92px; height: 92px; }
  .modal-world-icon { width: 60px; height: 60px; border-radius: 18px; }
  .modal-world-icon i { width: 32px; height: 32px; }
  .modal-body { padding: 16px 20px 22px; }
}

/* =================================================================
   Age switcher partial (`templates/_age_switcher.html`)
   -----------------------------------------------------------------
   Rendered on the worlds-index, category, and world pages so visitors
   can re-tune the active age band without losing their place. Lives
   in base.css (not home.css) because those directory pages don't load
   the landing's stylesheet — without it the pills collapse to flat
   inline text.
   ================================================================= */
.age-switcher {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 18px 0 0;
}
/* Each chip is colour-tinted via inline `--world-color` / `--world-color-rgb`
   set per-band in `_age_switcher.html`, so the same rule paints all bands in
   their signature colour without per-band CSS classes. Mirrors the
   `.home-cat-chip` style used by the world chips on the landing page. */
.age-switcher__chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px 8px 8px;
  border-radius: 999px;
  background: rgba(var(--world-color-rgb), 0.14);
  border: 1px solid rgba(var(--world-color-rgb), 0.30);
  color: var(--text);
  font-family: var(--font-h);
  font-weight: 700;
  font-size: 14px;
  text-decoration: none;
  transition: background .15s, border-color .15s, color .15s, transform .15s, box-shadow .15s;
}
@media (hover: hover) { .age-switcher__chip:hover {
  background: rgba(var(--world-color-rgb), 0.22);
  border-color: rgba(var(--world-color-rgb), 0.50);
  transform: translateY(-1px);
} }
.age-switcher__icon {
  display: inline-flex;
  width: 28px;
  height: 28px;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  background: rgba(var(--world-color-rgb), 0.30);
  color: var(--world-color);
  flex-shrink: 0;
}
.age-switcher__icon i { width: 16px; height: 16px; }
.age-switcher__num {
  font-weight: 900;
  letter-spacing: 0.02em;
}
.age-switcher__name {
  font-weight: 600;
  opacity: 0.88;
}
/* Active band pops with a saturated ring + glow + brighter icon chip
   so it reads as the current selection at a glance. */
.age-switcher__chip.is-active {
  background: rgba(var(--world-color-rgb), 0.28);
  border-color: rgba(var(--world-color-rgb), 0.70);
  box-shadow:
    inset 0 0 0 1px rgba(var(--world-color-rgb), 0.40),
    0 10px 24px rgba(var(--world-color-rgb), 0.30);
}
.age-switcher__chip.is-active .age-switcher__icon {
  background: var(--world-color);
  color: #fff;
}
.age-switcher__chip.is-active .age-switcher__name { opacity: 1; }
@media (max-width: 540px) {
  .age-switcher__name { display: none; }
  .age-switcher__chip { padding: 6px 12px 6px 6px; }
  .age-switcher__icon { width: 24px; height: 24px; }
  .age-switcher__icon i { width: 14px; height: 14px; }
}

/* =================================================================
   Primary nav — compact spacing so the canonical 6-link set
   (Home / Worlds / Blog / About / Privacy / Terms) fits on a
   single line at common desktop widths without wrapping.
   ================================================================= */
.site-nav { flex-wrap: wrap; }
.site-nav a { padding: 8px 12px; }
@media (min-width: 1100px) {
  .site-nav { gap: 6px; font-size: 16px; }
  .site-nav a { padding: 10px 14px; }
}

/* =================================================================
   Site footer — mirrors the canonical 6-link footer used on
   getxplain.ai/. Sits at the bottom of every page so visitors
   always have a path back to the marketing site, blog, and
   policy pages from inside the worlds navigator.

   Rendered fully transparent so the global starfield (rendered on
   <body>) shines through end-to-end. A soft full-bleed gradient
   line drawn via ::before replaces the old hard `border-top` so
   the footer melts into the page instead of reading as a boxed
   rectangle inside the 1280px `.app` column.
   ================================================================= */
.site-footer {
  position: relative;
  margin: 64px 0 0;
  padding: 28px 0 36px;
  background: transparent;
}
.site-footer::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100vw;
  max-width: 100%;
  height: 1px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    color-mix(in srgb, var(--text) 14%, transparent) 18%,
    color-mix(in srgb, var(--text) 22%, transparent) 50%,
    color-mix(in srgb, var(--text) 14%, transparent) 82%,
    transparent 100%
  );
  pointer-events: none;
}
.site-footer__inner {
  max-width: 1280px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
}
.site-footer__brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-h);
  font-weight: 900;
  font-size: 18px;
  color: var(--text);
  text-decoration: none;
  line-height: 1;
}
.site-footer__brand img {
  /* Match the natural 257×227 ratio of the logo source — keeps PSI
     from flagging the image as squashed. */
  width: 28px;
  aspect-ratio: 257 / 227;
  height: auto;
}
.site-footer__brand .b-get,
.site-footer__brand .b-plain { color: var(--text); }
.site-footer__brand .b-x {
  background: linear-gradient(180deg, #7B4DFF 0%, #AA8AFF 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.site-footer__brand .b-dot { color: #F5A623; }
.site-footer__brand .b-ai {
  background: linear-gradient(180deg, #F5A623 0%, #FFD700 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.site-footer__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 8px 14px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-muted);
}
.site-footer__links a {
  color: var(--text-muted);
  text-decoration: none;
  transition: color .15s;
}
@media (hover: hover) {
  .site-footer__links a:hover { color: var(--text); }
}
.site-footer__links span {
  color: color-mix(in srgb, var(--text) 18%, transparent);
}
.site-footer__copy {
  margin: 0;
  font-size: 12px;
  color: color-mix(in srgb, var(--text) 50%, transparent);
  letter-spacing: .02em;
}
@media (max-width: 600px) {
  .site-footer { margin-top: 48px; padding: 24px 0 32px; }
  .site-footer__links { font-size: 12.5px; gap: 6px 10px; }
}

/* =================================================================
   Deep-link share landings — profile / challenge / squad
   -----------------------------------------------------------------
   These pages render only when the OS *can't* hand the URL to the
   installed app via Universal / App Links, so they double as a
   recruitment surface. Layout aims for "polished mini-profile card
   + obvious install CTA" rather than the dense dashboard the
   in-app experience uses.
   ================================================================= */

/* Hero — large avatar with a glowing space ring, name + chips
   underneath. The halo + tier pip are siblings of the avatar
   (not pseudo-elements) so they can sit on top of the image
   without z-index gymnastics inside an element that also has
   `object-fit: cover`. */
.profile-hero {
  text-align: center;
  padding: 40px 16px 12px;
  position: relative;
}
.profile-hero__avatar-wrap {
  position: relative;
  display: inline-block;
  margin: 0 auto 18px;
  width: 128px;
  height: 128px;
}
.profile-hero__halo {
  position: absolute;
  inset: -28px;
  border-radius: 50%;
  background:
    radial-gradient(closest-side,
      rgba(var(--world-color-rgb), 0.45) 0%,
      rgba(var(--world-color-rgb), 0.18) 45%,
      transparent 75%);
  filter: blur(2px);
  pointer-events: none;
  z-index: 0;
  animation: profile-halo-pulse 6s ease-in-out infinite;
}
@keyframes profile-halo-pulse {
  0%, 100% { transform: scale(1);   opacity: 0.85; }
  50%      { transform: scale(1.05); opacity: 1; }
}
.profile-hero__avatar {
  position: relative;
  z-index: 1;
  width: 128px;
  height: 128px;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid rgba(255, 255, 255, 0.18);
  box-shadow:
    0 0 0 3px rgba(var(--world-color-rgb), 0.30),
    0 18px 42px rgba(var(--world-color-rgb), 0.35);
  background: var(--surface);
}
.profile-hero__avatar--placeholder {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.85);
  background:
    radial-gradient(circle at 30% 25%,
      rgba(var(--world-color-rgb), 0.55),
      rgba(var(--world-color-rgb), 0.10) 70%);
}
.profile-hero__avatar--placeholder i {
  width: 56px;
  height: 56px;
  stroke-width: 1.75;
}
.profile-hero__tier-pip {
  position: absolute;
  z-index: 2;
  right: -2px;
  bottom: -2px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--purple), var(--orange));
  color: #fff;
  border: 3px solid var(--bg-top);
  box-shadow: 0 6px 18px rgba(123, 77, 255, 0.45);
}
.profile-hero__tier-pip i {
  width: 18px;
  height: 18px;
  stroke-width: 2.25;
}

.profile-hero__name {
  margin: 8px 0 14px;
  font-size: clamp(28px, 4vw, 44px);
}

/* Quick-glance chips (age / joined / location). Reset the default
   <ul> spacing so the chip row sits flush under the name. */
.profile-chips {
  list-style: none;
  padding: 0;
  margin: 0 auto;
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  max-width: 620px;
}
.profile-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.10);
  color: var(--text-soft);
  font-family: var(--font-b);
  font-weight: 600;
  font-size: 13px;
  white-space: nowrap;
}
.profile-chip i {
  width: 14px;
  height: 14px;
  stroke-width: 2.25;
  color: var(--purple-light);
  flex-shrink: 0;
}

/* Stat cards — Total XP, Level, Member since. Three columns on
   desktop, two on tablet, single column on mobile. The middle
   level card is wider than its siblings on small viewports
   because of the inline progress bar. */
.profile-stats {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  max-width: 880px;
  margin: 28px auto 0;
  padding: 0 16px;
}
@media (min-width: 720px) {
  .profile-stats { grid-template-columns: repeat(3, 1fr); gap: 18px; }
}
.profile-stat {
  position: relative;
  background: var(--card-fill);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-xl);
  padding: 18px 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  overflow: hidden;
}
.profile-stat::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    rgba(var(--world-color-rgb), 0.10) 0%,
    transparent 60%);
  pointer-events: none;
}
.profile-stat__icon {
  position: relative;
  width: 38px;
  height: 38px;
  border-radius: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(var(--world-color-rgb), 0.18);
  color: var(--world-color);
  margin-bottom: 6px;
}
.profile-stat__icon i { width: 20px; height: 20px; stroke-width: 2; }
.profile-stat__value {
  position: relative;
  font-family: var(--font-h);
  font-weight: 800;
  font-size: 26px;
  line-height: 1.1;
  color: var(--text);
}
.profile-stat__label {
  position: relative;
  font-size: 13px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}
.profile-stat__progress {
  position: relative;
  margin-top: 12px;
  height: 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
}
.profile-stat__progress-bar {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--purple), var(--orange));
  transition: width .4s var(--easing);
}
.profile-stat__progress-label {
  position: relative;
  margin-top: 6px;
  font-size: 12px;
  color: var(--text-muted);
}
/* Stat-specific accents — paint each card with a different
   primary colour so the trio reads as "explore, win, journey"
   at a glance instead of three identical purple boxes. */
.profile-stat--xp { --world-color: var(--orange); --world-color-rgb: 245, 166, 35; }
.profile-stat--level { --world-color: var(--purple); --world-color-rgb: 123, 77, 255; }
.profile-stat--since { --world-color: var(--blue); --world-color-rgb: 59, 130, 246; }

/* About card — school + city/country in a labelled list. */
.profile-about,
.profile-pitch {
  max-width: 680px;
  margin: 36px auto 0;
  padding: 22px 22px 20px;
  background: var(--card-fill);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-xl);
}
.profile-about { padding: 22px 22px 14px; }
.profile-about__title,
.profile-pitch__title {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 16px;
  font-family: var(--font-h);
  font-weight: 800;
  font-size: 18px;
  color: var(--text);
}
.profile-about__title i,
.profile-pitch__title i {
  width: 18px;
  height: 18px;
  color: var(--purple-light);
}
.profile-about__rows,
.profile-pitch__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.profile-about__row,
.profile-pitch__item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.profile-about__row-icon,
.profile-pitch__item-icon {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(123, 77, 255, 0.15);
  color: var(--purple-light);
}
.profile-about__row-icon i,
.profile-pitch__item-icon i {
  width: 16px;
  height: 16px;
  stroke-width: 2.25;
}
.profile-about__row-label {
  display: block;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 700;
  margin-bottom: 2px;
}
.profile-about__row-value {
  display: block;
  font-size: 15px;
  color: var(--text);
  line-height: 1.4;
}
.profile-pitch__item {
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--text-soft);
}
.profile-pitch__item strong { color: var(--text); font-weight: 700; }

/* =================================================================
   Install CTA card (`templates/_install_cta.html`)
   -----------------------------------------------------------------
   Shared by the profile, challenge, and squad deeplink fallbacks.
   Layout is mascot-on-the-left, body-on-the-right at >=720px,
   stacked + centered below that.
   ================================================================= */
.install-cta {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 18px;
  max-width: 720px;
  margin: 40px auto 24px;
  padding: 28px 24px 26px;
  background: var(--card-fill-strong);
  border: 1px solid rgba(123, 77, 255, 0.32);
  border-radius: var(--radius-2xl);
  box-shadow: 0 24px 60px rgba(123, 77, 255, 0.18);
  overflow: hidden;
}
.install-cta__halo {
  position: absolute;
  inset: -20%;
  z-index: 0;
  background:
    radial-gradient(40% 60% at 20% 30%, rgba(123, 77, 255, 0.35) 0%, transparent 70%),
    radial-gradient(45% 55% at 85% 70%, rgba(245, 166, 35, 0.20) 0%, transparent 75%);
  pointer-events: none;
}
.install-cta__hero {
  position: relative;
  z-index: 1;
  width: 120px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.install-cta__mascot {
  display: inline-block;
  filter: drop-shadow(0 12px 28px rgba(123, 77, 255, 0.45));
  animation: install-mascot-float 5s ease-in-out infinite;
}
.install-cta__mascot picture,
.install-cta__mascot img {
  display: block;
  width: 100%;
  height: auto;
  max-width: 120px;
}
@keyframes install-mascot-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}
.install-cta__body {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}
.install-cta__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 5px 12px;
  border-radius: 999px;
  background: rgba(123, 77, 255, 0.18);
  border: 1px solid rgba(123, 77, 255, 0.40);
  color: var(--purple-light);
  font-family: var(--font-h);
  font-weight: 800;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.install-cta__eyebrow i { width: 13px; height: 13px; stroke-width: 2.25; }
.install-cta__headline {
  font-family: var(--font-h);
  font-weight: 900;
  font-size: clamp(22px, 3vw, 28px);
  line-height: 1.18;
  margin: 4px 0 4px;
  color: #fff;
  letter-spacing: -0.01em;
}
.install-cta__subcopy {
  font-family: var(--font-b);
  font-weight: 400;
  font-size: 14.5px;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.84);
  margin: 0 0 10px;
  max-width: 440px;
}
.install-cta__stores {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: 4px 0 6px;
}
.install-cta__store {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  padding: 4px;
  transition: transform .15s var(--easing), box-shadow .2s;
}
@media (hover: hover) { .install-cta__store:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 30px rgba(123, 77, 255, 0.35);
} }
.install-cta__store:focus-visible {
  outline: 2px solid var(--purple-light);
  outline-offset: 3px;
}
.install-cta__store img {
  display: block;
  height: 48px;
  width: auto;
}
.install-cta__microcopy {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 6px 0 0;
  padding: 8px 14px;
  border-radius: 999px;
  background: rgba(16, 185, 129, 0.12);
  border: 1px solid rgba(16, 185, 129, 0.30);
  color: var(--green-light);
  font-family: var(--font-b);
  font-weight: 600;
  font-size: 12px;
}
.install-cta__microcopy i {
  width: 14px;
  height: 14px;
  stroke-width: 2.25;
}

@media (min-width: 720px) {
  .install-cta {
    flex-direction: row;
    text-align: left;
    align-items: center;
    gap: 28px;
    padding: 32px 32px 30px;
  }
  .install-cta__body { align-items: flex-start; }
  .install-cta__stores { justify-content: flex-start; }
}

@media (max-width: 480px) {
  .profile-hero { padding: 28px 12px 8px; }
  .profile-hero__avatar-wrap,
  .profile-hero__avatar { width: 108px; height: 108px; }
  .profile-hero__avatar--placeholder i { width: 46px; height: 46px; }
  .profile-hero__tier-pip { width: 36px; height: 36px; }
  .profile-hero__tier-pip i { width: 16px; height: 16px; }
  .install-cta__hero { width: 96px; }
  .install-cta__mascot picture,
  .install-cta__mascot img { max-width: 96px; }
}

@font-face {
  font-family: 'MadikaArabic';
  src: url('../fonts/MadikaArabic-Regular.otf') format('opentype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

.brand,
.site-footer__brand { direction: ltr; unicode-bidi: isolate; }

html[dir="rtl"] .crumb-sep { transform: scaleX(-1); }

.ltr-fallback { direction: ltr; unicode-bidi: isolate; }
