:root {
  /* Brand: the magpie's navy and wing-blue, with walnut gold for rewards.
     Green keeps one job — correct / continue / progress — so it never
     doubles as decoration. --navy is a fill (stays navy in dark mode);
     --navy-ink is navy used as text, which lightens in dark mode. */
  --navy: #0b1b3f;
  --navy-2: #133a9c;
  --navy-ink: var(--navy);
  --green: #58cc02;
  --green-dark: #46a302;
  --blue: #1e56d6;
  --blue-dark: var(--navy-2);
  --red: #ff4b4b;
  --red-dark: #ea2b2b;
  --gold: #ffc800;
  --gold-2: #ff9600;
  --gold-dark: #c26f00;
  --gray-bg: #f7f7f7;
  --gray-line: #e5e5e5;
  --text: #3c3c3c;
  --text-light: #777;
  --purple: #ce82ff;

  /* Surface tokens: swapped in dark mode below. Everything that used to
     hardcode #fff/#fafafa for card/button/input backgrounds now goes
     through these so the whole app repaints for dark mode in one place. */
  --surface: #fff;
  --surface-alt: #fafafa;
  --overlay-chip: rgba(20, 22, 27, 0.95);

  /* Pastel state tints (correct/wrong/selected) computed from the brand
     color mixed into the current surface, so they stay legible on dark
     surfaces instead of showing up as a bright pastel block. */
  --tint-blue: color-mix(in srgb, var(--blue) 15%, var(--surface));
  --tint-green: color-mix(in srgb, var(--green) 22%, var(--surface));
  --tint-red: color-mix(in srgb, var(--red) 18%, var(--surface));
  --tint-yellow: color-mix(in srgb, var(--gold) 28%, var(--surface));

  /* Neumorphic dual-tone shadow pair: dark shadow bottom-right, light
     "highlight" top-left, both against the element's own surface color
     (not a distinct neumorphic background) — see dark-mode override
     below. Used only on the buttons/daily-goal-card/unit-circle surfaces
     that opted into the soft-UI treatment, not on answer-correctness
     surfaces (option-btn/match-item/etc.), which stay bordered for
     contrast. */
  --neu-dark: rgba(163, 177, 198, 0.5);
  --neu-light: rgba(255, 255, 255, 0.85);
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: var(--gray-bg);
  color: var(--text);
  font-family: 'Vazirmatn', Tahoma, sans-serif;
  min-height: 100%;
}

#app {
  max-width: 480px;
  margin: 0 auto;
  padding: 16px 16px 76px;
  min-height: 100vh;
}

.boot {
  text-align: center;
  padding: 60px 0;
  color: var(--text-light);
}

.boot-mascot {
  display: block;
  width: 96px;
  height: 96px;
  object-fit: contain;
  margin: 0 auto 8px;
  animation: mascotBob 2.8s ease-in-out infinite;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font-family: inherit;
  cursor: pointer;
  border: none;
}

/* ---------- Buttons ---------- */
/* Neumorphic soft-UI: raised dual shadow instead of the old offset
   border-bottom "3D" trick; :active presses the shadow inward instead
   of translating the button down. */
.btn {
  display: block;
  width: 100%;
  padding: 14px 16px;
  border-radius: 16px;
  font-weight: 700;
  font-size: 16px;
  text-align: center;
  border: none;
  box-shadow: 6px 6px 14px var(--neu-dark), -6px -6px 14px var(--neu-light);
  transition: box-shadow .1s ease;
}

.btn:active {
  box-shadow: inset 4px 4px 10px var(--neu-dark), inset -4px -4px 10px var(--neu-light);
}

.btn-green {
  background: linear-gradient(145deg, var(--green), var(--green-dark));
  color: #fff;
}

.btn-blue {
  background: linear-gradient(145deg, var(--blue), var(--blue-dark));
  color: #fff;
}

.btn-red {
  background: linear-gradient(145deg, var(--red), var(--red-dark));
  color: #fff;
}

.btn-outline {
  background: var(--surface);
  color: var(--blue);
}

.btn-gray {
  background: var(--gray-line);
  color: var(--text-light);
  box-shadow: inset 3px 3px 8px var(--neu-dark), inset -3px -3px 8px var(--neu-light);
  cursor: not-allowed;
}

.btn-sm {
  padding: 10px 14px;
  font-size: 14px;
  border-radius: 12px;
  width: auto;
  display: inline-block;
}

/* ---------- Cards ---------- */
.card {
  background: var(--surface);
  border: 2px solid var(--gray-line);
  border-radius: 16px;
  padding: 16px;
  margin-bottom: 14px;
}

.card-clickable:active {
  background: var(--surface-alt);
}

/* ---------- Skill detail (Reading/Listening/Speaking/Writing bar) ---------- */
.skill-bar {
  display: flex;
  gap: 8px;
  overflow-x: auto;
}

.skill-bar-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  flex: 1;
  min-width: 72px;
  padding: 10px 6px;
  border-radius: 14px;
  border: 2px solid var(--gray-line);
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
}

.skill-bar-item.active {
  border-color: var(--blue);
  background: color-mix(in srgb, var(--blue) 10%, var(--surface));
}

.skill-bar-emoji {
  font-size: 22px;
}

.skill-bar-label {
  font-size: 12px;
  font-weight: 600;
}

/* ---------- Concept graph (home) ---------- */
/* Full-bleed: breaks out of #app's centered/padded column so the graph
   fills the entire viewport width regardless of where it sits in the DOM. */
.graph-card {
  position: relative;
  left: 50%;
  right: 50%;
  width: 100vw;
  margin-left: -50vw;
  margin-right: -50vw;
  background: var(--surface);
  border-top: 2px solid var(--gray-line);
  border-bottom: 2px solid var(--gray-line);
  overflow: hidden;
  touch-action: none;
}

/* When the graph is the first thing in #app (no daily-goal card above it),
   cancel #app's own top padding so the graph sits flush under the header
   instead of leaving a blank strip. */
.graph-card.flush-top {
  margin-top: -16px;
}

body {
  overflow-x: hidden;
}

/* Small blocks inside the graph block, under the canvas: the next lesson,
   the course chooser, friends' nudges (see renderConceptGraph's footerHtml).
   Part of the block, not cards stacked around it. */
.graph-footer {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px 12px;
  border-top: 1px solid var(--gray-line);
  background: var(--surface-alt);
}

.graph-footer .card,
.graph-footer .home-nudges {
  margin: 0;
}

.graph-footer .card {
  padding: 8px 12px;
  border-width: 1px;
  border-radius: 14px;
  box-shadow: none;
}

.graph-footer .home-nudges {
  gap: 8px;
}

/* The home graph already sizes itself to stop at the tab bar, so the
   padding and full-screen minimum height #app has elsewhere would only let
   the fixed graph block scroll (by the header's height). */
#app:has(> #concept-graph-wrap) {
  padding-bottom: 0;
  min-height: 0;
}

/* Today's goal on the home graph (see goalClockHtml in app.js): fades in
   just above the footer, stays a few seconds, and fades away. */
.goal-clock {
  position: absolute;
  bottom: calc(var(--graph-footer-h, 0px) + 14px);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: calc(100% - 32px);
  padding: 6px;
  padding-inline: 6px 16px;
  border-radius: 999px;
  background: var(--surface);
  box-shadow: 4px 4px 10px var(--neu-dark), -4px -4px 10px var(--neu-light);
  pointer-events: none;
  opacity: 0;
  animation: goal-clock-life 7.5s ease 0.6s forwards;
}

.goal-clock-ring {
  flex: none;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: conic-gradient(var(--green) var(--goal-pct), var(--gray-line) 0);
}

.goal-clock-ring span {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--surface);
  font-size: 10px;
  font-weight: 800;
  color: var(--navy-ink);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  text-align: center;
}

.goal-clock-caption {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

@keyframes goal-clock-life {
  0% { opacity: 0; transform: translate(-50%, 10px); }
  10% { opacity: 1; transform: translate(-50%, 0); }
  85% { opacity: 1; transform: translate(-50%, 0); }
  100% { opacity: 0; transform: translate(-50%, 6px); visibility: hidden; }
}

@media (prefers-reduced-motion: reduce) {
  .goal-clock {
    animation-name: goal-clock-fade;
  }

  @keyframes goal-clock-fade {
    0% { opacity: 0; }
    10%, 85% { opacity: 1; }
    100% { opacity: 0; visibility: hidden; }
  }
}

.graph-canvas {
  display: block;
  cursor: grab;
}

/* Fixed to the physical right regardless of locale direction — see
   .graph-mute-btn below for why these two don't use logical inline-start/end
   like the rest of the app. */
.graph-greeting {
  position: absolute;
  top: 14px;
  right: 16px;
  /* leave room for the mute button (44px wide, 14px inset) plus a gap,
     so the fact line below can use the rest of the card's width */
  width: calc(100% - 16px - 14px - 44px - 8px);
  /* The box spans almost the full card width, so text-align (which follows
     dir: start = left in LTR) decides which side it visually reads on, not
     the box's own position. Pinned to physical right so the message reads
     on the right in every language, matching the fixed `right: 16px` above. */
  text-align: right;
  font-size: 18px;
  font-weight: 800;
  color: var(--text);
  pointer-events: none;
  z-index: 2;
}

.graph-fact {
  margin-top: 4px;
  font-size: 12px;
  font-weight: 400;
  color: var(--text-light);
  line-height: 1.4;
  /* The greeting box spans nearly the whole card, so on a wide viewport a
     fact renders as one long line that reaches left across the branch photo
     (drawn anchored to the card's top-left corner). Cap the measure so the
     longest fact (~100 chars at this size) breaks into two lines and both
     stay in the right-hand column, clear of the branch; margin-left: auto
     keeps the narrowed box against the physical right edge in either dir,
     matching .graph-greeting's fixed `right: 16px`. */
  max-width: 21em;
  margin-left: auto;
  /* and never more than two lines, in case a longer fact is added later */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

.graph-tip {
  position: absolute;
  transform: translate(-50%, -100%);
  background: rgba(20, 22, 27, 0.95);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.15);
  padding: 4px 10px;
  border-radius: 8px;
  font-size: 12px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity .1s;
  z-index: 2;
}

.graph-tip.show {
  opacity: 1;
}

/* Fixed to the physical left regardless of locale direction — the graph
   itself (canvas, avatar placement) isn't mirrored for RTL either, so
   pinning the greeting/mute-button pair to right/left keeps them consistent
   with the graph rather than flipping independently of it. */
.graph-mute-btn {
  position: absolute;
  top: 14px;
  left: 14px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  line-height: 1;
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12), 0 0 0 2px rgba(0, 0, 0, 0.05) inset;
  cursor: pointer;
  z-index: 3;
  transition: transform .12s, box-shadow .12s, background .15s;
}

.graph-mute-btn:hover {
  transform: scale(1.08);
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.16), 0 0 0 2px rgba(0, 0, 0, 0.06) inset;
}

.graph-mute-btn:active {
  transform: scale(0.94);
}

.graph-mute-btn.is-muted {
  background: rgba(255, 235, 235, 0.9);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12), 0 0 0 2px rgba(255, 71, 87, 0.25) inset;
}

.empty-state.small-empty {
  padding: 16px 20px;
  font-size: 14px;
}

.row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.row-between {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.col {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.grow {
  flex: 1;
}

.mt8 {
  margin-top: 8px;
}

.mt12 {
  margin-top: 12px;
}

.mt16 {
  margin-top: 16px;
}

.mt24 {
  margin-top: 24px;
}

.mb8 {
  margin-bottom: 8px;
}

.mb12 {
  margin-bottom: 12px;
}

.mb16 {
  margin-bottom: 16px;
}

.center {
  text-align: center;
}

.muted {
  color: var(--text-light);
  font-size: 14px;
}

.small {
  font-size: 13px;
}

h1 {
  font-size: 22px;
  font-weight: 800;
  margin: 4px 0 16px;
}

h2 {
  font-size: 18px;
  font-weight: 700;
  margin: 0 0 8px;
}

h3 {
  font-size: 15px;
  font-weight: 700;
  margin: 0;
}

.stat-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--surface);
  border-radius: 20px;
  padding: 6px 12px;
  font-weight: 700;
  font-size: 14px;
  box-shadow: 4px 4px 9px var(--neu-dark), -4px -4px 9px var(--neu-light);
}

.hearts-pill {
  cursor: pointer;
}

.disclosure-btn {
  display: flex;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-decoration: none;
}

.disclosure-chevron {
  color: var(--gray-line);
  transition: transform 0.15s ease;
}

.disclosure-btn.open .disclosure-chevron {
  transform: rotate(180deg);
}

#daily-goal-picker.hidden {
  display: none;
}

