:root{
  --indigo: #168BEA;
  --indigo-dark: #0568C9;
  --violet: #075FB8;
  --panel-dark: #0F1B33;
  --ink: #153A60;
  --ink-soft: #5C7692;
  --bg: #F3F9FF;
  --bg-panel: #FFFFFF;
  --amber: #FFC326;
  --red: #DC2626;
  --green: #16A34A;
  --line: #C9E2F8;
  --gradient: linear-gradient(135deg, #168BEA 0%, #0568C9 55%, #075FB8 100%);
  --font-display: 'Space Grotesk', sans-serif;
  --font-body: 'Inter', sans-serif;
}

*{ margin:0; padding:0; box-sizing:border-box; }
html{ scroll-behavior:smooth; }
body{
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  min-height:100vh;
}

/* Site interface language: Burmese (see js/i18n.js). Space Grotesk/Inter
   have no Myanmar glyphs, so any Burmese text was silently falling back to
   whatever Myanmar font each visitor's OS happens to ship — inconsistent,
   and often with tight default metrics. Noto Sans Myanmar (loaded in the
   <head> of every page) is designed for this script specifically, so once
   the page is in Burmese we point both font vars at it first (Latin
   fragments mixed into Burmese text — a name, "XP", "CEFR" — still fall
   through to Space Grotesk/Inter/sans-serif via the rest of the stack).
   This alone doesn't fix spacing, though — see the letter-spacing/
   line-height overrides below, which are the actual fix for text looking
   cramped in Burmese. */
html[lang="my"]{
  --font-display: 'Noto Sans Myanmar', 'Space Grotesk', sans-serif;
  --font-body: 'Noto Sans Myanmar', 'Inter', sans-serif;
}

/* Several headings/labels use a tight negative letter-spacing and a tight
   line-height (as low as 1.06) — a deliberate stylistic choice for the
   Latin display font, Space Grotesk, but Burmese script relies on normal
   spacing to keep stacked vowel signs and consonant conjuncts legible.
   With the tight values still applied, translated Burmese headings and
   pill/tag labels rendered visibly cramped — this resets both to
   comfortable defaults specifically when the page is in Burmese, without
   touching the English/default styling at all. */
html[lang="my"] h1,
html[lang="my"] h2,
html[lang="my"] h3,
html[lang="my"] h4,
html[lang="my"] .brand-text,
html[lang="my"] .langs span,
html[lang="my"] .lang-toggle-btn,
html[lang="my"] .tag,
html[lang="my"] .status-chip,
html[lang="my"] .stat span,
html[lang="my"] .nav-links a{
  letter-spacing: normal;
}
html[lang="my"] h1{ line-height:1.35; }
html[lang="my"] h2{ line-height:1.35; }
html[lang="my"] .subhead,
html[lang="my"] .section-head p,
html[lang="my"] .card p{ line-height:1.85; }
a{ color:inherit; text-decoration:none; }
img{ max-width:100%; display:block; }
button{ font-family:inherit; cursor:pointer; }
input, select{ font-family:inherit; }

.wrap{ max-width:1180px; margin:0 auto; padding:0 32px; }

/* ---------- NAV ---------- */
header{
  position:sticky; top:0; z-index:50;
  background: rgba(243,249,255,0.88);
  backdrop-filter: blur(10px);
  border-bottom:1px solid var(--line);
}
nav{
  display:flex; align-items:center; justify-content:space-between;
  padding:18px 32px;
  max-width:1180px; margin:0 auto;
}
.brand{ display:flex; align-items:center; gap:12px; }
.brand-mark{
  width:40px; height:40px; border-radius:11px;
  background: var(--gradient);
  display:flex; align-items:center; justify-content:center;
  color:white; font-family:var(--font-display); font-weight:700; font-size:18px;
  box-shadow: 0 6px 16px rgba(22,139,234,0.35);
}
.brand-text{ font-family:var(--font-display); font-weight:700; font-size:19px; letter-spacing:-0.01em; }
.brand-text span{ color:var(--indigo); }
.brand-sub{ font-size:10.5px; letter-spacing:0.12em; color:var(--ink-soft); font-weight:600; margin-top:1px; }

/* Tokify logo lockup (icon + wordmark + tagline in one image). Two PNGs are
   shipped — a dark-ink version for the light theme and a white-ink version
   for the dark theme (see js/theme-toggle.js, which toggles data-theme) —
   swapped purely with display:none so no JS is needed. */
.brand-logo{ height:60px; width:auto; display:block; }
.brand-logo-dark{ display:none; }
html[data-theme="dark"] .brand-logo-light{ display:none; }
html[data-theme="dark"] .brand-logo-dark{ display:block; }
.footer-brand .brand-logo{ height:74px; }

.nav-links{ display:flex; align-items:center; gap:6px; }
.nav-links a{
  font-size:14.5px; font-weight:500; color:var(--ink-soft);
  padding:9px 16px; border-radius:999px; transition:.18s;
  /* Flex items shrink below their text's natural width by default, and
     Myanmar phrases ("ပင်မ စာမျက်နှာ", etc.) are long enough that this
     squeezed them until the words wrapped onto two lines, turning each
     pill into an ugly tall box. nowrap + flex-shrink:0 keeps every link on
     one line at its natural width instead of getting compressed. */
  white-space:nowrap; flex-shrink:0;
}
.nav-links a:hover{ background:#E3F2FD; color:var(--indigo-dark); }
.nav-links a.active{ background:var(--gradient); color:#fff; box-shadow:0 4px 12px rgba(22,139,234,0.3); }

.nav-right{ display:flex; align-items:center; gap:10px; }
/* Login/Sign Up are plain .btn.btn-sm elements here (not .pill), which the
   earlier nowrap fix didn't cover — same squeeze-then-wrap problem with the
   longer Myanmar labels ("ဝင်ရောက်ရန်", "အခမဲ့စာရင်းသွင်းရန်"). Scoped to
   nav-right's direct children so it doesn't change .btn wrapping anywhere
   else on the site (e.g. narrow-mobile CTA buttons where wrapping is fine). */
.nav-right > *{ white-space:nowrap; flex-shrink:0; }
/* Myanmar script runs noticeably wider than Latin at the same size, so once
   wrapping was fixed above, the full row (nav links + EN/MY toggle + theme
   toggle + login/signup) no longer had room to breathe and every item
   pressed right up against its neighbor. Trimming font-size/padding/gaps
   specifically for lang="my" recovers spacing without touching the
   (already-fine) English layout. */
html[lang="my"] .nav-links{ gap:2px; }
html[lang="my"] .nav-links a{ font-size:13px; padding:8px 12px; }
html[lang="my"] .nav-right{ gap:6px; }
html[lang="my"] .nav-right .btn-sm{ font-size:12px; padding:8px 12px; }
html[lang="my"] .pill{ font-size:11.5px; padding:6px 10px; }
.pill{
  display:flex; align-items:center; gap:6px;
  font-size:13px; font-weight:600;
  padding:7px 13px; border-radius:999px;
  border:1px solid var(--line); background:#fff;
  white-space:nowrap; flex-shrink:0; /* same wrapping fix as .nav-links a, for the login/streak/xp pills */
}
.pill.streak{ color:#8A5A00; border-color:#FCE3B0; background:#FFF8EA; }
.pill.xp{ color:var(--indigo-dark); border-color:#BFE0FA; background:#E3F2FD; }
.pill-icon{ width:14px; height:14px; flex-shrink:0; }
.avatar{
  width:34px; height:34px; border-radius:50%;
  background: var(--gradient);
  display:flex; align-items:center; justify-content:center;
  color:#fff; font-size:13px; font-weight:700; font-family:var(--font-display);
}
.nav-toggle{
  display:none; background:none; border:1px solid var(--line); border-radius:10px;
  width:40px; height:40px; align-items:center; justify-content:center; font-size:18px;
}

/* ---------- BUTTONS ---------- */
.btn{
  font-family: var(--font-body); font-weight:700; font-size:15px;
  padding:15px 28px; border-radius:12px;
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  border:none; cursor:pointer; transition:.18s;
}
.btn-primary{
  background:var(--amber); color:var(--ink);
  box-shadow:0 10px 24px rgba(255,195,38,0.35);
}
.btn-primary:hover{ transform:translateY(-2px); box-shadow:0 14px 30px rgba(255,195,38,0.45); filter:brightness(0.96); }
.btn-primary:disabled{ opacity:0.6; cursor:not-allowed; transform:none; }

/* ---------- MINIMAL ARROW ICON ---------- */
/* js/arrow-icons.js swaps a trailing "→" text character (used at the end
   of most CTA button/link labels — "Start Learning →", "Log In →", the
   amber-circle .btn-arrow-badge on class cards, etc.) for
   <span class="ic-arrow"><svg>...</svg></span>. The icon is drawn with
   stroke="currentColor" — same convention as the sun/moon icon in
   js/theme-toggle.js — so it always renders in the element's own (already
   theme-aware) text color instead of a font glyph whose weight varies by
   OS/browser. Sizing is in `em` so it scales with whatever font-size its
   container already uses (a 15px .btn label vs. the 32px .btn-arrow-badge
   circle, for example) without needing a rule per context. */
.ic-arrow{ display:inline-flex; align-items:center; width:0.85em; height:0.85em; margin-left:6px; vertical-align:-0.125em; flex-shrink:0; transition:transform .2s ease; }
.ic-arrow svg{ width:100%; height:100%; display:block; }
/* Nudges every arrow icon a few pixels to the right on hover of its parent
   button/link — sitewide, since every "Start Learning →"-style label goes
   through this one shared .ic-arrow convention, not just the homepage CTA
   banner below. A small, common "this is clickable" cue rather than
   anything flashy. */
a:hover > .ic-arrow, button:hover > .ic-arrow{ transform:translateX(3px); }

/* ---------- Homepage closing CTA banner ("Ready to start speaking?") ----------
   A gentle lift + a blue-tinted glow (rather than the neutral grey shadow
   used elsewhere) on hover, since this card is the one solid-color gradient
   block on the page rather than a plain white surface — a grey shadow would
   barely read against it. Reveals on scroll the same way as every other
   animated section (js/scroll-reveal.js). */
.cta-banner{ transition:transform .3s ease, box-shadow .3s ease; }
.cta-banner:hover{ transform:translateY(-5px); box-shadow:0 22px 48px rgba(37,99,235,.35); }

@media (prefers-reduced-motion: reduce){
  .ic-arrow{ transition:none; }
  a:hover > .ic-arrow, button:hover > .ic-arrow{ transform:none; }
  .cta-banner{ transition:none; }
  .cta-banner:hover{ transform:none; }
}
/* .btn and .lang-class-cta are flex containers that already put a `gap`
   between their children, so the icon doesn't also need its own margin
   there — this only matters for a plain (non-.btn) inline link like
   "Go to log in →", where the margin above is what separates the text
   from the icon. */
.btn .ic-arrow, .lang-class-cta .ic-arrow{ margin-left:0; }

.btn-ghost{
  background:#fff; color:var(--ink); border:1.5px solid var(--line);
}
.btn-ghost:hover{ border-color:var(--indigo); color:var(--indigo-dark); }
.btn-sm{ padding:10px 18px; font-size:13.5px; border-radius:10px; }
.btn-block{ width:100%; }
/* Minimal line-icon (stroke:currentColor) instead of a colorful emoji, so
   it inherits the button's own text color/theme rather than looking like a
   mismatched sticker — used on "Start Free Test" in the hero. */
.btn-icon-svg{ width:16px; height:16px; flex-shrink:0; }

/* ---------- SPECULAR BUTTON (mouse-tracking shine ring) ---------- */
/* Add class="btn-specular" to any .btn to get a thin light line that
   traces the button's own border and follows the cursor within ~250px of
   it — a plain-CSS/JS recreation of reactbits.dev's "Specular Button"
   (followMouse, proximity=250, intensity=1, no idle/auto-animation — the
   line only appears once the cursor is near). The actual mouse-tracking
   (setting --spec-angle/--spec-opacity) lives in js/specular-button.js,
   shared across every .btn-specular on the page; this is just the ring
   itself, layered on top of whatever the button's own background/color
   already are (amber, ghost, etc. — this only adds the shine, it doesn't
   replace a button's existing look). */
.btn-specular{
  position:relative;
  --spec-line: 255,255,255;  /* lineColor, as r,g,b for rgba() */
  --spec-angle: 0deg;        /* set by JS: direction from button center to cursor */
  --spec-opacity: 0;         /* set by JS: 0 outside proximity, up to 1 near/over it */
}
.btn-specular::before{
  content:''; position:absolute; inset:0; border-radius:inherit;
  /* An actual `border` (not padding) is required for the padding-box vs
     border-box double-mask below to have two genuinely different regions
     to XOR against each other — that's what carves out a ring instead of
     filling the whole button. */
  border:1.5px solid transparent;
  /* Bright band sits at the gradient's 0%/100% wrap-around point, which is
     exactly the conic-gradient's "from" angle — so the shine faces the
     cursor directly instead of landing 180° opposite it. */
  background:
    conic-gradient(from var(--spec-angle),
      rgba(var(--spec-line), var(--spec-opacity)) 0%,
      rgba(var(--spec-line), var(--spec-opacity)) 6%,
      rgba(var(--spec-line), 0) 40%,
      rgba(var(--spec-line), 0) 60%,
      rgba(var(--spec-line), var(--spec-opacity)) 94%,
      rgba(var(--spec-line), var(--spec-opacity)) 100%) border-box;
  -webkit-mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  /* A soft drop-shadow glow (absent from the original preview, which used
     blur=0) — a crisp 1px line all but disappears against a busy gradient
     background at normal viewing size, so this adds just enough glow to
     read clearly without looking like a thick outline. */
  filter:drop-shadow(0 0 4px rgba(255,255,255,var(--spec-opacity)));
  pointer-events:none;
}

/* ---------- HERO ---------- */
.hero{ padding:96px 32px 70px; text-align:center; position:relative; overflow:hidden; background:var(--gradient); border-radius:0 0 40px 40px; color:#fff; margin-bottom:60px; }
#heroWaves{ position:absolute; inset:0; width:100%; height:100%; z-index:0; display:block; pointer-events:none; }
.hero::before{
  content:''; position:absolute; top:-200px; left:50%; transform:translateX(-50%);
  width:900px; height:600px;
  background: radial-gradient(circle, rgba(255,255,255,0.10) 0%, rgba(255,255,255,0.04) 45%, transparent 70%);
  pointer-events:none;
  z-index:0;
}
.hero .wrap{ position:relative; z-index:1; }
.eyebrow{
  display:inline-flex; align-items:center; gap:8px;
  font-size:12.5px; font-weight:700; letter-spacing:0.04em;
  color:var(--indigo-dark);
  background:#fff; border:1px solid rgba(255,255,255,0.6);
  padding:8px 18px; border-radius:999px; margin-bottom:28px;
  position:relative; z-index:1;
}
h1{
  font-family:var(--font-display);
  font-size:clamp(32px, 6.2vw, 68px);
  line-height:1.06; letter-spacing:-0.025em; font-weight:700; position:relative; z-index:1;
  /* No color here on purpose: this bare h1 selector applies to every page,
     not just the homepage hero. Forcing white here made every other page's
     h1 (dashboard, classes, lesson titles) invisible against their light
     background. White still applies correctly on the homepage because
     .hero itself sets color:#fff (see above), which this h1 inherits;
     everywhere else it now correctly inherits body's dark --ink color. */
}
h1 .grad{ color:var(--amber); background:none; -webkit-background-clip:unset; }
.subhead{ max-width:640px; margin:26px auto 0; font-size:17px; line-height:1.65; color:rgba(255,255,255,0.9); position:relative; z-index:1; }

.langs{ display:flex; flex-wrap:wrap; justify-content:center; gap:14px; margin:56px auto 44px; position:relative; z-index:1; }
/* This 56px/44px vertical margin is tuned for the homepage hero, where
   .langs is its own centered block below the subhead. On the dashboard,
   #langSwitcher reuses this same class but sits as a flex item next to the
   greeting inside .dash-head — the hero's margin doesn't apply there, so
   it's zeroed out and .dash-head's own `gap` handles the spacing instead. */
.dash-head .langs{ margin:0; }
/* Default (light-background) styling — used on the dashboard's language
   switcher, which sits on the normal page background, not the dark hero
   gradient. Same bug pattern as the earlier h1 fix: this class is shared
   between the homepage hero and the dashboard, and a white-on-translucent-
   white style tuned for the hero was leaking onto the light dashboard,
   making the language pills unreadable. */
.langs span{
  font-family:var(--font-display); font-weight:600; font-size:13.5px; color:var(--ink);
  padding:7px 16px; border-radius:999px; background:var(--bg-panel, #fff); border:1px solid var(--line);
}
.langs span.selectable{ cursor:pointer; transition:.15s; }
.langs span.selectable:hover{ background:var(--line); }
.langs span.selectable.active{ background:var(--indigo); color:#fff; border-color:transparent; }
.langs span.coming-soon{ cursor:not-allowed; color:var(--ink-soft); opacity:0.55; }
.langs span.coming-soon:hover{ opacity:0.8; }

/* Homepage hero override — dark gradient background needs the translucent-
   white treatment instead of the light-background default above. Scoped to
   .hero so it stays put and can't leak onto other pages again.
   Also recreates the "glass" look of reactbits.dev's GlassIcons component
   (per-item vibrant gradient tile + a diagonal glossy shine + hover lift) —
   bigger, and adapted onto these pill-shaped language badges rather than
   GlassIcons' own square icon tiles, since these already carry text labels
   instead of icon+hover-caption. */
.hero .langs span{
  position:relative; overflow:hidden; isolation:isolate;
  font-size:13px; padding:8px 16px;    /* back down close to the base .langs span size (13.5px / 7px 16px) */
  /* Back to the original plain translucent-white pill (not a colored
     gradient tile) per feedback — the glass *shine* and hover-lift motion
     below are kept, just not the GlassIcons color treatment underneath. */
  color:#fff; background:rgba(255,255,255,0.16); border:1px solid rgba(255,255,255,0.3);
  box-shadow:0 10px 22px rgba(6,20,45,0.28);
  transition:transform .2s ease, box-shadow .2s ease, background .2s ease;
}
/* The glossy diagonal streak — kept from the GlassIcons pass as the one
   "animation" element the user asked to keep even after the color reverted. */
.hero .langs span::before{
  content:''; position:absolute; inset:0;
  background:linear-gradient(135deg, rgba(255,255,255,0.4) 0%, rgba(255,255,255,0.05) 40%, rgba(255,255,255,0) 60%);
  pointer-events:none;
}
.hero .langs span:hover{ transform:translateY(-3px); box-shadow:0 16px 28px rgba(6,20,45,0.38); background:rgba(255,255,255,0.26); }
.hero .langs span.selectable:hover{ background:rgba(255,255,255,0.26); }
.hero .langs span.selectable.active{ background:#fff; color:var(--indigo-dark); border-color:transparent; }
.hero .langs span.selectable.active::before{ display:none; }

.cta-row{ display:flex; gap:14px; justify-content:center; flex-wrap:wrap; position:relative; z-index:1; }
.hero .btn-ghost{ background:rgba(255,255,255,0.1); color:#fff; border:1px solid rgba(255,255,255,0.35); }
.hero .btn-ghost:hover{ background:rgba(255,255,255,0.18); border-color:#fff; color:#fff; }

/* ---------- HERO: two-column layout + language "speaking practice" card stack ----------
   Left column keeps the original centered hero content (now left-aligned);
   right column is a stack of 5 cards (one per language), auto-cycling one
   at a time, matching the reference "pop-up photo + glass panel" card look.
   Colors are deliberately a darker navy-blue glass panel (not the same hue
   as the hero's own lighter gradient) so the card reads as a distinct
   floating element rather than blending into the background it sits on. */
.hero .wrap.hero-grid{
  display:grid; grid-template-columns:1.05fr 1fr; align-items:center; gap:48px;
  text-align:left;
}
/* The base h1 rule (clamp up to 68px) is shared by every page's h1, so it
   can't be shrunk globally — but at that size in this hero's narrower
   ~55%-width column, most words no longer fit two-to-a-line and each one
   wraps onto its own line ("Speak" / "Languages" / "With Native" /
   "Confidence."), reading as oversized. Scoped smaller just here. */
.hero-copy h1{ text-align:left; font-size:clamp(28px, 3.6vw, 48px); }
/* The base .subhead's max-width:640px was tuned for the old single-column
   centered hero; in this narrower two-column layout it let lines run long
   and uneven, ending in a short orphan line ("accredited certification.")
   dangling under two much longer ones. A tighter max-width plus
   text-wrap:pretty (balances line lengths where supported, and otherwise
   just avoids single-word trailing lines) gives more even, readable lines. */
.hero-copy .subhead{ margin:22px 0 0; text-align:left; max-width:480px; text-wrap:pretty; }
.hero-copy .langs{ justify-content:flex-start; margin:40px 0 32px; }
.hero-copy .cta-row{ justify-content:flex-start; margin:0; }
/* Burmese script runs visually larger than Latin at the same font-size
   (taller stacked vowel signs/conjuncts), so the translated hero headline
   and paragraph read oversized next to the English version even though the
   px values match. Scoped a bit smaller just for lang="my", just in the
   hero, rather than touching the shared clamp() everything else still uses. */
html[lang="my"] .hero-copy h1{ font-size:clamp(24px, 3.1vw, 42px); }
html[lang="my"] .hero-copy .subhead{ font-size:15px; }
/* Pill-shaped buttons, scoped to the hero only, to match the requested
   reference layout without changing button shape anywhere else on the site. */
.hero .btn{ border-radius:999px; }

/* Was just the card by itself, vertically centered by the grid's
   align-items:center against the taller left column — which left a big
   empty gap above it (the left column's own eyebrow badge, h1, paragraph
   etc. push the row taller than the card alone). Moving the eyebrow badge
   in here as a flex column fills that gap with it — but the grid's
   align-items:center was centering this whole (badge+card) block as a unit,
   which left the badge sitting low, right above the card, instead of up in
   that gap. align-self:flex-start pins this column to the top of the row
   instead, so the badge lands level with the headline on the left. */
.hero-visual{ position:relative; display:flex; flex-direction:column; align-items:center; gap:28px; align-self:flex-start; }
.hero-visual .eyebrow{ margin-bottom:0; }
.lang-card-stack{
  position:relative; width:100%; max-width:520px; margin:0 auto;
  aspect-ratio:16/10; min-height:260px;
}
.lang-card{
  position:absolute; inset:0; border-radius:26px; overflow:visible;
  background:rgba(15,27,51,0.55);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  border:1px solid rgba(255,255,255,0.18);
  box-shadow:0 30px 60px rgba(5,20,45,0.35);
  opacity:0; transform:translateY(18px) scale(0.97);
  transition:opacity .5s ease, transform .5s ease;
  pointer-events:none; cursor:pointer;
}
.lang-card.is-active{ opacity:1; transform:translateY(0) scale(1); pointer-events:auto; z-index:2; }
/* eyebrow+word used to each be their own position:absolute box with a
   hardcoded top (26px / 52px) — fine only as long as the eyebrow label
   stayed on one line. Several languages' labels ("SHAN · SPEAKING
   PRACTICE", "CHINESE · SPEAKING PRACTICE", ...) wrap to two lines at
   this width, which made the eyebrow taller than the 26px gap the word's
   fixed top left for it, so the big word text was drawn starting
   part-way through the eyebrow's own second line — a real overlap, not
   just tight spacing. Grouping them in one flow container (.lang-card-text
   below, which carries the position:absolute/top/left/right that used to
   be on the eyebrow alone) means the word always starts right after
   whatever height the eyebrow actually rendered at, 1 line or 2. */
.lang-card-text{ position:absolute; top:26px; left:26px; right:40%; }
.lang-card-eyebrow{
  font-size:11.5px; font-weight:700; letter-spacing:0.12em; color:rgba(255,255,255,0.85);
}
.lang-card-word{
  margin-top:4px;
  font-family:var(--font-display); font-weight:700; color:#fff;
  font-size:clamp(28px, 4vw, 44px); line-height:1.1;
}
.lang-card-photo{
  position:absolute; right:6%; top:-12%; height:124%; width:auto; max-width:46%;
  border-radius:18px; overflow:hidden;
  -webkit-mask-image:linear-gradient(to bottom, #000 78%, transparent 100%);
  mask-image:linear-gradient(to bottom, #000 78%, transparent 100%);
  /* The box is 124% of the card's height (top:-12%) on purpose, so the
     person's head/headphones can rise above the card's top edge. But that
     same math means the bottom of the box also overshoots the card by the
     same 12%, letting legs/pants spill out past the card's rounded bottom
     corner. Clip-path (not `overflow:hidden` on the parent .lang-card,
     which would also chop off the top pop-out effect) cuts off only that
     excess bottom sliver, right where it lines up with the card's own
     bottom edge — top overflow is untouched. */
  clip-path:inset(0 0 9.7% 0);
}
/* object-fit:contain (not cover) — these are transparent cutouts of the
   client's own reference photos, not rectangular stock images, so the full
   person should stay visible rather than being cropped to fill the box. */
.lang-card-photo img{ width:100%; height:100%; object-fit:contain; object-position:bottom center; display:block; }
.lang-card-badge{
  position:absolute; right:8%; bottom:10%; width:34px; height:34px; border-radius:50%;
  background:var(--amber); color:#1A1300; display:flex; align-items:center; justify-content:center;
  font-size:15px; box-shadow:0 6px 14px rgba(0,0,0,0.25); z-index:3;
}
/* Fixed hex colors (not the --ink/--ink-soft vars) on purpose: this glass
   panel is always a light card regardless of site theme, so it must not
   pick up dark mode's light-on-dark --ink swap (which would make its text
   nearly invisible against this permanently-light background). */
.lang-card-panel{
  position:absolute; left:5%; bottom:9%; width:60%; max-width:320px;
  background:rgba(255,255,255,0.88); backdrop-filter:blur(16px) saturate(180%);
  -webkit-backdrop-filter:blur(16px) saturate(180%);
  border:1px solid rgba(255,255,255,0.5); border-radius:16px; padding:14px 16px;
  display:flex; align-items:center; gap:10px;
}
.lang-card-panel-text{ flex:1; min-width:0; }
.lang-card-panel-text strong{ display:block; font-size:13px; color:#153A60; font-weight:700; }
.lang-card-panel-text span{ display:block; font-size:11px; color:#5C7692; margin-top:1px; }
.lang-card-wave{ display:flex; align-items:center; gap:2px; height:22px; flex-shrink:0; }
.lang-card-wave span{ display:block; width:2.5px; border-radius:2px; background:var(--indigo); height:40%; transition:background .2s; }
.lang-card-wave span:nth-child(2n){ height:70%; }
.lang-card-wave span:nth-child(3n){ height:100%; }
.lang-card-wave span:nth-child(5n){ height:55%; }
.lang-card-play{
  flex-shrink:0; width:32px; height:32px; border-radius:50%; border:none;
  background:var(--indigo); color:#fff; display:flex; align-items:center; justify-content:center;
  font-size:12px; cursor:pointer; transition:.15s;
}
.lang-card-play:hover{ background:var(--indigo-dark); }
.lang-card.is-playing .lang-card-wave span{ background:var(--amber); animation:langCardWave 0.8s ease-in-out infinite; }
.lang-card-wave span:nth-child(odd){ animation-delay:0.15s; }
@keyframes langCardWave{ 0%,100%{ transform:scaleY(0.6); } 50%{ transform:scaleY(1); } }

.hero-scroll-hint{ position:absolute; left:50%; bottom:28px; width:22px; height:38px; z-index:1; transform:translateX(-50%); }
.hero-scroll-dot{ animation:heroScrollBounce 1.6s ease-in-out infinite; }
@keyframes heroScrollBounce{ 0%,100%{ transform:translateY(0); opacity:1; } 50%{ transform:translateY(14px); opacity:0.4; } }

@media (max-width:900px){
  .hero .wrap.hero-grid{ grid-template-columns:1fr; text-align:center; gap:36px; }
  .hero-copy{ order:2; }
  .hero-visual{ order:1; }
  .hero-copy h1, .hero-copy .subhead{ text-align:center; margin-left:auto; margin-right:auto; }
  .hero-copy .langs, .hero-copy .cta-row{ justify-content:center; }
  .hero-scroll-hint{ display:none; }
}
@media (max-width:640px){
  /* This used to be aspect-ratio:4/5 (a tall portrait), which made the
     card much taller than its content (text block + photo + panel)
     actually needed — leaving a big empty patch of card background
     between the text and the panel, on the side the photo doesn't reach.
     A squarer card fits the same content snugly, no relocating the text
     required (moving it down would have run it straight into the
     photo's torso, which is much wider there than up near the
     headphones). */
  .lang-card-stack{ max-width:100%; aspect-ratio:1/1; min-height:280px; }
  .lang-card-text{ right:32%; }
  .lang-card-panel{ width:80%; max-width:none; }
  /* The base .lang-card-photo's height:124% was tuned for the desktop
     card's wide 16/10 aspect ratio. On this much taller 4:5 mobile card,
     124% of the (now much bigger) card height made the photo box far
     taller than any source portrait's own aspect ratio (~0.43-0.56)
     could fill at the 52% max-width cap, so object-fit:contain
     letterboxed every photo — leaving empty space above the head, worse
     for a wider-aspect source (Shan/Thai) than a narrower one (English),
     which read as inconsistent "people sizes" and a stray blank patch.
     Shrinking the box's height (and top, so it still pops the same
     amount above the card's own edge — top is a % of the *card*, not the
     box, so it isn't affected by the height change) to sit close to the
     photos' own aspect ratio removes the letterboxing almost entirely,
     so every card reads the same size, popping past the top edge same as
     the desktop card does. */
  .lang-card-photo{ max-width:52%; height:88%; top:-6%; }
}

/* ---------- STATS ---------- */
.stats{
  display:grid; grid-template-columns:repeat(4,1fr); gap:16px;
  max-width:900px; margin:64px auto 0; position:relative; z-index:1;
}
.stat{ background:rgba(255,255,255,0.14); border:1px solid rgba(255,255,255,0.18); padding:22px 16px; text-align:center; border-radius:16px; }
.stat b{ display:block; font-family:var(--font-display); font-size:26px; color:#fff; }
.stat span{ font-size:11.5px; color:rgba(255,255,255,0.8); font-weight:700; letter-spacing:0.03em; }

/* ---------- SECTIONS / CARDS ---------- */
section{ padding:90px 32px; }
.section-head{ text-align:center; max-width:600px; margin:0 auto 56px; }
.section-head .tag{ font-size:12.5px; font-weight:700; letter-spacing:0.08em; color:var(--indigo); text-transform:uppercase; margin-bottom:12px; display:block; }
.section-head h2{ font-family:var(--font-display); font-size:clamp(26px,4vw,40px); letter-spacing:-0.02em; margin-bottom:14px; color:var(--ink); }
.section-head p{ color:var(--ink-soft); font-size:16px; line-height:1.6; }

.grid-3{ display:grid; grid-template-columns:repeat(3,1fr); gap:22px; max-width:1180px; margin:0 auto; }
.card{ background:#fff; border:1px solid var(--line); border-radius:18px; padding:32px 26px; transition:.2s; }
.card:hover{ transform:translateY(-4px); box-shadow:0 18px 40px rgba(21,58,96,0.08); border-color:#BFE0FA; }
.card-icon{
  width:46px; height:46px; border-radius:12px; background:var(--gradient);
  display:flex; align-items:center; justify-content:center; font-size:20px; margin-bottom:18px;
  transition:transform .25s ease;
}
.card:hover .card-icon{ transform:scale(1.12) rotate(-6deg); }
.card h3{ font-family:var(--font-display); font-size:18px; margin-bottom:10px; letter-spacing:-0.01em; }
.card p{ font-size:14.5px; color:var(--ink-soft); line-height:1.6; }

@media (prefers-reduced-motion: reduce){
  .card{ transition:none; }
  .card:hover{ transform:none; }
  .card-icon{ transition:none; }
  .card:hover .card-icon{ transform:none; }
}

/* ---------- AUTH FORMS ---------- */
.auth-shell{ min-height:calc(100vh - 73px); display:flex; align-items:center; justify-content:center; padding:48px 24px; }
.auth-card{
  width:100%; max-width:420px; background:#fff; border:1px solid var(--line); border-radius:22px;
  padding:40px 34px; box-shadow:0 20px 50px rgba(21,58,96,0.07);
}
.auth-card h1{ font-size:26px; text-align:left; margin-bottom:8px; }
.auth-card .lede{ color:var(--ink-soft); font-size:14.5px; margin-bottom:28px; }
.field{ margin-bottom:18px; }
.field label{ display:block; font-size:13px; font-weight:600; margin-bottom:7px; color:var(--ink); }
.field input,
.field textarea{
  width:100%; padding:12px 14px; border-radius:10px; border:1.5px solid var(--line);
  font-size:14.5px; background:#F9FBFF; transition:.15s; font-family:inherit; color:var(--ink);
}
.field textarea{ resize:vertical; min-height:110px; line-height:1.5; }
.field input:focus,
.field textarea:focus{ outline:none; border-color:var(--indigo); background:#fff; box-shadow:0 0 0 3px rgba(22,139,234,0.14); }
.field-password{ position:relative; }
.field-password input{ padding-right:44px; }
.password-toggle{
  position:absolute; right:10px; top:50%; transform:translateY(-50%);
  background:none; border:none; cursor:pointer; padding:6px;
  color:var(--ink-soft); display:flex; align-items:center; justify-content:center;
  border-radius:8px; transition:.15s;
}
.password-toggle:hover{ color:var(--indigo); background:var(--bg); }
.password-toggle svg{ width:19px; height:19px; }
.field-hint{ font-size:12px; color:var(--ink-soft); margin-top:6px; }
.form-error{
  background:#FEF2F2; border:1px solid #FCC; color:var(--red); font-size:13.5px;
  padding:10px 14px; border-radius:10px; margin-bottom:16px; display:none;
}
.form-error.show{ display:block; }
.form-success{
  background:#F0FDF4; border:1px solid #BBF7D0; color:var(--green); font-size:13.5px;
  padding:10px 14px; border-radius:10px; margin-bottom:16px; display:none;
}
.form-success.show{ display:block; }

/* ---------- MODAL (admin add/edit dialogs) ---------- */
/* Hidden by default — the "Add class"/"Add lesson" dialog only appears as
   an overlay once JS adds .show (see openModal()/closeModal() in
   classes.html and admin.html). Without this rule the dialog's markup
   renders inline in the normal page flow instead of as a popup. */
.modal-backdrop{
  display:none; position:fixed; inset:0; z-index:200;
  background:rgba(15,27,51,0.45); backdrop-filter:blur(2px);
  align-items:center; justify-content:center; padding:20px;
}
.modal-backdrop.show{ display:flex; }
.modal{
  background:#fff; border-radius:18px; padding:28px 26px;
  width:100%; max-width:440px; max-height:calc(100vh - 40px); overflow-y:auto;
  box-shadow:0 24px 60px rgba(15,27,51,0.25);
}
.modal-head{ display:flex; align-items:flex-start; justify-content:space-between; margin-bottom:18px; }
.modal-head h2{ font-family:var(--font-display); font-size:19px; letter-spacing:-0.01em; }
.modal-close{
  background:none; border:none; font-size:16px; color:var(--ink-soft);
  width:30px; height:30px; border-radius:8px; transition:.15s; flex-shrink:0;
}
.modal-close:hover{ background:var(--bg); color:var(--ink); }
/* "or continue with Google" divider + button slot — see js/google-signin.js.
   The button itself is rendered by Google inside #googleSignInDiv as an
   iframe, so .google-signin-btn only needs to center/contain it; its
   colors come from the theme param passed to renderButton(), not our CSS
   variables. The whole wrap (divider + button) is hidden by
   google-signin.js when no RIC_GOOGLE_CLIENT_ID is configured yet. */
.auth-divider{ display:flex; align-items:center; gap:14px; margin:22px 0; color:var(--ink-soft); font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; }
.auth-divider::before, .auth-divider::after{ content:''; flex:1; height:1px; background:var(--line); }
.google-signin-btn{ display:flex; justify-content:center; min-height:44px; }
.google-signin-btn iframe{ max-width:100% !important; }

.auth-switch{ text-align:center; font-size:14px; color:var(--ink-soft); margin-top:22px; }
.auth-switch a{ color:var(--indigo); font-weight:600; }

/* ---------- DASHBOARD ---------- */
.dash-wrap{ max-width:1100px; margin:0 auto; padding:48px 32px 90px; }
.dash-head{ display:flex; justify-content:space-between; align-items:flex-end; flex-wrap:wrap; gap:20px; margin-bottom:36px; }
.dash-head h1{ font-size:clamp(26px,4vw,34px); text-align:left; margin-bottom:6px; }
.dash-head p{ color:var(--ink-soft); font-size:15px; }

.dash-stats{ display:grid; grid-template-columns:repeat(4,1fr); gap:16px; margin-bottom:40px; }
.dash-stat{ background:#fff; border:1px solid var(--line); border-radius:16px; padding:22px; }
.dash-stat .label{ font-size:12.5px; color:var(--ink-soft); font-weight:600; margin-bottom:8px; }
.dash-stat .value{ font-family:var(--font-display); font-size:26px; color:var(--indigo-dark); }
.dash-stat .value.amber{ color:#8A5A00; }

.progress-bar-track{ height:10px; border-radius:999px; background:var(--line); overflow:hidden; margin-top:10px; }
.progress-bar-fill{ height:100%; background:var(--gradient); border-radius:999px; transition:width .4s ease; }

.lesson-list{ display:flex; flex-direction:column; gap:12px; }
.lesson-row{
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  background:#fff; border:1px solid var(--line); border-radius:16px; padding:18px 22px;
  flex-wrap:wrap;
}
.lesson-left{ display:flex; align-items:center; gap:16px; }
.lesson-badge{
  width:42px; height:42px; border-radius:12px; flex-shrink:0;
  display:flex; align-items:center; justify-content:center; font-family:var(--font-display); font-weight:700; font-size:12px;
  background:#E3F2FD; color:var(--indigo-dark);
}
.lesson-badge.done{ background:var(--gradient); color:#fff; }
.lesson-title{ font-weight:700; font-size:15px; margin-bottom:3px; }
.lesson-desc{ font-size:13px; color:var(--ink-soft); }
.lesson-xp{ font-size:12.5px; font-weight:700; color:#8A5A00; background:#FFF8EA; border:1px solid #FCE3B0; padding:5px 11px; border-radius:999px; }

/* ---------- Notification bell (nav.js) ----------
   Same positioning/menu pattern as .profile-menu/.profile-dropdown below —
   a relatively-positioned button that reveals an absolutely-positioned
   panel — and the same red count-pill look as admin.html's .tab-badge,
   reused here for a student-facing unread count instead of an admin-facing
   one. */
.notif-menu{ position:relative; }
.notif-bell{
  position:relative; width:38px; height:38px; border-radius:50%; border:1px solid var(--line);
  background:#fff; cursor:pointer; color:var(--ink-soft); display:flex; align-items:center; justify-content:center;
}
.notif-bell:hover{ border-color:var(--indigo); color:var(--indigo); }
/* Same "stroke=currentColor, 19px" convention as .theme-toggle svg — see
   THEME TOGGLE BUTTON below — so the bell icon (previously the 🔔 emoji,
   which stayed the emoji's own fixed yellow regardless of theme) now
   follows this button's own text color in both light and dark mode. */
.notif-bell svg{ width:19px; height:19px; }
.notif-badge{
  position:absolute; top:-4px; right:-4px; font-size:10.5px; font-weight:700; color:#fff; background:var(--red);
  border-radius:999px; min-width:17px; height:17px; padding:0 4px; display:inline-flex; align-items:center; justify-content:center;
  border:2px solid #fff;
}
.notif-dropdown{
  display:none; position:absolute; top:calc(100% + 10px); right:0; z-index:60;
  background:#fff; border:1px solid var(--line); border-radius:14px; width:320px; max-width:88vw;
  box-shadow:0 18px 40px rgba(15,60,120,0.16); padding:8px; overflow:hidden;
  /* .notif-menu (this dropdown's parent) is a direct child of .nav-right,
     which forces `white-space:nowrap` on every direct child so the nav
     pills/buttons never wrap (see ".nav-right > *" above). That nowrap is
     inherited straight down into this dropdown even though it's positioned
     absolutely and out of that flex layout — which is what was forcing
     every notification's title/body onto one never-wrapping line and
     pushing it out past the panel's rounded border. Resetting it back to
     normal here is the actual fix; overflow-wrap below is just a second
     line of defense for a single very long unbroken token (e.g. a price).
  */
  white-space:normal;
}
.notif-dropdown.show{ display:block; }
/* Redesigned to match a reference "icon + bold title + gray timestamp,
   divider lines between rows" notification-list style, adapted to this
   site's own fonts/colors/corner-radius rather than copied wholesale —
   the reference used a plain blue/white theme; this keeps the site's
   Space Grotesk display font, indigo/green/red accent palette, and the
   rounded-corner language already used everywhere else (cards, buttons,
   the dropdown shell itself). */
.notif-dropdown-head{
  padding:10px 10px 12px; border-bottom:1px solid var(--line); margin-bottom:2px;
  display:flex; align-items:baseline; justify-content:space-between; gap:10px;
  font-family:var(--font-display); font-weight:700; font-size:14px; color:var(--ink); overflow-wrap:anywhere;
}
.notif-dropdown-count{ font-family:var(--font-body); font-weight:600; font-size:12px; color:var(--ink-soft); }
.notif-list{ max-height:360px; overflow-y:auto; overflow-x:hidden; }
.notif-item{
  display:flex; align-items:flex-start; gap:12px; padding:12px 6px;
  border-bottom:1px solid var(--line); max-width:100%; border-radius:8px;
}
.notif-list .notif-item:last-child{ border-bottom:none; }
.notif-item:hover{ background:var(--bg); }
/* Icon circle — colored by notification type (see notifIcon() in nav.js),
   same "tinted-pastel-circle + saturated stroke icon" pattern as the
   lesson-card status chips elsewhere on the site. */
.notif-item-icon{
  width:34px; height:34px; border-radius:50%; flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
}
.notif-item-icon svg{ width:17px; height:17px; }
.notif-item-icon.is-positive{ background:#EAF9EF; color:var(--green); }
.notif-item-icon.is-negative{ background:#FEECEC; color:var(--red); }
.notif-item-icon.is-info{ background:#EEF1FF; color:var(--indigo); }
.notif-item-text{ min-width:0; flex:1; }
/* Notification bodies interpolate a class name + price (see lib/notifications.js
   callers in routes/admin.js) which can run long — overflow-wrap:anywhere lets
   a long unbroken run (like a big price/currency token) break instead of
   pushing past the panel's rounded border. */
.notif-item-title{ font-size:13px; font-weight:700; color:var(--ink); margin-bottom:2px; overflow-wrap:anywhere; }
/* Small unread dot after the title instead of the old full-row background
   tint — reads more like a modern notification list and keeps every row's
   icon/divider treatment identical whether read or not. */
.notif-item.is-unread .notif-item-title::after{
  content:''; display:inline-block; width:6px; height:6px; margin-left:7px;
  border-radius:50%; background:var(--indigo); vertical-align:middle;
}
.notif-item-body{ font-size:12.5px; color:var(--ink-soft); line-height:1.5; overflow-wrap:anywhere; }
.notif-item-date{ font-size:11px; color:var(--ink-soft); margin-top:4px; }
.notif-empty{ padding:22px 10px; text-align:center; font-size:13px; color:var(--ink-soft); }

/* ---------- Site-wide footer (js/footer.js fills #siteFooter) ---------- */
footer{ margin-top:40px; }
.footer-wrap{ max-width:1180px; margin:0 auto; padding:48px 32px 28px; }
.footer-cols{ display:grid; grid-template-columns:1.3fr 1fr 1fr; gap:32px; text-align:left; margin-bottom:32px; }
.footer-col{ min-width:0; }
.footer-brand{ display:flex; align-items:center; gap:12px; text-decoration:none; color:inherit; margin-bottom:14px; }
.footer-tagline{ font-size:13px; color:var(--ink-soft); line-height:1.55; max-width:280px; }
.footer-col-head{
  font-family:var(--font-display); font-weight:700; font-size:12.5px; text-transform:uppercase;
  letter-spacing:0.05em; margin-bottom:14px; color:var(--ink);
}
.footer-links{ display:flex; flex-direction:column; gap:11px; }
.footer-links a{ font-size:13.5px; color:var(--ink-soft); text-decoration:none; transition:.15s; }
.footer-links a:hover{ color:var(--indigo-dark); }
.footer-email{ display:inline-block; font-size:13.5px; color:var(--ink-soft); text-decoration:none; margin-bottom:16px; transition:.15s; }
.footer-email:hover{ color:var(--indigo-dark); }
.footer-social{ display:flex; gap:8px; }
/* Solid white "chip" instead of a bare outline — the icon itself stays a
   simple two-tone glyph (minimal), but the white fill + soft shadow give it
   enough contrast to actually stand out against the page's pale gradient
   background rather than blending into it. */
.footer-social-btn{
  width:36px; height:36px; border-radius:10px; border:1px solid var(--line); background:#fff;
  display:flex; align-items:center; justify-content:center; color:var(--indigo-dark); transition:.15s; flex-shrink:0;
  box-shadow:0 1px 3px rgba(21,58,96,0.10);
}
.footer-social-btn svg{ width:18px; height:18px; }
.footer-social-btn:hover{ color:#fff; background:var(--indigo); border-color:var(--indigo); box-shadow:0 4px 10px rgba(22,139,234,0.28); }
.footer-bottom{
  text-align:center; padding-top:22px; border-top:1px solid var(--line);
  font-size:12.5px; color:var(--ink-soft);
}
.footer-credit{ margin-top:8px; font-size:12px; color:var(--ink-soft); line-height:1.6; }
.footer-credit strong{ color:var(--ink); font-weight:600; }
@media (max-width:720px){
  .footer-cols{ grid-template-columns:1fr; gap:28px; }
  .footer-tagline{ max-width:none; }
}

/* ---------- LANGUAGE CLASSES (index.html picker) ---------- */
/* Same markup/classes and the same render()/click-handler flow in index.html
   as before (locked vs available, href targets, the "coming soon" alert) —
   only the visual treatment changed, this time to a colored-tile "category
   card" style (client shared a reference video of an app whose category
   picker used solid gradient tiles with a title, a stat line, and a small
   corner icon — no photo). Each language gets its own fixed gradient plus a
   small decorative line-icon echoing the landmark that used to be its photo
   (a stupa for Thai, a clock tower for English, a crenellated wall for
   Chinese, a lattice tower for French, a boat+leaf for Shan), assigned via
   the same [data-code] attribute the old photo version used — no JS/markup
   change needed, index.html already renders data-code. The tile's own
   colors are fixed (not redefined per theme), matching how this site
   already treats other single-purpose colored widgets (the hero's own
   gradient, the hero card-stack) — a solid brand color doesn't need a dark-
   mode variant the way page chrome does. */
.lang-class-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:34px 20px; max-width:1180px; margin:0 auto; }
/* Stacked-deck wrapper — one per language, the actual grid item now (the
   card anchor moved one level down). Gives room above the card for
   .lang-class-peek to poke out. Redesigned per the client's own reference
   screenshots (a "before hover" and "during hover" frame of a different
   app): the backing card is a plain neutral skeleton-style card (two
   placeholder bars, no color), just a thin sliver visible at rest, and
   hovering lifts the front card up FAR enough to reveal the whole backing
   card clearly, rather than the smaller lift/tilt this used before. */
/* padding-top:52px reserves the peek's reveal space INSIDE the stack's own
   layout box (so the grid row itself grows to include it), rather than the
   peek escaping upward past the stack's box via a big negative offset. That
   escape approach broke down in testing: growing the peek above the stack
   pushed it into whatever sits above the row — the sticky header for the
   top row, the previous row otherwise — which painted over it. Keeping the
   whole reveal within the stack's own reserved padding means it can never
   collide with anything outside it, at any scroll position or viewport. */
.lang-class-stack{ position:relative; padding-top:52px; }
/* The peek's BOTTOM edge is pinned to y:52 (the card's resting top, via the
   top+height pair below always summing to 52) so it always meets the card
   with no gap. Growing on hover happens by extending the TOP upward toward
   y:0 while the bottom stays put — the card's own translateY(-22px) lift
   only eats into the bottom ~22px of that grown space, leaving the rest
   (the top of the reserved zone) clearly visible above it. */
.lang-class-peek{
  content:''; position:absolute; top:38px; left:14px; right:14px; height:14px;
  border-radius:18px 18px 0 0; z-index:0; pointer-events:none; overflow:hidden;
  background:#E7EAF1; transition:top .35s cubic-bezier(.22,1.4,.36,1), height .35s cubic-bezier(.22,1.4,.36,1);
}
.lang-class-peek::before, .lang-class-peek::after{
  content:''; position:absolute; left:18px; height:7px; border-radius:4px; background:rgba(20,30,55,0.14);
}
.lang-class-peek::before{ top:8px; width:56%; }
.lang-class-peek::after{ top:20px; width:38%; }
html[data-theme="dark"] .lang-class-peek{ background:#232A3D; }
html[data-theme="dark"] .lang-class-peek::before, html[data-theme="dark"] .lang-class-peek::after{ background:rgba(255,255,255,0.14); }
.lang-class-card{
  position:relative; z-index:1; border-radius:22px; text-align:left;
  transition:transform .35s cubic-bezier(.22,1.4,.36,1), box-shadow .3s ease, filter .3s ease;
  display:flex; flex-direction:column; overflow:hidden; min-height:200px;
  color:#fff; border:none; box-shadow:0 14px 32px rgba(15,25,45,0.16);
}
/* "Coming soon" tiles get an actual desaturating filter (not just a dim
   overlay) so the one open path (Thai, full color) visibly pops out from
   the four not-yet-available ones at a glance — muted color reads as
   "not open yet" the same way a disabled photo filter does. Hovering a
   locked tile eases the filter back a bit as a small "here's a preview"
   nudge, without ever matching the fully-open card's vividness. */
.lang-class-card.is-locked{ filter:grayscale(0.55) saturate(0.75) brightness(0.96); }
.lang-class-stack:hover .lang-class-card.is-locked{ filter:grayscale(0.3) saturate(0.85) brightness(0.98); }
/* Hover lift — triggered off the whole stack (not just the card itself) so
   hovering the sliver of .lang-class-peek poking out above the card also
   counts. A deliberately big vertical lift (no rotation, matching the
   reference frames exactly) so the backing card's placeholder bars become
   clearly visible underneath — "picking the front card up off the deck". */
.lang-class-stack:hover .lang-class-card{ transform:translateY(-22px); box-shadow:0 30px 54px rgba(15,25,45,0.30); }
.lang-class-stack:hover .lang-class-peek{ top:0; height:52px; }
.lang-class-stack:hover .lang-class-card::after{ opacity:.85; }
/* One solid/gradient background per language — Thai reuses the site's own
   primary --gradient (it's the flagship, already-open path); the other four
   get distinct saturated hues so the grid reads as clearly differentiated
   categories, echoing the variety the reference video's tiles had. */
.lang-class-card[data-code="th"]{ background:var(--gradient); }
.lang-class-card[data-code="en"]{ background:linear-gradient(135deg, #8B7CF6 0%, #6D5BD0 55%, #4C3FB0 100%); }
.lang-class-card[data-code="zh"]{ background:linear-gradient(135deg, #F2789E 0%, #E14C7A 55%, #C23A63 100%); }
.lang-class-card[data-code="fr"]{ background:linear-gradient(135deg, #4FD1C5 0%, #23AFA3 55%, #178F85 100%); }
.lang-class-card[data-code="shn"]{ background:linear-gradient(135deg, #FFD666 0%, #FFC326 55%, #E8A800 100%); }
/* Locked-state dim layer — sits between the gradient and the text/icon (z-
   index 1), so a "coming soon" tile reads as visibly muted without any
   filter touching the white text drawn above it. */
.lang-class-card::before{ content:''; position:absolute; inset:0; z-index:1; background:transparent; transition:background .25s ease; }
.lang-class-card.is-locked::before{ background:rgba(8,12,28,0.34); }
/* Corner accent: each language's own "hello" greeting, in its own script,
   instead of a small pictorial icon — plain text via the ::after content
   property so no new image assets are needed. Sized generously ("a bit
   wide" per the client) and kept low-opacity so it reads as a watermark
   behind the title, never competing with it. Sits above the dim layer
   (z-index 1, painted after ::before in source order) so it stays visible
   even on a locked/dimmed tile. Word choice matches the exact same
   translations already used by the hero's own card-stack widget
   (js/hero-language-cards.js), so "hello" reads identically everywhere on
   the site. */
.lang-class-card::after{
  position:absolute; z-index:1; right:16px; bottom:12px; left:16px; opacity:.34;
  font-family:var(--font-display); font-weight:800; line-height:1;
  color:#fff; text-align:right; pointer-events:none;
  transition:opacity .25s ease; white-space:nowrap; overflow:hidden; text-overflow:clip;
}
.lang-class-card[data-code="en"]::after{ content:'Hello'; font-size:32px; }
.lang-class-card[data-code="zh"]::after{ content:'你好'; font-size:38px; }
.lang-class-card[data-code="fr"]::after{ content:'Bonjour'; font-size:26px; }
.lang-class-card[data-code="shn"]::after{ content:'မႂ်ႇသုင်'; font-size:24px; }
.lang-class-card[data-code="th"]::after{ content:'สวัสดี'; font-size:28px; }
/* "Notify me" is a real, working sign-up now (see routes/notify.js), so the
   whole card stays a normal pointer cursor — only once a student has
   already subscribed (.is-subscribed, nothing left to click) does it fall
   back to not-allowed, same as before. Locked cards get the exact same
   lift/tilt/peek-settle hover as an available card (no more "transform:none"
   override) — the client asked for the animation to match the reference
   video across the board, not just on the one open language. */
.lang-class-card.is-locked{ cursor:pointer; }
.lang-class-card.is-locked.is-subscribed{ cursor:not-allowed; }
/* Status pill, top-right corner — a glassy translucent-white pill now that
   it sits on a solid color instead of a photo, matching the reference
   video's light corner badges. */
.lang-class-top{
  position:absolute; z-index:3; top:14px; right:14px; display:flex; align-items:center; justify-content:flex-end;
  padding:0; margin:0;
}
/* Small glassy language-code badge (e.g. "TH"), from an earlier design.
   Hidden per the client's earlier request — left in the markup (index.html)
   rather than removed, in case a future design wants it back. */
.lang-class-icon{ display:none; }
/* white-space:nowrap + flex-shrink:0 so a chip's own text (e.g. "✓
   Completed") never breaks across two lines when the row it sits in runs
   short on space — most visibly on an admin's lesson cards, where the
   lock/edit/delete cluster's reserved padding-right (see
   .lesson-card-v2-badges below) narrows this row the most. If the row
   truly can't fit every chip, the chip now wraps as a whole unit onto its
   own line (via the parent's flex-wrap) instead of splitting its own text. */
.status-chip{ font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:0.04em; padding:3px 8px; border-radius:999px; white-space:nowrap; flex-shrink:0; }
.status-chip.available{ background:#EEFCF3; color:var(--green); }
.status-chip.locked{ background:#F1F3F7; color:var(--ink-soft); }
/* .lang-class-top's own .status-chip is sized up from the base
   10px/3px-8px (client asked for a bigger "AVAILABLE"/"LOCKED" badge on
   these cards specifically) and given a translucent-glass treatment so it
   reads clearly against any of the five tile colors — scoped to
   .lang-class-top only, so it doesn't change the chip anywhere else it's
   reused (classes.html, admin.html, dashboard.html all keep the plain
   light base colors above). */
.lang-class-top .status-chip.available{ background:rgba(255,255,255,0.92); color:var(--green); font-size:11px; padding:5px 11px; box-shadow:0 4px 10px rgba(15,25,45,0.22); }
.lang-class-top .status-chip.locked{ background:rgba(255,255,255,0.22); color:#fff; border:1px solid rgba(255,255,255,0.45); font-size:11px; padding:5px 11px; box-shadow:0 4px 10px rgba(15,25,45,0.16); }
/* Title/native-name/description sit directly on the tile color now, so they
   switch from the site's ink tokens to plain white (full opacity for the
   heading, slightly dimmed for the supporting lines) for contrast against
   every one of the five gradients. */
.lang-class-card h3{ position:relative; z-index:2; font-family:var(--font-display); font-size:20px; margin:16px 16px 3px; color:#fff; }
.lang-class-native{ position:relative; z-index:2; font-size:13px; color:rgba(255,255,255,0.78); margin:0 16px 6px; }
.lang-class-card p{ position:relative; z-index:2; font-size:13.5px; color:rgba(255,255,255,0.82); line-height:1.45; margin:0 16px 14px; flex:1; }
/* Solid white pill for the "available" CTA — reads cleanly against any of
   the five tile colors without needing a per-language text-color variant.
   The locked "Notify me" state keeps the site's other primary-action color
   (the same amber/--ink combo .btn-primary uses for "Sign Up Free") so it
   still reads as clickable, not just decorative — same convention as
   before, just against a colored tile instead of a white card body. */
.lang-class-cta{
  position:relative; z-index:2; display:inline-flex; align-items:center; justify-content:center; gap:6px; width:fit-content;
  margin:0 16px 16px; padding:10px 18px; border-radius:999px;
  font-weight:700; font-size:13px; color:var(--indigo-dark); background:#fff; border:1px solid transparent; transition:.15s;
}
.lang-class-stack:hover .lang-class-cta{ box-shadow:0 6px 16px rgba(0,0,0,0.18); }
.lang-class-card.is-locked .lang-class-cta{ background:var(--amber); color:var(--ink); }
html[data-theme="dark"] .lang-class-card.is-locked .lang-class-cta{ background:var(--amber); color:#1A1300; }
.lang-class-card.is-locked .lang-class-cta:hover{ filter:brightness(0.96); }
.lang-class-card.is-locked .lang-class-cta.is-subscribed{ background:rgba(255,255,255,0.24); color:#fff; }
.lang-class-card.is-locked .lang-class-cta.is-subscribed:hover{ filter:none; }

/* ---------- CLASS LIST (classes.html + dashboard.html course path) ---------- */
/* Restyled to match a reference "course picker" card the client sent
   (colored top section + white bottom bar with a real progress readout),
   with one deliberate difference: the reference colors each card
   differently per-role; here every card in the grid is the SAME course
   language, so instead all cards in a language's grid share that
   language's own accent — the exact five colors already used for the
   language-picker cards on index.html/.lang-class-card[data-code] — via
   custom properties keyed off .class-grid[data-lang="..."] (set in both
   classes.html's JS: `classGrid.dataset.lang = langCode` and
   dashboard.html's JS: `area.dataset.lang = currentLang` on the course-
   path grid, so both pages' grids get the same per-language tint from one
   shared class selector instead of classes.html's grid id alone).
   --class-solid is the vivid brand color (progress bar fill + Start
   button, same in both themes); --class-tint is the soft card-background
   wash, which DOES change between themes (a pale tint in light mode, a
   translucent tint over the dark panel in dark mode, so the card doesn't
   glow white in a dark UI); --class-text is the accent used for the level
   pill's text, also swapped per theme for contrast. Falls back to the
   site's default indigo/amber if data-lang is ever missing/unrecognized. */
.class-grid{ display:grid; grid-template-columns:repeat(2,1fr); gap:18px; max-width:1180px; margin:0 auto; }
.class-grid[data-lang="th"]{ --class-solid:#168BEA; --class-btn-fg:#fff; --class-tint:#E7F3FF; --class-text:#0568C9; }
.class-grid[data-lang="en"]{ --class-solid:#7C6AE8; --class-btn-fg:#fff; --class-tint:#F1EEFF; --class-text:#6D5BD0; }
.class-grid[data-lang="zh"]{ --class-solid:#E8618C; --class-btn-fg:#fff; --class-tint:#FFEDF3; --class-text:#E14C7A; }
.class-grid[data-lang="fr"]{ --class-solid:#23AFA3; --class-btn-fg:#fff; --class-tint:#E6FBF8; --class-text:#178F85; }
.class-grid[data-lang="shn"]{ --class-solid:#FFC326; --class-btn-fg:#3A2E05; --class-tint:#FFF7DE; --class-text:#8A6300; }
html[data-theme="dark"] .class-grid[data-lang="th"]{ --class-tint:rgba(22,139,234,0.16); --class-text:#7FC0FF; }
html[data-theme="dark"] .class-grid[data-lang="en"]{ --class-tint:rgba(124,106,232,0.18); --class-text:#C3B8FF; }
html[data-theme="dark"] .class-grid[data-lang="zh"]{ --class-tint:rgba(232,97,140,0.18); --class-text:#FF9DBE; }
html[data-theme="dark"] .class-grid[data-lang="fr"]{ --class-tint:rgba(35,175,163,0.18); --class-text:#79E8DC; }
html[data-theme="dark"] .class-grid[data-lang="shn"]{ --class-tint:rgba(255,195,38,0.18); --class-text:var(--amber); }

.class-card{
  position:relative; display:flex; flex-direction:column; overflow:hidden;
  background:var(--class-tint, #fff); border:1px solid rgba(10,20,40,0.05); border-radius:22px; transition:.2s;
  box-shadow:0 4px 10px rgba(10,32,60,0.07), 0 14px 32px rgba(10,32,60,0.14);
}
html[data-theme="dark"] .class-card{
  border-color:var(--line); background:var(--class-tint, var(--bg-panel));
  box-shadow:0 4px 10px rgba(0,0,0,0.30), 0 14px 32px rgba(0,0,0,0.40);
}
.class-card.is-locked{ opacity:0.68; }
.class-card-body{ padding:18px 22px 18px; flex:1; }
/* Full-width banner photo — a real, topic-matched photo per class (see
   CLASS_PHOTOS in classes.html: the Grand Palace, a Bangkok tuk-tuk, pad
   thai, the Pattaya floating market, the Bangkok skyline, a notebook —
   matching the reference design's own per-card photo, instead of the
   arbitrary memoji/character illustration it used, or the small per-
   language circular photo this site tried first). A future class with no
   dedicated photo falls back to its language's own landmark photo rather
   than showing nothing (see classPhotoFor() in classes.html). The level +
   status pills sit on top of the photo, with a dark top-down scrim behind
   them so they stay legible over any photo, light or dark — and a second,
   lower "fog" gradient fades the photo's bottom edge into the card's own
   background color (the same --class-tint used just below it) instead of
   ending in a hard rectangular line, so the photo dissolves into the card
   body the way the reference design's own cards do. */
.class-card-photo{ position:relative; height:150px; overflow:hidden; }
.class-card-photo img{ width:100%; height:100%; object-fit:cover; display:block; }
.class-card-photo::after{
  content:''; position:absolute; inset:0;
  background:
    linear-gradient(180deg, rgba(10,20,40,0.55) 0%, rgba(10,20,40,0.05) 35%, rgba(10,20,40,0) 55%),
    linear-gradient(180deg, transparent 55%, var(--class-tint, #fff) 100%);
}
/* Dark mode fades to the card's OPAQUE panel color (--bg-panel), not the
   translucent --class-tint value used for the actual card background —
   --class-tint in dark mode is deliberately a low-opacity rgba (a soft
   tint over the page), so fading toward it directly left the photo still
   ~80% visible at the very bottom instead of genuinely dissolving into
   the card the way light mode's fully-opaque tint does. --bg-panel is a
   close enough match to the card's real (tint-over-panel) color that the
   seam disappears, and starting the fade sooner (45% vs 55%) makes it
   read clearly instead of being barely-there. */
html[data-theme="dark"] .class-card-photo::after{
  background:
    linear-gradient(180deg, rgba(10,20,40,0.55) 0%, rgba(10,20,40,0.05) 35%, rgba(10,20,40,0) 55%),
    linear-gradient(180deg, transparent 45%, var(--bg-panel) 100%);
}
.class-card-photo .class-card-badges{ position:absolute; top:14px; left:16px; z-index:1; }
/* Badges floating over a photo need their own, stronger contrast rules —
   a photo has its own lighting, not the page's theme, so the normal
   dark-mode pill treatment (a barely-there 8%-opacity white background,
   fine on a flat tinted card) went nearly invisible over a busy photo.
   These apply in both themes (a photo card looks the same regardless of
   site theme) and are also written as an explicit dark-mode selector so
   they reliably win the cascade over the theme-scoped base rules below. */
.class-card-photo .class-card-badges .level-tag,
html[data-theme="dark"] .class-card-photo .class-card-badges .level-tag{
  font-size:14px; padding:6px 15px; background:rgba(255,255,255,0.94);
  color:var(--class-text, var(--indigo-dark)); box-shadow:0 2px 8px rgba(10,20,40,0.28);
}
.class-card-photo .class-card-badges .status-chip.available,
html[data-theme="dark"] .class-card-photo .class-card-badges .status-chip.available{
  font-size:13px; padding:5px 14px; background:rgba(255,255,255,0.94); color:#8A6300;
  box-shadow:0 2px 8px rgba(10,20,40,0.28);
}
.class-card-photo .class-card-badges .status-chip.locked,
html[data-theme="dark"] .class-card-photo .class-card-badges .status-chip.locked{
  font-size:13px; padding:5px 14px; background:rgba(255,255,255,0.75); color:var(--ink-soft);
  box-shadow:0 2px 8px rgba(10,20,40,0.22);
}
.class-card-badges{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
/* Kept for the separate lesson-picker cards inside a class
   (renderLessonList()'s #lessonListGrid, e.g. "Addressing People &
   Question Words") — a different, simpler card that reuses the
   .class-card/.status-chip classes but not this round's photo/body
   restructuring. Out of scope for this round's redesign, so left as-is. */
.class-card-top{ display:flex; align-items:flex-start; justify-content:space-between; gap:12px; margin-bottom:14px; }
/* Fallback for a class with no photo at all (no CLASS_PHOTOS entry and no
   language landmark photo either) — badges just sit inline atop the card
   body instead of floating over a missing image. */
.class-card-badges-noPhoto{ padding:18px 22px 0; }
.class-card h4{ font-family:var(--font-display); font-size:18px; margin-bottom:8px; color:var(--ink); }
.class-card p{ font-size:13.5px; color:var(--ink-soft); margin-bottom:16px; line-height:1.55; }
.class-admin-actions{ position:absolute; top:14px; right:14px; display:flex; gap:6px; z-index:2; }
.class-admin-actions button{ width:28px; height:28px; border-radius:8px; background:rgba(255,255,255,0.85); border:1px solid var(--line); display:flex; align-items:center; justify-content:center; font-size:13px; }
.class-admin-actions button:hover{ border-color:var(--indigo); }
.class-admin-actions .class-lock-btn:hover{ background:#FFF8EA; border-color:#FCE3B0; }

/* Level pill — a small colored badge (the reference design's own top-left
   role pill, e.g. "Student") rather than the old giant standalone number. */
.class-card .level-tag{
  font-size:13px; font-weight:700; line-height:1; background:rgba(255,255,255,0.7); padding:5px 13px; border-radius:999px;
  color:var(--class-text, var(--indigo-dark)); font-family:var(--font-display);
}
html[data-theme="dark"] .class-card .level-tag{ background:rgba(255,255,255,0.08); color:var(--class-text, #7FC0FF); }
/* Status chip stays a warm amber-tinted pill (semantic, not per-language). */
.class-card .status-chip.available{ background:rgba(255,255,255,0.7); color:#8A6300; }
.class-card .status-chip.locked{ background:rgba(255,255,255,0.5); color:var(--ink-soft); }
html[data-theme="dark"] .class-card .status-chip.available{ background:rgba(255,195,38,0.16); color:var(--amber); }
html[data-theme="dark"] .class-card .status-chip.locked{ background:rgba(255,255,255,0.08); color:var(--ink-soft); }

/* Real stats row — lesson count + free/paid, both genuine fields from the
   backend response, not invented "tasks/projects" placeholders. */
.class-card-stats{ display:flex; gap:14px; margin-bottom:16px; flex-wrap:wrap; }
.class-stat{ display:flex; align-items:center; gap:8px; font-size:12.5px; font-weight:600; color:var(--ink); }
/* Plain white icon squares (not tinted to the card's own color) — matches
   the reference design's minimal gray-square icon chips, and keeps the
   two stat icons legible/consistent no matter which language's accent
   the surrounding card is currently tinted. Icons are inline SVGs drawn
   stroke="currentColor" (see ICON_BOOK/ICON_LOCK/ICON_UNLOCK in
   classes.html), same convention as the notification bell/theme toggle. */
.class-stat-ic{
  width:26px; height:26px; border-radius:8px; background:#fff;
  display:inline-flex; align-items:center; justify-content:center; flex-shrink:0;
  color:var(--ink-soft); box-shadow:0 1px 2px rgba(10,20,40,0.08);
}
.class-stat-ic svg{ width:14px; height:14px; }
html[data-theme="dark"] .class-stat-ic{ background:#0F1830; color:var(--ink-soft); box-shadow:none; }

/* Real progress bar — lessonsCompleted/lessonCount from the backend, same
   0%-for-not-started-yet convention the reference cards themselves use. */
.class-card-progress-head{ display:flex; justify-content:space-between; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:var(--ink-soft); margin-bottom:6px; }
.class-card-progress-track{ height:7px; border-radius:999px; background:rgba(10,20,40,0.08); overflow:hidden; }
html[data-theme="dark"] .class-card-progress-track{ background:rgba(255,255,255,0.12); }
/* min-width keeps a small rounded "dot" visible at 0% (matching the
   reference bar's own look for a not-yet-started row) instead of the
   fill disappearing to nothing. */
.class-card-progress-fill{ height:100%; min-width:9px; border-radius:999px; background:var(--class-solid, var(--indigo)); }

/* Bottom bar — white/panel ground (same dark-top/white-bottom split this
   site already uses for the flashcard back face), lesson-progress text on
   the left, the Start/Buy/Locked button on the right. */
.class-card-footer{
  display:flex; align-items:center; justify-content:flex-end; gap:10px; flex-wrap:wrap; row-gap:8px;
  padding:14px 22px; background:var(--bg-panel); border-top:1px solid rgba(10,20,40,0.06);
}
html[data-theme="dark"] .class-card-footer{ border-top-color:var(--line); }
/* No white-space:nowrap here on purpose — a long "Buy to Unlock — 25,000
   MMK" button next to this text has, in testing, no room left on a narrow
   phone width; letting the footer wrap (flex-wrap above) and this text
   break normally means it drops to its own line instead of overflowing
   off the edge of the (overflow:hidden) card. */
.class-card-footer-meta{ font-size:12.5px; font-weight:600; color:var(--ink-soft); margin-right:auto; }

/* Solid CTA pill in the language's own accent color (white text, except
   Shan's gold gets dark text for contrast — same convention this site
   already uses for its amber buttons elsewhere). The plain disabled
   "Locked" button keeps the ordinary .btn-ghost look, since there's
   nothing to point to. */
.class-card .btn.class-cta{
  width:auto; border-radius:999px; background:var(--class-solid, var(--indigo)); color:var(--class-btn-fg, #fff);
  border:none; box-shadow:none; padding:8px 8px 8px 18px;
  justify-content:space-between; font-size:13.5px; text-align:left;
}
.class-card .btn.class-cta:hover{ transform:none; box-shadow:none; filter:brightness(1.08); }
.class-card .cta-label{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.class-card .btn-arrow-badge{
  width:30px; height:30px; min-width:30px; border-radius:50%; background:rgba(127,127,127,0.28); color:inherit;
  display:inline-flex; align-items:center; justify-content:center; font-size:15px; flex-shrink:0;
}

/* ---------- Lessons-inside-a-class hero v2 (photo banner + doodles + quote,
   #lessonListPanel only — the individual-lesson-content panel, #lessonPanel,
   shares the base .lesson-hero class but never carries .lessons-hero-v2, so
   it's left untouched). Client sent a reference mockup of this whole page
   and asked for its layout/animation/illustration style exactly; the photo
   here is the site's own Thai landmark photo (already used elsewhere on the
   site), reused statically across all 6 classes the same way the previous
   hero illustration was. ---------- */
.lessons-hero-v2{
  position:relative; border-radius:28px; overflow:hidden; min-height:300px;
  display:flex; align-items:center; padding:40px; margin-bottom:28px;
  background:var(--bg-panel);
}
.lessons-hero-v2-photo{ position:absolute; inset:0; z-index:0; }
.lessons-hero-v2-photo img{ width:100%; height:100%; object-fit:cover; display:block; }
.lessons-hero-v2-photo::after{
  content:''; position:absolute; inset:0;
  background:linear-gradient(100deg, var(--bg-panel) 0%, var(--bg-panel) 28%, rgba(0,0,0,0) 62%);
}
html[data-theme="dark"] .lessons-hero-v2-photo::after{
  background:linear-gradient(100deg, var(--bg-panel) 0%, var(--bg-panel) 30%, rgba(10,18,32,0.15) 65%);
}
.lessons-hero-v2-content{ position:relative; z-index:1; max-width:520px; }
.lessons-hero-v2-content h1{ font-family:var(--font-display); font-size:clamp(24px,3.6vw,34px); line-height:1.15; margin:0; }
.lessons-hero-v2-content h1 .accent-word{ color:var(--indigo); }
html[data-theme="dark"] .lessons-hero-v2-content h1 .accent-word{ color:#7FC0FF; }
.lessons-hero-v2-content p{ color:var(--ink-soft); margin-top:10px; max-width:420px; line-height:1.6; font-size:14.5px; }
.lessons-hero-v2-features{ display:flex; flex-wrap:wrap; gap:20px; margin-top:18px; }
.lessons-hero-v2-feature{ display:flex; align-items:center; gap:7px; font-size:13px; font-weight:600; color:var(--ink); }
.lessons-hero-v2-doodle{
  position:absolute; z-index:1; top:20px; right:270px; width:150px;
  font-family:'Caveat', cursive; font-size:17px; line-height:1.22; color:#fff;
  text-shadow:0 2px 6px rgba(0,0,0,0.4); text-align:right;
}
.lessons-hero-v2-quote{
  position:absolute; z-index:1; top:22px; right:24px; max-width:190px;
  background:rgba(255,255,255,0.94); color:#1a2440; border-radius:16px 16px 4px 16px;
  padding:12px 15px; font-size:12.5px; font-weight:600; line-height:1.45;
  box-shadow:0 8px 22px rgba(10,20,40,0.28); font-style:italic;
}
@media (max-width:900px){
  .lessons-hero-v2{ padding:28px 22px; min-height:0; }
  .lessons-hero-v2-photo::after{ background:linear-gradient(180deg, rgba(0,0,0,0.05) 0%, var(--bg-panel) 88%); }
  html[data-theme="dark"] .lessons-hero-v2-photo::after{ background:linear-gradient(180deg, rgba(10,18,32,0.05) 0%, var(--bg-panel) 88%); }
  .lessons-hero-v2-doodle, .lessons-hero-v2-quote{ display:none; }
  .lessons-hero-v2-content{ max-width:100%; }
}

/* ---------- Lesson cards v2 (inside a class — #lessonListGrid) — a photo-
   panel layout replacing the earlier plain/icon versions of this same
   component, per the client's reference mockup. A rotating 5-hue palette
   (LESSON_CARD_PALETTE in classes.html) sets each card's own background;
   the photo (LESSON_PHOTOS) sits in a side panel rather than a full banner,
   since lessons within one class have no per-language theme color of their
   own to key off of the way the course-picker's .class-card does. */
.lesson-card-v2{
  position:relative; display:flex; overflow:hidden; border-radius:22px;
  background:var(--lesson-bg, #fff); border:1px solid rgba(10,20,40,0.05);
  box-shadow:0 4px 10px rgba(10,32,60,0.07), 0 14px 32px rgba(10,32,60,0.14);
  transition:transform .22s ease, box-shadow .22s ease;
  /* fill-mode "backwards" (not "both") on purpose: CSS Animations sit in a
     higher cascade priority than any normal author rule for the properties
     they touch — including a plain :hover selector, regardless of that
     selector's specificity. "both" would hold the animation's *end*
     keyframe (transform:translateY(0)) as a permanent override on this
     property forever after the entrance animation finishes, which silently
     blocked the hover lift/zoom below from ever visually applying. Only
     the *start* keyframe needs holding — during animation-delay, so a
     later card doesn't flash fully visible before its staggered fade-in
     begins — so "backwards" alone (holds "from" before start, but adds no
     override once the animation ends) fixes hover without changing the
     entrance effect itself. */
  animation:lessonCardIn .5s ease backwards; animation-delay:var(--lesson-delay, 0ms);
}
html[data-theme="dark"] .lesson-card-v2{
  border-color:var(--line); background:var(--lesson-dark-tint, var(--bg-panel));
  box-shadow:0 4px 10px rgba(0,0,0,0.30), 0 14px 32px rgba(0,0,0,0.40);
}
.lesson-card-v2.is-locked{ opacity:0.68; }
/* Hover lift + a small zoom (scale) rather than the lift alone, per the
   client's ask for "zoom animations" on the cards — subtle enough not to
   look gimmicky, still eases smoothly back down on mouse-out via the
   transition already declared on .lesson-card-v2 above. */
.lesson-card-v2:not(.is-locked):hover{ transform:translateY(-4px) scale(1.015); box-shadow:0 10px 20px rgba(10,32,60,0.12), 0 22px 42px rgba(10,32,60,0.18); }
html[data-theme="dark"] .lesson-card-v2:not(.is-locked):hover{ box-shadow:0 10px 20px rgba(0,0,0,0.40), 0 22px 42px rgba(0,0,0,0.5); }
@keyframes lessonCardIn{ from{ opacity:0; transform:translateY(16px); } to{ opacity:1; transform:translateY(0); } }

.lesson-card-v2-content{ flex:1 1 auto; min-width:0; padding:18px 20px 18px; display:flex; flex-direction:column; }
.lesson-card-v2-badges{ display:flex; align-items:flex-start; justify-content:space-between; gap:10px 8px; margin-bottom:10px; flex-wrap:wrap; }
/* An admin's lock/edit/delete cluster (.class-admin-actions, shared with the
   course-picker cards) sits absolutely positioned over this same top-right
   corner — without this, an admin viewing a card would see its badge
   overlap the action buttons. That reserved 100px leaves this row only a
   few px short of fitting "Available" + "✓ Completed" side by side (the
   two chips plus their gap come out just barely wider than what's left),
   so admin-only cards trim the chips' own horizontal padding and the gap
   between them slightly — enough to buy back that handful of px and keep
   both badges on one line the way every non-admin visitor already sees
   them, without shrinking anything on the far more common student view. */
.lesson-card-v2:has(.class-admin-actions) .lesson-card-v2-badges{ padding-right:100px; gap:10px 5px; }
.lesson-card-v2:has(.class-admin-actions) .status-chip{ padding:3px 6px; }
.lesson-card-v2-num{ font-family:var(--font-display); font-weight:800; font-size:30px; line-height:1; color:var(--lesson-accent, var(--indigo-dark)); margin-bottom:6px; }
.lesson-card-v2-content h4{ font-family:var(--font-display); font-size:17px; margin-bottom:6px; color:var(--ink); line-height:1.25; }
.lesson-card-v2-content p{ font-size:13px; color:var(--ink-soft); line-height:1.55; margin-bottom:14px; flex:1; }
.lesson-card-v2-btn{
  display:inline-flex; align-items:center; gap:6px; align-self:flex-start;
  padding:9px 18px; border-radius:999px; background:var(--lesson-accent, var(--indigo)); color:#fff;
  font-size:13.5px; font-weight:700; border:none; box-shadow:none;
  transition:transform .16s ease, filter .16s ease, box-shadow .16s ease;
}
.lesson-card-v2-btn:hover{ filter:brightness(1.08); transform:translateY(-1px) scale(1.035); box-shadow:0 6px 14px rgba(10,32,60,0.2); }
.lesson-card-v2-btn:active{ transform:scale(0.96); box-shadow:none; }
.lesson-card-v2-btn.is-ghost{ background:transparent; color:var(--ink-soft); border:1px solid var(--line); }
.lesson-card-v2-btn.is-ghost:hover{ transform:none; box-shadow:none; filter:none; }

.lesson-card-v2-photo{ position:relative; width:38%; min-width:120px; flex-shrink:0; overflow:hidden; }
.lesson-card-v2-photo img{ width:100%; height:100%; object-fit:cover; display:block; transition:transform .35s ease; }
/* A little zoom on the photo itself when the card is hovered — reinforces
   the card's own lift+scale instead of the photo just riding along flat. */
.lesson-card-v2:not(.is-locked):hover .lesson-card-v2-photo img{ transform:scale(1.08); }
/* Placed after every rule above it needs to cancel, using the exact same
   selectors — CSS gives equal priority to two normal-author rules with
   equal specificity, so it's *source order*, not the media query itself,
   that decides the winner. An earlier copy of this block sat higher up the
   file with lower-specificity selectors (missing ":not(.is-locked)" on the
   photo-zoom override, and colliding in source order with the later,
   real .lesson-card-v2-btn transition declaration) and silently lost every
   one of those cascade ties, so reduced-motion users still got the zoom. */
@media (prefers-reduced-motion: reduce){
  .lesson-card-v2{ animation:none; }
  .lesson-card-v2:not(.is-locked):hover{ transform:none; }
  .lesson-card-v2:not(.is-locked):hover .lesson-card-v2-photo img{ transform:none; }
  .lesson-card-v2-btn{ transition:none; }
  .lesson-card-v2-btn:hover, .lesson-card-v2-btn:active{ transform:none; }
}
.lesson-card-v2-photo::before{
  content:''; position:absolute; inset:0;
  background:linear-gradient(90deg, var(--lesson-bg, #fff) 0%, rgba(0,0,0,0) 26%);
}
html[data-theme="dark"] .lesson-card-v2-photo::before{
  background:linear-gradient(90deg, var(--lesson-dark-tint, var(--bg-panel)) 0%, rgba(0,0,0,0) 30%);
}
.lesson-card-v2-caption{
  position:absolute; z-index:1; top:10px; right:10px; max-width:88px; text-align:right;
  font-family:'Caveat', cursive; font-weight:600; font-size:14px; line-height:1.2;
  color:#1a2440; text-shadow:0 1px 4px rgba(255,255,255,0.55);
}
html[data-theme="dark"] .lesson-card-v2-caption{ color:#fff; text-shadow:0 1px 6px rgba(0,0,0,0.6); }

/* Tone-rules custom chip stack (Class 1 lesson 3) — no single stock photo
   fits 5 distinct tones, so a set of stacked colored chips stands in for
   the mockup's own 5 colored tone-mark cards. */
.lesson-tone-chips{ position:relative; width:38%; min-width:120px; flex-shrink:0; display:flex; flex-direction:column; gap:6px; justify-content:center; padding:14px 14px 14px 0; }
.lesson-tone-chip{
  border-radius:10px; padding:6px 10px; font-size:12.5px; font-weight:700; text-align:center;
  color:#3a2f1a; box-shadow:0 2px 6px rgba(10,20,40,0.12);
}
.lesson-tone-chip:nth-child(1){ background:#FFD9C2; transform:rotate(-2deg); }
.lesson-tone-chip:nth-child(2){ background:#FFF3B0; transform:rotate(1.5deg); }
.lesson-tone-chip:nth-child(3){ background:#C7EBD6; transform:rotate(-1deg); }
.lesson-tone-chip:nth-child(4){ background:#CFE3FB; transform:rotate(2deg); }
.lesson-tone-chip:nth-child(5){ background:#E6D7F7; transform:rotate(-1.5deg); }

/* Addressing-people question-word bubbles overlaid on the photo (Class 1
   lesson 5) — stands in for the mockup's own scattered speech bubbles. */
.lesson-qbubbles{ position:absolute; inset:0; z-index:1; pointer-events:none; }
.lesson-qbubble{
  position:absolute; background:rgba(255,255,255,0.95); border-radius:999px; padding:3px 8px;
  font-size:9px; font-weight:700; color:#4b3a1a; box-shadow:0 2px 6px rgba(10,20,40,0.2);
  white-space:nowrap; max-width:76px; overflow:hidden; text-overflow:ellipsis;
}

/* ---------- Lessons-page footer branding (below #lessonListGrid) --------- */
.lessons-footer{
  display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:16px;
  margin-top:34px; padding-top:22px; border-top:1px solid var(--line);
}
.lessons-footer-brand{ display:flex; align-items:center; gap:10px; }
.lessons-footer-flower{ width:30px; height:30px; color:var(--amber); flex-shrink:0; }
.lessons-footer-tagline{ font-family:'Caveat', cursive; font-size:20px; line-height:1.1; color:var(--indigo); }
html[data-theme="dark"] .lessons-footer-tagline{ color:#7FC0FF; }
.lessons-footer-tagline em{ font-style:normal; display:block; font-size:23px; font-weight:700; }
.lessons-footer-mid{ font-size:11px; font-weight:700; letter-spacing:0.14em; color:var(--ink-soft); text-transform:uppercase; }
.lessons-footer-right{ display:flex; align-items:center; gap:8px; }
.lessons-footer-right svg{ width:26px; height:26px; color:var(--ink-soft); flex-shrink:0; }
.lessons-footer-right span{ font-size:12px; color:var(--ink-soft); }
@media (max-width:760px){
  .lessons-footer{ flex-direction:column; align-items:flex-start; text-align:left; margin-top:44px; padding-top:24px; gap:18px; }
  .lessons-footer-mid{ line-height:1.6; }
  .lessons-footer-right span{ line-height:1.5; display:inline-block; }
}

@media (max-width:640px){
  .lesson-card-v2, .lesson-tone-chips{ flex-direction:column; }
  .lesson-card-v2-photo, .lesson-tone-chips{ width:100%; height:120px; order:-1; }
  .lesson-card-v2-photo::before{ background:linear-gradient(180deg, var(--lesson-bg,#fff) 0%, rgba(0,0,0,0) 30%); }
  .lesson-tone-chips{ flex-direction:row; height:auto; padding:14px; }

  /* "Back to Classes" / "Next class" pair inside .class-complete-banner
     (see lessonListNavSectionHtml() and classCompleteBannerHtml() in
     classes.html — both render this same markup with inline styles, so
     !important is needed here to win over the inline `display:flex; gap:10px`
     on the button row at this width). Previously these two buttons just
     wrapped onto separate lines with a bare 10px gap and no side margin,
     reading as cramped — now they stack full-width with real breathing
     room between them and the banner's own edges. */
  .class-complete-banner{ padding:20px 18px !important; margin-top:26px !important; }
  .class-complete-banner > div:first-child{
    flex-direction:column !important;
    align-items:stretch !important;
    gap:14px !important;
  }
  .class-complete-banner .btn{ width:100%; }
  .class-complete-gated-notice{
    display:flex; flex-direction:column; align-items:center; gap:14px;
    margin-top:16px; line-height:1.6;
  }
}

/* ---------- Classes-page hero ("Thai Classes" heading) ---------- */
/* Used to be a two-column grid holding this text block beside a landmark
   photo (.classes-hero-photo) — the client asked for that photo removed
   entirely, so this is now just a plain block. The breadcrumb and the
   back-button/title row that used to live inside this same block now sit
   above it instead, as their own elements in classes.html's markup (see
   .classes-hero-topline in classes.html's own <style>). */
.classes-hero{ margin-bottom:36px; }
.classes-hero-dots{ display:flex; align-items:center; gap:6px; margin-top:16px; }
.classes-hero-dots .bar{ width:34px; height:6px; border-radius:999px; background:var(--amber); }
.classes-hero-dots .dot{ width:6px; height:6px; border-radius:999px; background:var(--line); }
.class-admin-actions .class-del-btn:hover{ background:#FEF2F2; border-color:#FCC; color:var(--red); }
.add-class-card{ display:flex; align-items:center; justify-content:center; flex-direction:column; gap:8px; border:2px dashed var(--line); cursor:pointer; min-height:150px; padding:26px 24px; background:transparent; }
.add-class-card:hover{ border-color:var(--indigo); }
.add-class-card .plus{ font-size:26px; color:var(--ink-soft); }
.add-class-card span.lbl{ font-weight:700; color:var(--ink-soft); font-size:13.5px; }

.loading-state{ text-align:center; padding:60px 20px; color:var(--ink-soft); }
.spinner{
  width:28px; height:28px; border-radius:50%; border:3px solid var(--line); border-top-color:var(--indigo);
  animation:spin .7s linear infinite; margin:0 auto 14px;
}
@keyframes spin{ to{ transform:rotate(360deg); } }

/* ---------- RESPONSIVE ---------- */
@media (max-width: 900px){
  .nav-links{ display:none; }
  .nav-toggle{ display:none; }
  .dash-stats{ grid-template-columns:repeat(2,1fr); }
  .stats{ grid-template-columns:repeat(2,1fr); }
  .grid-3{ grid-template-columns:1fr; }
  body{ padding-bottom:86px; }
}
@media (min-width: 901px){
  .dock-nav{ display:none !important; }
}

/* ---------- DOCK NAVIGATION (mobile/tablet) ---------- */
.dock-nav{
  position:fixed; left:50%; bottom:18px; transform:translateX(-50%);
  z-index:200;
  display:flex; align-items:flex-end; gap:10px;
  padding:10px 16px;
  background:rgba(21,58,96,0.92);
  border:1px solid rgba(255,255,255,0.14);
  border-radius:26px;
  box-shadow:0 16px 40px rgba(7,95,184,0.35), 0 2px 8px rgba(0,0,0,0.15);
  backdrop-filter:blur(14px);
  max-width:94vw;
  overflow-x:auto;
}
/* Each item is icon-over-label now (was icon-only, name shown solely as a
   hover tooltip via ::after below — useless on a touch phone, which is
   exactly where this dock lives, so every icon was unlabeled and, per
   client feedback, confusing). dock.js now renders a real
   <span class="dock-label"> under the icon so the name is always visible,
   not just on hover. */
.dock-item{
  position:relative;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:3px;
  width:56px; height:56px; flex-shrink:0;
  border-radius:14px;
  background:rgba(255,255,255,0.08);
  color:#fff;
  transition:transform .12s ease-out, background .15s;
  transform-origin:bottom center;
}
.dock-item:hover, .dock-item:focus-visible{ background:var(--amber); color:var(--ink); }
/* dock.js's mouse-follow "magnify" (macOS-dock-style scale-up, see
   applyMagnify) is a nice touch with a real cursor, but on a touch phone —
   the only place this dock ever shows, see the display:none rule right
   below — a tap has no cursor to follow, so it just blows the tapped icon
   up in place with no smooth build-up, overlapping its neighbors and
   reading as a glitch/error rather than an effect. Neutralizing the
   transform here (it still gets set inline by the JS, so this needs
   !important to win) keeps the plain amber "selected" highlight above
   without the jarring scale-and-overlap. */
.dock-item{ transform:none !important; }
.dock-icon{ width:19px; height:19px; flex-shrink:0; }
.dock-label{
  font-size:9.5px; font-weight:600; line-height:1; letter-spacing:0.01em;
  max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  padding:0 2px;
}
/* Tooltip-on-hover is redundant now that .dock-label is always visible, but
   left in place (inert on touch, harmless on the rare hover) rather than
   ripped out, in case the dock is ever shown somewhere a mouse hovers it. */
.dock-item::after{
  content:attr(data-label);
  position:absolute; bottom:calc(100% + 10px); left:50%; transform:translateX(-50%);
  background:var(--ink); color:#fff; font-size:11px; font-weight:600;
  padding:5px 9px; border-radius:8px; white-space:nowrap;
  opacity:0; pointer-events:none; transition:opacity .15s;
}
.dock-item:hover::after, .dock-item:focus-visible::after{ opacity:1; }
@media (max-width:640px){
  .dock-item::after{ display:none; }
  .dock-nav{ bottom:14px; padding:8px 10px; gap:6px; }
  .dock-item{ width:50px; height:50px; gap:2px; }
  .dock-label{ font-size:8.5px; }
  /* Burmese dock labels (see js/dock.js's dockT() + the dock.* keys in
     i18n.js) run wider than their English equivalents at the same size —
     enough that most were ellipsis-truncating to 1-2 characters inside
     this ~50px item, which defeats the point of a label. Shrinking the
     font specifically for lang="my" here gets every current label
     (including the longest, "စာရင်းသွင်းရန်") to fit without truncating. */
  html[lang="my"] .dock-label{ font-size:7px; letter-spacing:normal; }
}
@media (max-width: 640px){
  .wrap, section, .dash-wrap{ padding-left:20px; padding-right:20px; }
  .hero{ padding:56px 20px 50px; }
  .auth-card{ padding:30px 22px; }
  .lesson-row{ flex-direction:column; align-items:flex-start; }
  .lesson-xp{ align-self:flex-start; }
  .nav-right .pill span.pill-text{ display:none; }
}


/* ---------- THEME TOGGLE BUTTON ---------- */
.theme-toggle{
  width:38px; height:38px; border-radius:999px;
  background:#fff; border:1px solid var(--line);
  display:flex; align-items:center; justify-content:center;
  cursor:pointer; color:var(--ink-soft); transition:.15s; flex-shrink:0;
}
.theme-toggle:hover{ color:var(--indigo); border-color:var(--indigo); background:var(--bg); }
.theme-toggle svg{ width:19px; height:19px; }

/* ---------- SITE LANGUAGE TOGGLE (EN / MY) ---------- */
/* Sits beside the theme toggle — switches the site's own interface text,
   not which language course a student is studying (that's the separate
   .langs switcher on the dashboard). See js/i18n.js. */
.lang-toggle{
  display:flex; align-items:center; gap:2px; padding:3px;
  border:1px solid var(--line); border-radius:999px; background:#fff; flex-shrink:0;
}
.lang-toggle-btn{
  font-family:var(--font-display); font-weight:700; font-size:11.5px; letter-spacing:.02em;
  color:var(--ink-soft); background:none; border:none; border-radius:999px;
  padding:6px 11px; cursor:pointer; transition:.15s; line-height:1;
}
.lang-toggle-btn:hover{ color:var(--ink); }
.lang-toggle-btn.active{ background:var(--indigo); color:#fff; }
html[data-theme="dark"] .lang-toggle{ background:var(--bg-panel); border-color:var(--line); }

@media (max-width: 640px){
  /* Mobile nav sizing lives HERE — after .theme-toggle/.lang-toggle/
     .lang-toggle-btn's own base (non-media) rules just above — not back
     up near the 900px hero breakpoint where an earlier attempt at this
     placed it. Same specificity + later source order meant that earlier,
     earlier-in-the-file version was silently overridden back to full
     size by these base rules underneath it, so on real narrow phones
     nothing actually shrank: the logo and nav-right controls kept eating
     full-size space until .brand (the only nav child without
     flex-shrink:0) got squeezed all the way to zero width — the logo
     "disappearing" that's most visible in Burmese mode, where the longer
     button labels ("ဝင်ရောက်ရန်", "အခမဲ့စာရင်းသွင်းရန်") made the squeeze
     worse. Giving .brand flex-shrink:0 here stops it from being the one
     item sacrificed to zero width; shrinking everything else (including
     Burmese-specific sizes below, since Myanmar script runs wider than
     Latin at a shared font-size) is what actually makes room. */
  nav{ padding:12px 12px; gap:4px; }
  .brand{ flex-shrink:0; }
  .brand-logo{ height:30px; }
  .lang-toggle{ padding:2px; }
  .lang-toggle-btn{ padding:4px 6px; font-size:9.5px; }
  .theme-toggle{ width:26px; height:26px; }
  .theme-toggle svg{ width:13px; height:13px; }
  .nav-right{ gap:4px; }
  .nav-right .btn-sm{ padding:6px 8px; font-size:10px; }
}

/* ---------- Mobile feedback round ---------- */
/* Themed SVG padlock (replaces the yellow 🔒 emoji — see lockify() in js/i18n.js). */
.i-lock{ width:1.05em; height:1.05em; flex-shrink:0; vertical-align:-0.18em; margin-right:.4em; }
.lesson-badge .i-lock{ margin-right:0; vertical-align:middle; }
.btn-primary .i-lock{ color:inherit; }

/* Header: keep the EN/MY toggle in the same spot on every page. It used to float
   (nav was space-between) so it moved whenever the buttons on its right changed
   width — Log in/Sign up vs. avatar, English vs. Burmese. Now the logo, toggle and
   theme button are anchored left and only .nav-right is pushed to the far edge. */
@media (max-width: 900px){
  nav{ justify-content:flex-start; }
  nav > .lang-toggle{ margin-left:10px; }
  nav > .theme-toggle{ margin-left:6px; }
  nav > .nav-right{ margin-left:auto; }
}
@media (max-width: 640px){
  /* html[lang="my"] rules earlier in the file out-rank the plain mobile shrink above,
     which is why Burmese Log in / Sign Up stayed big on phones. */
  html[lang="my"] .nav-right{ gap:4px; }
  html[lang="my"] .nav-right .btn-sm{ font-size:10px; padding:6px 8px; }
  html[lang="my"] .pill{ font-size:10.5px; padding:5px 8px; }
  nav > .lang-toggle{ margin-left:8px; }
  nav > .theme-toggle{ margin-left:4px; }

  /* Class cards: lesson count on its own line, button full width under it, so the
     two never touch (Burmese labels are long). */
  .class-card-footer{ flex-direction:column; align-items:stretch; justify-content:flex-start; gap:10px; padding:14px 16px; }
  .class-card-footer-meta{ margin-right:0; }
  .class-card-footer > .btn{ width:100%; }
  .class-card .btn.class-cta .cta-label{ white-space:normal; text-align:left; line-height:1.35; }
}

/* ---------- DARK MODE ---------- */
html[data-theme="dark"]{
  --ink: #EAF1FB;
  --ink-soft: #93A6C2;
  --bg: #0B1220;
  --bg-panel: #131B2E;
  --line: #223055;
}
html[data-theme="dark"] body{ background:var(--bg); color:var(--ink); }
html[data-theme="dark"] header{ background:rgba(11,18,32,0.9); border-bottom-color:var(--line); }
html[data-theme="dark"] .nav-links a:hover{ background:#1B2740; color:#fff; }
html[data-theme="dark"] .theme-toggle{ background:var(--bg-panel); border-color:var(--line); color:var(--ink-soft); }
html[data-theme="dark"] .theme-toggle:hover{ color:var(--gold); border-color:var(--gold); }

html[data-theme="dark"] .pill{ background:var(--bg-panel); border-color:var(--line); color:var(--ink); }
html[data-theme="dark"] .pill.streak{ background:#2A2110; border-color:#4A3A16; color:#FFC94D; }
html[data-theme="dark"] .pill.xp{ background:#0F2A47; border-color:#1E4066; color:#7FC0FF; }
html[data-theme="dark"] .avatar{ box-shadow:0 0 0 2px var(--bg); }

/* ---------- Profile dropdown (avatar menu) ---------- */
.profile-menu{ position:relative; }
.profile-menu .avatar{ cursor:pointer; border:none; }
.profile-dropdown{
  display:none; position:absolute; top:calc(100% + 10px); right:0; z-index:60;
  background:#fff; border:1px solid var(--line); border-radius:14px; min-width:220px;
  box-shadow:0 18px 40px rgba(15,60,120,0.16); padding:8px; overflow:hidden;
}
.profile-dropdown.show{ display:block; }
.profile-dropdown-head{ padding:10px 12px 12px; border-bottom:1px solid var(--line); margin-bottom:6px; }
.profile-dropdown-name{ font-family:var(--font-display); font-weight:700; font-size:14.5px; color:var(--ink); }
.profile-dropdown-email{ font-size:12.5px; color:var(--ink-soft); margin-top:2px; }
.profile-dropdown a, .profile-dropdown button{
  display:block; width:100%; text-align:left; padding:10px 12px; border-radius:8px;
  font-size:13.5px; font-weight:600; color:var(--ink); background:none; border:none; cursor:pointer; font-family:inherit;
}
.profile-dropdown a:hover, .profile-dropdown button:hover{ background:#F3F9FF; }
.profile-dropdown button{ color:var(--red); }
.profile-dropdown button:hover{ background:#FEF2F2; }

/* profile-dropdown-head is now a clickable link to profile.html (it used to
   be a plain, non-interactive div) — the generic ".profile-dropdown a" rule
   just above wins by specificity and would otherwise collapse its padding
   and wipe out its border-bottom divider (its "border:none" reset touches
   border-bottom too), so restore that layout explicitly here. */
.profile-dropdown a.profile-dropdown-head{
  padding:10px 12px 12px; border:none; border-bottom:1px solid var(--line);
  border-radius:0; margin-bottom:6px; text-decoration:none; cursor:pointer;
}
.profile-dropdown a.profile-dropdown-head:hover{ background:#F3F9FF; }

html[data-theme="dark"] .profile-dropdown{ background:var(--bg-panel); border-color:var(--line); }
html[data-theme="dark"] .profile-dropdown a:hover, html[data-theme="dark"] .profile-dropdown button:hover{ background:#131F38; }
html[data-theme="dark"] .profile-dropdown a.profile-dropdown-head:hover{ background:#131F38; }

html[data-theme="dark"] .notif-bell{ background:var(--bg-panel); border-color:var(--line); color:var(--ink); }
html[data-theme="dark"] .notif-dropdown{ background:var(--bg-panel); border-color:var(--line); }
html[data-theme="dark"] .notif-item:hover{ background:#131F38; }
html[data-theme="dark"] .notif-item-icon.is-positive{ background:#123821; }
html[data-theme="dark"] .notif-item-icon.is-negative{ background:#3B1717; }
html[data-theme="dark"] .notif-item-icon.is-info{ background:#132A46; }

/* ---------- Course path section (index.html "Your course path") ----------
   Themed like every other panel on the site: a soft light card in light
   mode, and a dark navy accent preserved in dark mode via the override
   below (was previously hardcoded to dark navy regardless of theme, which
   read as a jarring black band in light mode). */
.path-section{ background:var(--bg-panel); border:1px solid var(--line); color:var(--ink); }
.path-section .path-sub{ color:var(--ink-soft); }
/* display:flex + flex-direction:column so each card's own content (level
   pill, title, subtitle) just stacks normally — the actual "same height"
   behavior comes from the row below stretching every .path-card to match
   its tallest sibling (align-items:stretch), instead of each card sizing
   to only its own content, which is what let a longer-wrapping subtitle
   (or a longer translation, e.g. Burmese) make just that one card taller
   than the rest. */
.path-card{
  background:var(--bg); border:1px solid var(--line); display:flex; flex-direction:column;
  transition:transform .25s ease, box-shadow .25s ease, border-color .25s ease;
}
.path-card:hover{ transform:translateY(-5px); box-shadow:0 12px 26px rgba(15,23,42,.10); border-color:var(--indigo); }
.path-card .path-level{
  display:inline-block; padding:4px 9px; border-radius:7px;
  color:var(--indigo-dark); background:#E3F2FD;
  transition:transform .25s ease, background-color .25s ease;
}
.path-card:hover .path-level{ transform:scale(1.08); background:#D3E7FD; }
.path-card .path-sub-label{ color:var(--ink-soft); }

/* Connector lines between level cards — plain divs with no class before,
   now carrying their base look here instead of inline styles so the
   data-reveal override below (a left-to-right "growing line" instead of the
   generic fade-up) has something to attach to. */
.path-connector{
  width:44px; height:2px; align-self:center; flex-shrink:0;
  background:linear-gradient(90deg, var(--indigo), var(--violet)); opacity:.6;
}
/* Overrides the generic [data-reveal] fade-up (see js/scroll-reveal.js) for
   just these lines: instead of drifting upward like a card, each one grows
   from its left edge once scrolled into view, so the path visually draws
   itself between the level cards on either side as you scroll down. Higher
   specificity than the plain [data-reveal] rule (class + attribute beats
   attribute alone) is what makes this win the cascade. */
.path-connector[data-reveal]{
  opacity:0; transform:scaleX(0); transform-origin:left center;
  transition:transform .5s ease, opacity .5s ease;
}
.path-connector[data-reveal].is-visible{ opacity:.6; transform:scaleX(1); }

html[data-theme="dark"] .path-section{ background:#0F1B33; border-color:#2B2E56; color:#fff; }
html[data-theme="dark"] .path-section .path-sub{ color:#A9ACC9; }
html[data-theme="dark"] .path-card{ background:#1A1D3B; border-color:#2B2E56; }
html[data-theme="dark"] .path-card:hover{ box-shadow:0 12px 26px rgba(0,0,0,.4); }
html[data-theme="dark"] .path-card .path-level{ background:none; padding:0; color:var(--amber); }
html[data-theme="dark"] .path-card:hover .path-level{ background:none; transform:scale(1.08); }
html[data-theme="dark"] .path-card .path-sub-label{ color:#8B8EB0; }

@media (prefers-reduced-motion: reduce){
  .path-card{ transition:none; }
  .path-card:hover{ transform:none; }
  .path-card .path-level{ transition:none; }
  .path-card:hover .path-level{ transform:none; }
  .path-connector[data-reveal]{ opacity:.6; transform:scaleX(1); transition:none; }
}

/* ---------- How It Works ---------- */
.how-grid{ display:grid; grid-template-columns:repeat(5,1fr); gap:18px; max-width:1180px; margin:0 auto; }
.how-step{
  background:var(--surface,#fff); border:1px solid var(--line); border-radius:16px; padding:22px 18px;
  transition:transform .25s ease, box-shadow .25s ease, border-color .25s ease;
}
/* Hover lift — a small, tasteful "this is alive" cue rather than a big
   effect; the number badge gets its own little tilt+scale on top of it so
   the step number itself feels like the interactive part being pointed at. */
.how-step:hover{ transform:translateY(-6px); box-shadow:0 14px 30px rgba(15,23,42,.10); border-color:var(--indigo); }
.how-num{
  width:34px; height:34px; border-radius:10px; background:var(--gradient); color:#fff;
  display:flex; align-items:center; justify-content:center; font-family:var(--font-display); font-weight:700; font-size:14px; margin-bottom:14px;
  transition:transform .25s ease;
}
.how-step:hover .how-num{ transform:scale(1.14) rotate(-6deg); }
.how-step h4{ font-family:var(--font-display); font-size:14.5px; margin-bottom:6px; }
.how-step p{ font-size:12.5px; color:var(--ink-soft); line-height:1.5; }

/* ---------- Scroll-reveal entrance (js/scroll-reveal.js) ----------
   Generic: any element with data-reveal starts hidden/offset and fades up
   into place the first time it scrolls into view, staggered per sibling by
   the JS-set transition-delay above. Used here for the "How Tokify works"
   step cards; reusable for future sections just by adding the attribute. */
[data-reveal]{ opacity:0; transform:translateY(24px); transition:opacity .6s ease, transform .6s ease; }
[data-reveal].is-visible{ opacity:1; transform:translateY(0); }

@media (prefers-reduced-motion: reduce){
  .how-step{ transition:none; }
  .how-step:hover{ transform:none; }
  .how-num{ transition:none; }
  .how-step:hover .how-num{ transform:none; }
  [data-reveal]{ opacity:1; transform:none; transition:none; }
}

/* ---------- FAQ ---------- */
.faq-list{ max-width:760px; margin:0 auto; display:flex; flex-direction:column; gap:10px; }
.faq-item{ background:#fff; border:1px solid var(--line); border-radius:14px; padding:4px 20px; }
.faq-item summary{
  cursor:pointer; list-style:none; font-family:var(--font-display); font-weight:600; font-size:15px;
  padding:16px 0; display:flex; align-items:center; justify-content:space-between;
}
.faq-item summary::-webkit-details-marker{ display:none; }
.faq-item summary::after{ content:"+"; font-size:20px; color:var(--ink-soft); font-weight:400; }
.faq-item[open] summary::after{ content:"–"; }
.faq-item p{ padding-bottom:18px; margin-top:-6px; color:var(--ink-soft); font-size:14px; line-height:1.6; }

@media (max-width: 1024px){
  .how-grid{ grid-template-columns:repeat(3,1fr); }
}
@media (max-width: 640px){
  .how-grid{ grid-template-columns:1fr 1fr; }
}

html[data-theme="dark"] .how-step{ background:var(--bg-panel); border-color:var(--line); }
html[data-theme="dark"] .how-step:hover{ box-shadow:0 14px 30px rgba(0,0,0,.4); }
html[data-theme="dark"] .faq-item{ background:var(--bg-panel); border-color:var(--line); }

html[data-theme="dark"] .btn-ghost{ background:var(--bg-panel); color:var(--ink); border-color:var(--line); }
html[data-theme="dark"] .btn-ghost:hover{ border-color:var(--indigo); color:#7FC0FF; }
html[data-theme="dark"] .btn-primary{ color:#1A1300; }

html[data-theme="dark"] .card,
html[data-theme="dark"] .dash-stat,
html[data-theme="dark"] .lesson-row,
html[data-theme="dark"] .auth-card,
html[data-theme="dark"] .student-table,
html[data-theme="dark"] .modal,
html[data-theme="dark"] .admin-stat{
  background:var(--bg-panel); border-color:var(--line); color:var(--ink);
}
html[data-theme="dark"] .card:hover{ border-color:#2C4370; box-shadow:0 18px 40px rgba(0,0,0,0.35); }

html[data-theme="dark"] .field input,
html[data-theme="dark"] .field textarea,
html[data-theme="dark"] .search-input{
  background:#0F1830; border-color:var(--line); color:var(--ink);
}
html[data-theme="dark"] .field input:focus,
html[data-theme="dark"] .field textarea:focus,
html[data-theme="dark"] .search-input:focus{ background:#131B2E; border-color:var(--indigo); }
html[data-theme="dark"] .password-toggle:hover{ background:#1B2740; }

html[data-theme="dark"] .lesson-badge{ background:#132A4E; color:#7FC0FF; }
html[data-theme="dark"] .lesson-desc{ color:var(--ink-soft); }

html[data-theme="dark"] .section-head h2{ color:var(--ink); }
html[data-theme="dark"] .card h3{ color:var(--ink); }

html[data-theme="dark"] .student-table th{ background:#0F1830; color:var(--ink-soft); border-bottom-color:var(--line); }
html[data-theme="dark"] .student-table tr.clickable:hover td{ background:#0F1830; }
html[data-theme="dark"] .badge-admin{ background:#0F2A47; color:#7FC0FF; }
html[data-theme="dark"] .badge-verified{ background:#0F2E1E; color:#4ADE80; }
html[data-theme="dark"] .badge-unverified{ background:#1B2740; color:var(--ink-soft); }
.level-tag{ font-family:var(--font-display); font-weight:700; font-size:12px; color:var(--indigo-dark); background:#E3F2FD; padding:4px 9px; border-radius:7px; }
html[data-theme="dark"] .level-tag{ background:#0F2A47; color:#7FC0FF; }
html[data-theme="dark"] .level-row{ border-color:var(--line); }
html[data-theme="dark"] .modal-backdrop{ background:rgba(0,0,0,0.65); }

html[data-theme="dark"] .form-error{ background:#2E1414; border-color:#5C2222; color:#FF8A8A; }
html[data-theme="dark"] .form-success{ background:#10281A; border-color:#1F4A32; color:#5CE0A0; }

html[data-theme="dark"] footer{ border-top-color:var(--line); color:var(--ink-soft); }
html[data-theme="dark"] .loading-state{ color:var(--ink-soft); }
html[data-theme="dark"] .spinner{ border-color:var(--line); border-top-color:var(--indigo); }

html[data-theme="dark"] .dock-nav{ background:rgba(11,18,32,0.95); border-color:var(--line); }

/* ---------- TTS SLOW/SHADOWING TOGGLE ----------
   Mounted inline by js/tts-player.js's mountToggle() right into each
   Practice Sentences list and flashcard deck (see renderPhraseLines /
   renderRefFlashcards / renderGrammarPoints in classes.html) — sitting
   right next to the 🔊 buttons it controls, rather than a single pill
   floating in the page's corner (an earlier version of this did that; the
   client's own testing showed it was too easy to miss since it wasn't
   near any of the audio it affected). Every instance on the page shares
   and controls the same on/off flag, so tapping any one of them puts every
   🔊 button anywhere on the site into 0.5x "shadowing" playback. */
.tts-toggle-btn{
  display:inline-flex; align-items:center; gap:7px;
  padding:8px 14px; border-radius:999px; border:1px solid rgba(255,255,255,0.14);
  background:rgba(21,58,96,0.92); color:#fff; font-size:12.5px; font-weight:700;
  cursor:pointer; user-select:none;
  box-shadow:0 4px 12px rgba(7,95,184,0.22);
  transition:background .15s ease, border-color .15s ease;
}
.tts-toggle-btn:hover{ border-color:#BFE0FF; }
.tts-toggle-btn[aria-pressed="true"]{ background:var(--indigo); border-color:var(--indigo); }
.tts-slow-toggle-dot{
  width:8px; height:8px; border-radius:50%; background:rgba(255,255,255,0.35); flex-shrink:0;
}
.tts-toggle-btn[aria-pressed="true"] .tts-slow-toggle-dot{ background:#5CF29A; box-shadow:0 0 6px #5CF29A; }
html[data-theme="dark"] .tts-toggle-btn{ background:rgba(11,18,32,0.95); border-color:var(--line); }
html[data-theme="dark"] .tts-toggle-btn[aria-pressed="true"]{ background:var(--indigo); border-color:var(--indigo); }
@media (max-width:480px){
  .tts-toggle-btn span:not(.tts-slow-toggle-dot){ display:none; }
}

/* .class-card's own background now comes from the per-language --class-tint
   custom property set higher up (.class-grid[data-lang="..."] blocks), which
   already has its own dark-mode variant — no flat override needed here any
   more (border-color's dark-mode swap is set right where .class-card is
   defined instead). */
html[data-theme="dark"] .status-chip.available{ background:#0F2E1E; color:#4ADE80; }
html[data-theme="dark"] .status-chip.locked{ background:#1B2740; color:var(--ink-soft); }
/* .lang-class-card itself needs no dark-mode override any more — its five
   tile colors are fixed gradients, not page chrome, so they look the same
   in both themes (same reasoning as the hero's own gradient). Only its
   locked-CTA state still needs a dark-mode swap — see the
   html[data-theme="dark"] .lang-class-card.is-locked .lang-class-cta rule
   right after .lang-class-cta above. */
html[data-theme="dark"] .class-admin-actions button{ background:#0F1830; border-color:var(--line); color:var(--ink); }
html[data-theme="dark"] .add-class-card{ border-color:var(--line); }

@media (max-width: 900px){
  .lang-class-grid{ grid-template-columns:repeat(2,1fr); }
  .class-grid{ grid-template-columns:1fr; }
}
@media (max-width: 640px){
  .lang-class-grid{ grid-template-columns:1fr; }
}

/* ---------- PAYMENT (payment.html — manual bank-transfer checkout) ---------- */
.payment-card{ max-width:560px; }

.order-summary{
  display:flex; justify-content:space-between; align-items:center; gap:14px;
  padding:16px 18px; border:1.5px solid var(--line); border-radius:14px;
  margin-bottom:22px; background:var(--bg);
}
.order-summary .course-name{ font-weight:700; font-size:15px; }
.order-summary .course-sub{ font-size:12.5px; color:var(--ink-soft); margin-top:2px; }
.order-summary .course-price{ font-family:var(--font-display); font-weight:700; font-size:20px; color:var(--indigo-dark); white-space:nowrap; }

/* Cart line items on payment.html — one per course actually for sale (see
   GET /api/payments/catalog). Each row carries its own checkbox and status
   (buyable / pending / rejected / already-approved) so a checkout can cover
   more than one course at once. */
.cart-item{
  display:flex; align-items:flex-start; gap:14px; padding:16px 18px; border:1.5px solid var(--line);
  border-radius:14px; margin-bottom:12px; background:var(--bg);
}
.cart-item.is-locked{ opacity:0.7; }
.cart-item input[type="checkbox"]{ width:20px; height:20px; margin-top:2px; accent-color:var(--indigo); cursor:pointer; flex-shrink:0; }
.cart-item input[type="checkbox"]:disabled{ cursor:not-allowed; }
.cart-item-body{ flex:1; min-width:0; }
.cart-item-top{ display:flex; justify-content:space-between; align-items:flex-start; gap:10px; }
.cart-item-name{ font-weight:700; font-size:15px; }
.cart-item-native{ font-size:12.5px; color:var(--ink-soft); margin-top:1px; }
.cart-item-price{ font-family:var(--font-display); font-weight:700; font-size:16px; color:var(--indigo-dark); white-space:nowrap; }
.cart-item-note{ font-size:12.5px; color:var(--ink-soft); margin-top:8px; line-height:1.5; }
.cart-item-note.is-rejected{ color:var(--red); }
.cart-item-link{ font-size:12.5px; font-weight:700; color:var(--indigo); margin-top:8px; display:inline-block; }
.cart-item-goto-btn{ margin-top:10px; }

.cart-total-row{
  display:flex; justify-content:space-between; align-items:center; padding:14px 2px; margin:2px 0 22px;
  border-top:1.5px dashed var(--line);
}
.cart-total-row .lbl{ font-size:13.5px; color:var(--ink-soft); font-weight:600; }
.cart-total-row .val{ font-family:var(--font-display); font-weight:700; font-size:20px; color:var(--indigo-dark); }

html[data-theme="dark"] .cart-item{ background:#0F1830; border-color:var(--line); }

.bank-details-box{
  border:1.5px solid var(--line); border-radius:14px; padding:18px 20px; margin-bottom:22px; background:#F9FBFF;
}
.bank-details-box h4{ font-size:12px; text-transform:uppercase; letter-spacing:.05em; color:var(--ink-soft); font-weight:700; margin-bottom:12px; }
.bank-details-row{ display:flex; justify-content:space-between; gap:14px; padding:8px 0; font-size:14px; border-bottom:1px solid var(--line); }
.bank-details-row:last-child{ border-bottom:none; }
.bank-details-row .lbl{ color:var(--ink-soft); }
.bank-details-row .val{ font-weight:700; text-align:right; }
.bank-details-note{ font-size:12.5px; color:var(--ink-soft); margin-top:12px; line-height:1.55; }

/* ---------- Payment method tabs (bank transfer / QR scan) ----------
   One tab per entry in window.RIC_PAYMENT_METHODS (js/config.js) — a
   student picks whichever one they actually paid with before uploading
   their slip/screenshot. Same pill-tab look as .lang-toggle-btn elsewhere
   on auth pages, just sized for a row of several labels that can wrap. */
.bank-method-tabs{ display:flex; flex-wrap:wrap; gap:8px; margin-bottom:16px; }
.bank-method-tab{
  font-family:var(--font-body); font-weight:700; font-size:13px; color:var(--ink-soft);
  padding:9px 16px; border-radius:999px; border:1.5px solid var(--line); background:#fff; cursor:pointer; transition:.15s;
}
.bank-method-tab:hover{ border-color:var(--indigo); color:var(--indigo-dark); }
.bank-method-tab.active{ background:var(--indigo); border-color:var(--indigo); color:#fff; }
.bank-qr-box{
  margin-top:14px; border-radius:12px; overflow:hidden; text-align:center;
}
.bank-qr-box img{ max-width:220px; width:100%; margin:0 auto; border-radius:12px; border:1.5px solid var(--line); }
.bank-qr-placeholder{
  border:1.5px dashed var(--line); border-radius:12px; padding:26px 16px; font-size:13px; color:var(--ink-soft); line-height:1.55;
}
html[data-theme="dark"] .bank-method-tab{ background:#0F1830; border-color:var(--line); color:var(--ink-soft); }
html[data-theme="dark"] .bank-method-tab.active{ background:var(--indigo); border-color:var(--indigo); color:#fff; }

.slip-upload-box{
  border:1.5px dashed var(--line); border-radius:14px; padding:26px 20px; text-align:center; margin-bottom:20px;
  cursor:pointer; transition:.15s;
}
.slip-upload-box:hover{ border-color:var(--indigo); background:#F6FAFF; }
.slip-upload-box.has-file{ border-style:solid; border-color:var(--green); background:#F0FDF4; }
.slip-preview{ max-width:100%; max-height:220px; border-radius:10px; margin:0 auto 12px; display:none; }
.slip-upload-icon{ font-size:26px; margin-bottom:8px; }
.slip-upload-label{ font-size:14px; font-weight:600; }
.slip-filename{ font-size:12.5px; color:var(--ink-soft); margin-top:6px; word-break:break-all; }

.payment-status-card{ text-align:center; padding:10px 0 4px; }
.payment-status-icon{ font-size:38px; margin-bottom:12px; }
.payment-status-card h2{ font-size:21px; margin-bottom:8px; }
.payment-status-card p{ color:var(--ink-soft); font-size:14.5px; line-height:1.6; margin-bottom:22px; }

html[data-theme="dark"] .order-summary,
html[data-theme="dark"] .bank-details-box{ background:#0F1830; border-color:var(--line); }
html[data-theme="dark"] .slip-upload-box{ background:transparent; }
html[data-theme="dark"] .slip-upload-box:hover{ background:#0F1830; }
html[data-theme="dark"] .slip-upload-box.has-file{ background:#10281A; border-color:#1F4A32; }

/* ---------- ADMIN — Payments review tab ---------- */
.payment-order-card{ background:#fff; border:1px solid var(--line); border-radius:16px; padding:18px 20px; margin-bottom:12px; }
.payment-order-head{ display:flex; justify-content:space-between; align-items:flex-start; gap:12px; margin-bottom:12px; flex-wrap:wrap; }
.payment-order-name{ font-weight:700; font-size:14.5px; }
.payment-order-email{ font-size:12.5px; color:var(--ink-soft); margin-top:2px; }
.payment-order-meta{ font-size:12.5px; color:var(--ink-soft); text-align:right; }
.payment-order-amount{ font-family:var(--font-display); font-weight:700; font-size:16px; color:var(--indigo-dark); }
.payment-order-actions{ display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
.badge-pending{ font-size:11px; font-weight:700; color:#92400E; background:#FEF3C7; padding:3px 9px; border-radius:999px; }
.badge-approved{ font-size:11px; font-weight:700; color:var(--green); background:#EEFCF3; padding:3px 9px; border-radius:999px; }
.badge-rejected{ font-size:11px; font-weight:700; color:var(--red); background:#FEF2F2; padding:3px 9px; border-radius:999px; }
.payment-order-note{ font-size:12.5px; color:var(--ink-soft); margin-top:8px; font-style:italic; }

.slip-lightbox-backdrop{ position:fixed; inset:0; background:rgba(15,18,41,0.75); display:none; align-items:center; justify-content:center; z-index:200; padding:24px; }
.slip-lightbox-backdrop.show{ display:flex; }
.slip-lightbox-backdrop img{ max-width:min(90vw,640px); max-height:85vh; border-radius:14px; background:#fff; }

html[data-theme="dark"] .payment-order-card{ background:var(--bg-panel); border-color:var(--line); }
html[data-theme="dark"] .badge-pending{ background:#3A2A0A; color:#FCD34D; }
html[data-theme="dark"] .badge-approved{ background:#0F2E1E; color:#4ADE80; }
html[data-theme="dark"] .badge-rejected{ background:#2E1414; color:#FF8A8A; }

/* ---------- PROFILE PAGE (profile.html) ---------- */
.profile-wrap{ max-width:820px; margin:0 auto; padding:0 32px 90px; }
.profile-cover{
  position:relative; width:100%; height:220px; margin-bottom:64px;
  border-radius:0 0 24px 24px; overflow:hidden; background:var(--gradient);
  background-size:cover; background-position:center;
}
.profile-cover-overlay{
  position:absolute; inset:0; background:linear-gradient(180deg, rgba(8,18,32,0.05) 0%, rgba(8,18,32,0.35) 100%);
}
/* Faint diagonal texture behind the default branded cover — purely
   decorative, so it's hidden (see js in profile.html) the moment a real
   cover photo is uploaded, same as the brand text below. */
.profile-cover-pattern{
  position:absolute; inset:0;
  background-image:repeating-linear-gradient(135deg, rgba(255,255,255,0.07) 0px, rgba(255,255,255,0.07) 2px, transparent 2px, transparent 34px);
}
/* Default cover shown until the user uploads their own photo — the
   Tokify wordmark + its own "Speak. Save. Swift." slogan, centered over
   the brand gradient so a fresh profile never looks bare/unbranded. */
.profile-cover-brand{
  position:absolute; inset:0; z-index:1;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:5px; text-align:center; pointer-events:none;
}
/* The class rule above sets its own `display`, which otherwise beats the
   browser's default `[hidden]{display:none}` rule at equal specificity (the
   later same-specificity rule wins) — so a real uploaded cover photo left
   this branding visibly stuck on top of it. This rule outranks both so
   toggling the `hidden` attribute in profile.html actually hides it. */
.profile-cover-brand[hidden]{ display:none; }
.profile-cover-brand-name{
  font-family:var(--font-display); font-weight:700; font-size:30px; color:#fff;
  letter-spacing:0.3px; text-shadow:0 2px 14px rgba(0,0,0,0.3);
}
.profile-cover-brand-slogan{
  font-size:12.5px; font-weight:700; color:rgba(255,255,255,0.9);
  letter-spacing:3px; text-transform:uppercase; text-shadow:0 1px 8px rgba(0,0,0,0.3);
}
.profile-cover-upload{
  position:absolute; right:16px; bottom:16px; z-index:2;
  display:inline-flex; align-items:center; gap:7px; padding:9px 16px; border-radius:999px;
  background:rgba(10,20,36,0.55); backdrop-filter:blur(6px); color:#fff; border:1px solid rgba(255,255,255,0.4);
  font-size:13px; font-weight:700; cursor:pointer; transition:.2s;
}
.profile-cover-upload:hover{ background:rgba(10,20,36,0.75); }
.profile-cover-upload svg{ width:16px; height:16px; flex-shrink:0; }
.profile-cover-input{ display:none; }
.profile-identity{
  display:flex; align-items:flex-end; gap:18px; margin-top:-64px; padding:0 8px; position:relative; z-index:1;
}
.profile-avatar-lg{
  width:96px; height:96px; border-radius:50%; background:var(--gradient);
  display:flex; align-items:center; justify-content:center; color:#fff;
  font-size:34px; font-weight:700; font-family:var(--font-display);
  border:4px solid var(--bg); box-shadow:0 6px 18px rgba(15,60,120,0.22); flex-shrink:0;
}
.profile-identity-text{ padding-bottom:6px; min-width:0; }
/* Plain ink text, not white-on-photo — the name/email sit mostly below the
   cover image (only the avatar actually overlaps it), so white text here
   was landing on the ordinary page background and going invisible in light
   mode. var(--ink)/var(--ink-soft) already flip to light colors under dark
   theme, so this reads correctly in both without any extra override. */
.profile-identity-name{ font-family:var(--font-display); font-weight:700; font-size:22px; color:var(--ink); }
.profile-identity-email{ font-size:13.5px; color:var(--ink-soft); margin-top:2px; }
.profile-below{ margin-top:28px; }
/* Sized to the password form it wraps (not stretched to the full profile
   column width) so the card hugs its content instead of leaving a big
   empty panel beside/below the fields. */
.profile-section{ background:#fff; border:1px solid var(--line); border-radius:18px; padding:22px 24px; margin-top:22px; max-width:420px; }
.profile-section h2{ font-family:var(--font-display); font-size:18px; margin-bottom:16px; }
.profile-password-form{ max-width:100%; }

@media (max-width:640px){
  .profile-wrap{ padding:0 20px 70px; }
  .profile-cover{ height:170px; margin-bottom:56px; }
  .profile-avatar-lg{ width:76px; height:76px; font-size:28px; }
  .profile-identity{ margin-top:-52px; gap:14px; }
  .profile-identity-name{ font-size:18px; }
  .profile-cover-upload{ padding:8px 12px; font-size:12px; }
  .profile-cover-brand-name{ font-size:22px; }
  .profile-cover-brand-slogan{ font-size:11px; letter-spacing:2px; }
}

html[data-theme="dark"] .profile-avatar-lg{ border-color:var(--bg); }
html[data-theme="dark"] .profile-section{ background:var(--bg-panel); border-color:var(--line); }