.plan-option {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  border: 2px solid var(--gray-line);
  border-radius: 14px;
  padding: 12px 14px;
}

.plan-option+.plan-option {
  margin-top: 10px;
}

.topbar {
  position: sticky;
  top: 0;
  background: var(--gray-bg);
  padding: 10px 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
}

.back-btn {
  background: var(--surface);
  border-radius: 50%;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  flex-shrink: 0;
  box-shadow: 3px 3px 8px var(--neu-dark), -3px -3px 8px var(--neu-light);
}

.back-btn:active {
  box-shadow: inset 2px 2px 6px var(--neu-dark), inset -2px -2px 6px var(--neu-light);
}

.progress-bar-track {
  background: var(--gray-line);
  border-radius: 10px;
  height: 14px;
  overflow: hidden;
}

.progress-bar-fill {
  background: var(--green);
  height: 100%;
  border-radius: 10px;
  transition: width .3s;
}

/* ---------- Auth ---------- */
.auth-wrap {
  padding-top: 40px;
}

.auth-title {
  text-align: center;
  font-weight: 800;
  font-size: 22px;
  margin-bottom: 8px;
}

.auth-logo-wrap {
  text-align: center;
  margin-bottom: 20px;
}

.auth-logo {
  height: 270px;
  width: auto;
}

/* Light/dark logo variants: only the one matching the browser's color
   scheme is shown; the other stays hidden (see prefers-color-scheme block). */
.logo-dark {
  display: none;
}

.auth-subtitle {
  text-align: center;
  color: var(--text-light);
  font-size: 14px;
  line-height: 1.6;
  max-width: 320px;
  margin: 0 auto 24px;
}

/* "Get the Android app" card under the sign-in form (appDownloadHtml). */
.app-download {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 12px;
}

.app-download-icon {
  width: 52px;
  height: 52px;
  border-radius: 14px;
}

.app-download-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  line-height: 1.6;
}

.app-download .btn,
.app-download-hint {
  grid-column: 1 / -1;
}

.app-download-hint {
  margin: 0;
  line-height: 1.6;
}

.auth-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text-light);
  font-size: 13px;
}

.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--gray-line);
}

.google-btn-wrap {
  display: flex;
  justify-content: center;
  overflow: hidden;
}

.turnstile-wrap {
  display: flex;
  justify-content: center;
}

input[type=text],
input[type=password],
input[type=tel],
input[type=number] {
  width: 100%;
  padding: 14px;
  border-radius: 14px;
  border: 2px solid var(--gray-line);
  font-size: 16px;
  font-family: inherit;
  margin-bottom: 12px;
  background: var(--surface);
  color: var(--text);
}

input:focus {
  outline: none;
  border-color: var(--blue);
}

.field-error {
  color: var(--red);
  font-size: 13px;
  margin: -6px 0 10px;
}

textarea,
select {
  width: 100%;
  padding: 14px;
  border-radius: 14px;
  border: 2px solid var(--gray-line);
  font-size: 16px;
  font-family: inherit;
  margin-bottom: 12px;
  background: var(--surface);
  color: var(--text);
  resize: vertical;
}

textarea:focus,
select:focus {
  outline: none;
  border-color: var(--blue);
}

.field-label {
  font-weight: 700;
  font-size: 14px;
  margin: 4px 0 8px;
}

.feedback-category-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-bottom: 16px;
}

.feedback-category-option {
  min-width: 0;
  overflow-wrap: anywhere;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 16px 8px;
  border-radius: 14px;
  border: 2px solid var(--gray-line);
  background: var(--surface);
  cursor: pointer;
  font-weight: 700;
  font-size: 14px;
  transition: transform 0.1s ease;
}

.feedback-category-option:active {
  transform: scale(0.96);
}

.feedback-category-option .emoji {
  font-size: 26px;
}

.feedback-category-option.selected {
  border-color: var(--blue);
  background: var(--blue-light, var(--tint-blue));
}

#fb-problem-fields.hidden {
  display: none;
}

/* ---------- Account settings page ---------- */
.account-section-label {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-light);
  margin: 14px 4px 6px;
}

.account-section-label:first-of-type {
  margin-top: 4px;
}

.account-danger-label {
  color: var(--red);
}

.card.account-card {
  padding: 14px 14px 12px;
}

.account-section-hint {
  margin: 0 0 12px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-light);
}

.af-field {
  margin-bottom: 10px;
}

.af-field.mb0 {
  margin-bottom: 0;
}

/* Pairs up short fields (name/name, sex/age) side by side on anything but
   the narrowest phones, instead of every field taking the full card width —
   two rows saved is most of what keeps this form on one screen, and on
   desktop a lone "25" in a 640px-wide input reads as an oversized, mostly-
   empty box. Below 380px they stack, where half a card is too cramped. */
@media (min-width: 380px) {
  .af-row {
    display: flex;
    gap: 10px;
  }

  .af-row .af-field {
    flex: 1;
    min-width: 0;
  }
}

.af-label {
  display: block;
  font-weight: 700;
  font-size: 13px;
  margin-bottom: 4px;
  color: var(--text);
}

input.af-input,
select.af-input {
  width: 100%;
  padding: 9px 12px;
  border-radius: 10px;
  border: 1.5px solid var(--gray-line);
  font-size: 15px;
  font-family: inherit;
  background: var(--gray-bg);
  color: var(--text);
  transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease;
}

.af-input::placeholder {
  color: var(--text-light);
}

.af-input:hover {
  border-color: var(--gray-line);
}

.af-input:focus {
  outline: none;
  border-color: var(--green);
  background: var(--surface);
  box-shadow: 0 0 0 4px rgba(88, 204, 2, 0.15);
}

.af-input:disabled {
  opacity: .6;
  cursor: not-allowed;
}

select.af-select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238B93A1' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  /* The dropdown arrow belongs at the END of the field, opposite the label
     text — physically left in RTL, right in LTR. background-position has no
     logical keyword, so the two directions are spelled out; padding uses the
     logical property so the text never runs under the arrow. */
  background-position: left 12px center;
  padding-inline-end: 34px;
}

:root[dir="ltr"] select.af-select {
  background-position: right 12px center;
}

.account-save-btn {
  margin-top: 4px;
  padding: 11px 16px;
  font-size: 15px;
}

.account-save-btn:disabled {
  opacity: .7;
  cursor: not-allowed;
}

.card.account-danger-card {
  background: rgba(242, 84, 91, 0.05);
  border-color: rgba(242, 84, 91, 0.3);
}

.account-danger-copy {
  margin: 0 0 10px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-light);
}

.account-buttons-row {
  display: flex;
  gap: 10px;
}

.account-buttons-row .btn {
  width: auto;
  flex: 1;
}

.btn-sm {
  padding: 10px 12px;
  font-size: 13px;
  border-radius: 12px;
}

.btn:focus-visible,
.af-input:focus-visible {
  outline: 3px solid rgba(88, 204, 2, 0.5);
  outline-offset: 2px;
}

/* ---------- Tracks / levels ---------- */
.track-card {
  border-color: var(--gray-line);
}

.level-badge {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  color: #fff;
  font-size: 14px;
  flex-shrink: 0;
}

.unit-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 22px 0 10px;
}

.unit-icon {
  font-size: 26px;
}

.lesson-node {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--surface);
  border: 2px solid var(--gray-line);
  border-radius: 14px;
  padding: 12px 14px;
  margin-bottom: 10px;
}

.lesson-circle {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  color: #fff;
  background: var(--green);
}

.lesson-circle.done {
  background: var(--gold);
}

/* ---------- Exercise player ---------- */
/* The viewport's vertical space is shared with two things outside #app:
   the sticky .app-header (56px, now a fixed height) above it, and the
   fixed .tabbar below it (which #app reserves 76px of bottom padding
   for, on top of its own 16px top padding = 92px). This wrap's
   min-height must subtract all of that (56 + 92 = 148px), otherwise it
   overshoots the real visible viewport and the check button sits below
   the fold. */
.exercise-wrap {
  display: flex;
  flex-direction: column;
  min-height: calc(100vh - 148px);
  min-height: calc(100dvh - 148px);
}

.hearts-row {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 15px;
  font-weight: 700;
}

.exercise-body {
  flex: 1;
  padding-top: 18px;
}

.prompt-text {
  font-size: 20px;
  font-weight: 700;
  margin-bottom: 18px;
  line-height: 1.8;
}

/* A prompt with a Persian cue line and a separate target-language (e.g.
   English) line (see FILL_BLANK's "{from_text}\n{blanked}" prompt) is
   split client-side into one <div dir="auto"> per line — dir="auto" lets
   the browser's own bidi algorithm pick ltr/rtl per line instead of the
   whole block inheriting the page's dir="rtl", so an embedded English
   sentence reads left-to-right on its own line instead of being
   bidi-mangled inside the surrounding Persian paragraph. */
.prompt-line+.prompt-line {
  margin-top: 6px;
}

/* Dialogue/passage context shown above a subunit's exercises for the
   conversation/read kinds — same card language as .card, styled like a
   quote block so it reads as reference text, not the question itself. */
.subunit-context-block {
  border: 2px solid var(--gray-line);
  /* Quote-block accent bar: belongs on the side the text starts from, which
     flips with the app language — physically right in RTL, left in LTR. */
  border-inline-start: 4px solid var(--blue);
  border-radius: 14px;
  padding: 14px 16px;
  margin-bottom: 18px;
  font-size: 15px;
  line-height: 1.9;
  color: var(--text-light);
  background: var(--surface-alt);
}

.exercise-report-row {
  /* The flag sits at the FAR end of the row, away from where the eye starts
     reading. In RTL that end is physically left, in LTR it is right, so this
     has to be logical: a hardcoded `left` put the button under the start of
     the prompt in an LTR locale. */
  text-align: end;
  margin-bottom: 4px;
}

.exercise-report-btn {
  border: none;
  background: none;
  color: var(--text-light);
  font-size: 13px;
  padding: 4px 2px;
  opacity: .6;
}

.exercise-report-btn:hover {
  opacity: 1;
}

.play-audio-btn {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--blue);
  color: #fff;
  font-size: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-bottom: 4px solid var(--blue-dark);
  margin-bottom: 20px;
}

.option-btn {
  display: block;
  width: 100%;
  text-align: right;
  padding: 14px 16px;
  border: 2px solid var(--gray-line);
  border-bottom-width: 4px;
  border-radius: 14px;
  background: var(--surface);
  font-size: 16px;
  font-weight: 600;
  margin-bottom: 10px;
}

.option-btn.selected {
  border-color: var(--blue);
  background: var(--tint-blue);
}

.option-btn.correct {
  border-color: var(--green);
  background: var(--tint-green);
  color: var(--green-dark);
}

.option-btn.wrong {
  border-color: var(--red);
  background: var(--tint-red);
  color: var(--red-dark);
}

.image-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin-bottom: 20px;
}

.image-option {
  border: 2px solid var(--gray-line);
  border-bottom-width: 4px;
  border-radius: 14px;
  background: var(--surface);
  padding: 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.image-option img {
  width: 100%;
  max-width: 140px;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  display: block;
  margin: 0 auto;
}

.image-option span {
  font-size: 14px;
  color: var(--text-light);
  text-align: center;
}

/* The emoji tile stands in for a photo (see Meaning.emoji), so it occupies the
   same square as .image-option img rather than flowing as text — the grid must
   not reshuffle when one option has a picture and the next only has a glyph.
   The font-size rule comes after `.image-option span` on purpose: the label is
   also a span. */
.image-option .image-option-emoji {
  width: 100%;
  max-width: 140px;
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 56px;
  line-height: 1;
}

.image-option.selected {
  border-color: var(--blue);
  background: var(--tint-blue);
}

.image-option.correct {
  border-color: var(--green);
  background: var(--tint-green);
}

.image-option.wrong {
  border-color: var(--red);
  background: var(--tint-red);
}

.flashcard {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  padding: 16px 0 24px;
}

.flashcard-image {
  width: 100%;
  max-width: 160px;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  border-radius: 16px;
  background: var(--surface-alt);
  margin-bottom: 8px;
}

.flashcard-emoji {
  width: 100%;
  max-width: 160px;
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 80px;
  line-height: 1;
  border-radius: 16px;
  background: var(--surface-alt);
  margin-bottom: 8px;
}

.flashcard-image-playable {
  cursor: pointer;
  transition: transform 0.15s ease;
}

.flashcard-image-playable:active {
  transform: scale(0.96);
}

.flashcard-word {
  font-size: 28px;
  font-weight: 800;
}

.flashcard-translation {
  font-size: 17px;
  color: var(--text-light);
}

.wordbank-area {
  min-height: 56px;
  border-bottom: 2px solid var(--gray-line);
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 8px 2px;
  margin-bottom: 20px;
  /* The sentence being built runs in its own script's direction, not the
     page's: app.js sets dir="rtl" for an Arabic-script sentence (az-Arab,
     Persian) and dir="ltr" for a Latin one (bankDirAttr). Left-to-right
     is the default when it couldn't tell. */
  direction: ltr;
  justify-content: flex-start;
}

.wordbank-pool {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  direction: ltr;
  justify-content: flex-start;
}

.wordbank-area[dir="rtl"],
.wordbank-pool[dir="rtl"] {
  direction: rtl;
}

.chip {
  padding: 10px 14px;
  border-radius: 10px;
  border: 2px solid var(--gray-line);
  border-bottom-width: 3px;
  background: var(--surface);
  font-weight: 600;
  font-size: 15px;
}

.chip.used {
  opacity: .35;
  pointer-events: none;
}

.match-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 20px;
}

.match-col {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.match-item {
  padding: 12px 10px;
  border: 2px solid var(--gray-line);
  border-bottom-width: 4px;
  border-radius: 12px;
  background: var(--surface);
  font-size: 15px;
  font-weight: 600;
  text-align: center;
}

.match-item.selected {
  border-color: var(--blue);
  background: var(--tint-blue);
}

.match-item.correct {
  border-color: var(--green);
  background: var(--tint-green);
  color: var(--green-dark);
  opacity: .6;
}

.match-item.wrong {
  border-color: var(--red);
  background: var(--tint-red);
  color: var(--red-dark);
}

.match-item:disabled {
  pointer-events: none;
}

.speak-recorder {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 16px 0;
}

.record-btn {
  padding: 14px 28px;
  border: 2px solid var(--gray-line);
  border-bottom-width: 4px;
  border-radius: 999px;
  background: var(--surface);
  font-size: 16px;
  font-weight: 700;
}

.record-btn.recording {
  border-color: var(--red);
  background: var(--tint-red);
  color: var(--red-dark);
  animation: record-pulse 1.2s ease-in-out infinite;
}

@keyframes record-pulse {

  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: .6;
  }
}

.playback-audio {
  width: 100%;
  max-width: 320px;
}

.feedback-bar {
  position: sticky;
  bottom: 0;
  margin: 0 -16px -16px;
  padding: 16px;
  border-top: 2px solid var(--gray-line);
}

.feedback-bar.ok {
  background: var(--tint-green);
  border-color: #b6e88d;
}

.feedback-bar.bad {
  background: var(--tint-red);
  border-color: #ffb3b6;
}

.feedback-title {
  font-weight: 800;
  font-size: 17px;
  margin-bottom: 2px;
}

.feedback-title.ok-text {
  color: var(--green-dark);
}

.feedback-title.bad-text {
  color: var(--red-dark);
}

.feedback-answer {
  font-size: 14px;
  color: var(--text);
  margin-bottom: 10px;
}

.feedback-audio-btn {
  width: 32px;
  height: 32px;
  margin-inline-start: 6px;
  border: none;
  border-radius: 50%;
  background: var(--surface);
  font-size: 15px;
  vertical-align: middle;
  cursor: pointer;
  box-shadow: 2px 2px 6px var(--neu-dark), -2px -2px 6px var(--neu-light);
}

.feedback-audio-btn:active {
  box-shadow: inset 2px 2px 5px var(--neu-dark), inset -2px -2px 5px var(--neu-light);
}

/* ---------- Result screens ---------- */
.result-wrap {
  text-align: center;
  padding-top: 40px;
}

.result-emoji {
  font-size: 72px;
  margin-bottom: 8px;
}

.result-mascot {
  width: 170px;
  height: 170px;
  object-fit: contain;
  margin: 0 auto 8px;
  display: block;
}

.result-stat {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: var(--surface);
  border: 2px solid var(--gray-line);
  border-radius: 14px;
  padding: 14px 18px;
  margin-bottom: 10px;
  font-weight: 700;
}

/* ---------- Home: Continue row / course chooser ----------
   Both one slim row: the home graph takes whatever height is left. */
.continue-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  margin-bottom: 10px;
  color: inherit;
  text-decoration: none;
}

.continue-icon {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 20px;
  background: var(--tint-blue);
}

.continue-title {
  font-size: 15px;
  color: var(--navy-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.continue-sub {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.continue-go {
  flex: none;
  padding: 8px 16px;
  border-radius: 999px;
  background: var(--green);
  color: #fff;
  font-weight: 800;
  font-size: 14px;
}

.course-chooser {
  padding: 10px 12px;
  margin-bottom: 10px;
}

.course-chooser-title {
  display: block;
  font-weight: 700;
  font-size: 14px;
  margin-bottom: 8px;
}

.course-chips {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
}

.course-chips::-webkit-scrollbar {
  display: none;
}

.course-chip {
  flex: none;
  padding: 7px 14px;
  border-radius: 999px;
  border: 2px solid var(--gray-line);
  background: var(--surface);
  color: var(--blue);
  font-weight: 700;
  font-size: 14px;
  text-decoration: none;
  white-space: nowrap;
}

/* ---------- Placement self-rating ---------- */
.placement-intro {
  text-align: center;
  padding-top: 24px;
}

.level-picker {
  display: block;
  padding: 22px 20px 16px;
}

.level-readout {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-height: 92px;
  margin-bottom: 18px;
}

.level-value {
  font-size: 30px;
  font-weight: 800;
  color: var(--navy-ink);
  font-variant-numeric: tabular-nums;
}

.level-band {
  font-size: 17px;
  font-weight: 700;
  color: var(--blue);
}

/* A range input drawn as the app's soft controls: an inset groove with a
   wing-blue fill up to the value (--fill, set from app.js) and a raised
   thumb. The fill is a background on the input itself so one rule serves
   every engine; it starts from the right in a right-to-left page, where
   the browser also puts the minimum on the right. */
.level-slider {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  height: 12px;
  margin: 0;
  border-radius: 999px;
  background:
    linear-gradient(var(--blue), var(--blue)) left center / var(--fill, 0%) 100% no-repeat,
    var(--gray-bg);
  box-shadow: inset 2px 2px 5px var(--neu-dark), inset -2px -2px 5px var(--neu-light);
  cursor: pointer;
  touch-action: pan-y;
}

html[dir="rtl"] .level-slider {
  background-position: right center, 0 0;
}

.level-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--surface);
  border: 6px solid var(--blue);
  box-shadow: 3px 3px 8px var(--neu-dark), -3px -3px 8px var(--neu-light);
  transition: transform .1s ease;
}

.level-slider::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--surface);
  border: 6px solid var(--blue);
  box-shadow: 3px 3px 8px var(--neu-dark), -3px -3px 8px var(--neu-light);
}

.level-slider::-moz-range-track {
  background: transparent;
}

.level-slider:active::-webkit-slider-thumb {
  transform: scale(1.12);
}

.level-slider:focus-visible {
  outline: 3px solid var(--tint-blue);
  outline-offset: 6px;
}

.level-scale {
  display: flex;
  justify-content: space-between;
  margin-top: 12px;
}

/* ---------- Media ---------- */
.media-filter {
  display: flex;
  gap: 8px;
  margin-bottom: 14px;
}

.filter-chip {
  padding: 8px 16px;
  border-radius: 20px;
  border: 2px solid var(--gray-line);
  background: var(--surface);
  font-weight: 700;
  font-size: 14px;
}

.filter-chip.active {
  background: var(--blue);
  border-color: var(--blue-dark);
  color: #fff;
}

.media-thumb {
  width: 100%;
  aspect-ratio: 40/10;
  border-radius: 12px;
  background: linear-gradient(135deg, var(--purple), var(--blue));
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 34px;
  color: #fff;
  margin-bottom: 10px;
}

.media-prose {
  line-height: 1.8;
}

.media-prose p {
  margin: 0 0 12px;
}

.media-prose p:last-child {
  margin-bottom: 0;
}

/* One stanza of the transcript: the number in the gutter, the lines, then
   the translation of the stanza as a whole (translation lives on the
   segment, not the line — see data/media-authoring-format.md). */
.media-segment {
  padding: 12px 8px;
  border-radius: 12px;
  margin-bottom: 8px;
  cursor: pointer;
}

.media-segment:hover {
  background: var(--bg-soft, rgba(0, 0, 0, 0.03));
}

.media-segment-num {
  float: inline-start;
  min-width: 24px;
}

.media-line {
  font-size: 16px;
  padding: 4px 6px;
  border-radius: 8px;
  line-height: 1.9;
}

.media-line.active {
  background: var(--tint-yellow);
}

.media-translation {
  color: var(--text-light);
  font-size: 14px;
  margin-top: 6px;
  line-height: 1.7;
}

/* Session view: the stanza is the whole screen, so the lines get room. */
.media-lines-lg .media-line {
  font-size: 22px;
  line-height: 2.1;
}

.media-session-card {
  min-height: 180px;
  display: flex;
  align-items: center;
  cursor: pointer;
}

.media-session-nav {
  display: flex;
  gap: 12px;
}

.media-session-nav .btn {
  flex: 1;
}

@media (max-width: 480px) {
  .media-lines-lg .media-line {
    font-size: 19px;
  }
}

/* ---------- Leaderboard ---------- */
/* Shared by the full /leaderboard page and the desktop sidebar widget, so
   both read as the same list. A standings table is scanned, not read: the
   name carries the weight and rank/XP sit back a step. */
.lb-league {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-light);
  margin-bottom: 10px;
}

.lb-card {
  padding: 6px 10px;
}

.lb-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 6px;
  border-radius: 10px;
  font-size: 14px;
  /* Rows are <a>s into profiles — they should read as list rows, not links. */
  color: inherit;
  text-decoration: none;
}

/* Dividers go BETWEEN rows, never after the last one — a border-bottom on
   every row leaves a stray line floating above the card's padding. */
.lb-row+.lb-row {
  border-top: 1px solid var(--gray-line);
}

.lb-rank {
  width: 20px;
  flex-shrink: 0;
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-light);
  font-variant-numeric: tabular-nums;
}

.lb-row .grow {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lb-xp {
  flex-shrink: 0;
  font-size: 12px;
  color: var(--text-light);
  font-variant-numeric: tabular-nums;
}

.lb-xp b {
  font-size: 14px;
  color: var(--text);
}

.lb-row.you {
  background: var(--tint-blue);
  font-weight: 700;
}

/* The tint is a solid block: no divider may cut across its top or bottom. */
.lb-row.you,
.lb-row.you+.lb-row {
  border-top-color: transparent;
}

/* ---------- Tab bar ---------- */
.tabbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--surface);
  border-top: 2px solid var(--gray-line);
  display: flex;
  z-index: 10;
  padding-bottom: env(safe-area-inset-bottom);
}

.tabbar.hidden {
  display: none;
}

.tab {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 8px 0 6px;
  font-size: 8.25px;
  font-weight: 700;
  color: var(--text-light);
}

.tab.active {
  color: var(--blue);
}

.tab-icon {
  width: 39px;
  height: 39px;
  object-fit: contain;
}

.toast {
  position: fixed;
  top: 14px;
  left: 50%;
  transform: translateX(-50%) translateY(-60px);
  background: #333;
  color: #fff;
  padding: 10px 18px;
  border-radius: 12px;
  font-size: 14px;
  z-index: 100;
  transition: transform .25s;
  max-width: 90%;
}

.toast.show {
  transform: translateX(-50%) translateY(0);
}

.empty-state {
  text-align: center;
  padding: 40px 20px;
  color: var(--text-light);
}

.empty-emoji {
  font-size: 44px;
  margin-bottom: 10px;
}

.empty-mascot {
  display: block;
  width: 120px;
  height: 120px;
  object-fit: contain;
  margin: 0 auto 10px;
}

hr.sep {
  border: none;
  border-top: 2px solid var(--gray-line);
  margin: 18px 0;
}



/* ===== Page tokens (the brand colours are in the first :root block) ===== */
:root {
  --paper: #FAFAF7;
  --ink: #1B2430;
  --red: #F2545B;
  --purple: #7C5CFC;
  /* kept for existing track badges */
  --text-light: #8B93A1;
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: "Vazirmatn", sans-serif;
}

/* ===== Header + logo ===== */
.app-header {
  position: sticky;
  top: 0;
  z-index: 20;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  background: var(--paper);
  border-bottom: 2px solid var(--gray-line);
}

.logo {
  display: flex;
  align-items: center;
  text-decoration: none;
}

.header-logo {
  height: 28px;
  width: auto;
}

.header-stats {
  display: flex;
  gap: 8px;
}

/* Desktop-only: the nav column's own logo, shown instead of the top header
   (see .app-header/.nav-logo rules in the min-width: 900px block below). */
.nav-logo {
  display: none;
}

/* ===== Stat pills ===== */
.stat-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 9px;
  border-radius: 999px;
  background: var(--surface);
  font-weight: 700;
  font-size: 12px;
  box-shadow: 4px 4px 9px var(--neu-dark), -4px -4px 9px var(--neu-light);
}

.stat-pill.streak-pill {
  cursor: pointer;
  transition: transform .15s ease;
}

.stat-pill.streak-pill:active {
  transform: scale(.92);
}

/* ===== Notifications: bell, inbox, settings switches ===== */
.bell-pill {
  position: relative;
  color: inherit;
  text-decoration: none;
}

.bell-badge {
  position: absolute;
  top: -6px;
  inset-inline-end: -6px;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--red);
  color: #fff;
  font-size: 11px;
  line-height: 18px;
  text-align: center;
}

.inbox-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.inbox-item {
  display: block;
  color: inherit;
  text-decoration: none;
  border-inline-start: 4px solid transparent;
}

.inbox-item.unread {
  border-inline-start-color: var(--blue);
  background: var(--tint-blue);
}

.inbox-time {
  flex-shrink: 0;
}

.switch-row {
  gap: 12px;
  cursor: pointer;
}

/* A native checkbox drawn as a switch, so it stays keyboard- and
   screen-reader-accessible. The knob's travel is flipped under RTL. */
input.switch {
  appearance: none;
  flex-shrink: 0;
  position: relative;
  width: 44px;
  height: 26px;
  margin: 0;
  border-radius: 999px;
  background: var(--gray-line);
  cursor: pointer;
  transition: background .15s ease;
}

input.switch::after {
  content: "";
  position: absolute;
  top: 3px;
  inset-inline-start: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
  transition: transform .15s ease;
}

input.switch:checked {
  background: var(--green);
}

input.switch:checked::after {
  transform: translateX(18px);
}

[dir="rtl"] input.switch:checked::after {
  transform: translateX(-18px);
}

input.switch:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

input.switch:disabled {
  opacity: .6;
}

/* ===== Admin monitoring dashboard ===== */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-bottom: 14px;
}

.stat-tile {
  background: var(--surface);
  border: 2px solid var(--gray-line);
  border-bottom-width: 5px;
  border-radius: 16px;
  padding: 14px;
  text-align: center;
}

.stat-tile-emoji {
  font-size: 22px;
}

.stat-tile-value {
  font-size: 20px;
  font-weight: 800;
  color: var(--ink);
  margin-top: 2px;
}

.stat-tile-label {
  font-size: 13px;
  color: var(--text-light);
  margin-top: 2px;
}

.monitoring-card-title {
  margin: 0 0 10px;
  font-size: 15px;
}

.dataset-grid {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.dataset-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 0;
  border-bottom: 1px solid var(--gray-line);
}

.dataset-row:last-child {
  border-bottom: none;
}

/* ===== Chunky "3D button" cards (Duolingo's actual trick: an offset
   bottom border you can press, not a soft drop shadow) ===== */
.card {
  background: var(--surface);
  border: 2px solid var(--gray-line);
  border-bottom-width: 5px;
  border-radius: 16px;
  padding: 16px;
  margin-bottom: 12px;
  transition: transform 0.05s ease, border-bottom-width 0.05s ease;
}

.card-clickable:active {
  transform: translateY(3px);
  border-bottom-width: 2px;
}

.track-card {
  border-color: var(--track-color, var(--blue));
  border-bottom-color: var(--track-color, var(--blue));
}

.level-badge {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  flex-shrink: 0;
}

/* ===== Daily goal progress ===== */
.card.daily-goal-card {
  border: none;
  box-shadow: 8px 8px 18px var(--neu-dark), -8px -8px 18px var(--neu-light);
}

.goal-track {
  height: 12px;
  border-radius: 999px;
  background: var(--gray-line);
  overflow: hidden;
  margin-top: 8px;
}

.daily-goal-card .goal-track {
  background: var(--surface);
  box-shadow: inset 3px 3px 6px var(--neu-dark), inset -3px -3px 6px var(--neu-light);
}

.goal-fill {
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--green), var(--green-dark));
  transition: width 0.6s ease;
}

.streak-risk-row {
  align-items: center;
  gap: 10px;
  margin-top: 12px;
}

.streak-risk-mascot {
  width: 40px;
  height: 40px;
  object-fit: contain;
  flex-shrink: 0;
}

/* ===== Section headings use the display face too ===== */
h1,
h2 {
  font-family: "Vazirmatn", sans-serif;
  font-weight: 700;
}

h1 {
  font-size: 26px;
  color: var(--navy-ink);
}

h2 {
  font-size: 20px;
  color: var(--navy-ink);
}

.mt24 {
  margin-top: 24px;
}

.row {
  display: flex;
  align-items: center;
  gap: 12px;
}

.col {
  display: flex;
  flex-direction: column;
}

.grow {
  flex: 1;
}

.muted {
  color: var(--text-light);
}

.small {
  font-size: 13px;
}

.empty-state {
  text-align: center;
  padding: 40px 20px;
  color: var(--text-light);
}

.empty-emoji {
  font-size: 40px;
  margin-bottom: 8px;
}

/* ===== Bottom tab bar =====
   Five tabs at most: the icons are detailed illustrations, so they need room
   around them to read as a menu. Labels at 11px (the platform minimum is
   10-12px); the current tab gets a pill behind its icon, not just a colour. */
.tabbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  background: var(--surface);
  border-top: 2px solid var(--gray-line);
  padding: 6px 4px max(6px, env(safe-area-inset-bottom));
  z-index: 20;
}

.tab {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 0;
  text-decoration: none;
  color: var(--text-light);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}

.tab.active {
  color: var(--navy-ink);
  font-weight: 800;
}

.tab-icon {
  box-sizing: content-box;
  width: 30px;
  height: 30px;
  padding: 2px 14px;
  border-radius: 999px;
  object-fit: contain;
  transition: background-color .15s ease;
}

.tab.active .tab-icon {
  background: color-mix(in srgb, var(--blue) 16%, transparent);
}



.avatar-circle {
  width: 84px;
  height: 84px;
  border-radius: 50%;
  border: none;
  font-size: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 8px;
  cursor: pointer;
  transition: transform 0.1s ease;
}

.avatar-circle:active {
  transform: scale(0.94);
}

.link-btn {
  background: none;
  border: none;
  color: var(--navy-ink);
  font-weight: 700;
  font-size: 14px;
  cursor: pointer;
  padding: 4px;
}

.avatar-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  margin-top: 14px;
}

.avatar-grid.hidden {
  display: none;
}

.avatar-option {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 4px;
  border-radius: 14px;
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform 0.1s ease;
}

.avatar-option:active {
  transform: scale(0.95);
}

.avatar-option.selected {
  border-width: 3px;
  box-shadow: 0 0 0 2px var(--surface) inset;
}

.toast {
  position: fixed;
  top: -60px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--overlay-chip);
  color: #fff;
  padding: 10px 18px;
  border-radius: 12px;
  font-size: 14px;
  font-weight: 600;
  transition: top 0.3s ease;
  z-index: 50;
}

.toast.show {
  top: 16px;
}







/* ===== Circle path (one circle per unit, each a ring of levels) ===== */
.trail-wrap {
  position: relative;
  padding: 12px 0 40px;
}

#trail-svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.node-layer {
  position: relative;
  z-index: 2;
}

/* Course-name divider inside a Phase's continuous multi-course path (see
   renderPhasePath in app.js) — height must match its headerSlotHeight JS
   constant (64px) so the SVG curve overlay stays in sync with the DOM. */
.path-section-header {
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.path-section-header span {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-light);
  background: var(--gray-bg);
  padding: 4px 16px;
  border: 2px solid var(--gray-line);
  border-radius: 999px;
}

.circle-slot {
  position: relative;
  height: 140px;
}

.mascot-decor {
  position: absolute;
  top: 24px;
  width: 120px;
  height: 120px;
  object-fit: contain;
  filter: drop-shadow(0 4px 6px rgba(0, 0, 0, .18));
  animation: mascotBob 2.8s ease-in-out infinite;
  pointer-events: none;
  z-index: 1;
}

@keyframes mascotBob {

  0%,
  100% {
    transform: translateY(0) rotate(var(--mascot-rot, 0deg));
  }

  50% {
    transform: translateY(-10px) rotate(var(--mascot-rot, 0deg));
  }
}

.unit-circle {
  position: absolute;
  top: 12px;
  width: 88px;
  height: 88px;
  border-radius: 50%;
  padding: 6px;
  cursor: pointer;
  transition: transform .05s ease;
}

.unit-circle:active {
  transform: scale(.95);
}

.unit-circle-inner {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: var(--surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 34px;
  box-shadow: 6px 6px 14px var(--neu-dark), -6px -6px 14px var(--neu-light);
}

.unit-circle.locked {
  cursor: default;
}

.unit-circle.locked .unit-circle-inner {
  color: var(--text-light);
  /* Locked reads as "pressed in" — the shadow direction reverses to
     look recessed rather than raised, which happens to double as a
     legible locked affordance for free. */
  box-shadow: inset 4px 4px 10px var(--neu-dark), inset -4px -4px 10px var(--neu-light);
}

.unit-circle.locked.shake {
  animation: nodeShake .35s;
}

@keyframes nodeShake {

  0%,
  100% {
    transform: translateX(0);
  }

  25% {
    transform: translateX(-6px);
  }

  75% {
    transform: translateX(6px);
  }
}

.unit-circle.solved .unit-circle-inner {
  background: var(--tint-yellow);
}

/* Open because the placement test said the learner knows it, not because
   they played it: a quiet blue tint and a tick, distinct from a solved
   (gold) circle. */
.unit-circle.tested-out .unit-circle-inner {
  background: var(--tint-blue);
}

.unit-circle.tested-out::after {
  content: "✓";
  position: absolute;
  top: 0;
  inset-inline-end: 0;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--blue);
  color: #fff;
  font-size: 14px;
  font-weight: 800;
  line-height: 26px;
  text-align: center;
}

.unit-circle-label {
  position: absolute;
  top: 100px;
  transform: translateX(-50%);
  width: 150px;
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-light);
}

.exam-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  z-index: 2;
}

.exam-slot-top {
  margin-bottom: 16px;
}

.exam-node {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  cursor: pointer;
  background: linear-gradient(160deg, var(--gold), var(--gold-2));
  border: 2px solid var(--gold-dark);
  border-bottom-width: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 42px;
  animation: trophyFloat 3s ease-in-out infinite;
  transition: transform .05s ease, border-bottom-width .05s ease;
}

.exam-node:active {
  transform: translateY(4px);
  border-bottom-width: 2px;
}

.exam-node.locked {
  filter: grayscale(1) opacity(.6);
  animation: none;
}

.exam-node.locked.shake {
  animation: nodeShake .35s;
}

@keyframes trophyFloat {

  0%,
  100% {
    transform: translateY(0) rotate(0deg);
  }

  50% {
    transform: translateY(-6px) rotate(-3deg);
  }
}

.checkpoint-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  z-index: 2;
  margin-bottom: 8px;
}

.checkpoint-node {
  width: 76px;
  height: 76px;
  border-radius: 50%;
  cursor: pointer;
  background: linear-gradient(160deg, var(--tint-blue), var(--blue));
  border: 2px solid var(--blue-dark);
  border-bottom-width: 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
  transition: transform .05s ease, border-bottom-width .05s ease;
}

.checkpoint-node:active {
  transform: translateY(3px);
  border-bottom-width: 2px;
}

.checkpoint-node.passed {
  background: linear-gradient(160deg, var(--tint-green), var(--green));
  border-color: var(--green-dark);
}

/* ---- unit click popover — small box anchored next to the clicked circle ---- */
.unit-popover-overlay {
  position: fixed;
  inset: 0;
  background: transparent;
  opacity: 0;
  pointer-events: none;
  transition: opacity .15s ease;
  z-index: 50;
}

.unit-popover-overlay.open {
  opacity: 1;
  pointer-events: auto;
}

.unit-popover {
  position: absolute;
  width: 240px;
  background: var(--paper);
  border-radius: 18px;
  padding: 20px 16px 16px;
  text-align: center;
  box-shadow: 0 10px 34px rgba(27, 36, 48, .28);
  transform: scale(.92);
  transition: transform .15s ease;
}

.unit-popover-overlay.open .unit-popover {
  transform: scale(1);
}

.unit-popover-icon {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  margin: -44px auto 10px;
  background: var(--blue);
  color: #fff;
  font-size: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 4px solid var(--paper);
}

.unit-popover h2 {
  margin: 0 0 4px;
  font-size: 16px;
}

.unit-popover p.muted {
  margin: 0 0 12px;
  font-size: 13px;
}

.unit-popover .btn {
  padding: 8px 12px;
  font-size: 14px;
}

/* ---- centered modal — for congrats / message-style overlays, room for a gif ---- */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(27, 36, 48, .45);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease;
  z-index: 60;
  padding: 20px;
}

.modal-overlay.open {
  opacity: 1;
  pointer-events: auto;
}

.modal-box {
  width: 100%;
  max-width: 380px;
  background: var(--paper);
  border-radius: 24px;
  padding: 28px 24px 24px;
  text-align: center;
  transform: scale(.9);
  opacity: 0;
  transition: transform .25s ease, opacity .25s ease;
}

.modal-overlay.open .modal-box {
  transform: scale(1);
  opacity: 1;
}

.modal-box img,
.modal-box video {
  max-width: 100%;
  border-radius: 16px;
  margin-bottom: 12px;
}

.modal-mascot {
  width: 140px;
  height: 140px;
  object-fit: contain;
  border-radius: 0;
  margin: 0 auto 8px;
}

/* The hearts/XP modal is a status read-out, not a celebration: it carries a
   heading, a note, one action and the plan list, so the congrats sizing
   (72px emoji, 26px h1) pushed it past the fold on a phone. .modal-compact
   keeps the same box at informational scale. */
.modal-compact {
  max-width: 320px;
  padding: 18px 18px 16px;
}

.modal-compact .result-emoji {
  font-size: 40px;
  line-height: 1.1;
  margin-bottom: 4px;
}

.modal-compact h1 {
  font-size: 19px;
  margin: 0 0 6px;
}

.modal-compact p {
  margin: 0 0 8px;
}

.modal-compact .btn {
  padding: 10px 14px;
  font-size: 15px;
}

.modal-compact .mt16 {
  margin-top: 12px;
}

.modal-compact .plan-option {
  padding: 8px 10px;
  border-radius: 12px;
}

.modal-compact .plan-option+.plan-option {
  margin-top: 8px;
}

/* ===========================================================================
   Desktop layout (>=900px): three columns, addressed LOGICALLY. Column 1 is
   the inline-start edge, which is physically right in an RTL locale and left
   in an LTR one — so the nav is column 1 and the leaderboard/blog sidebar is
   column 3, and both land on the correct side in either direction. <html dir>
   now follows the learner's app language (see applyLocaleChrome in app.js),
   so nothing here may assume RTL. Below 900px, none of this applies: phone
   layout (top hearts/xp bar, bottom tab bar) is untouched.
   Which routes get the sidebar is decided in JS — see
   SIDEBAR_ROUTE_SEGMENTS in app.js — via the body.has-sidebar class.
   =========================================================================== */
.sidebar-left {
  display: none;
}

@media (min-width: 900px) {
  body {
    display: grid;
    grid-template-columns: 286px 1fr 390px;
    min-height: 100vh;
  }

  body:not(.has-sidebar) {
    grid-template-columns: 286px 1fr 0;
  }

  /* Logged-out screens (login/register) hide the tab bar entirely — collapse
     its column too instead of leaving an empty gutter on the right. */
  body:has(#tabbar.hidden) {
    grid-template-columns: 0 1fr 0;
  }

  /* No shared top bar on desktop — the logo lives at the top of the nav
     column instead (see .nav-logo below), and the header-stats pills move
     into the sidebar's top (or stay hidden on routes with no sidebar). */
  .app-header {
    display: none;
  }

  #app {
    grid-column: 2;
    grid-row: 1;
    max-width: 640px;
    width: 100%;
    margin: 0 auto;
    padding: 24px 24px 40px;
  }

  .sidebar-left {
    grid-column: 3;
    grid-row: 1;
    position: sticky;
    top: 0;
    align-self: start;
    height: 100vh;
    overflow-y: auto;
    padding: 20px 16px;
    /* Logical, not physical: this column is grid-column 3, so the edge facing
       the content is its inline-START side — physically left in LTR, right in
       RTL. A hardcoded border-right drew it on the outer edge in LTR. */
    border-inline-start: 2px solid var(--gray-line);
  }

  body.has-sidebar .sidebar-left {
    display: block;
  }

  .sidebar-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 20px;
  }

  .sidebar-heading {
    margin: 0 0 10px;
    font-size: 15px;
  }

  /* Daily goal card sits at the top of this column, above the leaderboard.
     :empty covers the routes/accounts where the API sends no goal fields —
     no card, no gap. */
  .sidebar-goal {
    margin-bottom: 20px;
  }

  .sidebar-goal:empty {
    margin-bottom: 0;
  }

  /* ...which makes the inline copy on /home a duplicate up here. Hide it and
     drop the margin it was carrying for the graph below it. */
  /* Nav becomes a vertical column pinned to the inline-start edge instead
     of a bar fixed to the bottom of the viewport — physically right in RTL,
     left in LTR. */
  .tabbar {
    position: sticky;
    top: 0;
    align-self: start;
    grid-column: 1;
    grid-row: 1;
    bottom: auto;
    left: auto;
    right: auto;
    height: 100vh;
    flex-direction: column;
    justify-content: flex-start;
    gap: 6px;
    padding: 16px 0 24px;
    border-top: none;
    /* grid-column 1, so the edge facing the content is inline-END. */
    border-inline-end: 2px solid var(--gray-line);
    /* Mobile's tab bar sits on --surface (a card-like white); on desktop
       it's a plain column like .sidebar-left, so match its background
       (--paper, i.e. same as the page) instead. */
    background: var(--paper);
  }

  .nav-logo {
    display: flex;
    justify-content: center;
    padding: 18px 0 30px;
  }

  .nav-logo .header-logo {
    height: 42px;
  }

  .tab {
    flex: none;
    flex-direction: row;
    justify-content: flex-start;
    gap: 18px;
    padding: 18px 36px;
    font-size: 15.75px;
  }

  .tab-icon {
    width: 67.5px;
    height: 67.5px;
    padding: 0;
    object-fit: contain;
  }

  .tab.active .tab-icon {
    background: none;
  }

  /* The mobile graph goes full-bleed via negative viewport margins; on
     desktop it should just fill its own (centered) column instead. Kept
     position: relative (not static) — .graph-greeting/.graph-mute-btn are
     positioned absolute against this element; losing that containing block
     sends them to the page's top-left corner instead, which lands them
     inside the left sidebar column. */
  .graph-card {
    position: relative;
    left: auto;
    right: auto;
    width: 100%;
    margin-left: 0;
    margin-right: 0;
    /* The graph is always the last thing in #app on /home now (the
       "more courses" list that used to follow it is gone) — cancel #app's
       bottom padding so its bottom edge reaches the same y as the nav/
       sidebar columns, which are a flat 100vh with no such padding. */
    margin-bottom: -40px;
    border-radius: 16px;
    border-left: 2px solid var(--gray-line);
    border-right: 2px solid var(--gray-line);
  }

  .graph-card.flush-top {
    /* Cancel #app's top padding too, so with no daily-goal card above it
       the graph starts at the same y as the nav/sidebar columns instead of
       being inset — otherwise it reads as shorter than them by that gap. */
    margin-top: -24px;
  }
}

@media (prefers-reduced-motion: reduce) {

  .unit-circle.locked.shake,
  .exam-node {
    animation: none !important;
  }
}

/* ===== Dark mode: follows the browser/OS color-scheme preference,
   no in-app toggle. Everything above is themed through these tokens, so
   this block only needs to redefine the tokens, not re-style components. */
@media (prefers-color-scheme: dark) {
  :root {
    --gray-bg: #1c2027;
    --gray-line: #2c323c;
    --text: #e7e9ec;
    --text-light: #97a1b0;

    --surface: #20242c;
    --surface-alt: #272c35;

    --paper: #14171c;
    --ink: #eceef0;

    /* Wing-blue lifted so it still reads as text on a dark surface; navy as
       text turns into a pale navy (navy fills keep --navy). */
    --blue: #4f7ff5;
    --blue-dark: #2f5fd0;
    --navy-ink: #c9d6ff;

    /* Dark surfaces are close in lightness to their own shadows, so the
       light/dark split has to come from near-black vs. a faint white
       glow rather than the light-mode gray/white pairing. */
    --neu-dark: rgba(0, 0, 0, 0.55);
    --neu-light: rgba(255, 255, 255, 0.06);
  }

  .logo-light {
    display: none;
  }

  .logo-dark {
    display: inline-block;
  }
}

/* ===== Profile page — scoped shrink =====
   .card/.avatar-circle/.disclosure-btn/.stat-pill/h2 are shared across the
   whole app (home, lessons, etc.), so the size reduction is scoped to
   .profile-page rather than changing those rules globally. */
.profile-page .card {
  padding: 12px;
  margin-bottom: 8px;
  border-bottom-width: 4px;
}

.profile-page .avatar-circle {
  width: 64px;
  height: 64px;
  font-size: 30px;
}

.profile-page h2 {
  font-size: 16px;
}

.profile-page .stat-pill {
  padding: 4px 9px;
  font-size: 12px;
}

.profile-page .disclosure-btn {
  font-size: 14px;
}

.profile-page .row-between {
  font-size: 14px;
}

/* ===========================================================================
   SOCIAL — profile header, statistics tiles, achievements, the XP week
   chart, friend lists and the language snapshot.

   Sizes are deliberately a touch smaller than the app's defaults because the
   profile stacks six sections; the `.profile-page` scoped shrink above does
   the same for the shared components.
   =========================================================================== */

.profile-header {
  text-align: center;
  padding-top: 0 !important;
  overflow: hidden;
}

/* The tinted band the avatar sits on, as on the reference profiles — it also
   gives the card a horizon so the name does not float. */
.profile-header-banner {
  background: linear-gradient(180deg, var(--tint-yellow), var(--surface));
  margin: -12px -12px 8px;
  padding: 20px 12px 12px;
}

/* On your own profile the avatar is the way into account details — only
   there, so a stranger's picture stays inert. */
.profile-avatar-link {
  display: inline-block;
  border-radius: 50%;
  text-decoration: none;
  transition: transform .15s ease;
}

.profile-avatar-link:active {
  transform: scale(.96);
}

.profile-name {
  margin: 0;
}

.profile-meta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 10px;
}

.profile-friends-link {
  color: var(--blue);
  font-weight: 700;
  font-size: 14px;
  text-decoration: none;
}

.profile-flags {
  display: flex;
  gap: 4px;
  align-items: center;
}

.profile-flag {
  font-size: 18px;
  line-height: 1;
}

.profile-flag-more {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-light);
  background: var(--surface-alt);
  border: 1px solid var(--gray-line);
  border-radius: 6px;
  padding: 2px 5px;
}

.profile-actions {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}

.section-heading {
  font-size: 15px;
  margin: 18px 0 8px;
}

/* ----- Statistics tiles ----- */
.stat-tile-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 8px;
}

.stat-tile {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface);
  border: 2px solid var(--gray-line);
  border-radius: 12px;
  padding: 10px;
}

.stat-tile-emoji {
  font-size: 20px;
  line-height: 1;
}

.stat-tile-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.stat-tile-body b {
  font-size: 16px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ----- Achievements ----- */
.achievement-row {
  display: flex;
  gap: 10px;
  justify-content: center;
}

.achievement-badge {
  /* --badge-color is set per badge from the catalog (social/achievements.py),
     so one rule styles all nine and a new badge needs no CSS. */
  width: 84px;
  border-radius: 12px;
  padding: 10px 6px 6px;
  background: linear-gradient(160deg, var(--badge-color), color-mix(in srgb, var(--badge-color) 70%, #000));
  color: #fff;
  text-align: center;
}

.achievement-badge.locked {
  background: var(--gray-line);
  color: var(--text-light);
  filter: grayscale(1);
}

.achievement-emoji {
  font-size: 30px;
  line-height: 1.1;
}

.achievement-level {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-top: 6px;
  opacity: 0.9;
}

.achievement-more {
  margin-top: 10px;
  border-top: 1px solid var(--gray-line);
  padding-top: 10px;
}

.achievement-card-head {
  display: flex;
  align-items: center;
  gap: 12px;
}

.achievement-progress {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
}

.achievement-bar,
.division-bar {
  flex: 1;
  height: 8px;
  border-radius: 4px;
  background: var(--gray-line);
  overflow: hidden;
}

.achievement-fill {
  display: block;
  height: 100%;
  border-radius: 4px;
  background: var(--badge-color, var(--green));
}

/* ----- XP this week ----- */
.xp-legend-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  padding: 2px 0;
}

.xp-legend-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 2px solid var(--blue);
  background: var(--blue);
}

.xp-legend-dot.you {
  background: transparent;
  border-color: var(--text-light);
}

.xp-chart {
  width: 100%;
  height: auto;
  margin-top: 8px;
  /* The chart is drawn left-to-right from oldest to newest; that is a time
     axis, not text, so it must not mirror in RTL. */
  direction: ltr;
}

.xp-grid {
  stroke: var(--gray-line);
  stroke-width: 1;
}

.xp-axis {
  fill: var(--text-light);
  font-size: 9px;
}

.xp-line {
  fill: none;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.xp-line.them {
  stroke: var(--blue);
}

.xp-line.you {
  stroke: var(--gray-line);
}

.xp-dot.them {
  fill: var(--blue);
}

.xp-dot.you {
  fill: var(--surface);
  stroke: var(--text-light);
  stroke-width: 2;
}

/* ----- Friends ----- */
.friend-tabs {
  display: flex;
  border-bottom: 2px solid var(--gray-line);
  margin-bottom: 8px;
}

.friend-tab {
  flex: 1;
  background: none;
  border: none;
  border-bottom: 3px solid transparent;
  margin-bottom: -2px;
  padding: 10px 4px;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-light);
  cursor: pointer;
}

.friend-tab.active {
  color: var(--blue);
  border-bottom-color: var(--blue);
}

.person-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--gray-line);
}

.person-row:last-child {
  border-bottom: none;
}

.person-row .avatar-circle {
  margin: 0;
  cursor: inherit;
}

.invite-link {
  background: var(--surface-alt);
  border: 1px solid var(--gray-line);
  border-radius: 8px;
  padding: 8px;
  font-size: 12px;
  word-break: break-all;
  direction: ltr;
  text-align: start;
}

.link-btn.danger {
  color: var(--text-light);
}

/* ----- Language snapshot ----- */
.lang-snapshot+.lang-snapshot {
  margin-top: 12px;
  border-top: 1px solid var(--gray-line);
  padding-top: 12px;
}

.lang-snapshot-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.lang-snapshot-flag {
  font-size: 20px;
}

.lang-snapshot-divisions {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 8px;
}

.division-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
}

.division-chip.locked {
  opacity: 0.45;
}

.division-label {
  width: 72px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.division-fill {
  display: block;
  height: 100%;
  border-radius: 4px;
  background: var(--green);
}

@media (min-width: 640px) {
  .stat-tile-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}
/* ===========================================================================
   Flashcards — deck shelf, study stack, mastered shelf (see #/cards in app.js)
   The cards are drawn as physical cards: a paper face with a thin inner
   rule, a stack of sheets behind, a 3D flip, and a swipe that throws them.
   =========================================================================== */
:root {
  --fc-paper: #fffdf7;
  --fc-paper-back: #f3f8ff;
  --fc-rule: color-mix(in srgb, var(--blue) 18%, transparent);
  --fc-edge: #e9e3d4;
  --fc-shadow: 0 14px 30px rgba(60, 60, 60, 0.16), 0 2px 6px rgba(60, 60, 60, 0.08);
}

@media (prefers-color-scheme: dark) {
  :root {
    --fc-paper: #262b34;
    --fc-paper-back: #1f2a36;
    --fc-rule: color-mix(in srgb, var(--blue) 22%, transparent);
    --fc-edge: #333a46;
    --fc-shadow: 0 14px 30px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.35);
  }
}

.cards-page { padding-bottom: 24px; }
.cards-review-all { margin: 4px 0 18px; }
.cards-review-all[disabled] { opacity: .55; box-shadow: none; }
.cards-heading { margin: 18px 0 10px; font-size: 16px; }

.deck-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 14px;
}

.deck-tile {
  position: relative;
  background: var(--surface);
  border: 2px solid var(--gray-line);
  border-bottom-width: 5px;
  border-radius: 18px;
  padding: 14px 12px 12px;
  text-align: center;
  cursor: pointer;
  transition: transform .12s ease;
}
.deck-tile:hover { transform: translateY(-2px); }
.deck-tile:active { transform: translateY(1px); }
.deck-tile:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }
.deck-tile-available { border-style: dashed; }

.deck-stack {
  position: relative;
  width: 78px;
  height: 96px;
  margin: 4px auto 12px;
}
.deck-sheet {
  position: absolute;
  inset: 0;
  border-radius: 12px;
  background: var(--fc-paper);
  border: 1.5px solid var(--fc-edge);
  box-shadow: 0 3px 8px rgba(0, 0, 0, .10);
  transition: transform .2s ease;
}
.deck-sheet-3 { transform: rotate(-9deg) translate(-6px, 2px); }
.deck-sheet-2 { transform: rotate(6deg) translate(5px, 1px); }
.deck-sheet-1 {
  display: flex;
  align-items: center;
  justify-content: center;
  background-image: repeating-linear-gradient(to bottom, transparent 0 15px, var(--fc-rule) 15px 16px);
}
.deck-tile:hover .deck-sheet-3 { transform: rotate(-14deg) translate(-12px, 2px); }
.deck-tile:hover .deck-sheet-2 { transform: rotate(11deg) translate(11px, 1px); }
.deck-emoji { font-size: 36px; line-height: 1; }
.deck-badge {
  position: absolute;
  top: -8px;
  inset-inline-end: -12px;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  border-radius: 12px;
  background: var(--red);
  color: #fff;
  font-size: 13px;
  font-weight: 800;
  line-height: 24px;
  box-shadow: 0 2px 0 var(--red-dark);
}
.deck-title { font-weight: 800; font-size: 15px; }
.deck-sub { margin-top: 2px; min-height: 2.6em; }
.deck-progress {
  height: 6px;
  margin-top: 8px;
  border-radius: 3px;
  background: var(--gray-line);
  overflow: hidden;
}
.deck-progress-fill { height: 100%; background: var(--green); border-radius: 3px; }
.deck-leave {
  position: absolute;
  top: 6px;
  inset-inline-start: 8px;
  border: none;
  background: none;
  color: var(--text-light);
  font-size: 18px;
  opacity: .5;
}
.deck-leave:hover { opacity: 1; }
.cards-mastered-link {
  display: block;
  margin-top: 22px;
  text-align: center;
  color: var(--text-light);
  font-weight: 700;
}

/* ----- Study screen ----- */
/* A dragged or thrown card is transformed past the viewport edge, which
   would otherwise widen the page and slide the whole layout sideways. */
html:has(.study-wrap), body:has(.study-wrap) { overflow-x: clip; }
.study-wrap {
  display: flex;
  flex-direction: column;
  min-height: calc(100dvh - 140px);
}
.study-count { min-width: 52px; text-align: end; }

.card-stage {
  position: relative;
  flex: 1;
  min-height: 420px;
  margin: 18px 0 8px;
  perspective: 1400px;
}

.fc {
  position: absolute;
  inset: 0 6px 18px;
  max-width: 420px;
  margin: 0 auto;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  cursor: grab;
  transition: transform .32s cubic-bezier(.2, .8, .3, 1.1), opacity .32s ease;
  --know: 0;
  --again: 0;
}
.fc[data-depth="1"] { transform: translateY(12px) scale(.95) rotate(-1.5deg); pointer-events: none; }
.fc[data-depth="2"] { transform: translateY(24px) scale(.90) rotate(1.5deg); pointer-events: none; }
.fc[data-depth="1"] .fc-face, .fc[data-depth="2"] .fc-face { filter: brightness(.97); }
.fc.fc-enter { transform: translateY(36px) scale(.85); opacity: 0; }
.fc.dragging { transition: none; cursor: grabbing; }
.fc.fc-leaving { pointer-events: none; transition: transform .38s ease-in, opacity .38s ease-in; }
.fc:focus-visible { outline: none; }
.fc:focus-visible .fc-face { box-shadow: 0 0 0 3px var(--blue), var(--fc-shadow); }

.fc-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform .55s cubic-bezier(.3, .7, .3, 1);
}
.fc.flipped .fc-inner { transform: rotateY(180deg); }

.fc-face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  border-radius: 24px;
  border: 1.5px solid var(--fc-edge);
  background-color: var(--fc-paper);
  box-shadow: var(--fc-shadow);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  overflow: hidden;
  padding: 22px 20px 18px;
}
/* The inner rule every index card has, inset from the edge. */
.fc-face::before {
  content: "";
  position: absolute;
  inset: 10px;
  border: 1px solid var(--fc-rule);
  border-radius: 16px;
  pointer-events: none;
}
.fc-front { justify-content: center; gap: 14px; }
.fc-back {
  transform: rotateY(180deg);
  background-color: var(--fc-paper-back);
  background-image: repeating-linear-gradient(to bottom, transparent 0 31px, var(--fc-rule) 31px 32px);
  background-position: 0 86px;
}

.fc-kind {
  position: absolute;
  top: 20px;
  inset-inline-start: 22px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .02em;
  color: var(--blue-dark);
  background: var(--tint-blue);
  padding: 3px 10px;
  border-radius: 10px;
}
.fc-picture {
  width: 120px;
  height: 120px;
  object-fit: contain;
  border-radius: 18px;
}
.fc-picture-emoji {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 76px;
  line-height: 1;
  background: var(--surface-alt);
}
.fc-text {
  font-size: 34px;
  font-weight: 800;
  text-align: center;
  line-height: 1.35;
  overflow-wrap: anywhere;
}
.fc-text-long { font-size: 24px; }
.fc-audio {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: none;
  color: #fff;
  font-size: 22px;
  background: linear-gradient(145deg, var(--blue), var(--blue-dark));
  box-shadow: 3px 3px 8px var(--neu-dark), -3px -3px 8px var(--neu-light);
  flex-shrink: 0;
}
.fc-audio:active { box-shadow: inset 3px 3px 8px var(--neu-dark), inset -3px -3px 8px var(--neu-light); }
.fc-audio-small { width: 34px; height: 34px; font-size: 14px; }
.fc-flip-hint { position: absolute; bottom: 20px; }

.fc-back-head { width: 100%; text-align: center; padding-bottom: 10px; }
/* Nothing but the translation (no example taught yet): centre it like the
   front, with the picture, instead of heading an empty ruled page. */
.fc-back-plain { justify-content: center; gap: 14px; background-image: none; }
.fc-back-plain .fc-translation { font-size: 34px; }
.fc-back-original { font-size: 17px; color: var(--text-light); font-weight: 700; }
.fc-translation { font-size: 27px; font-weight: 800; margin-top: 4px; line-height: 1.35; }
.fc-back-scroll {
  width: 100%;
  flex: 1;
  overflow-y: auto;
  touch-action: pan-y;
  padding: 2px 4px 6px;
}
.fc-section-label {
  font-size: 12px;
  font-weight: 800;
  color: var(--text-light);
  margin: 10px 0 6px;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.fc-words, .fc-examples { list-style: none; margin: 0; padding: 0; }
.fc-word {
  display: inline-flex;
  gap: 6px;
  align-items: baseline;
  margin: 0 0 6px;
  margin-inline-end: 6px;
  padding: 4px 10px;
  border-radius: 12px;
  background: var(--surface);
  border: 1px solid var(--gray-line);
}
.fc-word-text { font-weight: 800; }
.fc-word-gloss { color: var(--text-light); font-size: 14px; }
.fc-example {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 8px 10px;
  margin-bottom: 8px;
  border-radius: 14px;
  background: var(--surface);
  border: 1px solid var(--gray-line);
}
.fc-example-text { font-weight: 700; font-size: 16px; }

/* Rubber stamps that fade in with the drag. */
.fc-stamp {
  position: absolute;
  top: 26px;
  padding: 4px 12px;
  border: 3px solid;
  border-radius: 10px;
  font-weight: 900;
  font-size: 20px;
  text-transform: uppercase;
  pointer-events: none;
  opacity: 0;
}
.fc-stamp-know { color: var(--green); inset-inline-start: 22px; transform: rotate(-12deg); opacity: var(--know); }
.fc-stamp-again { color: var(--red); inset-inline-end: 22px; transform: rotate(12deg); opacity: var(--again); }
[dir="rtl"] .fc-stamp-know { transform: rotate(12deg); }
[dir="rtl"] .fc-stamp-again { transform: rotate(-12deg); }
.fc-face { box-shadow: var(--fc-shadow), inset 0 0 0 calc(var(--know) * 4px) var(--green), inset 0 0 0 calc(var(--again) * 4px) var(--red); }

.study-actions {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  max-width: 420px;
  width: 100%;
  margin: 8px auto 0;
}
.rate-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 6px;
  border-radius: 16px;
  border: 2px solid;
  border-bottom-width: 5px;
  background: var(--surface);
  font-weight: 800;
  font-size: 14px;
}
.rate-btn b { font-size: 20px; }
.rate-btn:active { transform: translateY(3px); border-bottom-width: 2px; }
.rate-again { color: var(--red); border-color: var(--red); }
.rate-hard { color: var(--gold-dark); border-color: var(--gold); }
.rate-know { color: var(--green-dark); border-color: var(--green); }
.study-tools {
  display: flex;
  justify-content: center;
  gap: 18px;
  margin: 14px 0 6px;
}
.study-tool {
  border: none;
  background: none;
  color: var(--text-light);
  font-weight: 700;
  font-size: 13px;
  padding: 6px 4px;
}
.study-tool:hover { color: var(--text); }

.fc-confetti {
  position: absolute;
  top: 45%;
  left: 50%;
  width: 9px;
  height: 14px;
  border-radius: 2px;
  z-index: 50;
  pointer-events: none;
  animation: fc-confetti 1s ease-out forwards;
}
@keyframes fc-confetti {
  0% { transform: translate(0, 0) rotate(0); opacity: 1; }
  100% { transform: translate(var(--x), calc(var(--y) + 260px)) rotate(var(--r)); opacity: 0; }
}

.study-done { text-align: center; padding: 24px 0; position: relative; }
.study-tally {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin: 18px 0 24px;
}
.study-tally div {
  display: flex;
  flex-direction: column;
  padding: 12px 4px;
  border-radius: 14px;
  background: var(--surface);
  border: 2px solid var(--gray-line);
}
.study-tally b { font-size: 24px; }
.study-tally span { font-size: 12px; color: var(--text-light); }

.undo-toast {
  position: fixed;
  left: 50%;
  bottom: 96px;
  transform: translate(-50%, 30px);
  display: flex;
  gap: 14px;
  align-items: center;
  padding: 10px 16px;
  border-radius: 14px;
  background: var(--overlay-chip);
  color: #fff;
  font-size: 14px;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
  z-index: 1000;
  max-width: calc(100vw - 32px);
}
.undo-toast.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.undo-toast button { border: none; background: none; color: var(--gold); font-weight: 800; }

.mastered-row { display: flex; gap: 12px; align-items: center; }
.mastered-text { font-weight: 800; font-size: 17px; }
.mastered-restore { width: auto; padding: 8px 14px; font-size: 14px; }

.fc-star-btn { margin-inline-end: 12px; }
.fc-star-btn.on { color: var(--gold-dark); opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .fc, .fc-inner, .fc.fc-leaving, .deck-sheet, .deck-tile { transition-duration: .01ms !important; }
}

/* ===========================================================================
   Arena — timed sprints (see the ARENA section of app.js). The brand's navy
   and wing-blue for the chrome, per-test gradients (--arena-c1/--arena-c2)
   in the family of the profile's achievement badges.
   =========================================================================== */
.arena-page {
  padding-bottom: 16px;
}

/* Hero banner: navy → blue with the magpie. */
.arena-hero {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px 18px;
  margin-bottom: 16px;
  border-radius: 24px;
  color: #fff;
  background:
    radial-gradient(120% 90% at 100% 0%, rgba(28, 176, 246, .55), transparent 60%),
    linear-gradient(160deg, var(--navy), var(--navy-2));
  box-shadow: 0 10px 28px rgba(11, 27, 63, .28);
}

.arena-hero::after {
  content: "";
  position: absolute;
  inset: auto -30% -70% -30%;
  height: 120%;
  border-radius: 50%;
  border-top: 2px solid rgba(255, 255, 255, .12);
  pointer-events: none;
}

.arena-hero-mascot {
  width: 86px;
  height: 86px;
  object-fit: contain;
  flex-shrink: 0;
  filter: drop-shadow(0 6px 12px rgba(0, 0, 0, .35));
}

.arena-hero-text h1 {
  margin: 0 0 4px;
  font-size: 24px;
  font-weight: 800;
  color: #fff;
}

.arena-hero-text p {
  margin: 0 0 6px;
  font-size: 13px;
  line-height: 1.7;
  color: #cde1ff;
}

.arena-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  background: rgba(255, 255, 255, .18);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22);
  white-space: nowrap;
}

/* Test cards: a saturated gradient per test, glass stats, a white CTA. */
.arena-test {
  position: relative;
  overflow: hidden;
  padding: 18px;
  margin-bottom: 14px;
  border-radius: 24px;
  color: #fff;
  background:
    radial-gradient(90% 70% at 0% 0%, rgba(255, 255, 255, .22), transparent 60%),
    linear-gradient(150deg, var(--arena-c1), var(--arena-c2));
  box-shadow: 6px 6px 14px var(--neu-dark), -6px -6px 14px var(--neu-light);
}

.arena-test-top {
  display: flex;
  align-items: center;
  gap: 14px;
}

.arena-test-top h2 {
  margin: 0 0 6px;
  font-size: 20px;
  font-weight: 800;
  color: #fff;
}

.arena-test-icon {
  width: 60px;
  height: 60px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
  border-radius: 18px;
  background: rgba(255, 255, 255, .22);
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .35);
}

.arena-test-icon.small {
  width: 46px;
  height: 46px;
  font-size: 24px;
  border-radius: 14px;
}

.arena-test-desc {
  margin: 12px 0 0;
  font-size: 13px;
  line-height: 1.7;
  color: rgba(255, 255, 255, .88);
}

.arena-glass-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin: 14px 0;
}

.arena-glass-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 4px;
  border-radius: 16px;
  background: rgba(255, 255, 255, .16);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .2);
  text-align: center;
}

.arena-glass-emoji {
  font-size: 18px;
  line-height: 1;
}

.arena-glass-stat b {
  font-size: 17px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.arena-glass-stat span:last-child {
  font-size: 11px;
  color: rgba(255, 255, 255, .85);
}

.arena-btn-start,
.arena-btn-glass {
  display: block;
  width: 100%;
  text-align: center;
  text-decoration: none;
  font-weight: 800;
  border-radius: 16px;
  padding: 14px;
  transition: box-shadow .1s ease;
}

.arena-btn-start {
  font-size: 18px;
  color: var(--arena-c2);
  background: #fff;
  box-shadow: 4px 4px 10px rgba(0, 0, 0, .18), -3px -3px 8px rgba(255, 255, 255, .25);
}

.arena-btn-glass {
  margin-top: 8px;
  font-size: 14px;
  color: #fff;
  background: rgba(255, 255, 255, .14);
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .3);
}

.arena-btn-start:active {
  box-shadow: inset 3px 3px 8px rgba(0, 0, 0, .18), inset -3px -3px 8px rgba(255, 255, 255, .6);
}

.arena-btn-glass:active {
  box-shadow: inset 3px 3px 8px rgba(0, 0, 0, .25), inset 0 0 0 1.5px rgba(255, 255, 255, .3);
}

/* Scoring rules. */
.arena-rules-card {
  padding: 6px 14px;
}

.arena-rule {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  font-size: 14px;
}

.arena-rule + .arena-rule {
  border-top: 1px solid var(--gray-line);
}

.arena-rule-icon {
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  font-size: 18px;
}

.arena-rule-icon.good { background: var(--tint-green); }
.arena-rule-icon.fast { background: var(--tint-yellow); }
.arena-rule-icon.hot { background: color-mix(in srgb, var(--gold-2) 22%, var(--surface)); }
.arena-rule-icon.bad { background: var(--tint-red); }
.arena-rule b { font-size: 16px; font-weight: 800; font-variant-numeric: tabular-nums; }
.arena-rule b.good { color: var(--green-dark); }
.arena-rule b.fast { color: #d99a00; }
.arena-rule b.hot { color: #e0542b; }
.arena-rule b.bad { color: var(--red); }

/* Countdown. */
.arena-countdown {
  min-height: 70vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border-radius: 28px;
  color: #fff;
  background:
    radial-gradient(90% 60% at 100% 0%, rgba(28, 176, 246, .55), transparent 60%),
    linear-gradient(170deg, var(--navy), var(--navy-2));
}

.arena-countdown-mascot {
  width: 120px;
  filter: drop-shadow(0 8px 16px rgba(0, 0, 0, .35));
}

.arena-countdown-label {
  font-size: 18px;
  font-weight: 700;
  color: #cde1ff;
}

.arena-countdown b {
  font-size: 110px;
  font-weight: 800;
  line-height: 1;
  color: var(--gold);
  text-shadow: 0 6px 24px rgba(255, 200, 0, .45);
}

.arena-countdown b.pop {
  animation: arena-pop .5s ease-out;
}

@keyframes arena-pop {
  0% { transform: scale(1.8); opacity: 0; }
  60% { transform: scale(.92); opacity: 1; }
  100% { transform: scale(1); }
}

/* The sprint itself. */
.arena-play {
  padding-bottom: 16px;
}

.arena-play-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 4px 0 8px;
}

.arena-quit {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: 26px;
  line-height: 1;
  text-decoration: none;
  color: var(--text-light);
  background: var(--surface);
  box-shadow: 0 2px 8px rgba(0, 0, 0, .08);
}

.arena-timer {
  position: relative;
  flex: 1;
  height: 30px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--gray-line);
}

.arena-timer-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--blue), var(--navy-2));
}

[dir="rtl"] .arena-timer-fill {
  inset: 0 0 0 auto;
}

.arena-timer-fill.low {
  background: linear-gradient(90deg, var(--red), var(--red-dark));
  animation: arena-pulse 1s ease-in-out infinite;
}

@keyframes arena-pulse {
  50% { opacity: .75; }
}

.arena-timer span {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  font-size: 13px;
  font-weight: 800;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .45);
  font-variant-numeric: tabular-nums;
}

.arena-score-pill {
  position: relative;
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 72px;
  justify-content: center;
  padding: 6px 12px;
  border-radius: 999px;
  color: #fff;
  background: linear-gradient(145deg, var(--gold), var(--gold-2));
  box-shadow: 3px 3px 8px var(--neu-dark), -3px -3px 8px var(--neu-light);
}

.arena-score-pill b {
  font-size: 17px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.arena-score-pill b.bump {
  animation: arena-bump .3s ease-out;
}

@keyframes arena-bump {
  50% { transform: scale(1.3); }
}

.arena-points {
  position: absolute;
  top: 100%;
  inset-inline-start: 50%;
  transform: translate(-50%, 0);
  font-style: normal;
  font-weight: 800;
  font-size: 15px;
  opacity: 0;
  pointer-events: none;
}

.arena-points.show {
  animation: arena-float .65s ease-out;
}

.arena-points.up { color: var(--green); }
.arena-points.down { color: var(--red); }

@keyframes arena-float {
  0% { opacity: 1; transform: translate(-50%, 0); }
  100% { opacity: 0; transform: translate(-50%, 18px); }
}

.arena-combo {
  min-height: 30px;
  display: flex;
  justify-content: center;
  margin-bottom: 4px;
}

.arena-combo-chip {
  padding: 4px 14px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 800;
  color: #e0542b;
  background: color-mix(in srgb, var(--gold-2) 18%, var(--surface));
}

.arena-combo-chip.hot {
  color: #fff;
  background: linear-gradient(145deg, var(--gold-2), #e0542b);
  box-shadow: 0 0 18px rgba(255, 150, 0, .55);
}

.arena-question {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 26px 18px 30px;
  margin-bottom: 16px;
  border-radius: 24px;
  background: var(--surface);
  box-shadow: 6px 6px 14px var(--neu-dark), -6px -6px 14px var(--neu-light);
}

.arena-cue {
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  color: var(--blue-dark);
  background: var(--tint-blue);
}

.arena-prompt {
  font-size: 30px;
  font-weight: 800;
  line-height: 1.4;
  text-align: center;
  overflow-wrap: anywhere;
}

.arena-prompt.latin {
  font-size: 42px;
  letter-spacing: .5px;
}

.arena-question.reading .arena-prompt {
  font-size: 17px;
  text-align: start;
}

.arena-options {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.arena-options.stacked {
  grid-template-columns: 1fr;
}

.arena-options .arena-option {
  margin: 0;
  min-height: 78px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center !important;
  font-size: 17px;
  font-weight: 700;
  line-height: 1.5;
  border-radius: 18px;
  transition: transform .08s ease;
}

.arena-options .arena-option:active {
  transform: translateY(2px);
}

.arena-options .arena-option:disabled {
  cursor: default;
  opacity: 1;
}

.arena-options .arena-option.correct {
  animation: arena-bump .3s ease-out;
}

.arena-options .arena-option.wrong {
  animation: arena-shake .35s ease-in-out;
}

@keyframes arena-shake {
  25% { transform: translateX(-6px); }
  75% { transform: translateX(6px); }
}

.arena-passage {
  max-height: 34vh;
  overflow-y: auto;
  text-align: left;
  line-height: 1.8;
  margin-bottom: 12px;
}

.arena-passage h3 {
  margin: 0 0 6px;
  font-size: 16px;
}

.arena-timeup {
  min-height: 40vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 56px;
}

.arena-timeup b {
  font-size: 26px;
}

/* Result. */
.arena-result-hero {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 22px 18px 24px;
  margin-bottom: 14px;
  border-radius: 28px;
  color: #fff;
  text-align: center;
  background:
    radial-gradient(100% 70% at 100% 0%, rgba(28, 176, 246, .55), transparent 60%),
    radial-gradient(80% 60% at 0% 100%, rgba(92, 200, 255, .25), transparent 60%),
    linear-gradient(170deg, var(--navy), var(--navy-2));
  box-shadow: 0 12px 30px rgba(11, 27, 63, .3);
}

.arena-result-mascot {
  width: 96px;
  filter: drop-shadow(0 6px 12px rgba(0, 0, 0, .35));
}

.arena-pb {
  padding: 5px 16px;
  border-radius: 999px;
  font-weight: 800;
  font-size: 14px;
  color: #fff;
  background: linear-gradient(145deg, var(--red), var(--red-dark));
  box-shadow: 3px 3px 8px var(--neu-dark), -3px -3px 8px var(--neu-light);
}

.arena-result-score {
  font-size: 84px;
  font-weight: 800;
  line-height: 1;
  text-shadow: 0 6px 24px rgba(28, 176, 246, .45);
}

.arena-result-label {
  font-size: 14px;
  color: #cde1ff;
}

.arena-rank-badge {
  margin-top: 6px;
  padding: 10px 22px;
  border-radius: 999px;
  font-size: 16px;
  font-weight: 800;
  color: var(--navy);
  background: linear-gradient(90deg, var(--gold), var(--gold-2));
  box-shadow: 4px 4px 10px rgba(0, 0, 0, .3), -3px -3px 8px rgba(255, 255, 255, .08);
}

.arena-xp {
  font-weight: 800;
  color: #8fdcff;
}

.arena-save-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 10px;
}

.arena-btn-ig {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 10px;
  border: 0;
  border-radius: 16px;
  font: inherit;
  font-size: 14px;
  font-weight: 800;
  color: #fff;
  cursor: pointer;
  background: linear-gradient(45deg, #f9ce34, #ee2a7b 45%, #6228d7);
  box-shadow: 6px 6px 14px var(--neu-dark), -6px -6px 14px var(--neu-light);
  transition: box-shadow .1s ease;
}

.arena-btn-ig:active {
  box-shadow: inset 4px 4px 10px var(--neu-dark), inset -4px -4px 10px var(--neu-light);
}

.arena-btn-ig:disabled {
  opacity: .6;
}

.arena-ig-icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

.arena-wide {
  display: block;
  width: 100%;
  text-align: center;
}

.arena-actions {
  display: flex;
  gap: 10px;
  margin-top: 12px;
}

.arena-actions .btn {
  text-align: center;
  text-decoration: none;
}

/* Board. */
.arena-seg-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 14px;
}

.arena-seg {
  display: flex;
  padding: 4px;
  border-radius: 999px;
  background: var(--gray-line);
}

.arena-seg button {
  flex: 1;
  padding: 8px 4px;
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-light);
  background: none;
  cursor: pointer;
}

.arena-seg button.active {
  color: #fff;
  background: linear-gradient(145deg, var(--blue), var(--navy-2));
  box-shadow: 0 2px 6px rgba(23, 71, 184, .35);
}

.arena-podium {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  margin: 8px 0 14px;
}

.arena-podium-spot {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  color: inherit;
  text-decoration: none;
}

.arena-podium-avatar {
  position: relative;
}

.arena-podium-avatar .avatar-circle {
  box-shadow: 0 0 0 4px var(--surface), 0 0 0 7px var(--podium-ring, #ccc);
}

.arena-crown {
  position: absolute;
  top: -24px;
  left: 50%;
  transform: translateX(-50%) rotate(-8deg);
  font-size: 26px;
}

.arena-podium-name {
  max-width: 100%;
  margin-top: 6px;
  font-size: 13px;
  font-weight: 800;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.arena-podium-score {
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 800;
  color: var(--podium-ink, #555);
  background: color-mix(in srgb, var(--podium-ring, #ccc) 25%, var(--surface));
  font-variant-numeric: tabular-nums;
}

.arena-podium-block {
  width: 100%;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 10px;
  border-radius: 16px 16px 6px 6px;
  font-size: 30px;
  background: linear-gradient(180deg, var(--podium-ring), color-mix(in srgb, var(--podium-ring) 70%, #000));
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, .35);
}

.arena-podium-spot.place-1 { --podium-ring: var(--gold); --podium-ink: #a36b00; }
.arena-podium-spot.place-2 { --podium-ring: #b8c4d4; --podium-ink: #52606f; }
.arena-podium-spot.place-3 { --podium-ring: #e39a5b; --podium-ink: #8c4a14; }
.arena-podium-spot.place-1 .arena-podium-block { height: 120px; }
.arena-podium-spot.place-2 .arena-podium-block { height: 88px; }
.arena-podium-spot.place-3 .arena-podium-block { height: 68px; }
.arena-podium-spot.place-1 { margin-top: 26px; }
.arena-podium-spot.empty { visibility: hidden; }

.arena-podium-spot.you .arena-podium-name {
  color: var(--blue-dark);
}

.arena-rows {
  padding: 6px 8px;
}

.arena-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 8px;
  border-radius: 14px;
  color: inherit;
  text-decoration: none;
}

.arena-row + .arena-row {
  border-top: 1px solid var(--gray-line);
}

.arena-row.you {
  background: linear-gradient(90deg, var(--tint-blue), color-mix(in srgb, var(--blue) 8%, var(--surface)));
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--blue) 45%, transparent);
  border-top-color: transparent;
}

.arena-row.you + .arena-row {
  border-top-color: transparent;
}

.arena-row-rank {
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: 13px;
  font-weight: 800;
  color: var(--text-light);
  background: var(--gray-line);
  font-variant-numeric: tabular-nums;
}

.arena-row .avatar-circle {
  flex-shrink: 0;
}

.arena-row-name {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.arena-row-name b {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
}

.arena-row-score {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1.2;
}

.arena-row-score b {
  font-size: 17px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.arena-row-score span {
  font-size: 11px;
  color: var(--text-light);
}

.arena-row-gap {
  text-align: center;
  font-size: 12px;
  letter-spacing: 3px;
  color: var(--text-light);
  padding: 4px 0;
}

.arena-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 24px 16px;
  text-align: center;
  font-weight: 700;
}

.arena-empty img {
  width: 110px;
}

/* Share sheet. */
.arena-share-box {
  max-width: 420px;
  max-height: 92vh;
  overflow-y: auto;
  padding: 20px 16px 16px;
}

.arena-share-box h3 {
  margin: 0 0 12px;
}

.arena-share-preview {
  display: block;
  width: 62%;
  height: auto;
  margin: 0 auto 14px;
  border-radius: 18px;
  box-shadow: 0 10px 26px rgba(0, 0, 0, .25);
}

.arena-share-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-bottom: 10px;
}

.arena-share-link {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 8px 6px;
  border: 0;
  border-radius: 14px;
  font: inherit;
  font-size: 13px;
  font-weight: 800;
  color: #fff;
  text-decoration: none;
  cursor: pointer;
}

.arena-share-link.telegram { background: #2aabee; }
.arena-share-link.whatsapp { background: #25d366; }
.arena-share-link.x { background: #14171a; }
.arena-share-link.copy,
.arena-share-link.more,
.arena-share-link.save { background: var(--gray-line); color: var(--text); }

/* Profile tile. */
.arena-profile-tile {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px;
  margin-bottom: 8px;
  border-radius: 20px;
  color: #fff;
  text-decoration: none;
  background:
    radial-gradient(90% 80% at 0% 0%, rgba(255, 255, 255, .22), transparent 60%),
    linear-gradient(150deg, var(--arena-c1), var(--arena-c2));
  box-shadow: 6px 6px 14px var(--neu-dark), -6px -6px 14px var(--neu-light);
}

.arena-profile-tile b {
  font-size: 15px;
}

.arena-profile-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}

.arena-profile-score {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1.1;
}

.arena-profile-score b {
  font-size: 26px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.arena-profile-score span {
  font-size: 11px;
  color: rgba(255, 255, 255, .85);
}

/* ---------------------------------------------------------------------------
   Nudges — the at-risk list, the message sheet and the home slot. Logical
   properties and flex only, so the same rules lay out in rtl.
--------------------------------------------------------------------------- */
.nudge-person {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}

.nudge-person .avatar-circle {
  margin: 0;
}

.nudge-btn {
  flex-shrink: 0;
  width: auto;
}

.nudge-messages {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 16px;
}

.nudge-message {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 12px 14px;
  font: inherit;
  text-align: start;
  color: inherit;
  background: var(--surface);
  border: 2px solid var(--gray-line);
  border-radius: 14px;
  cursor: pointer;
}

.nudge-message:hover:not(:disabled) {
  border-color: var(--blue);
  background: var(--tint-blue);
}

.nudge-message-emoji {
  font-size: 22px;
  flex-shrink: 0;
}

.home-nudges {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 16px;
}

.nudge-banner {
  border-color: var(--blue);
  background: var(--tint-blue);
}

.nudge-home-card {
  display: flex;
  align-items: center;
  gap: 12px;
  color: inherit;
  text-decoration: none;
}

.nudge-home-emoji {
  font-size: 28px;
  flex-shrink: 0;
}

.home-nudges .card {
  margin-bottom: 0;
}

/* Arena listening question: the clip is the prompt. */
.arena-question.listening {
  gap: 8px;
}

.arena-listen-btn {
  position: relative;
  width: 112px;
  height: 112px;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  background: linear-gradient(145deg, var(--blue), var(--navy-2));
  box-shadow: 6px 6px 14px var(--neu-dark), -6px -6px 14px var(--neu-light);
  transition: box-shadow .1s ease;
}

.arena-listen-btn:active {
  box-shadow: inset 4px 4px 10px var(--neu-dark), inset -4px -4px 10px var(--neu-light);
}

.arena-listen-icon {
  position: relative;
  font-size: 48px;
  line-height: 1;
}

.arena-listen-wave {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
}

.arena-listen-btn.playing .arena-listen-wave {
  animation: arena-wave 1.1s ease-out infinite;
}

@keyframes arena-wave {
  0% { box-shadow: 0 0 0 0 rgba(28, 176, 246, .55); }
  100% { box-shadow: 0 0 0 26px rgba(28, 176, 246, 0); }
}

.arena-transcript {
  max-width: 100%;
  min-height: 0;
  font-size: 15px;
  font-weight: 700;
  line-height: 1.6;
  text-align: center;
  color: var(--blue-dark);
  opacity: 0;
  transition: opacity .15s;
}

.arena-transcript.show {
  opacity: 1;
}

/* ===== On-screen keyboard for the target script (see SCRIPT_KEYBOARDS in
   app.js). Fixed to the bottom of the viewport, above the tab bar; while it
   is open #app reserves its height so the check button stays visible. ===== */
.osk-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: 2px solid var(--gray-line);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text-light);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

.osk-toggle[aria-pressed="true"] {
  border-color: var(--blue);
  color: var(--blue);
}

.osk {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  max-width: 640px;
  margin: 0 auto;
  padding: 8px 4px max(8px, env(safe-area-inset-bottom));
  background: var(--gray-bg);
  border-top: 2px solid var(--gray-line);
  user-select: none;
  -webkit-user-select: none;
}

.osk[hidden] {
  display: none;
}

.osk-row {
  display: flex;
  justify-content: center;
  gap: 4px;
  margin-bottom: 6px;
}

.osk-row:last-child {
  margin-bottom: 0;
}

.osk-key {
  flex: 1 1 0;
  min-width: 0;
  max-width: 46px;
  height: 46px;
  padding: 0;
  border: 1px solid var(--gray-line);
  border-bottom-width: 3px;
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  font-family: "Vazirmatn", Tahoma, sans-serif;
  font-size: 20px;
  cursor: pointer;
  touch-action: manipulation;
}

.osk-key:active {
  background: var(--tint-blue);
}

.osk-wide {
  flex-grow: 1.6;
  max-width: 76px;
  font-size: 14px;
}

.osk-space {
  flex-grow: 4;
  max-width: none;
  font-size: 14px;
}

body.osk-open #app {
  padding-bottom: calc(var(--osk-h, 0px) + 16px);
}

body.osk-open .exercise-wrap {
  min-height: calc(100dvh - 88px - var(--osk-h, 0px));
}

/* ===== Phone scale =====
   Headings, buttons and cards were sized for a wide column; on a 360px
   phone they crowded the content out. One step down below 480px. Inputs stay
   at 16px or more: iOS zooms the page into any field below that on focus. */
@media (max-width: 480px) {
  h1 {
    font-size: 22px;
  }

  h2 {
    font-size: 17px;
  }

  .btn {
    padding: 12px 14px;
    font-size: 15px;
  }

  .card {
    padding: 14px;
    margin-bottom: 12px;
  }

  input.af-input,
  select.af-input {
    font-size: 16px;
  }
}
