/* ═══════════════════════════════════════════════════════════════════════
   Design system v3.

   The identity is one hue held across the whole product — a deep blue that is
   the page's ink, its dark surfaces and its accent at three different depths —
   on a warm cream ground. The restraint is the same as v2's; only the colour
   it is being restrained around has changed.

   Class names are unchanged from v1 on purpose: all exercise engines,
   scorers and dashboards keep working untouched.
   ═══════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════
   The palette: deep blue → mid blue → mint → cream.

   Four supplied colours, used as a system rather than as four paint buckets.
   Cream is the page and white is the card, so surfaces separate without a
   border doing all the work. Ink is not black but the deep band taken most of
   the way down, which is what stops a blue page reading as two unrelated
   halves. The mid band is the accent, because it is the only one of the four
   that survives on both cream and a dark ground.

   Two shades are adjusted rather than used flat, which the brief allows and
   the contrast requires. The darkest band is deepened for large dark surfaces
   (#16324F): at the supplied #2F5F94 an accent button would sit at 2.4:1
   against its own background, under the 3:1 a control needs. And the mint is
   lightened for washes, so text on a chip clears AA comfortably.

   Everything else in this file resolves through these tokens, so the two
   blocks below are the whole colour system.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* paper + ink */
  --paper: #F0EDE7;            /* the supplied cream, as the page */
  --paper-2: #E7E3DA;
  --paper-3: #DBD6CB;
  --canvas: #16324F;           /* the deep band, taken down for dark surfaces */
  --canvas-2: #1E4062;
  --ink: #14263A;              /* the deep band as text, not black */
  --ink-2: #3E5A75;
  --ink-3: #4E6274;   /* clears AA on all three light grounds: cream, paper-2, white */

  /* the signal */
  --signal: #64A3C1;           /* the mid band — the accent */
  --signal-deep: #2F5F94;      /* the deep band — accessible on cream */
  --signal-ink: #08182A;
  --signal-wash: #DCEBE8;      /* the mint, lightened for washes */

  /* semantic — right and wrong stay green and red: an exam has to signal
     correctness faster than it signals brand */
  --ok: #1A6E54;   /* has to clear AA on --ok-bg, not just on white */
  --ok-bg: #DFF0EA;
  --ok-line: #A5D6C6;
  --bad: #B3261E;
  --bad-bg: #FBEAE8;
  --bad-line: #EFB0AA;
  --warn: #8A5A00;
  --warn-bg: #FDF3DF;
  --warn-line: #E8C98A;

  /* aliases kept so v1 component CSS keeps resolving */
  --bg: var(--paper);
  --bg-alt: var(--paper-2);
  --surface: #FFFFFF;
  --surface-2: var(--paper-2);
  --ink-soft: var(--ink-2);
  --muted: var(--ink-3);
  --line: #D9D5CC;
  --line-soft: #E6E2D9;
  --brand: var(--ink);
  --brand-2: #2A4761;
  --brand-ink: var(--ink);
  --brand-soft: var(--paper-2);
  --accent: var(--signal-deep);
  --accent-2: var(--signal);
  --accent-soft: var(--signal-wash);
  --accent-ink: #24507F;

  --shadow-sm: 0 1px 2px rgba(20, 38, 58, .05);
  --shadow: 0 1px 3px rgba(20, 38, 58, .07), 0 12px 32px -12px rgba(20, 38, 58, .16);
  --shadow-lift: 0 2px 4px rgba(20, 38, 58, .08), 0 24px 60px -20px rgba(20, 38, 58, .26);

  --radius-lg: 20px;
  --radius: 14px;
  --radius-sm: 9px;
  --maxw: 1180px;
  --rail: 64px;

  --font-ar: "Cairo", "Tajawal", "Segoe UI", Tahoma, sans-serif;
  --font-de: "Space Grotesk", "Inter", -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-read: "Source Serif 4", Georgia, "Times New Roman", serif;
  --font-mono: "Space Grotesk", ui-monospace, "SF Mono", Menlo, monospace;

  --ease: cubic-bezier(.2, .8, .25, 1);
}

/* Dark keeps the same hue and inverts the ladder: the page becomes the deep
   band pushed further down, and the accent lifts to stay legible on it. */
html[data-theme="dark"] {
  --paper: #0D1B27;
  --paper-2: #142534;
  --paper-3: #1C3145;
  --canvas: #081420;
  --canvas-2: #0E1E2C;
  --ink: #E8F0F2;
  --ink-2: #B4C6D0;
  --ink-3: #96AEBC;

  --signal: #7FC0DC;
  --signal-deep: #7FC0DC;
  --signal-ink: #06131F;
  --signal-wash: #123049;

  --ok: #6FD7B5;
  --ok-bg: #0F2A26;
  --ok-line: #2E6659;
  --bad: #F2A49C;
  --bad-bg: #2A1512;
  --bad-line: #74352E;
  --warn: #EFCB86;
  --warn-bg: #2A2211;
  --warn-line: #6A5426;

  --surface: #112130;
  --surface-2: #16293A;
  --line: #22394C;
  --line-soft: #1A2E3E;
  --brand: var(--signal);
  --brand-2: #A5D4E8;
  --brand-ink: var(--signal);
  --brand-soft: #123049;
  --accent: var(--signal);
  --accent-ink: var(--signal);
  --accent-soft: #123049;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .5);
  --shadow: 0 1px 3px rgba(0, 0, 0, .6), 0 16px 40px -16px rgba(0, 0, 0, .8);
  --shadow-lift: 0 24px 60px -20px rgba(0, 0, 0, .9);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-ar);
  font-size: 16px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

h1, h2, h3, h4 { line-height: 1.2; letter-spacing: -.015em; font-weight: 700; }

.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: 24px; }
.wrap-narrow { max-width: 860px; margin-inline: auto; padding-inline: 24px; }

/* German islands inside the Arabic shell */
[lang="de"], .de, .de-inline {
  font-family: var(--font-de);
  direction: ltr;
  text-align: start;
  font-feature-settings: "ss01";
}
.prose[lang="de"], .prose.de { font-family: var(--font-read); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; inset-inline-start: -9999px; top: 0; z-index: 200;
  background: var(--ink); color: var(--paper); padding: 12px 18px; border-radius: 0 0 12px 0;
}
.skip-link:focus { inset-inline-start: 0; }

:focus-visible { outline: 2px solid var(--signal-deep); outline-offset: 2px; border-radius: 4px; }

/* ══════════════════════════════════════════════════════════════ header */

.site-header {
  position: sticky; top: 0; z-index: 90;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(180%) blur(16px);
  border-bottom: 1px solid var(--line);
}
.site-header .wrap {
  display: flex; align-items: center; gap: 8px;
  height: 60px;
}

.brand { display: flex; align-items: center; gap: 9px; flex: none; }
/* The mark: a bowl with two dots, which is ق read in Arabic and ü read in
   German — the same glyph in both scripts, which is the whole business in one
   shape. The dots sit at different heights: B1, then B2.

   Free-standing rather than on a tile, so it takes the page's own ink and
   follows the theme without a second rule. The tiled version of the same mark
   is the favicon, where it needs its own ground to sit on. */
.brand-mark {
  width: 30px; height: 30px; flex: none;
  display: grid; place-items: center;
  color: var(--ink);
}
.brand-mark svg { display: block; width: 100%; height: 100%; }
.bm-bowl { fill: none; stroke: currentColor; stroke-width: 12; stroke-linecap: round; }
.bm-lo { fill: var(--ink-3); }
.bm-hi { fill: var(--signal-deep); }
.brand-name {
  font-weight: 700; font-size: 1.02rem; letter-spacing: -.02em;
}
.brand small { display: none; }

/* level pill — the persistent "where am I" anchor */
.level-pill {
  display: inline-flex; align-items: center; gap: 6px;
  margin-inline-start: 4px;
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: 999px;
  padding: 5px 6px 5px 12px;
  font-family: var(--font-de); font-size: .82rem; font-weight: 700;
  cursor: pointer; color: var(--ink);
  transition: border-color .15s var(--ease), background .15s var(--ease);
}
.level-pill:hover { border-color: var(--ink-3); }
.level-pill .lp-caret { font-size: .6rem; opacity: .5; }
.level-pill .lp-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--signal-deep);
}

.nav {
  display: flex; align-items: center; gap: 2px;
  margin-inline-start: auto;
}
.nav a {
  position: relative;
  padding: 7px 13px; border-radius: 8px;
  font-size: .9rem; font-weight: 600; color: var(--ink-2);
  white-space: nowrap;
  transition: color .15s var(--ease), background .15s var(--ease);
}
.nav a:hover { color: var(--ink); background: var(--paper-2); }
.nav a.active { color: var(--ink); }
.nav a.active::after {
  content: ''; position: absolute; inset-inline: 13px; bottom: 1px;
  height: 2px; border-radius: 2px; background: var(--signal-deep);
}
html[data-theme="dark"] .nav a.active::after { background: var(--signal); }

.header-actions { display: flex; align-items: center; gap: 6px; flex: none; }

.icon-btn {
  background: transparent; border: 1px solid var(--line); color: var(--ink-2);
  width: 34px; height: 34px; border-radius: 9px; cursor: pointer;
  display: grid; place-items: center; font-size: .9rem; flex: none;
  transition: border-color .15s var(--ease), color .15s var(--ease);
}
.icon-btn:hover { border-color: var(--ink-3); color: var(--ink); }

.cta-mini {
  border: 0; border-radius: 9px; padding: 8px 15px;
  background: var(--ink); color: var(--paper);
  font: inherit; font-size: .86rem; font-weight: 700; cursor: pointer;
  white-space: nowrap;
  transition: transform .12s var(--ease), opacity .15s var(--ease);
}
.cta-mini:hover { transform: translateY(-1px); }
html[data-theme="dark"] .cta-mini { background: var(--signal); color: var(--canvas); }

/* mobile bottom tab bar */
.tabbar { display: none; }

/* 940px, measured rather than picked.
   The desktop header needs 892px of content — brand, six nav items, the level
   pill, two icon buttons and the CTA — plus the wrap's 32px inset, so it stops
   fitting at about 924px. The switch used to sit at 860, which left the band
   861–923px claiming to be a desktop it could not draw: the CTA hung 22px off
   the left edge and every page scrolled sideways. Below 940 the phone shell
   takes over, where the tab bar and the menu reach everything the nav and the
   CTA were carrying.

   Only the five SHELL blocks moved. The other 860px rules in this file —
   pt-stats, the certificate frame, the review track — are about their own
   content and are untouched. */
@media (max-width: 940px) {
  .site-header .wrap { height: 54px; gap: 6px; }
  .nav { display: none; }
  .brand-name { font-size: .96rem; }

  .tabbar {
    display: flex;
    position: fixed; inset-inline: 0; bottom: 0; z-index: 95;
    background: color-mix(in srgb, var(--paper) 94%, transparent);
    backdrop-filter: saturate(180%) blur(16px);
    border-top: 1px solid var(--line);
    padding: 6px 6px calc(6px + env(safe-area-inset-bottom));
  }
  .tabbar a {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
    padding: 6px 2px; border-radius: 10px;
    font-size: .68rem; font-weight: 700; color: var(--ink-3);
  }
  .tabbar a .tb-i { font-size: 1.15rem; line-height: 1; }
  .tabbar a.active { color: var(--ink); }
  .tabbar a.active .tb-i { transform: translateY(-1px); }
  body { padding-bottom: 68px; }
}

/* ═══════════════════════════════════════════════════════════════ buttons */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: 1px solid transparent; border-radius: 11px;
  padding: 11px 20px;
  font: inherit; font-size: .93rem; font-weight: 700;
  cursor: pointer;
  background: var(--ink); color: var(--paper);
  transition: transform .12s var(--ease), box-shadow .18s var(--ease), background .15s var(--ease);
}
.btn:hover { transform: translateY(-1px); box-shadow: var(--shadow); text-decoration: none; }
.btn:active { transform: translateY(0); }
.btn:disabled { opacity: .5; cursor: default; transform: none; }
html[data-theme="dark"] .btn:not(.secondary):not(.ghost):not(.accent) {
  background: var(--signal); color: var(--canvas);
}

.btn.secondary {
  background: transparent; color: var(--ink); border-color: var(--line);
}
.btn.secondary:hover { border-color: var(--ink-3); background: var(--paper-2); }
html[data-theme="dark"] .btn.secondary { background: transparent; color: var(--ink); }

.btn.ghost { background: transparent; color: var(--ink-2); border-color: transparent; padding-inline: 12px; }
.btn.ghost:hover { background: var(--paper-2); box-shadow: none; }

.btn.accent { background: var(--signal); color: var(--signal-ink); }
.btn.accent:hover { background: var(--signal); }

.btn.block { display: flex; width: 100%; }
.btn.lg { padding: 14px 26px; font-size: 1rem; border-radius: 13px; }

.link-btn {
  background: none; border: 0; padding: 0; color: var(--ink);
  font: inherit; font-weight: 700; cursor: pointer;
  border-bottom: 2px solid var(--signal); line-height: 1.2;
}

/* ═══════════════════════════════════════════════════════════ structure */

section.block { padding-block: 72px; }
section.block.alt { background: var(--paper-2); border-block: 1px solid var(--line); }
section.block.tight { padding-block: 44px; }

/* numbered section rail — the signature structural motif */
.block-head { margin-bottom: 34px; max-width: 62ch; }
.block-head .idx {
  display: inline-block;
  font-family: var(--font-de); font-size: .74rem; font-weight: 700;
  letter-spacing: .12em; color: var(--ink-3);
  padding-bottom: 6px; margin-bottom: 12px;
  border-bottom: 2px solid var(--signal);
}
.block-head h2 {
  font-size: clamp(1.6rem, 3.4vw, 2.5rem); margin: 0 0 10px; font-weight: 700;
}
.block-head p { margin: 0; color: var(--ink-2); font-size: 1.02rem; }
.block-head.center { text-align: center; margin-inline: auto; }

.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: 16px; }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

/* ═══════════════════════════════════════════════════════════════ cards */

.card {
  display: block; position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
  transition: border-color .18s var(--ease), transform .18s var(--ease), box-shadow .18s var(--ease);
}
a.card:hover {
  text-decoration: none; transform: translateY(-2px);
  border-color: var(--ink-3); box-shadow: var(--shadow);
}
.card h3 { margin: 0 0 6px; font-size: 1.02rem; }
.card p { margin: 0; color: var(--ink-3); font-size: .89rem; }
.card-row { display: flex; align-items: center; gap: 7px; margin-bottom: 12px; flex-wrap: wrap; }

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: .72rem; font-weight: 700; letter-spacing: .01em;
  padding: 3px 9px; border-radius: 6px;
  background: var(--paper-2); color: var(--ink-3);
  border: 1px solid var(--line-soft);
}
.badge.brand { background: var(--ink); color: var(--paper); border-color: transparent; }
html[data-theme="dark"] .badge.brand { background: var(--signal); color: var(--canvas); }
.badge.ok { background: var(--ok-bg); color: var(--ok); border-color: var(--ok-line); }
/* accent-ink, not signal-deep: the latter is only 2.65 on signal-wash. */
.badge.audio { background: var(--signal-wash); color: var(--accent-ink); border-color: transparent; }
/* A Hören exercise with no recording. Said plainly on the card, because
   the absence of an "audio" badge is not something anyone notices. */
.badge.warn { background: var(--warn-bg); color: var(--warn); border-color: var(--warn-line); }
html[data-theme="dark"] .badge.audio { color: var(--signal); }
.badge.de { font-family: var(--font-de); direction: ltr; }
.badge.lock { background: transparent; color: var(--ink-3); }
.badge.free { background: var(--signal-wash); color: var(--signal-deep); border-color: transparent; font-weight: 700; }

/* ══════════════════════════════════════════════════════════ page heads */

.crumbs { font-size: .82rem; color: var(--ink-3); padding-top: 22px; }
.crumbs a:hover { color: var(--ink); }
.crumbs span { margin-inline: 6px; opacity: .4; }

.page-head { padding: 16px 0 28px; margin-bottom: 28px; border-bottom: 1px solid var(--line); }
.page-head h1 { margin: 12px 0 8px; font-size: clamp(1.7rem, 3.6vw, 2.4rem); }
.page-head h1[lang="de"] { font-family: var(--font-de); }
.page-head .meta { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; color: var(--ink-3); font-size: .87rem; }

/* ═════════════════════════════════════════════════════════════ filters */

.filter-bar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 22px; }
.field { flex: 1 1 200px; min-width: 160px; }
.field.grow { flex: 2 1 280px; }
.field input, .field select {
  width: 100%; padding: 10px 14px;
  border-radius: 10px; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: .91rem;
  transition: border-color .15s var(--ease);
}
.field input:focus, .field select:focus { border-color: var(--ink); outline: none; }
.count-note { color: var(--ink-3); font-size: .85rem; }

/* ══════════════════════════════════════════════════════ exercise layout */

.exercise-layout {
  display: grid;
  /* RTL page: column 1 is on the right, column 2 on the left. Answers take
     column 1 and the German passage column 2, which puts the passage on the
     left. Numbered rather than named, because .exam-wrap below redefines these
     tracks and named lines would not survive that. */
  grid-template-columns: minmax(300px, .9fr) minmax(0, 1.35fr);
  gap: 20px; align-items: start;
}
.exercise-layout > *:first-child  { grid-column: 2; grid-row: 1; }  /* passage — left */
.exercise-layout > *:nth-child(2) { grid-column: 1; grid-row: 1; }  /* answers — right */

@media (max-width: 960px) {
  .exercise-layout { grid-template-columns: 1fr; }
  /* Stacked, the passage comes first — you read before you answer. */
  .exercise-layout > *:first-child  { grid-column: 1; grid-row: 1; }
  .exercise-layout > *:nth-child(2) { grid-column: 1; grid-row: 2; }
}

.panel {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 22px;
}
.panel + .panel { margin-top: 14px; }
.panel h2 { margin: 0 0 14px; font-size: 1.02rem; font-weight: 700; }

/* Sticky answer rail: the lesson text scrolls, the controls stay put. */
.sticky-side {
  position: sticky; top: 76px;
  max-height: calc(100vh - 96px);
  display: flex; flex-direction: column;
}
.sticky-side .option-bank,
.sticky-side .gap-list,
.sticky-side .word-bank { overflow-y: auto; overscroll-behavior: contain; flex: 1; min-height: 0; }
.panel-scroll { max-height: min(76vh, 720px); overflow-y: auto; overscroll-behavior: contain; }

@media (max-width: 960px) {
  .sticky-side { position: static; max-height: none; }
  .panel-scroll { max-height: none; }
}

.prose {
  font-family: var(--font-read); direction: ltr; text-align: left;
  font-size: 1.04rem; line-height: 1.85; color: var(--ink);
}
.prose p { margin: 0 0 1.05em; }
.prose h2, .prose h3, .prose h4, .prose h5 { font-family: var(--font-de); margin: 1.2em 0 .5em; }

.instructions {
  position: relative;
  background: var(--surface); border: 1px solid var(--line);
  border-inline-start: 3px solid var(--signal);
  border-radius: var(--radius-sm);
  padding: 14px 16px; font-size: .92rem; color: var(--ink-2);
  margin-bottom: 18px;
}
.instructions strong { display: block; margin-bottom: 3px; color: var(--ink); font-size: .78rem; letter-spacing: .04em; }

.notice {
  background: var(--warn-bg); color: var(--warn);
  border: 1px solid var(--warn-line); border-radius: var(--radius-sm);
  padding: 12px 14px; font-size: .87rem; margin-bottom: 16px;
}

/* --- matching --- */
.match-item {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 15px; margin-bottom: 12px; background: var(--surface);
  transition: border-color .2s var(--ease), background .2s var(--ease);
}
.match-item[data-state="correct"] { border-color: var(--ok-line); background: var(--ok-bg); }
.match-item[data-state="incorrect"] { border-color: var(--bad-line); background: var(--bad-bg); }
.match-head { display: flex; align-items: center; gap: 10px; margin-bottom: 11px; }
.match-num {
  flex: none; width: 26px; height: 26px; border-radius: 7px;
  background: var(--ink); color: var(--paper);
  font-family: var(--font-de); font-size: .78rem; font-weight: 700;
  display: grid; place-items: center;
}
html[data-theme="dark"] .match-num { background: var(--signal); color: var(--canvas); }

.slot {
  flex: 1; min-height: 42px;
  border: 1.5px dashed var(--line); border-radius: var(--radius-sm);
  padding: 9px 12px; color: var(--ink-3); font-size: .89rem;
  cursor: pointer; display: flex; align-items: center;
  background: var(--paper-2);
  transition: border-color .15s var(--ease), background .15s var(--ease);
}
.slot.filled, .slot.correct, .slot.incorrect { font-family: var(--font-de); direction: ltr; text-align: left; }
.slot:hover, .slot.armed { border-color: var(--signal-deep); background: var(--signal-wash); color: var(--ink); }
.slot.filled { border-style: solid; border-color: var(--line); background: var(--surface); color: var(--ink); font-weight: 600; }
.slot.correct { border-color: var(--ok-line); background: var(--ok-bg); color: var(--ok); }
.slot.incorrect { border-color: var(--bad-line); background: var(--bad-bg); color: var(--bad); }

.solution { margin-top: 9px; font-size: .85rem; color: var(--ok); background: var(--ok-bg); border-radius: 8px; padding: 8px 11px; }
.solution.hidden { display: none; }
.solution .de-inline { font-family: var(--font-de); direction: ltr; display: inline-block; }

.option-bank { display: flex; flex-direction: column; gap: 7px; }
.chip {
  text-align: start; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink);
  border-radius: 10px; padding: 10px 13px;
  font-family: var(--font-de); direction: ltr; font-size: .88rem;
  cursor: pointer;
  transition: border-color .13s var(--ease), background .13s var(--ease), transform .1s var(--ease);
}
.chip:hover { border-color: var(--ink-3); }
.chip:active { transform: scale(.985); }
.chip.selected { border-color: var(--ink); background: var(--signal-wash); font-weight: 700; }
html[data-theme="dark"] .chip.selected { background: var(--signal-wash); border-color: var(--signal); }
.chip.used { opacity: .3; pointer-events: none; }

/* --- multiple choice --- */
.q-card {
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 15px 16px; margin-bottom: 11px; background: var(--surface);
}
.q-card[data-state="correct"] { border-color: var(--ok-line); background: var(--ok-bg); }
.q-card[data-state="incorrect"] { border-color: var(--bad-line); background: var(--bad-bg); }
.q-card h3 { margin: 0 0 10px; font-size: .95rem; font-family: var(--font-de); direction: ltr; text-align: left; }

.opt {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 9px 11px; border-radius: 9px; cursor: pointer;
  font-size: .91rem; border: 1px solid transparent;
  font-family: var(--font-de); direction: ltr; text-align: left;
  transition: background .13s var(--ease);
}
.opt:hover { background: var(--paper-2); }
.opt input { margin-top: 4px; accent-color: var(--ink); flex: none; }
.opt.is-correct { background: var(--ok-bg); border-color: var(--ok-line); color: var(--ok); font-weight: 700; }
.opt.is-wrong { background: var(--bad-bg); border-color: var(--bad-line); color: var(--bad); }

/* --- cloze --- */
.gap {
  display: inline-block; min-width: 88px; padding: 1px 9px; margin: 0 2px;
  border-bottom: 2px solid var(--signal-deep); border-radius: 5px 5px 0 0;
  background: var(--signal-wash); color: var(--ink);
  font-family: var(--font-de); font-size: .92em; font-weight: 700;
  text-align: center; cursor: pointer;
  transition: background .15s var(--ease);
}
.gap.armed { outline: 2px solid var(--signal-deep); outline-offset: 1px; }
.gap.empty { color: var(--ink-3); font-weight: 600; }
.gap.correct { background: var(--ok-bg); border-color: var(--ok-line); color: var(--ok); }
.gap.incorrect { background: var(--bad-bg); border-color: var(--bad-line); color: var(--bad); }

.word-bank { display: flex; flex-wrap: wrap; gap: 7px; }
.word-bank .chip { padding: 8px 14px; border-radius: 999px; }

.gap-list { display: flex; flex-direction: column; gap: 10px; }
.gap-row { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 12px 13px; background: var(--surface); }
.gap-row[data-state="correct"] { border-color: var(--ok-line); background: var(--ok-bg); }
.gap-row[data-state="incorrect"] { border-color: var(--bad-line); background: var(--bad-bg); }
.gap-row.armed { outline: 2px solid var(--signal-deep); outline-offset: 2px; }
.gap-row .gap-num { font-family: var(--font-de); font-weight: 700; font-size: .76rem; color: var(--ink-3); margin-bottom: 7px; letter-spacing: .04em; }
.gap-row .opts { display: flex; flex-wrap: wrap; gap: 5px; }
.gap-row .chip { border-radius: 999px; padding: 6px 14px; }

/* --- listening --- */
.audio-part { border: 1px solid var(--line); border-radius: var(--radius); padding: 18px; margin-bottom: 16px; background: var(--surface); }
.audio-part h3 { margin: 0 0 12px; font-size: 1rem; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.audio-part h3 .de-inline { font-family: var(--font-de); direction: ltr; }
.audio-part audio { width: 100%; margin-bottom: 14px; }

.tf-table-wrap { overflow-x: auto; }
.tf-table { width: 100%; border-collapse: collapse; font-size: .91rem; }
.tf-table th { font-family: var(--font-de); font-size: .68rem; color: var(--ink-3); font-weight: 700; padding: 7px 8px; text-align: center; white-space: nowrap; letter-spacing: .06em; }
.tf-table td { padding: 10px 8px; border-top: 1px solid var(--line-soft); vertical-align: middle; }
.tf-table td.pick { text-align: center; width: 64px; }
.tf-table td.pick input { accent-color: var(--ink); width: 17px; height: 17px; }
.tf-table td.stmt { font-family: var(--font-de); direction: ltr; text-align: left; }
.tf-table tr[data-state="correct"] td { background: var(--ok-bg); }
.tf-table tr[data-state="incorrect"] td { background: var(--bad-bg); }
.tf-answer { font-family: var(--font-de); font-size: .74rem; font-weight: 700; color: var(--ok); white-space: nowrap; }

/* --- writing --- */
.writing-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 18px; align-items: start;
}
.writing-grid > *:first-child  { grid-column: 2; grid-row: 1; }  /* task — left */
.writing-grid > *:nth-child(2) { grid-column: 1; grid-row: 1; }  /* editor — right */

@media (max-width: 960px) {
  .writing-grid { grid-template-columns: 1fr; }
  .writing-grid > *:first-child  { grid-column: 1; grid-row: 1; }
  .writing-grid > *:nth-child(2) { grid-column: 1; grid-row: 2; }
}
.material { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 18px; background: var(--paper-2); }
.material h3 { margin-top: 0; font-family: var(--font-de); direction: ltr; text-align: left; }
.task-points { margin: 0; padding-inline-start: 20px; }
.task-points li { margin-bottom: 7px; font-family: var(--font-de); direction: ltr; text-align: left; }

textarea.essay {
  width: 100%; min-height: 380px; resize: vertical;
  padding: 16px 18px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--surface); color: var(--ink);
  font-family: var(--font-read); direction: ltr; text-align: left;
  font-size: 1rem; line-height: 1.8;
}
textarea.essay:focus { border-color: var(--ink); outline: none; }

.writing-meter { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; font-size: .86rem; color: var(--ink-3); margin-bottom: 10px; }
.writing-meter b { color: var(--ink); font-family: var(--font-de); }
.writing-meter .reached { color: var(--ok); }

.ai-status { font-size: .82rem; border-radius: var(--radius-sm); padding: 9px 12px; margin-bottom: 12px; border: 1px solid var(--line); background: var(--paper-2); color: var(--ink-3); }
.ai-status.ready { background: var(--ok-bg); color: var(--ok); border-color: var(--ok-line); }
.ai-status.pending { background: var(--signal-wash); color: var(--signal-deep); border-color: transparent; }
html[data-theme="dark"] .ai-status.pending { color: var(--signal); }

/* correction report */
.report { margin-top: 18px; border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; background: var(--surface); }
.report-head { display: flex; align-items: center; gap: 18px; padding: 16px 18px; border-radius: var(--radius-sm); margin-bottom: 20px; }
.report-head.good { background: var(--ok-bg); }
.report-head.mid { background: var(--warn-bg); }
.report-head.poor { background: var(--bad-bg); }
.report-score { display: flex; align-items: baseline; gap: 4px; font-family: var(--font-de); }
.report-score b { font-size: 2.6rem; font-weight: 700; line-height: 1; letter-spacing: -.03em; }
.report-score span { font-size: .88rem; opacity: .65; }
.report-head.good .report-score b { color: var(--ok); }
.report-head.mid .report-score b { color: var(--warn); }
.report-head.poor .report-score b { color: var(--bad); }
.report-verdict { display: flex; flex-direction: column; }
.report-verdict strong { font-size: 1rem; }
.report-verdict span { font-size: .82rem; color: var(--ink-3); }
.report-h { margin: 22px 0 12px; font-family: var(--font-de); font-size: .72rem; font-weight: 700; color: var(--ink-3); letter-spacing: .1em; padding-bottom: 7px; border-bottom: 1px solid var(--line-soft); }
.report-h:first-of-type { margin-top: 0; }

.criteria { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.crit { display: flex; gap: 11px; align-items: flex-start; }
.crit-dot { flex: none; width: 9px; height: 9px; border-radius: 50%; margin-top: 8px; background: var(--ink-3); }
.crit.ok .crit-dot { background: var(--ok); }
.crit.warn .crit-dot { background: var(--signal-deep); }
.crit.bad .crit-dot { background: var(--bad); }
.crit b { font-size: .93rem; }
.crit em { font-style: normal; font-family: var(--font-de); font-size: .72rem; font-weight: 700; padding: 1px 8px; border-radius: 5px; margin-inline-start: 7px; background: var(--paper-2); color: var(--ink-3); }
.crit.ok em { background: var(--ok-bg); color: var(--ok); }
.crit.warn em { background: var(--warn-bg); color: var(--warn); }
.crit.bad em { background: var(--bad-bg); color: var(--bad); }
.crit em.zeroed { background: var(--bad-bg); color: var(--bad); }
.crit p { margin: 3px 0 0; font-size: .88rem; color: var(--ink-2); line-height: 1.65; }
.crit p.de-inline { font-family: var(--font-de); direction: ltr; text-align: left; }

.fixes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.fix { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 11px 13px; background: var(--paper-2); }
.fix-type { display: inline-block; font-family: var(--font-de); font-size: .68rem; font-weight: 700; color: var(--signal-deep); background: var(--signal-wash); padding: 2px 8px; border-radius: 5px; margin-bottom: 7px; letter-spacing: .04em; }
html[data-theme="dark"] .fix-type { color: var(--signal); }
.fix-pair { display: flex; flex-direction: column; gap: 3px; font-family: var(--font-de); }
.fix-pair del { color: var(--bad); text-decoration-thickness: 2px; font-size: .92rem; }
.fix-pair ins { color: var(--ok); text-decoration: none; font-weight: 700; font-size: .92rem; }

.ai-level { font-size: .92rem; margin: 0 0 10px; }
.ai-level b { font-family: var(--font-de); }
.ai-summary { font-family: var(--font-de); direction: ltr; text-align: left; font-size: .9rem; color: var(--ink-2); background: var(--paper-2); border-radius: var(--radius-sm); padding: 11px 13px; margin: 0 0 14px; }
.ai-note { font-size: .87rem; color: var(--ink-3); margin: 0; }
.ai-note.ok-note { color: var(--ok); }

.redemittel { display: grid; gap: 12px; }
.rm-group { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 13px 15px; background: var(--paper-2); }
.rm-group h5 { margin: 0 0 8px; font-size: .8rem; font-weight: 700; color: var(--signal-deep); letter-spacing: .02em; }
html[data-theme="dark"] .rm-group h5 { color: var(--signal); }
.rm-group ul { margin: 0; padding-inline-start: 18px; }
.rm-group li { font-family: var(--font-de); direction: ltr; text-align: left; font-size: .89rem; margin-bottom: 5px; color: var(--ink-2); }

/* ══════════════════════════════════════════════════════ actions/results */

.actions { display: flex; flex-wrap: wrap; gap: 9px; align-items: center; margin-top: 18px; }

.result { margin-top: 16px; border-radius: var(--radius-sm); padding: 14px 17px; font-weight: 700; display: none; }
.result.show { display: block; }
.result.good { background: var(--ok-bg); color: var(--ok); }
.result.mid { background: var(--warn-bg); color: var(--warn); }
.result.poor { background: var(--bad-bg); color: var(--bad); }
.result .score-line { font-size: 1.02rem; }
.result .pct { font-family: var(--font-de); }

/* ───────────────────────────────────────────── the Sprechen walkthrough
   Six steps shown once. The drawings are markup rather than images: an <img>
   is a request that can fail on the connection these learners are on, and a
   screenshot goes stale the first time a button is relabelled — which has
   already happened twice. These are the real labels in the real shapes. */
.st-modal { width: min(440px, 100%); padding: 22px 22px 18px; text-align: start; }
.st-x {
  position: absolute; inset-inline-end: 12px; top: 10px;
  width: 30px; height: 30px; border-radius: 50%;
  border: 0; background: var(--surface-2); color: var(--ink-2);
  font-size: .85rem; cursor: pointer; line-height: 1;
}
.st-x:hover { background: var(--paper-3); }
.st-kicker {
  margin: 0 0 2px; font-size: .72rem; font-weight: 700;
  color: var(--signal-deep); letter-spacing: .02em;
}
.st-title { margin: 0 0 14px; font-size: 1.06rem; line-height: 1.45; }
.st-p { margin: 0; font-size: .88rem; line-height: 1.8; color: var(--ink-2); }
.st-p b { color: var(--ink); }

/* the little stage each step draws into */
.st-art {
  display: grid; gap: 8px; justify-items: center;
  margin: 0 0 14px; padding: 16px 12px;
  border-radius: var(--radius);
  background: var(--signal-wash);
  border: 1px solid color-mix(in srgb, var(--signal) 32%, transparent);
  min-height: 104px; align-content: center;
}

.st-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 16px; border-radius: 999px;
  font-size: .82rem; font-weight: 700; line-height: 1;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line);
}
.st-primary { background: var(--accent); color: #fff; border-color: transparent; }
.st-micbtn { background: var(--ok-bg); color: var(--ok); border-color: var(--ok-line); }
.st-stop { background: var(--bad-bg); color: var(--bad); border-color: var(--bad-line); }
.st-btnrow, .st-two { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; justify-content: center; }
.st-then { font-size: .74rem; color: var(--ink-3); font-weight: 700; }

/* step 1 — two turns of a conversation */
.st-chat { display: grid; gap: 7px; width: 100%; max-width: 260px; }
.st-bubble {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 11px; border-radius: 12px; font-size: .78rem;
  background: var(--surface); border: 1px solid var(--line);
}
.st-ex { justify-content: flex-start; }
.st-you { justify-content: flex-end; background: var(--accent-soft); border-color: transparent; }
.st-who { font-size: .66rem; color: var(--ink-3); font-weight: 700; flex: none; }
.st-mic { font-size: 1rem; }

/* step 2 — three things to do first */
.st-rows { display: grid; gap: 6px; width: 100%; max-width: 250px; }
.st-row {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: 10px;
  background: var(--surface); font-size: .76rem; color: var(--ink);
}
.st-n {
  flex: none; display: grid; place-items: center;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--signal-wash); color: var(--signal-deep);
  font-size: .66rem; font-weight: 700;
}

/* step 3 — the browser's own permission bar, which is what they will see */
.st-perm {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  justify-content: center;
  padding: 8px 11px; border-radius: 10px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: .72rem; color: var(--ink-2); max-width: 280px;
}
.st-allow {
  padding: 4px 10px; border-radius: 999px;
  background: var(--accent); color: #fff; font-weight: 700; font-size: .7rem;
}

/* step 4 — words appearing as they speak */
.st-live {
  width: 100%; max-width: 290px;
  padding: 8px 11px; border-radius: 10px;
  background: var(--surface); border: 1px dashed var(--line);
  font-size: .74rem; color: var(--ink); text-align: left;
}
.st-live-cap {
  display: block; font-size: .64rem; color: var(--ink-3);
  font-weight: 700; text-align: right; margin-bottom: 2px;
}

/* step 6 — a score and four criteria */
.st-score { display: flex; align-items: baseline; gap: 4px; color: var(--ok); }
.st-score b { font-size: 1.5rem; line-height: 1; }
.st-score span { font-size: .8rem; color: var(--ink-3); }
.st-crit { display: flex; gap: 5px; }
.st-crit span {
  width: 26px; height: 5px; border-radius: 3px;
  background: color-mix(in srgb, var(--ok) 55%, transparent);
}
.st-crit span:last-child { background: color-mix(in srgb, var(--warn) 60%, transparent); }

/* footer */
.st-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-top: 18px; flex-wrap: wrap;
}
.st-dots { display: flex; gap: 5px; }
.st-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--line); transition: background .15s ease, width .15s ease;
}
.st-dot.on { background: var(--accent); width: 16px; border-radius: 3px; }
.st-nav { display: flex; gap: 8px; margin-inline-start: auto; }
.st-b { font-size: .82rem; padding: 8px 15px; white-space: nowrap; }

/* The way back into the walkthrough.

   Four tries to get the placement right, and then a fifth problem: it was
   legible and nobody pressed it. A flat pill sitting under a flat B2 badge
   reads as another badge — this site's own label shape — and labels are not
   things you press.

   So it takes on the cues a badge never has: a play mark, a shadow to lift it
   off the page, motion under the cursor, and a slow breath of the ring around
   it so the eye lands there once without anything blinking.

   Still inline inside the <h1>. Nothing is lifted out of flow, so it is laid
   out on the title's line rather than placed over anything. */
.sp-tour-tag {
  display: inline-flex; align-items: center; gap: 7px; vertical-align: middle;
  /* A physical margin, deliberately.

     This button carries dir="rtl" for its Arabic label, but it sits inside an
     <h1 lang="de"> that computes direction: ltr. A logical property resolves
     against the element's OWN direction, so margin-inline-start landed on the
     right — the far side from the title — and the gap never moved however
     large the number got. The side that matters here is the heading's, and
     the heading is left-to-right. */
  margin-left: 36px;
  padding: 6px 14px 6px 11px; border: 0; border-radius: 999px;
  background: var(--accent); color: #fff;
  font: 700 .74rem/1.2 var(--font-ar);
  white-space: nowrap; cursor: pointer;
  box-shadow: 0 2px 6px -1px color-mix(in srgb, var(--accent) 55%, transparent),
              0 0 0 0 color-mix(in srgb, var(--accent) 38%, transparent);
  transition: transform .15s var(--ease), box-shadow .2s var(--ease), background .15s ease;
  animation: sp-tour-breathe 2.6s ease-out 3;
}
/* Three breaths, then still. Long enough to catch an eye arriving at the
   title, short enough that it is not a thing blinking on the page while
   somebody is trying to read German. */
@keyframes sp-tour-breathe {
  0%, 100% { box-shadow: 0 2px 6px -1px color-mix(in srgb, var(--accent) 55%, transparent),
                         0 0 0 0 color-mix(in srgb, var(--accent) 38%, transparent); }
  45%      { box-shadow: 0 2px 6px -1px color-mix(in srgb, var(--accent) 55%, transparent),
                         0 0 0 7px color-mix(in srgb, var(--accent) 0%, transparent); }
}
.sp-tour-tag:hover {
  background: var(--signal-deep);
  transform: translateY(-1px);
  box-shadow: 0 5px 14px -3px color-mix(in srgb, var(--accent) 65%, transparent);
}
.sp-tour-tag:active { transform: translateY(0); }
.sp-tour-tag:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* A play triangle drawn from a border, so it needs no glyph and cannot be
   flipped by the surrounding right-to-left text. */
.sp-tour-play {
  flex: none; display: grid; place-items: center;
  width: 16px; height: 16px; border-radius: 50%;
  background: rgba(255, 255, 255, .22);
}
.sp-tour-play::before {
  content: ''; display: block;
  border-style: solid;
  border-width: 4px 0 4px 6px;
  border-color: transparent transparent transparent #fff;
  margin-inline-start: 2px;
}

@media (max-width: 560px) {
  /* Wrapped onto its own line it starts at the heading's left edge; an
     indent here would read as a stray one. */
  .sp-tour-tag { margin-left: 0; padding: 5px 12px 5px 9px; font-size: .7rem; gap: 6px; }
  .sp-tour-play { width: 15px; height: 15px; }
}

@media (prefers-reduced-motion: reduce) {
  .sp-tour-tag { animation: none; transition: background .15s ease; }
  .sp-tour-tag:hover { transform: none; }
}

@media (max-width: 560px) {
  .st-modal { padding: 20px 16px 16px; }
  .st-title { font-size: 1rem; }
  .st-p { font-size: .84rem; line-height: 1.75; }
  .st-art { padding: 14px 10px; min-height: 96px; }
  .st-foot { margin-top: 15px; }
  .st-b { font-size: .8rem; padding: 8px 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .st-dot { transition: none; }
}

/* ────────────────────────────────────────────────────────── the link counter
   Two numbers, opened from a URL by somebody with no account. Big because
   there is nothing else on the page to compete with them. */
.rl-wrap { display: grid; gap: 14px; margin: 18px 0 40px; }
.rl-top h1 { margin: 0; font-size: 1.3rem; }
.rl-sub { margin: 4px 0 0; font-size: .82rem; color: var(--ink-3); }
.rl-sub code {
  font-family: var(--font-mono); background: var(--surface-2);
  padding: 1px 7px; border-radius: 6px; color: var(--ink);
}

.rl-big { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.rl-n {
  display: grid; gap: 4px; justify-items: center; text-align: center;
  padding: 26px 14px; border-radius: var(--radius-lg);
  background: var(--surface); border: 1px solid var(--line);
}
.rl-n b { font-size: 2.6rem; line-height: 1; font-variant-numeric: tabular-nums; }
.rl-n span { font-size: .82rem; color: var(--ink-2); font-weight: 700; }
.rl-paid {
  background: var(--ok-bg); border-color: var(--ok-line);
}
.rl-paid b, .rl-paid span { color: var(--ok); }

/* The funnel: three stages of the same measure, so one bar each, scaled
   against the widest. Recessive track, thin bar, 4px rounded end anchored to
   the start edge. The count sits in ink beside the bar rather than inside it,
   because a number on a 6%-wide bar has nowhere to live. */
.rl-funnel {
  padding: 18px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--line);
  display: grid; gap: 14px;
}
.rl-h { margin: 0; font-size: .82rem; color: var(--ink-3); font-weight: 700; }
.rl-f-row { display: grid; gap: 6px; }
.rl-f-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.rl-f-k { font-size: .84rem; font-weight: 700; color: var(--ink); }
.rl-f-step { font-size: .72rem; color: var(--ink-3); margin-inline-start: auto; }
.rl-f-track {
  background: var(--surface-2); border-radius: 999px; padding: 3px;
}
.rl-f-bar {
  height: 16px; border-radius: 4px; flex: none;
  background: var(--accent); min-width: 4px;
  transition: width .35s var(--ease);
}
.rl-f-ok { background: var(--ok); }
.rl-f-v { font-size: .9rem; font-variant-numeric: tabular-nums; color: var(--ink); }

@media (prefers-reduced-motion: reduce) { .rl-f-bar { transition: none; } }

.rl-strip {
  display: flex; gap: 18px; flex-wrap: wrap; justify-content: center;
  padding: 11px 14px; border-radius: var(--radius);
  background: var(--surface-2); font-size: .82rem; color: var(--ink-2);
}
.rl-strip b { color: var(--ink); font-variant-numeric: tabular-nums; }
.rl-foot { margin: 0; font-size: .74rem; color: var(--ink-3); text-align: center; line-height: 1.7; }

.rl-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 20px;
}
.rl-mid { text-align: center; }
.rl-note { margin: 0; font-size: .85rem; color: var(--ink-2); line-height: 1.7; }
.rl-own h2 { margin: 0 0 6px; font-size: 1rem; }
.rl-form { display: flex; gap: 8px; margin: 12px 0 0; flex-wrap: wrap; }
.rl-form input {
  flex: 1 1 220px; min-width: 0; padding: 9px 11px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); font: inherit; font-size: .85rem;
}
.rl-pair { display: grid; gap: 3px; margin: 12px 0 0; }
.rl-pair span { font-size: .74rem; font-weight: 700; color: var(--ink-3); }
.rl-pair code {
  font-family: var(--font-mono); font-size: .78rem; word-break: break-all;
  background: var(--surface-2); padding: 8px 10px; border-radius: var(--radius-sm);
}
.rl-bad {
  margin: 12px 0 0; padding: 9px 11px; border-radius: var(--radius-sm);
  background: var(--bad-bg); color: var(--bad); font-size: .82rem;
}

@media (max-width: 560px) {
  .rl-big { grid-template-columns: 1fr; gap: 10px; }
  .rl-n { padding: 22px 12px; }
  .rl-n b { font-size: 2.2rem; }
}

/* ───────────────────────────────────────────────────── the partner dashboard
   A page whose only job is to be checkable. The totals in the footer are the
   column above them added up, so a partner can verify the headline by hand —
   which is worth more than any assurance the copy could make. */
.pt-wrap { display: grid; gap: 14px; margin: 8px 0 32px; }
.pt-head { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
.pt-head h1 { margin: 0; font-size: 1.4rem; }
.pt-sub { margin: 3px 0 0; font-size: .85rem; color: var(--ink-3); }
.pt-sub code, .pt-linkbox code {
  font-family: var(--font-mono); background: var(--surface-2);
  padding: 1px 7px; border-radius: 6px; color: var(--ink);
}
.pt-head .btn { margin-inline-start: auto; }

.pt-linkbox {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px 13px; border-radius: var(--radius);
  background: var(--signal-wash);
  border: 1px solid color-mix(in srgb, var(--signal) 40%, transparent);
}
.pt-linkcap { font-size: .76rem; font-weight: 700; color: var(--signal-deep); flex: none; }
.pt-linkbox code { font-size: .8rem; word-break: break-all; }

.pt-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.pt-stat {
  display: grid; gap: 2px; padding: 13px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius);
}
.pt-stat b { font-size: 1.5rem; line-height: 1.1; color: var(--ink); }
.pt-stat span { font-size: .8rem; color: var(--ink-2); font-weight: 700; }
.pt-stat small { font-size: .72rem; color: var(--ink-3); }

.pt-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 4px;
}
.pt-mid { padding: 28px; text-align: center; display: grid; gap: 12px; justify-items: center; }
.pt-note { margin: 0; font-size: .88rem; color: var(--ink-2); }

/* Wide tables scroll inside their own box; the page never scrolls sideways. */
.pt-tablewrap { overflow-x: auto; }
.pt-table { width: 100%; border-collapse: collapse; font-size: .84rem; min-width: 560px; }
.pt-table th, .pt-table td {
  padding: 10px 11px; text-align: start;
  border-bottom: 1px solid var(--line-soft);
}
.pt-table th { font-size: .74rem; color: var(--ink-3); font-weight: 700; }
.pt-table tbody tr:last-child td { border-bottom: 0; }
.pt-table .pt-num { text-align: end; font-variant-numeric: tabular-nums; }
.pt-on td { background: color-mix(in srgb, var(--ok-bg) 55%, transparent); }
.pt-comm { font-weight: 700; color: var(--ok); }
.pt-dash { color: var(--ink-3); }
.pt-id { display: grid; gap: 1px; }
.pt-id code { font-family: var(--font-mono); font-size: .76rem; color: var(--ink-3); }
.pt-id span { font-size: .78rem; color: var(--ink); }
.pt-renew {
  display: block; font-size: .68rem; font-weight: 400; color: var(--ink-3);
}
.pt-empty { text-align: center; color: var(--ink-3); padding: 26px 10px; }
.pt-table tfoot td {
  border-top: 2px solid var(--line); font-weight: 700;
  background: var(--surface-2);
}

/* The rules, on the page rather than in a message somewhere. A partner who
   can read why a row did or did not earn does not have to ask. */
.pt-rules {
  padding: 14px 16px; border-radius: var(--radius);
  background: var(--surface-2); border: 1px solid var(--line);
}
.pt-rules b { font-size: .86rem; }
.pt-rules ul { margin: 8px 0 0; padding-inline-start: 18px; display: grid; gap: 6px; }
.pt-rules li { font-size: .8rem; line-height: 1.7; color: var(--ink-2); }

@media (max-width: 860px) {
  .pt-stats { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .pt-head h1 { font-size: 1.2rem; }
  .pt-head .btn { margin-inline-start: 0; }
  .pt-stat b { font-size: 1.25rem; }
  .pt-table { font-size: .8rem; }
  .pt-table th, .pt-table td { padding: 9px 8px; }
}

/* ──────────────────────────────────────────── the strip between neighbours
   Sticky under the header, never at the bottom: on a phone the bottom belongs
   to the tab bar, and a second fixed bar there would cover it or shove the
   page's own controls up.

   Thin on purpose. It is chrome, so it stays under 40px and carries only what
   chrome should — where you are, and the two ways out. Naming the destination
   is the bottom pager's job; a name is what makes a bar too tall to live on
   screen. */
/*
 * Opaque, and a different colour from the page.
 *
 * It used to be 92% --paper over a --paper page, which is the same cream
 * painted on itself: no edge, nothing to see, and the missing 8% let whatever
 * scrolled underneath show through the bar. Where backdrop-filter is
 * unsupported or switched off there was not even a blur to disguise it, so
 * the instructions read straight through the buttons.
 *
 * --surface is the colour every card on the site already uses, so the strip
 * now reads as a band sitting on the page rather than a hole in it. Fully
 * opaque, with a real border and a shadow under it to say that content passes
 * beneath. The blur stays as an enhancement for the browsers that have it.
 */
.quicknav {
  position: sticky; top: 60px; z-index: 80;
  background: var(--surface);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 0 var(--line-soft), 0 6px 14px -10px rgba(0, 0, 0, .35);
}
.qn-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  height: 38px;
}
/* Both words carry full weight. The first version made "السابق" a muted
   grey pill, which reads as disabled rather than as secondary — and a way out
   that looks switched off is a way out nobody takes. Going back is a smaller
   decision than going on, so it is quieter in colour, not in contrast. */
.qn-btn {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 14px; border-radius: 999px;
  font-size: .84rem; font-weight: 800; line-height: 1;
  text-decoration: none; white-space: nowrap;
  border: 1px solid transparent;
}
.qn-prev {
  background: var(--surface); color: var(--accent-ink);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}
.qn-next { background: var(--accent); color: #fff; }
.qn-prev:hover { background: var(--accent-soft); }
.qn-next:hover { filter: brightness(1.06); }
/* An end of the list is a fact about the list, not a button that failed. */
.qn-btn[aria-disabled] { opacity: .38; pointer-events: none; }

.qn-count {
  font-size: .8rem; color: var(--ink-2);
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
}
.qn-count b { color: var(--ink); font-weight: 700; }

@media (max-width: 940px) {
  /* The header shortens here, so the strip follows it up. */
  .quicknav { top: 54px; }
  .qn-row { height: 36px; gap: 8px; }
  .qn-btn { padding: 6px 11px; font-size: .8rem; }
  .qn-count { font-size: .74rem; }
}

/* The side column parks below the strip instead of sliding under it. */
body[data-pager] .sticky-side { top: 106px; }
@media (max-width: 960px) {
  body[data-pager] .sticky-side { top: auto; }
}

/* Printing a page should not print the way out of it. */
@media print { .quicknav { display: none !important; } }

.pager { display: flex; justify-content: space-between; gap: 12px; margin: 32px 0 10px; flex-wrap: wrap; }
.pager .btn { font-size: .86rem; }

.empty-state { text-align: center; padding: 52px 20px; color: var(--ink-3); }

/* ══════════════════════════════════════════════════════════════ footer */

.site-footer {
  border-top: 1px solid var(--line);
  margin-top: 64px; padding: 44px 0 52px;
  color: var(--ink-3); font-size: .86rem;
  background: var(--paper-2);
}
.site-footer p { margin: 0 0 8px; max-width: 60ch; }
.site-footer strong { color: var(--ink); }
.footer-links { display: flex; flex-wrap: wrap; gap: 16px; }
.footer-links a:hover { color: var(--ink); }

@media (max-width: 700px) {
  .wrap, .wrap-narrow { padding-inline: 18px; }
  section.block { padding-block: 48px; }
  .panel { padding: 16px; }
  .page-head { padding: 12px 0 20px; margin-bottom: 20px; }
}

@media print {
  .site-header, .site-footer, .actions, .nav, .pager, .tabbar, .ai-status { display: none !important; }
  body { background: #fff; padding-bottom: 0; }
  .panel { border-color: #ccc; }
}

/* ════════════════════════════════════════════════════ v2 components */

/* ---------------------------------------------------------- dark hero */

.hero-dark {
  background: var(--canvas);
  color: #EAF2F4;
  /* The zero used to be right: .hero-stats filled the bottom and was meant to
     sit flush against the section edge. With the stats gone the hero's own
     content ran into the boundary — the certificate's white sheet ended
     exactly where the dark band did, and `overflow: hidden` clipped the glow
     along that same line. */
  padding-block: 72px 76px;
  position: relative;
  overflow: hidden;
}
.hero-dark::before {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(900px 420px at 82% -10%, rgba(100, 163, 193, .16), transparent 62%),
    radial-gradient(600px 400px at 10% 110%, rgba(100, 163, 193, .07), transparent 60%);
  pointer-events: none;
}
.hero-dark .wrap { position: relative; }

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(320px, .95fr);
  gap: 48px;
  align-items: center;
}
@media (max-width: 940px) { .hero-grid { grid-template-columns: 1fr; gap: 32px; } }
/* No certificate on disk yet: one column, so the hero does not reserve an
   empty half and read as something that failed to load. */
.hero-grid.solo {
  /* One real column. `minmax(0, 1fr)` alone collapsed to 0 here because the
     empty second column still participated in the track sizing. */
  display: block; max-width: 760px;
}
.hero-grid.solo .hero-demo { display: none; }

.hero-eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: .8rem; font-weight: 700;
  color: rgba(234, 242, 244, .75);
  border: 1px solid rgba(234, 242, 244, .18);
  padding: 6px 14px; border-radius: 999px; margin-bottom: 22px;
}
.he-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--signal); }

.hero-dark h1 {
  margin: 0 0 20px;
  /* Sized for the headline it holds. It has grown again: the question is now
     followed by a full sentence naming what the platform is, so the type comes
     down another step and the second line is set smaller still. At the old
     size this ran to seven lines on a phone and put the CTA well under the
     fold — the headline would have been read by nobody who did not scroll. */
  font-size: clamp(1.35rem, 2.5vw, 1.95rem);
  font-weight: 700; line-height: 1.16; letter-spacing: -.03em;
}
/* The claim under the question is support, not a second headline: coloured to
   carry the eye, a step down in size and weight so the question still leads. */
.hero-dark h1 .hl {
  color: var(--signal);
  display: inline-block; margin-top: .32em;
  font-size: .76em; font-weight: 600; line-height: 1.4; letter-spacing: -.01em;
}

.hero-lede {
  margin: 0 0 30px; max-width: 46ch;
  font-size: clamp(1rem, 1.6vw, 1.16rem);
  color: rgba(234, 242, 244, .74); line-height: 1.75;
}
.hero-cta { display: flex; flex-wrap: wrap; gap: 11px; margin-bottom: 14px; }
.btn.on-dark { color: #EAF2F4; border-color: rgba(234, 242, 244, .28); }
.btn.on-dark:hover { background: rgba(234, 242, 244, .08); border-color: rgba(234, 242, 244, .66); }
.hero-fine { margin: 0; font-size: .84rem; color: rgba(234, 242, 244, .62); }


/* --------------------------------------------------------- try-it demo */

/* ───────────────────────────────────────── the certificate on the homepage
   Where the sample question used to be. A real telc result answers the
   question a visitor is actually asking, so it takes the weight the demo had:
   the largest object in the hero, lit rather than framed.

   Two layers. A blurred colour wash sits behind the sheet and bleeds past its
   edges — that is the shadow in the background. The sheet carries a thin
   luminous rule and a matching outer bloom, which is what reads as neon
   against the dark hero without turning the page into a toy. */
.cert {
  position: relative;
  margin: 0; display: grid; justify-items: center;
  isolation: isolate;
}
.cert-glow {
  position: absolute; z-index: -1;
  inset: -12% -8% -6%;
  border-radius: 50%;
  background:
    radial-gradient(48% 42% at 30% 22%, color-mix(in srgb, var(--signal) 62%, transparent), transparent 70%),
    radial-gradient(52% 46% at 74% 72%, color-mix(in srgb, #7de3c8 52%, transparent), transparent 72%);
  filter: blur(46px);
  opacity: .58;
  pointer-events: none;
  /* Breathing, not blinking. Opacity and transform are the two things a
     browser can animate without repainting, so the certificate itself is
     never redrawn — only the light behind it moves. Animating the rim's
     box-shadow instead would repaint the sheet sixty times a second for an
     effect nobody would describe differently. */
  animation: cert-breathe 4.2s ease-in-out infinite;
  will-change: opacity, transform;
}

@keyframes cert-breathe {
  0%, 100% { opacity: .40; transform: scale(1); }
  50%      { opacity: .95; transform: scale(1.10); }
}

/* The visible one. A ring on the sheet's edge that expands and fades, twice
   over per cycle so the motion never fully stops. Opacity and transform only,
   so the certificate is never repainted — the ring is its own layer. */
.cert-ring {
  position: absolute; inset: 0;
  border-radius: 14px;
  border: 1.5px solid rgba(138, 246, 230, .95);
  box-shadow: 0 0 16px 1px rgba(122, 240, 226, .65);
  pointer-events: none;
  opacity: 0;
  animation: cert-ping 2.8s cubic-bezier(.22, .61, .36, 1) infinite;
}
.cert-ring.late { animation-delay: 1.4s; }

@keyframes cert-ping {
  0%   { opacity: .9; transform: scale(1); }
  70%  { opacity: 0;  transform: scale(1.085); }
  100% { opacity: 0;  transform: scale(1.085); }
}

/* Motion nobody asked for is motion somebody has to sit through. */
@media (prefers-reduced-motion: reduce) {
  .cert-glow { animation: none; opacity: .58; transform: none; }
  .cert-ring { animation: none; opacity: 0; }
}
.cert-frame {
  position: relative;
  width: 100%; max-width: 330px;
  line-height: 0;
}
.cert-img {
  display: block; width: 100%; height: auto;
  border-radius: 14px;
  background: #fff;
  /* The neon is three rings, not one: a hard bright edge on the sheet, a
     tight bloom just outside it, and a wide soft one past that. A single
     large shadow reads as haze; the hard edge is what makes it a rim. */
  /* Dimmed. The three rings stay — a hard edge, a tight bloom, a wide soft
     one — because that structure is what reads as a rim rather than haze.
     Only the intensities come down, so it still lifts the sheet off the dark
     hero without being the brightest thing on the page. */
  border: 1px solid color-mix(in srgb, #b8f5ea 50%, transparent);
  box-shadow:
    0 0 0 1px rgba(122, 240, 226, .34),
    0 0 8px 0 rgba(122, 240, 226, .26),
    0 0 22px -4px color-mix(in srgb, var(--signal) 42%, transparent),
    0 0 54px -8px color-mix(in srgb, #6fd7d7 30%, transparent),
    0 26px 60px -24px rgba(0, 0, 0, .78);
}
@media (max-width: 860px) {
  /* The frame owns the width now; the rings are pinned to it, so capping
     the image instead would leave them 80px wider than the sheet. */
  .cert-frame { max-width: 250px; }
  .cert-glow { filter: blur(34px); opacity: .7; }
}

.demo {
  background: rgba(234, 242, 244, .05);
  border: 1px solid rgba(234, 242, 244, .16);
  border-radius: var(--radius-lg);
  padding: 22px;
  backdrop-filter: blur(8px);
}
.demo-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 16px; }
.demo-kicker {
  font-size: .74rem; font-weight: 700; color: var(--signal);
  letter-spacing: .04em;
}
.demo .badge { background: rgba(234, 242, 244, .1); color: rgba(234, 242, 244, .7); border-color: transparent; }
.demo-q {
  font-family: var(--font-read); font-size: 1.06rem; line-height: 1.8;
  margin: 0 0 18px; color: #EAF2F4;
}
.demo-opts { display: grid; gap: 8px; }
.demo-opt {
  border: 1px solid rgba(234, 242, 244, .2); background: transparent;
  color: #EAF2F4; border-radius: 10px; padding: 12px 15px;
  font-family: var(--font-de); font-size: .96rem; font-weight: 500;
  text-align: left; cursor: pointer;
  transition: border-color .14s var(--ease), background .14s var(--ease), transform .1s var(--ease);
}
.demo-opt:hover:not(:disabled) { border-color: var(--signal); background: rgba(100, 163, 193, .08); }
.demo-opt:active:not(:disabled) { transform: scale(.99); }
.demo-opt.right { border-color: var(--signal); background: rgba(100, 163, 193, .16); color: var(--signal); font-weight: 700; }
.demo-opt.wrong { border-color: rgba(242, 160, 150, .6); background: rgba(242, 160, 150, .12); color: #F2A49C; }

.demo-fb { margin-top: 16px; padding: 15px; border-radius: 12px; }
.demo-fb.good { background: rgba(100, 163, 193, .12); }
.demo-fb.bad { background: rgba(242, 160, 150, .1); }
.demo-fb b { display: block; margin-bottom: 8px; color: #EAF2F4; }
.demo-fb p { margin: 0 0 14px; font-size: .89rem; color: rgba(234, 242, 244, .7); line-height: 1.7; }
.demo-corr { display: flex; flex-direction: column; gap: 3px; margin-bottom: 10px; font-family: var(--font-de); }
.demo-corr del { color: #F2A49C; }
.demo-corr ins { color: var(--signal); text-decoration: none; font-weight: 700; }

/* ------------------------------------------------------- level chooser */

.lvl-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 18px; }
.lvl-card {
  position: relative; display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 28px; background: var(--surface);
  transition: border-color .2s var(--ease), transform .2s var(--ease), box-shadow .2s var(--ease);
}
.lvl-card:hover { border-color: var(--ink); transform: translateY(-3px); box-shadow: var(--shadow-lift); }
.lvl-card.picked { border-color: var(--signal-deep); border-width: 2px; padding: 27px; }
.lvl-card.picked::after {
  content: 'مستواك'; position: absolute; top: 18px; inset-inline-end: 18px;
  font-size: .7rem; font-weight: 700; color: var(--signal-deep);
  background: var(--signal-wash); padding: 3px 10px; border-radius: 6px;
}
.lvl-tag {
  font-family: var(--font-de); font-size: 3.2rem; font-weight: 700;
  line-height: 1; letter-spacing: -.04em; color: var(--ink); margin-bottom: 14px;
}
.lvl-card h3 { margin: 0 0 16px; font-size: 1.05rem; font-weight: 600; color: var(--ink-2); }
.lvl-list { list-style: none; margin: 0 0 20px; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.lvl-list li {
  font-size: .76rem; padding: 3px 9px; border-radius: 6px;
  background: var(--paper-2); color: var(--ink-3); border: 1px solid var(--line-soft);
}
.lvl-foot {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: auto; padding-top: 16px; border-top: 1px solid var(--line-soft);
  font-size: .84rem; color: var(--ink-3);
}
.lvl-go { font-weight: 700; color: var(--ink); }

/* level pill menu */
.level-menu {
  position: absolute; z-index: 100; margin-top: 8px;
  min-width: 230px; padding: 6px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 13px; box-shadow: var(--shadow-lift);
}
#levelPill { position: relative; }
.level-opt {
  display: flex; flex-direction: column; gap: 1px; width: 100%;
  padding: 9px 12px; border: 0; border-radius: 9px;
  background: transparent; color: var(--ink); text-align: start;
  font: inherit; cursor: pointer;
}
.level-opt:hover { background: var(--paper-2); }
.level-opt b { font-family: var(--font-de); font-size: .95rem; }
.level-opt span { font-size: .78rem; color: var(--ink-3); }
.level-opt.on { background: var(--signal-wash); }
.level-opt.plain { border-top: 1px solid var(--line-soft); border-radius: 0 0 9px 9px; margin-top: 4px; padding-top: 11px; font-size: .84rem; color: var(--ink-3); }

.off-level { display: none !important; }

/* -------------------------------------------------------- why section */


/* --- restored: the credibility pair -----------------------------------------
   Two cards, not the original six: the other four said what the feature
   section above now shows with a figure. */
.why-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden; }
.why-card { background: var(--paper); padding: 28px; position: relative; transition: background .2s var(--ease); }
.why-card:hover { background: var(--surface); }
.why-idx { position: absolute; top: 22px; inset-inline-end: 22px; font-family: var(--font-de); font-size: .74rem; font-weight: 700; color: var(--ink-3); opacity: .5; }
.why-icon { display: block; font-size: 1.5rem; color: var(--signal-deep); margin-bottom: 14px; }
html[data-theme="dark"] .why-icon { color: var(--signal); }
.why-card h3 { margin: 0 0 8px; font-size: 1.04rem; }
.why-card p { margin: 0; font-size: .93rem; color: var(--ink-2); line-height: 1.72; }

/* --- الطريق ديالك لألمانيا --------------------------------------------------
   Inverted, so the one section about the learner's life rather than the
   product reads as a different kind of page. Colours are literal rather than
   tokens here on purpose: the band is dark in both themes, so a token that
   flips would break the contrast the section is built on. */
.road { position: relative; background: var(--canvas); color: #EAF2F4; overflow: hidden; }
/* Three stops, no caption needed. */
.road-flag { position: absolute; inset-block-start: 0; inset-inline: 0; height: 3px; background: linear-gradient(to left, #111 33%, #C1121F 33% 66%, #E4B429 66%); }
.road .block-head h2 { color: #EAF2F4; }
.road .block-head p, .road .idx { color: #9DB4C2; }

.road-chips { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-bottom: 26px; }
.road-chip {
  font: inherit; font-size: .85rem; cursor: pointer;
  padding: 10px 18px; min-height: 44px; border-radius: 100px;
  background: transparent; color: #BCCFD9; border: 1px solid #2A4E6C;
  transition: background .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
@media (hover: hover) { .road-chip:hover { border-color: var(--signal); color: #EAF2F4; } }
.road-chip.is-on { background: var(--signal); border-color: var(--signal); color: var(--signal-ink); font-weight: 700; }

/* ---- the goal ----------------------------------------------------------- */
.road-goal { max-width: 760px; margin: 0 auto; text-align: center; }
.road-goal-t { margin: 0 0 8px; font-size: 1.4rem; letter-spacing: .02em; color: #EAF2F4; }
.road-hook { margin: 0 auto 24px; max-width: 52ch; font-size: 1rem; line-height: 1.7; color: #BCCFD9; }
.road-q { display: block; margin: 0 0 12px; font-size: .78rem; letter-spacing: .06em; color: var(--signal); }

.road-levels { display: grid; grid-template-columns: 1fr; gap: 12px; text-align: start; }
@media (min-width: 720px) { .road-levels { grid-template-columns: 1fr 1fr; } }
.road-lv { background: #12293F; border: 1px solid #254764; border-radius: var(--radius); padding: 18px 20px; }
.road-lv p { margin: 0; font-size: .86rem; line-height: 1.7; color: #9DB4C2; }
.road-lv-h { display: flex; align-items: center; gap: 9px; margin-bottom: 9px; }
.road-lv-h b { font-size: .98rem; color: #EAF2F4; }
/* The author's 🟢 / 🔵 as design elements: an emoji here renders differently on
   every platform and sits badly next to the level it labels. */
.road-dot { width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto; }
.road-lv.b1 .road-dot { background: #6FD1B0; }
.road-lv.b2 .road-dot { background: #8FC2DE; }
.road-fields { margin-top: 9px !important; font-family: var(--font-de); font-size: .82rem; color: #CFE0E6 !important; }
/* The one-line summary the author closes each level with — it is the line a
   skimmer reads, so it sits apart from the paragraph rather than after it. */
.road-lv-tag { display: block; margin-top: 12px; padding-top: 11px; border-top: 1px dashed #274A67; font-size: .84rem; font-weight: 700; color: #EAF2F4; }
.road-lv.b1 .road-lv-tag { color: #6FD1B0; }
.road-lv.b2 .road-lv-tag { color: #9FCFE6; }
.road-vary { margin: 14px 0 0; font-size: .76rem; line-height: 1.7; color: #A8BECB; }

@keyframes road-swap { from { opacity: .3; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.road-swap { animation: road-swap .3s var(--ease); }

/* ---- what the platform drills ------------------------------------------- */
.road-prep { margin-top: 42px; text-align: center; }
.road-prep h3 { margin: 0 0 8px; font-size: 1.14rem; color: #EAF2F4; }
.road-prep-lead { margin: 0 auto 22px; max-width: 48ch; font-size: .92rem; line-height: 1.7; color: #BCCFD9; }
/* Names the exam and the certificate — the step the section used to skip. */
.road-bridge { margin: 0 auto 6px; max-width: 46ch; font-size: .88rem; line-height: 1.7; color: #9DB4C2; }
.road-bridge [lang="de"] { color: #EAF2F4; font-weight: 600; }
.road-prep-q { margin: 0 0 12px; font-size: .8rem; color: #9DB4C2; }
/* The line that hands the reader over to what the site actually drills: the
   turn from "here is the level you need" to "here is how you get it". Sized
   as a step in the argument rather than as a caption. */
.road-prep-q.lead {
  display: inline-block; margin: 6px 0 18px; padding: 10px 22px;
  font-size: 1rem; font-weight: 700; color: var(--signal-ink);
  background: var(--signal); border-radius: 100px;
}
.road-prep-q.lead [lang="de"] { font-family: var(--font-de); }
.road-prep-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; text-align: start; margin-bottom: 20px; }
@media (min-width: 720px) { .road-prep-grid { grid-template-columns: repeat(5, 1fr); } }
.road-prep-card { background: #12293F; border: 1px solid #254764; border-radius: var(--radius); padding: 16px 14px; }
/* The fifth card has no partner on a two-column phone layout, so it takes the
   row — it is the simulator, which is the one worth the extra width anyway. */
@media (max-width: 719px) { .road-prep-card:last-child { grid-column: 1 / -1; } }
.road-prep-i { display: block; font-size: 1.25rem; line-height: 1; margin-bottom: 9px; }
.road-prep-card b { display: block; font-family: var(--font-de); font-size: .88rem; color: var(--signal); margin-bottom: 4px; }
.road-prep-card span { font-size: .76rem; line-height: 1.55; color: #9DB4C2; }
.road-pills { display: flex; flex-wrap: wrap; gap: 7px; justify-content: center; }
.road-pills span { font-family: var(--font-de); font-size: .82rem; color: #BCCFD9; background: #12293F; border: 1px solid #254764; border-radius: 100px; padding: 6px 14px; }

/* ---- the ask ------------------------------------------------------------ */
.road-cta { display: flex; flex-direction: column; align-items: center; gap: 12px; margin-top: 38px; padding-top: 30px; border-top: 1px solid #20415C; }
.road-cta p { margin: 0; max-width: 46ch; font-size: 1rem; line-height: 1.6; color: #EAF2F4; }
.road-fine { font-size: .76rem; color: #9DB4C2; }

@media (prefers-reduced-motion: reduce) { .road-swap { animation: none; } }

@media (max-width: 620px) {
  /* The chips must never wrap into three ragged lines on a phone. */
  .road-chips { flex-wrap: nowrap; overflow-x: auto; justify-content: flex-start; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; padding-bottom: 4px; }
  .road-chips::-webkit-scrollbar { display: none; }
  .road-chip { flex: 0 0 auto; scroll-snap-align: start; }
  .road-goal-t { font-size: 1.2rem; }
  .road-hook { font-size: .93rem; }
  .road-cta .btn { width: 100%; justify-content: center; }
}

/* --- talk to us ------------------------------------------------------------
   A floating contact button, on every page. WhatsApp is where this audience
   already is — it is how the subscription is paid for and how the answer
   disputes get settled — so the way to reach a person should not be buried in
   a footer.

   Placed at the inline end, which is the left on this RTL site, so it never
   sits over the text a reader is following. On a phone it lifts above the tab
   bar rather than covering it: the tab bar is 68px including its safe-area
   padding, and a button that hides a navigation item is worse than no button.

   It carries WhatsApp's own green rather than a palette token. This is a
   recognised mark, and recolouring it to match the site would make it read as
   a decorative circle instead of "message us here". */
/* Solid WhatsApp green, at the size the pattern is normally used.
   The quiet treatment that was here — a white disc with a green glyph — was
   correct on paper and wrong in practice: on a cream page a white circle has
   barely any edge, so the thing people are meant to press read as part of the
   layout. Recognition is the whole job of this button, and the green is what
   carries it. */
.wa-fab {
  position: fixed; z-index: 96;
  inset-inline-end: 18px; bottom: calc(18px + env(safe-area-inset-bottom));
  width: 58px; height: 58px; border-radius: 50%;
  display: grid; place-items: center;
  background: #25D366; color: #fff;
  /* Layered rather than one soft blur: the tight shadow gives the disc an
     edge against the cream, the wide one lifts it off the page. */
  box-shadow: 0 2px 6px rgba(20, 38, 58, .22), 0 10px 26px rgba(20, 38, 58, .26);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease);
}
/* On the dark page the green is bright enough to stand alone, but the disc's
   own edge disappears — a hairline in the same green, lightened, restores it
   without introducing a second colour. */
html[data-theme="dark"] .wa-fab {
  box-shadow: 0 0 0 1px rgba(122, 240, 168, .35),
              0 2px 8px rgba(0, 0, 0, .5), 0 10px 26px rgba(0, 0, 0, .45);
}
.wa-fab svg { width: 33px; height: 33px; display: block; }
@media (hover: hover) {
  .wa-fab:hover {
    transform: translateY(-2px) scale(1.04);
    box-shadow: 0 4px 10px rgba(20, 38, 58, .26), 0 16px 34px rgba(20, 38, 58, .3);
  }
}
.wa-fab:focus-visible { outline: 3px solid var(--signal-deep); outline-offset: 3px; }

@media (max-width: 940px) {
  /* Clear of the tab bar, which is fixed to the bottom at 68px. */
  .wa-fab { bottom: calc(78px + env(safe-area-inset-bottom)); width: 56px; height: 56px; }
  .wa-fab svg { width: 32px; height: 32px; }
}

/* Embedded views hide the site's own chrome; this belongs to the site. */
html[data-embed] .wa-fab { display: none; }

@media print { .wa-fab { display: none; } }

/* --- student reviews -------------------------------------------------------
   Screenshots, framed as plainly as possible: a WhatsApp thread argues by
   being obviously unretouched, and any styling that reads as art direction
   works against it.

   The strip moves on a CSS animation rather than on a script. The scripted
   version advanced scrollLeft on a timer, which needs a running script, a
   foregrounded tab, an observer that has fired and a browser that is not
   throttling timers — and when any of those was false it did nothing at all,
   so the strip looked like something you had to push by hand. This runs on
   the compositor and has none of those dependencies.

   Seamless because the markup holds the reviews twice and the animation
   travels exactly one set: at the end, the duplicate sits where the original
   began, so the reset is invisible and the motion never stops or reverses.
   It moves left to right, which is why it starts translated and returns to
   zero rather than the other way round.

   Nothing in here takes a pointer. The images are inert, and there are no
   arrows or dots to click. */
/* direction:ltr belongs on the window, not just on the strip. The track is
   width:max-content and so overflows its container; in an RTL container an
   overflowing child is aligned to the *right* edge, which put the strip's
   right edge at the window's right edge — and then translating it left by one
   set pushed the whole thing off-screen. The section was blank at the start of
   every loop and filled in only as it travelled. Anchored left, the strip
   spans the window at every point of the animation. */
.rv { overflow: hidden; padding: 4px 0 2px; direction: ltr; }
.rv-track {
  display: flex;
  gap: 18px;
  width: max-content;
  animation: rv-marquee 34s linear infinite;
  will-change: transform;
}
/* Travels one full set: the strip is two identical sets, so -50% of its own
   width is exactly one set. Ending at 0 means the content moves rightwards. */
@keyframes rv-marquee {
  from { transform: translateX(-50%); }
  to   { transform: translateX(0); }
}
/* Someone reading a review should be able to stop it. */
@media (hover: hover) { .rv:hover .rv-track { animation-play-state: paused; } }

.rv-slide { flex: 0 0 auto; margin: 0; width: min(72vw, 300px); }
.rv-slide img {
  display: block; width: 100%; height: auto;
  border-radius: var(--radius); box-shadow: var(--shadow);
  /* Inert on purpose: nothing to click, drag, select or long-press. */
  pointer-events: none; user-select: none; -webkit-user-select: none;
  -webkit-user-drag: none; -webkit-touch-callout: none;
}

@media (max-width: 860px) {
  /* Shorter strip, so the same speed would feel slower — and a phone shows
     fewer at once, so it should come round sooner. */
  .rv-track { animation-duration: 24s; gap: 14px; }
}

/* Motion is the whole point of this section, so reduced-motion gets the strip
   standing still and scrollable by hand instead of a moving one. */
@media (prefers-reduced-motion: reduce) {
  .rv { overflow-x: auto; scrollbar-width: none; }
  .rv::-webkit-scrollbar { display: none; }
  .rv-track { animation: none; }
}

/* --- homepage feature section ----------------------------------------------
   The part of the page that has to earn a signup. Structure carries the
   hierarchy: one full-width flagship panel for the thing nobody else offers,
   a grid of five beneath it, then a deliberately quiet strip for the rest.

   Everything is a token, never a literal colour, so the dark theme repaints
   it; the SVG and the flow arrows run right-to-left like the page. Motion is
   opt-in through .is-in, added by home-features.js — the CSS resting state is
   the visible one, so a page whose script never runs still reads correctly. */

.feat-tag {
  display: inline-block; font-size: .7rem; font-weight: 700; letter-spacing: .06em;
  color: var(--accent-ink); background: var(--accent-soft);
  border-radius: 100px; padding: 5px 11px;
}
.feat h3, .feat-lead h3 { margin: 12px 0 8px; font-size: 1.14rem; line-height: 1.4; letter-spacing: -.01em; }
/* One line, and it is allowed to be one line: the figure carries the detail. */
.feat-line { margin: 0; font-size: .9rem; line-height: 1.65; color: var(--ink-2); }

.feat-chips { list-style: none; display: flex; flex-wrap: wrap; gap: 7px; margin: 14px 0 0; padding: 0; }
.feat-chips li {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 6px 11px; border: 1px solid var(--line); border-radius: 100px;
  background: var(--paper); font-size: .74rem; color: var(--ink-3);
}
.feat-chips b { font-family: var(--font-de); font-size: .86rem; color: var(--ink); }

/* ---- 01, the flagship --------------------------------------------------- */
.feat-lead {
  display: grid; grid-template-columns: 1fr; gap: 26px; margin-bottom: 18px;
  padding: 30px; border-radius: var(--radius-lg);
  background: var(--surface); border: 1px solid var(--line);
  position: relative; overflow: hidden;
}
/* A single accent edge, on the right where an Arabic line starts. */
.feat-lead::before {
  content: ""; position: absolute; inset-block: 0; inset-inline-end: 0;
  width: 3px; background: linear-gradient(var(--signal-deep), transparent);
}
@media (min-width: 900px) { .feat-lead { grid-template-columns: 1fr 1fr; gap: 34px; align-items: center; padding: 38px; } }
.feat-lead h3 { font-size: 1.5rem; }
@media (min-width: 900px) { .feat-lead h3 { font-size: 1.75rem; } }
.feat-cta-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 20px; }
.feat-fine { font-size: .74rem; color: var(--ink-3); }

/* the mock exchange: what the product actually looks like, not an icon */
.sp-demo { display: flex; flex-direction: column; gap: 10px; }
.sp-turn { border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; background: var(--paper); }
.sp-turn.me { background: var(--accent-soft); border-color: var(--signal-deep); margin-inline-start: 22px; }
.sp-turn.examiner { margin-inline-end: 22px; }
.sp-who { display: flex; align-items: center; gap: 7px; font-size: .7rem; color: var(--ink-3); margin-bottom: 6px; }
.sp-turn p { margin: 0; font-family: var(--font-de); font-size: .87rem; line-height: 1.6; color: var(--ink); }
/* three bars, so "it is listening to you" needs no caption */
.sp-wave { display: inline-flex; align-items: flex-end; gap: 2px; height: 12px; }
.sp-wave i { width: 3px; height: 4px; border-radius: 2px; background: var(--signal-deep); }
.is-in .sp-wave i { animation: sp-bounce 1.05s var(--ease) infinite; }
.is-in .sp-wave i:nth-child(2) { animation-delay: .16s; }
.is-in .sp-wave i:nth-child(3) { animation-delay: .32s; }
@keyframes sp-bounce { 0%, 100% { height: 4px; } 50% { height: 12px; } }

.sp-score { border: 1px solid var(--line); border-radius: var(--radius); padding: 13px 14px; background: var(--surface); }
.sp-bands { display: flex; flex-wrap: wrap; gap: 6px; }
.sp-band { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-de); font-size: .68rem; color: var(--ink-2); border: 1px solid var(--line); border-radius: 100px; padding: 4px 9px; }
.sp-band i { font-style: normal; font-weight: 700; width: 16px; height: 16px; display: grid; place-items: center; border-radius: 50%; font-size: .64rem; background: var(--ok-bg); color: var(--ok); }
.sp-band.b i { background: var(--warn-bg); color: var(--warn); }
.sp-band.c i { background: var(--bad-bg); color: var(--bad); }
.sp-note { margin: 10px 0 0; font-size: .78rem; line-height: 1.7; color: var(--ink-2); }
.sp-note b { font-family: var(--font-de); color: var(--ink); font-weight: 600; }

/* ---- 02–06 -------------------------------------------------------------- */
.feat-grid { display: grid; grid-template-columns: 1fr; gap: 16px; }
@media (min-width: 760px) { .feat-grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1040px) { .feat-grid { grid-template-columns: repeat(3, 1fr); } }
.feat {
  display: flex; flex-direction: column; padding: 26px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg);
  transition: border-color .2s var(--ease), transform .2s var(--ease), box-shadow .2s var(--ease);
}
@media (hover: hover) { .feat:hover { transform: translateY(-3px); border-color: var(--signal-deep); box-shadow: var(--shadow); } }
/* Figures sit at the bottom so they line up across a row of uneven copy. */
.feat-viz { margin-top: auto; padding-top: 18px; }

.fx-card { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.fx-fix { padding: 12px 14px; background: var(--paper-2); border-bottom: 1px solid var(--line); }
.fx-fix s { display: block; font-family: var(--font-de); font-size: .82rem; color: var(--bad); opacity: .8; }
.fx-fix b { display: block; font-family: var(--font-de); font-size: .86rem; color: var(--ink); margin-top: 3px; }
.fx-tag { display: inline-block; margin-top: 8px; font-family: var(--font-de); font-size: .65rem; color: var(--ink-3); border: 1px solid var(--line); border-radius: 100px; padding: 3px 8px; }
.fx-rows { padding: 4px 14px 10px; }
.fx-row { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 6px 0; font-size: .72rem; color: var(--ink-3); border-bottom: 1px dashed var(--line-soft); }
.fx-row em { font-style: normal; font-family: var(--font-de); font-weight: 700; color: var(--ink-2); }
.fx-row.total { border-bottom: 0; color: var(--ink); font-size: .78rem; }
.fx-row.total em { color: var(--signal-deep); font-size: 1.05rem; }

.fx-steps { list-style: none; margin: 0; padding: 0; counter-reset: fx; }
.fx-steps li {
  counter-increment: fx; position: relative; padding: 7px 30px 7px 0;
  font-size: .78rem; color: var(--ink-2); border-bottom: 1px dashed var(--line-soft);
}
.fx-steps li:last-child { border-bottom: 0; }
.fx-steps li::before {
  content: counter(fx); position: absolute; inset-inline-end: 0; top: 6px;
  width: 20px; height: 20px; display: grid; place-items: center; border-radius: 50%;
  font-family: var(--font-de); font-size: .62rem; font-weight: 700;
  background: var(--accent-soft); color: var(--accent-ink);
}
.fx-loop { display: flex; align-items: center; gap: 8px; margin-top: 12px; padding: 9px 12px; border: 1px dashed var(--signal-deep); border-radius: var(--radius-sm); font-size: .72rem; color: var(--ink-2); background: var(--accent-soft); }

.fx-svg { display: block; width: 100%; height: auto; overflow: visible; }
.ig-area { fill: var(--signal-wash); }
.ig-curve { fill: none; stroke: var(--signal-deep); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.ig-axis { stroke: var(--line); stroke-width: 1; }
.ig-dot { fill: var(--paper); stroke: var(--signal-deep); stroke-width: 1.5; }
.ig-dot.now { fill: var(--signal-deep); }
.ig-cell { fill: var(--line); }
.ig-cell.l2 { fill: var(--signal-deep); opacity: .42; }
.ig-cell.l3 { fill: var(--signal-deep); }
/* The weekly plan figure. Days already done are filled and quiet, today is
   the bright one with a dot over it, and the days ahead are outlines — so the
   week reads left-unfinished at a glance without a single label. */
.pl-bar { fill: none; stroke: var(--signal-deep); stroke-width: 1.5; opacity: .5; }
.pl-bar.done { fill: var(--signal-wash); stroke: none; opacity: 1; }
.pl-bar.today { fill: var(--signal-deep); stroke: none; opacity: 1; }
.pl-tick { fill: none; stroke: var(--signal-deep); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.pl-now { fill: var(--signal-deep); }
.pl-day { fill: var(--line); }

.fx-legend { display: flex; justify-content: space-between; font-size: .7rem; color: var(--ink-3); margin-top: 4px; }


/* the wrong answer everyone has, next to the right one */
.fx-verify { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.fx-vrow { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 13px; font-family: var(--font-de); font-size: .8rem; }
.fx-vrow.bad { background: var(--bad-bg); color: var(--bad); text-decoration: line-through; }
.fx-vrow.good { background: var(--ok-bg); color: var(--ok); font-weight: 700; }
.fx-vtag { font-family: var(--font-ar); font-size: .68rem; font-weight: 400; text-decoration: none; opacity: .85; }
.fx-vnote { padding: 9px 13px; font-size: .7rem; color: var(--ink-3); border-top: 1px solid var(--line); background: var(--paper-2); }


/* ---- the quiet strip ---------------------------------------------------- */
.feat-more {
  display: grid; grid-template-columns: 1fr; gap: 1px; margin-top: 18px;
  background: var(--line); border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden;
}
@media (min-width: 620px) {
  .feat-more { grid-template-columns: 1fr 1fr; }
  /* Odd count: the last one takes the whole row rather than leaving a gap. */
  .feat-more-item:last-child { grid-column: 1 / -1; }
}
@media (min-width: 1000px) {
  .feat-more { grid-template-columns: repeat(5, 1fr); }
  .feat-more-item:last-child { grid-column: auto; }
}
.feat-more-item { display: flex; gap: 10px; padding: 14px 16px; background: var(--paper); }
.feat-more-icon { color: var(--signal-deep); font-size: 1rem; line-height: 1.3; }
.feat-more-item b { display: block; font-size: .82rem; margin-bottom: 2px; }
.feat-more-item span { font-size: .74rem; color: var(--ink-3); line-height: 1.5; }


/* ---- motion ------------------------------------------------------------- */
.feat-anim { opacity: 0; transform: translateY(14px); transition: opacity .5s var(--ease), transform .5s var(--ease); }
.feat-anim.is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .feat-anim { opacity: 1; transform: none; transition: none; }
  .is-in .sp-wave i, .is-in .fx-dot { animation: none; }
  .sp-wave i { height: 8px; }
}

@media (max-width: 620px) {
  .feat-lead { padding: 22px; }
  .feat { padding: 20px; }
  .sp-turn.me { margin-inline-start: 12px; }
  .sp-turn.examiner { margin-inline-end: 12px; }
  /* Full-width tap target: the primary ask must not be a small pill on a phone. */
  .feat-cta-row .btn { width: 100%; justify-content: center; }
}

/* --------------------------------------------------------- final CTA */

.cta-final {
  display: flex; align-items: center; justify-content: space-between; gap: 26px;
  flex-wrap: wrap;
  background: var(--canvas); color: #EAF2F4;
  border-radius: var(--radius-lg); padding: 44px;
}
.cta-final h2 { margin: 0 0 8px; font-size: clamp(1.5rem, 3vw, 2.1rem); }
.cta-final p { margin: 0; color: rgba(234, 242, 244, .65); }

/* ------------------------------------------------------ explain button */

.xp-host { position: relative; }
.xp-btn {
  position: absolute; top: 4px; inset-inline-end: 0;
  width: auto; height: 21px; border-radius: 6px;
  padding: 0 7px; gap: 4px;
  border: 1px solid var(--line); background: var(--surface);
  color: var(--ink-3); cursor: pointer;
  font-family: var(--font-ar); font-size: .68rem; font-weight: 700;
  display: inline-flex; align-items: center; line-height: 1;
  opacity: .75;
  transition: opacity .15s var(--ease), border-color .15s var(--ease), color .15s var(--ease);
}

/* Reserve the button's lane so no line of German ever runs underneath it. */
.xp-host { padding-top: 30px; }
.xp-host:hover .xp-btn { opacity: 1; }
.xp-btn:hover { border-color: var(--ink); color: var(--ink); }
.xp-btn.on { background: var(--signal-wash); border-color: var(--signal-deep); color: var(--signal-deep); opacity: 1; }
html[data-theme="dark"] .xp-btn.on { color: var(--signal); }

.xp-box {
  /*
   * The panel hangs inside .prose, which is the German — LTR and left-aligned.
   * An Arabic explanation inheriting that alignment strands every list bullet
   * on the far side of its own line, so the box states its own direction.
   */
  direction: rtl; text-align: right;
  margin-top: 10px; padding: 11px 13px;
  background: var(--signal-wash); border-radius: 9px;
  font-size: .9rem; line-height: 1.75;
  animation: trIn .18s var(--ease) both;
}
html[data-theme="dark"] .xp-box { background: var(--paper-3); }
@keyframes trIn { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }
.tr-ar { margin: 0; color: var(--ink); }
.tr-ar + .tr-ar { margin-top: 9px; }
.tr-hint { margin: 6px 0 0; font-size: .78rem; color: var(--ink-3); }
.tr-loading { margin: 0; color: var(--ink-3); }
.tr-gloss { display: flex; flex-wrap: wrap; gap: 6px; }
.gl-pair {
  font-size: .8rem; background: var(--surface); border: 1px solid var(--line);
  border-radius: 6px; padding: 3px 8px; color: var(--ink-2);
}
.gl-pair b { font-family: var(--font-de); direction: ltr; margin-inline-end: 4px; color: var(--ink); }

/* ---------------------------------------------------- explanation panel */

/*
 * A translation was one paragraph; an explanation is several short sections,
 * and they only read as an explanation if the eye can tell them apart. Each
 * heading is small and quiet — the German inside is what should stand out.
 */
.xp-sec + .xp-sec { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.xp-sec h4 {
  margin: 0 0 6px; font-size: .74rem; font-weight: 800; letter-spacing: .02em;
  color: var(--ink-3); text-transform: none;
}
.xp-kind {
  margin: 0 0 10px; font-size: .78rem; font-weight: 700;
  color: var(--signal-deep); background: var(--signal-wash);
  border-radius: 6px; padding: 4px 9px; display: inline-block;
}
html[data-theme="dark"] .xp-kind { color: var(--signal); background: var(--paper-2); }
.xp-p { margin: 0; color: var(--ink-2); font-size: .86rem; }

/* What the text is about: the first thing read, so it carries some weight. */
/*
 * The written summary, which is not the same kind of thing as the rest of the
 * panel: everything below it the page worked out from the German in front of
 * it, and this one sentence a person wrote about what the text is actually
 * about. It carries the site's signal wash, the same lift given to a sentence
 * a reader must not skim past.
 */
.xp-summary {
  margin: 0 0 14px; padding: 12px 14px;
  border: 1px solid color-mix(in srgb, var(--signal) 42%, transparent);
  border-radius: 12px;
  background: var(--signal-wash);
}
.xp-summary h4 {
  margin: 0 0 6px;
  font-size: .74rem; font-weight: 800; letter-spacing: .02em;
  color: var(--signal-deep);
}
.xp-summary p {
  margin: 0;
  font-size: .95rem; line-height: 1.85; font-weight: 700;
  color: var(--accent-ink);
}
html[data-theme="dark"] .xp-summary {
  background: var(--paper-2);
  border-color: color-mix(in srgb, var(--signal) 32%, transparent);
}
html[data-theme="dark"] .xp-summary h4 { color: var(--signal); }
html[data-theme="dark"] .xp-summary p { color: var(--ink); }

/* The clause that proves the structure, under the name of the structure. */
.xp-eg {
  display: block; margin-top: 3px;
  font-family: var(--font-de); font-size: .8rem; color: var(--ink-3);
  border-inline-start: 2px solid var(--line); padding-inline-start: 8px;
  text-align: left; overflow-wrap: anywhere;
}
.xp-eg em { font-style: normal; font-weight: 700; color: var(--ink); }
.xp-list { margin: 0; padding-inline-start: 18px; display: grid; gap: 5px; }
.xp-list li { font-size: .86rem; color: var(--ink-2); line-height: 1.6; }
.xp-list b { font-family: var(--font-de); color: var(--ink); }
.xp-order {
  font-size: .72rem; color: var(--ink-3);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 5px; padding: 1px 6px; display: inline-block;
  /* On a phone this wraps under its connector rather than pushing the row wide. */
  max-width: 100%; overflow-wrap: anywhere;
}

/* A long sentence taken apart: main clause, then the clause hanging off it. */
.xp-split { display: grid; gap: 5px; }
.xp-split + .xp-split { margin-top: 10px; }
.xp-split > div {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 7px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 8px; padding: 7px 10px;
}
.xp-split span[lang="de"] {
  font-family: var(--font-de); font-size: .85rem; color: var(--ink);
  text-align: left;
  flex: 1; min-width: 0; overflow-wrap: anywhere;
}
.xp-tag {
  flex: none; font-size: .68rem; font-weight: 800;
  color: var(--signal-deep); background: var(--signal-wash);
  border-radius: 5px; padding: 2px 7px;
}
.xp-tag.alt { color: var(--ink-2); background: var(--line); }
html[data-theme="dark"] .xp-tag { color: var(--signal); }
.xp-note { margin: 2px 0 0; font-size: .78rem; color: var(--ink-3); }
.xp-note b { font-family: var(--font-de); color: var(--ink-2); }


.gloss-tip {
  position: absolute; z-index: 150;
  display: flex; flex-direction: column; gap: 2px;
  background: var(--canvas); color: #EAF2F4;
  padding: 9px 13px; border-radius: 10px;
  font-size: .85rem; max-width: 260px;
  box-shadow: var(--shadow-lift);
  opacity: 0; transform: translateY(3px);
  transition: opacity .14s var(--ease), transform .14s var(--ease);
  pointer-events: none;
}
.gloss-tip.in { opacity: 1; transform: none; }
.gloss-tip b { font-family: var(--font-de); color: var(--signal); font-size: .9rem; }

/* --------------------------------------------------------- exam date */

.exam-section { margin-bottom: 26px; }

.exam-set {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; flex-wrap: wrap;
  border: 1px dashed var(--ink-3); border-radius: var(--radius-lg);
  padding: 26px 28px; background: var(--surface);
}
.exam-set-copy h3 { margin: 0 0 6px; font-size: 1.22rem; }
.exam-set-copy p { margin: 0; color: var(--ink-3); font-size: .93rem; max-width: 48ch; }
.exam-set-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.exam-set-form.inline { margin-top: 12px; }
.exam-set-form input, .exam-set-form select {
  padding: 10px 13px; border-radius: 10px; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink); font: inherit; font-size: .9rem;
}

.exam-count {
  display: grid; grid-template-columns: minmax(200px, .7fr) minmax(0, 1.3fr);
  gap: 28px; align-items: start;
  border-radius: var(--radius-lg); padding: 28px;
  background: var(--canvas); color: #EAF2F4;
  position: relative; overflow: hidden;
}
.exam-count::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(500px 260px at 88% -20%, rgba(100, 163, 193, .16), transparent 65%);
  pointer-events: none;
}
.exam-count.hot::before { background: radial-gradient(500px 260px at 88% -20%, rgba(242, 160, 150, .22), transparent 65%); }
.exam-count > * { position: relative; }
@media (max-width: 820px) { .exam-count { grid-template-columns: 1fr; gap: 20px; } }

.exam-kicker { font-size: .82rem; color: rgba(234, 242, 244, .6); display: block; margin-bottom: 6px; }
.exam-days { display: flex; align-items: baseline; gap: 9px; margin-bottom: 4px; }
.exam-days b {
  font-family: var(--font-de); font-size: clamp(3rem, 7vw, 4.4rem);
  font-weight: 700; line-height: 1; letter-spacing: -.04em; color: var(--signal);
}
.exam-count.hot .exam-days b { color: #F2A49C; }
.exam-days span { font-size: .95rem; color: rgba(234, 242, 244, .7); }
.exam-count .count-note { color: rgba(234, 242, 244, .62); display: block; margin-bottom: 10px; }
.exam-count .btn.ghost { color: rgba(234, 242, 244, .7); }
.exam-count .btn.ghost:hover { background: rgba(234, 242, 244, .1); }

.exam-count-plan h3 { margin: 0 0 14px; font-size: 1rem; color: rgba(234, 242, 244, .85); }
.exam-focus { list-style: none; margin: 0 0 16px; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.exam-focus li { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; font-size: .93rem; }
.ef-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--signal); flex: none; }
.exam-focus b { font-weight: 600; }
.exam-focus .count-note { color: rgba(234, 242, 244, .66); display: inline; margin: 0; }
.exam-count .btn.secondary { color: #EAF2F4; border-color: rgba(234, 242, 244, .28); }
.exam-locked p { margin: 0 0 12px; font-size: .93rem; color: rgba(234, 242, 244, .75); }
.exam-focus.preview { opacity: .9; }

/* -------------------------------------------------------- misc v2 bits */

.plan-note { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 16px; font-size: .87rem; }
#levelScopeNote { font-size: .86rem; color: var(--ink-3); margin: 0 0 14px; }

@media (max-width: 700px) {
  /* Same reason as the desktop rule: nothing fills the bottom any more. */
  .hero-dark { padding-block: 44px 52px; }
  .demo { padding: 18px; }
  .lvl-card { padding: 22px; }
  .lvl-tag { font-size: 2.6rem; }
  .cta-final { padding: 28px 22px; }
  .exam-count, .exam-set { padding: 20px; }
  .xp-btn { opacity: 1; }
}

/* ═════════════════════════════════════════════════ embedded exam mode */

/* An exercise opened inside the simulator is a fragment of another page,
   not a page of its own: it must not bring a second header, footer,
   breadcrumb trail or tab bar with it. */
html[data-embed] .site-header,
html[data-embed] .site-footer,
html[data-embed] .tabbar,
html[data-embed] .crumbs,
html[data-embed] .pager,
html[data-embed] .skip-link { display: none !important; }

html[data-embed] body { padding-bottom: 0; }
html[data-embed] .page-head { padding-top: 0; margin-bottom: 18px; }
html[data-embed] .wrap,
html[data-embed] .wrap-narrow { padding-inline: 16px; max-width: none; }
html[data-embed] .sticky-side { position: static; max-height: none; }

/* On mobile the tab bar already carries the daily challenge, so the header
   button beside it is a duplicate of the same destination. */
@media (max-width: 940px) {
  .cta-mini { display: none; }
}

/* ═══════════════════════════════════════════ inverted surfaces (colour fix)

   Root cause of the "phrases inherit the wrong theme colour" bug: several
   surfaces are permanently dark regardless of theme (the hero, the exam
   countdown, the closing CTA, the homepage demo, tooltips). Any component
   dropped on them still resolved --ink-2 / --muted / --line against the *page*
   theme, so in light mode dark-grey text landed on a near-black card.

   Fixed at the source by re-declaring the token set for those surfaces, so
   every current and future component inherits correct colours automatically
   instead of each phrase being patched by hand.                            */

.hero-dark,
.exam-count,
.cta-final,
.demo,
.gloss-tip,
.gloss-onboard {
  --ink: #EAF2F4;
  --ink-2: rgba(234, 242, 244, .76);
  --ink-3: rgba(234, 242, 244, .72);
  --muted: rgba(234, 242, 244, .72);
  --ink-soft: rgba(234, 242, 244, .76);
  --line: rgba(234, 242, 244, .18);
  --line-soft: rgba(234, 242, 244, .12);
  --surface: rgba(234, 242, 244, .07);
  --surface-2: rgba(234, 242, 244, .1);
  --paper-2: rgba(234, 242, 244, .1);
  /* --paper is the ground, and on an inverted surface the ground is dark.
     It was never re-declared here, so .btn.accent — background var(--ink),
     colour var(--paper) — put the page's own near-white text on the
     inverted near-white ink: the hero's primary button was invisible in
     light mode. It now reads light-on-dark, which is what it always looked
     like in dark mode. */
  --paper: var(--canvas);
  /* the paper-safe variant is unreadable here; use the bright signal. The
     mid band clears 3:1 against the deep one but not 4.5:1, and this token
     ends up on small text, so it is lifted a step for inverted surfaces. */
  --signal: #8FC6E0;
  --signal-deep: var(--signal);
  --accent: var(--signal);
  --accent-ink: var(--signal);
  --brand-ink: var(--signal);
  --accent-soft: rgba(100, 163, 193, .14);
  --brand-soft: rgba(234, 242, 244, .1);
  color: var(--ink);
}

/* Buttons and badges inside an inverted surface. */
.hero-dark .btn.secondary,
.exam-count .btn.secondary,
.cta-final .btn.secondary { color: var(--ink); border-color: var(--line); }
.hero-dark .btn.ghost,
.exam-count .btn.ghost,
.cta-final .btn.ghost { color: var(--ink-2); }
.hero-dark .btn.ghost:hover,
.exam-count .btn.ghost:hover,
.cta-final .btn.ghost:hover { background: rgba(234, 242, 244, .1); color: var(--ink); }
.hero-dark .badge,
.exam-count .badge,
.demo .badge { background: rgba(234, 242, 244, .1); color: var(--ink-2); border-color: transparent; }
.hero-dark .count-note,
.exam-count .count-note { color: var(--ink-3); }


/* ═══════════════════════════════════════════════ teaching explanation */

.pr-why.teach { padding: 0; background: transparent; }
.pr-why.teach .pr-why-t {
  display: block; padding: 11px 14px;
  background: var(--surface); border-radius: 10px 10px 0 0;
  border: 1px solid var(--line); border-bottom: 0;
  font-size: .8rem; font-weight: 700; color: var(--ink);
}
.pr-why.teach .pr-why-t [lang="de"] { color: var(--ink-3); font-weight: 600; }

.tx-row {
  display: grid; grid-template-columns: 92px minmax(0, 1fr);
  gap: 12px; align-items: baseline;
  padding: 11px 14px;
  background: var(--surface);
  border: 1px solid var(--line); border-top: 0;
  font-size: .89rem;
}
.tx-row:last-child { border-radius: 0 0 10px 10px; }
.tx-l {
  font-size: .72rem; font-weight: 700; letter-spacing: .01em;
  padding: 2px 0; color: var(--ink-3);
}
.tx-row p { margin: 0; line-height: 1.75; color: var(--ink-2); }
.tx-row.bad .tx-l { color: var(--bad); }
.tx-row.ok .tx-l { color: var(--ok); }
.tx-row.rule .tx-l, .tx-row.applied .tx-l { color: var(--accent-ink); }
html[data-theme="dark"] .tx-row.rule .tx-l,
html[data-theme="dark"] .tx-row.applied .tx-l { color: var(--signal); }
.tx-row.ex { background: var(--paper-2); }
.tx-row.ex p { font-family: var(--font-de); direction: ltr; text-align: left; }
.tx-row.ex b { color: var(--ink); font-weight: 700; }

@media (max-width: 620px) {
  .tx-row { grid-template-columns: 1fr; gap: 3px; padding: 10px 12px; }
}

/* ═══════════════════════════════════════════════ recording indicator

   This was a full-width sentence styled as prose and placed directly under the
   live transcript, so learners read it as something the microphone had heard.
   It is now unmistakably instrumentation: a chip, a meter driven by real input
   level, and a short verdict on whether we can hear anything at all. */

.rec-strip {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  margin-top: 12px; padding: 9px 12px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface);
}
.rec-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: .72rem; font-weight: 700; letter-spacing: .02em;
  color: var(--ink-2); white-space: nowrap;
}
.rec-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--bad); flex: none;
  animation: recPulse 1.3s ease-in-out infinite;
}
@keyframes recPulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .45; transform: scale(.82); } }
@media (prefers-reduced-motion: reduce) { .rec-dot { animation: none; } }

/* Twelve bars, lit in proportion to measured input level. */
.rec-meter { display: inline-flex; align-items: flex-end; gap: 2px; height: 16px; flex: none; }
.rec-meter i {
  display: block; width: 3px; height: 5px; border-radius: 1px;
  background: var(--line);
  transition: height .08s linear, background .08s linear;
}
.rec-meter i.on { background: var(--signal-deep); height: 14px; }
.rec-meter i:nth-child(n+9).on { background: var(--bad); }

.rec-hear { font-size: .72rem; font-weight: 600; color: var(--ink-3); }
.rec-hear.ok { color: var(--signal-deep); }
.rec-hear.warn { color: #B4541A; }
html[data-theme="dark"] .rec-hear.ok { color: var(--signal); }
html[data-theme="dark"] .rec-hear.warn { color: #F2A25C; }

.rec-note { font-size: .7rem; color: var(--ink-3); margin-inline-start: auto; }
@media (max-width: 620px) { .rec-note { display: none; } }

/* Captioned, so nothing else in this column can be taken for the transcript. */
.sp-livewrap {
  margin-top: 10px; padding: 10px 12px;
  border: 1px dashed var(--line); border-radius: 10px;
  background: var(--surface);
}
.sp-livecap {
  display: block; font-size: .68rem; font-weight: 700;
  color: var(--ink-3); margin-bottom: 4px;
}
.sp-live {
  margin: 0; font-family: var(--font-de);
  font-size: .95rem; color: var(--ink); line-height: 1.5;
}

.mic-btn.listening { background: var(--bad); color: #fff; }
html[data-theme="dark"] .mic-btn.listening { color: #fff; }

/* ════════════════════════════════════════════ explain control + gloss */

.xp-ico { width: 12px; height: 12px; flex: none; }
.xp-label { font-size: .64rem; font-weight: 700; }
/*
 * The label survives on a phone. The old button was "A⇄ع", which could just
 * about be guessed from the two scripts in it; a lightbulb on its own says
 * nothing at all, and a phone is where most of these readers are.
 */
@media (max-width: 620px) { .xp-btn { padding: 0 6px; } }

/* Tappable words must look tappable before anyone explains them. */
.gw {
  cursor: pointer;
  border-bottom: 1.5px dotted color-mix(in srgb, var(--signal-deep) 70%, transparent);
  border-radius: 2px;
  transition: background .12s var(--ease);
}
.gw:hover { background: var(--signal-wash); }
html[data-theme="dark"] .gw:hover { background: rgba(100, 163, 193, .14); }
.gw-demo {
  background: var(--signal-wash);
  box-shadow: 0 0 0 3px var(--signal-wash);
  border-radius: 3px;
  animation: gwBlink 1.6s ease-in-out 3;
}
@keyframes gwBlink { 0%, 100% { background: var(--signal-wash); } 50% { background: color-mix(in srgb, var(--signal) 45%, transparent); } }
@media (prefers-reduced-motion: reduce) { .gw-demo { animation: none; } }

.gloss-onboard {
  display: flex; align-items: flex-start; gap: 12px;
  background: var(--canvas);
  border-radius: 12px; padding: 14px 16px; margin-bottom: 14px;
  animation: trIn .22s var(--ease) both;
}
.gloss-onboard b { display: block; font-size: .93rem; margin-bottom: 3px; color: var(--ink); }
.gloss-onboard p { margin: 0; font-size: .85rem; line-height: 1.7; color: var(--ink-2); }
.gloss-onboard > div { flex: 1; min-width: 0; }
.go-arrow { color: var(--signal); font-size: 1.1rem; line-height: 1.4; }
.go-ico {
  font-family: var(--font-de); font-size: .76rem; font-weight: 700;
  background: rgba(234, 242, 244, .14); color: var(--signal);
  padding: 1px 6px; border-radius: 5px; display: inline-block;
}
/* The one action on this card, so it is filled rather than outlined — a ghost
   button next to two lines of explanation reads as optional, and a reader who
   does not dismiss this keeps seeing it. */
.go-x {
  flex: none; align-self: center;
  border: 1px solid transparent; background: var(--signal);
  color: var(--canvas); border-radius: 8px; padding: 6px 14px;
  font: inherit; font-size: .8rem; font-weight: 800; cursor: pointer;
  box-shadow: 0 0 12px color-mix(in srgb, var(--signal) 50%, transparent);
  transition: box-shadow .15s var(--ease), filter .15s var(--ease);
}
.go-x:hover {
  filter: brightness(1.08);
  box-shadow: 0 0 18px color-mix(in srgb, var(--signal) 75%, transparent);
}
.go-x:focus-visible { outline: 2px solid var(--paper); outline-offset: 2px; }

/* ═════════════════════════════════════ Lesen: text scrolls, answers stay */

/* The reading column gets its own scroll so the answer rail beside it never
   leaves the screen — the drag target is always in view. */
.exercise-layout .panel.reading-scroll {
  max-height: calc(100vh - 130px);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}
.exercise-layout .panel.reading-scroll::-webkit-scrollbar { width: 8px; }
.exercise-layout .panel.reading-scroll::-webkit-scrollbar-thumb {
  background: var(--line); border-radius: 8px;
}

.sticky-side .option-bank,
.sticky-side .word-bank,
.sticky-side .gap-list { max-height: calc(100vh - 300px); }

.answers-hint {
  font-size: .78rem; color: var(--ink-3);
  margin: -6px 0 12px;
}

@media (max-width: 960px) {
  .exercise-layout .panel.reading-scroll { max-height: none; overflow: visible; }
  /* On small screens a fixed rail would eat the screen, so the answers dock
     to the bottom instead and stay reachable while the text scrolls. */
  .exercise-layout .sticky-side {
    position: sticky; bottom: 0; top: auto;
    z-index: 40;
    max-height: 46vh; overflow-y: auto;
    box-shadow: 0 -8px 24px -12px rgba(12, 13, 12, .3);
  }
  html[data-theme="dark"] .exercise-layout .sticky-side { box-shadow: 0 -8px 24px -12px rgba(0, 0, 0, .7); }
  html[data-theme="dark"] .exercise-layout[data-sprechen] .sticky-side { box-shadow: none; }
  .sticky-side .option-bank, .sticky-side .word-bank, .sticky-side .gap-list { max-height: none; }
  /* Docking is for answers the learner reaches for while reading the passage
     above them. The Sprechen column holds the Teil list — reference, read once
     — so pinning it to the bottom of a phone gives a short static list its own
     scrollbar and takes 46vh of the screen to do it. */
  .exercise-layout[data-sprechen] .sticky-side {
    position: static; bottom: auto; top: auto;
    max-height: none; overflow-y: visible;
    box-shadow: none; z-index: auto;
  }
  body { padding-bottom: 68px; }
}

/* ═══════════════════════════════════════════ bilingual concept labels */

.cl { display: inline-flex; flex-direction: column; gap: 1px; }
.cl b { font-size: inherit; }
.cl em {
  font-style: normal; font-family: var(--font-de); direction: ltr;
  font-size: .78em; color: var(--ink-3); font-weight: 600;
}
.badge .cl { flex-direction: row; gap: 5px; align-items: baseline; }
.badge .cl em { font-size: .9em; opacity: .8; }

.cl-de { display: block; font-style: normal; font-family: var(--font-de); direction: ltr; font-size: .72rem; color: var(--ink-3); font-weight: 600; }


/* ═══════════════════════════════════════════════════════ exam sizing

   Density. A Prüfung is read closely, but the page was spending the screen on
   everything except the exam: on a 375px phone the first question began at
   y=1194, and 327 of those pixels were heading, crumbs, quicknav and
   instructions stacked above a passage that had not started yet. On a 1440px
   desktop the passage column was 855px inside a 1360px shell while the prose
   ran to 1546px against a 782px window, so the reader scrolled a narrow
   column inside a page that had room to spare.

   So: the shell is wider, the padding is smaller, the type is a step down but
   still sized for sustained reading, and the chrome above the exam is cut to
   what earns its height. Everything is scoped to .exam-wrap, so no other page
   moves. */

.exam-wrap { max-width: 1560px; }

.exam-wrap .exercise-layout {
  /* Same swap as above: answers in column 1 (right), passage in column 2.
     The passage takes more of the extra width than the answers do — options
     are short lines that only get harder to scan as they stretch. */
  grid-template-columns: minmax(320px, .72fr) minmax(0, 1.85fr);
  gap: 16px;
}

.exam-wrap .panel { padding: 16px 18px; }
.exam-wrap .panel + .panel { margin-top: 10px; }

/* The chrome above the exam. The title is already in the tab, the crumbs and
   the quicknav; at 2.4rem it was repeating itself in the largest type on the
   page. */
.exam-wrap .crumbs { padding-top: 12px; }

/*
 * One row, not four.
 *
 * The head stacked a badge row, an h1 and a question count as three full-width
 * blocks, so on a wide screen the title sat alone on the right of 1500px of
 * nothing and the count sat alone under it. Nothing is removed — level,
 * section, name and count are all still there — they just share a line and
 * sit at its two ends instead of each claiming a row of their own.
 */
.exam-wrap .page-head {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 14px;
  padding: 6px 0 10px; margin-bottom: 12px;
}
.exam-wrap .page-head h1 {
  margin: 0; font-size: clamp(1.25rem, 2.2vw, 1.6rem);
  flex: 0 1 auto; min-width: 0;
}
/* The badges follow the name; the count is pushed to the far end of the row. */
.exam-wrap .page-head .meta { margin: 0; }
.exam-wrap .page-head .meta:last-child { margin-inline-start: auto; }
.exam-wrap .instructions {
  font-size: .88rem; line-height: 1.6; padding: 9px 12px; margin-bottom: 11px;
}

/* The German passage itself. */
.exam-wrap .prose { font-size: 1.01rem; line-height: 1.62; }
.exam-wrap .prose p { margin: 0 0 .72em; }
.exam-wrap .prose h2 { font-size: 1.08rem; }
.exam-wrap .prose h3, .exam-wrap .prose h4 { font-size: 1rem; }

/* Everything the learner has to act on: options, chips, gaps, headings. */
.exam-wrap .chip { font-size: .91rem; padding: 6px 11px; }
.exam-wrap .opt, .exam-wrap .option { font-size: .93rem; line-height: 1.45; padding: 6px 9px; }
.exam-wrap .opt input { margin-top: 3px; }
.exam-wrap .q-card { padding: 10px 12px; margin-bottom: 8px; }
.exam-wrap .q-card h3 { margin: 0 0 6px; font-size: .9rem; line-height: 1.4; }
.exam-wrap .option-bank { gap: 5px; }
.exam-wrap .match-item { padding-bottom: 4px; }
.exam-wrap .solution { font-size: .88rem; }
.exam-wrap .answers-hint { font-size: .78rem; }
.exam-wrap .panel h2 { font-size: .98rem; margin: 0 0 9px; }

/* Taller reading viewport, since the shell above it is shorter than it was. */
.exam-wrap .exercise-layout .panel.reading-scroll { max-height: calc(100vh - 92px); }

/*
 * The pager was justify-content: space-between across the full shell, which at
 * 1560px put "previous" and "next" a metre apart with a void between them.
 * They sit together now, centred, where a thumb or a cursor can reach both.
 */
.exam-wrap .pager { justify-content: center; gap: 10px; margin: 18px 0 8px; }

/* ── Arabic under the Optionen ──────────────────────────────────────────
   The German keeps its weight and its place; the Arabic sits under it a step
   smaller and lighter, the same relationship the Redemittel use. It is a
   second line inside the same label, so clicking it still selects the answer
   rather than doing nothing. */
.opt { flex-wrap: wrap; }
/*
 * Quiet, but not invisible.
 *
 * The first version was .84em in --ink-3: 12.5px of grey under 14.9px of
 * near-black, the smallest and faintest thing in the panel. It passed contrast
 * at 6.3:1 and was still missed entirely by the first person to look for it,
 * which is the only test that counts. It stays subordinate to the German —
 * that is the point of the pairing — but it is now a step larger, a step
 * darker, and separated from the line above rather than tucked under it.
 */
.opt-ar {
  flex: 1 0 100%;
  font-family: var(--font-ar, inherit);
  font-size: .92em; line-height: 1.5; color: var(--ink-2);
  direction: rtl; text-align: right;
  margin-top: 4px; padding-inline-start: 22px;
}
.opt.is-correct .opt-ar, .opt.is-wrong .opt-ar { color: inherit; opacity: .75; }
body.opt-ar-off .opt-ar { display: none; }

/* The question in Arabic, under the German question it belongs to. */
.q-ar {
  margin: 3px 0 9px; font-size: .86rem; line-height: 1.5;
  color: var(--ink-2); direction: rtl; text-align: right;
}
body.opt-ar-off .q-ar { display: none; }

/* A gap's three choices sit side by side, so each keeps its Arabic inside
   itself on a second line rather than pushing the row apart. */
.opts .chip { display: inline-flex; flex-direction: column; align-items: flex-start; }
.opts .chip .opt-ar { padding-inline-start: 0; margin-top: 2px; font-size: .8em; }

/* A chip is a button, so its Arabic goes inside it on a line of its own. */
.option-bank .chip { display: block; width: 100%; text-align: start; }
.option-bank .chip .opt-ar { display: block; padding-inline-start: 0; margin-top: 2px; }

.opt-ar-bar { display: flex; justify-content: flex-end; margin: 0 0 7px; }
.opt-ar-btn {
  background: none; border: 1px solid var(--line); color: var(--ink-3);
  border-radius: 100px; padding: 3px 11px; font: inherit; font-size: .74rem;
  font-weight: 700; cursor: pointer;
}
.opt-ar-btn:hover:not(:disabled) { color: var(--ink); border-color: var(--ink-3); }
.opt-ar-btn:disabled { opacity: .6; cursor: default; }
.opt-ar-note { font-size: .74rem; color: var(--ink-3); line-height: 1.5; }

@media (max-width: 960px) {
  .exam-wrap .exercise-layout { grid-template-columns: 1fr; }
  .exam-wrap .panel { padding: 12px 13px; }
  .exam-wrap .prose { font-size: .99rem; }
  /*
   * On a phone the passage is given a window instead of the whole page.
   *
   * Stacked, the passage sits above the questions, so its full height is
   * something the reader scrolls past before reaching anything to answer —
   * the first question began at y=1119 on a 812px screen. Capped at 62vh it
   * still shows a solid block of German and scrolls inside itself, and the
   * questions start about one screen in rather than one and a half.
   */
  .exam-wrap .exercise-layout .panel.reading-scroll {
    max-height: 62vh; overflow-y: auto; overscroll-behavior: contain;
  }
  /*
   * The head said everything three times. The crumbs read
   * "الرئيسية / B2 / Lesen Teil 2 / Puppenmacher", the badge row underneath
   * repeated "B2" and "Lesen Teil 2", and the h1 repeated "Puppenmacher".
   * On a phone that is a screenful of the same four words. The two German
   * badges go; the exercise-type badge stays, because it is the only thing
   * in the row the crumbs do not already say.
   */
  .exam-wrap .page-head .meta .badge.de { display: none; }

  /* On a phone every pixel above the passage is a pixel of scrolling. */
  .exam-wrap .crumbs { padding-top: 9px; font-size: .76rem; }
  .exam-wrap .page-head { padding: 6px 0 9px; margin-bottom: 10px; gap: 4px 10px; }
  .exam-wrap .instructions { margin-bottom: 9px; padding: 8px 11px; }
}


/* ═════════════════════════════════════ the exam paper inside the simulator

   Embedded in the exam shell, the page heading repeats what the simulator's
   own bar already says — level, section, title — and cost 146px of height
   between the learner and the paper. Hidden here, both columns then scroll
   independently against the shell, so the passage and the answers stay side
   by side for the whole section. */

html[data-embed] .exam-wrap .page-head { display: none; }
html[data-embed] .exam-wrap .instructions { margin-bottom: 12px; }

html[data-embed] .exam-wrap .exercise-layout .panel.reading-scroll {
  max-height: calc(100vh - 120px);
}
html[data-embed] .exam-wrap .sticky-side {
  position: sticky; top: 0;
  max-height: calc(100vh - 120px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

@media (max-width: 960px) {
  html[data-embed] .exam-wrap .exercise-layout .panel.reading-scroll,
  html[data-embed] .exam-wrap .sticky-side {
    max-height: none; overflow: visible; position: static;
  }
}

/* ═══════════════════════════════════ Sprechen Teil 2 reading text

   Teil 2 starts from a magazine article the candidate reads before
   discussing it. It is marked up like the Lesen passages, so it inherits the
   same tap-a-word gloss and translate affordances rather than inventing a
   second reading experience. */

.sp-stimulus { margin-bottom: 18px; }
.sp-stim-instruction {
  margin: 0 0 14px; padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-de); font-size: .88rem; line-height: 1.65;
  color: var(--ink-3);
}
/* The German passage, folded. The label carries the meaning — an arrow alone
   says "something is here" without saying what — and the arrow turns a quarter
   when it opens so the state is readable at a glance. */
.sp-stim-fold { margin-top: 6px; }
/* Lifted with the site's own signal wash, the same treatment the plan notice
   and the activation instruction use. A plain bordered row read as decoration
   and said nothing about what pressing it would do — and the text behind it is
   the thing the exam is about, so it is not a row to skim past. */
.sp-stim-fold > summary {
  display: flex; align-items: center; gap: 11px;
  padding: 13px 15px; border-radius: 14px;
  border: 2px solid var(--signal);
  background: var(--signal-wash); color: var(--accent-ink);
  cursor: pointer; list-style: none; user-select: none;
  /* Lit rather than outlined. This is the text the exam is about and it ships
     folded on a phone, so a visitor who does not notice it never reads the
     thing they came for. Steady, not pulsing — the glow is strong enough to
     find without moving, and movement in the middle of a reading task is the
     kind of thing that gets a page closed. */
  box-shadow:
    0 0 20px color-mix(in srgb, var(--signal) 70%, transparent),
    0 0 4px color-mix(in srgb, var(--signal-deep) 35%, transparent),
    inset 0 0 14px color-mix(in srgb, var(--signal) 20%, transparent);
}
/* Opened, it settles: once a reader has found it, it no longer needs to
   announce itself. */
.sp-stim-fold[open] > summary {
  animation: none;
  border-color: color-mix(in srgb, var(--signal) 55%, transparent);
  box-shadow: none;
}

.sp-stim-fold > summary::-webkit-details-marker { display: none; }
.sp-stim-fold > summary:hover { border-color: var(--signal-deep); }
.sp-stim-fold > summary:focus-visible { outline: 2px solid var(--signal-deep); outline-offset: 2px; }
.sp-stim-sum-t { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sp-stim-sum-t b { font-weight: 800; font-size: .92rem; }
/* The hint carries the instruction, and swaps with the state — a reader should
   never have to work out what the arrow means. */
.sp-stim-sum-h { font-size: .78rem; color: var(--accent-ink); opacity: .78; line-height: 1.5; }
.sp-stim-fold > summary .sum-open { display: none; }
.sp-stim-fold[open] > summary .sum-closed { display: none; }
.sp-stim-fold[open] > summary .sum-open { display: inline; }
.sp-stim-chev {
  flex: none; color: var(--signal-deep); font-size: 1.05rem; line-height: 1;
  transition: transform .16s var(--ease);
}
/* Pointing down when there is more to see, up once it is open. */
.sp-stim-fold[open] > summary .sp-stim-chev { transform: rotate(180deg); }
.sp-stim-fold[open] > summary { margin-bottom: 4px; }

.sp-stim-title {
  margin: 0 0 14px !important;
  font-family: var(--font-read); font-size: 1.35rem; font-weight: 700;
  color: var(--ink); text-align: center;
}
.sp-stim-text { font-size: 1.04rem; line-height: 1.8; }
.sp-stim-text p { margin: 0 0 .9em; }
.sp-stim-text p:last-child { margin-bottom: 0; }

/* Teil 3 restates its task in the rail so it can be re-read while planning. */
.sp-task {
  margin: 0 0 12px; padding: 10px 12px;
  border-inline-start: 3px solid var(--signal-deep);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--surface-2, var(--surface));
  font-family: var(--font-de); font-size: .84rem; line-height: 1.6;
  color: var(--ink-2);
}

/* The telc requirements for one Teil. Collapsed by default: a learner who
   already knows the format should not have to scroll past it every session,
   and one who does not is a tap away. */
.sp-telc { margin: 0 0 12px; }
.sp-telc > summary {
  cursor: pointer; list-style: none;
  padding: 7px 10px; border-radius: var(--radius-sm);
  background: var(--surface-2, var(--surface));
  border-inline-start: 3px solid var(--signal);
  font-size: .82rem; font-weight: 600; color: var(--ink-2);
}
.sp-telc > summary::-webkit-details-marker { display: none; }
.sp-telc > summary::after {
  content: '+'; float: inline-end; opacity: .6; font-weight: 700;
}
.sp-telc[open] > summary::after { content: '−'; }
.sp-telc > summary:hover { color: var(--ink); }
.sp-telc > summary:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.sp-telc-list {
  margin: 8px 0 0; padding-inline-start: 20px;
  font-size: .82rem; line-height: 1.75; color: var(--ink-2);
}
.sp-telc-list li { margin: 0 0 5px; }

@media (max-width: 620px) {
  .sp-stim-title { font-size: 1.15rem; }
  .sp-stim-text { font-size: 1rem; }
}


/* The two speakers in a B1 Teil 2 theme read as labelled positions rather
   than as another paragraph of the same argument. */
.sp-speaker {
  margin: 0 0 .3em !important;
  font-size: .84rem; color: var(--ink-3);
}
.sp-speaker b { color: var(--ink-2); font-weight: 700; }
.sp-speaker + p { margin-top: 0; }
.sp-stim-text p + .sp-speaker { margin-top: 1.2em !important; }


/* The seven Teil 1 themes: a list to choose from, not prose. */
.sp-stim-kicker {
  display: block; margin-bottom: 10px;
  font-size: .7rem; font-weight: 700; letter-spacing: .04em;
  /* signal-deep is only 2.80 on the panel surface at this size. */
  color: var(--accent-ink); text-transform: uppercase;
}
.sp-themen {
  margin: 0; padding-inline-start: 20px;
  font-family: var(--font-de); direction: ltr; text-align: left;
}
.sp-themen li { margin: 0 0 .55em; line-height: 1.55; font-size: .98rem; color: var(--ink); }
.sp-themen li:last-child { margin-bottom: 0; }
.sp-themen em { font-style: normal; color: var(--ink-3); font-size: .9em; }
.sp-teil1 { border-inline-start: 3px solid var(--signal-deep); }

@media (max-width: 620px) { .sp-themen li { font-size: .93rem; } }


/* ═══════════════════════════════ Sprechen access states

   A learner should be able to read the list once and know where they stand:
   what they may practise now, what they have finished, and what their plan has
   not opened. A finished theme is dimmed but never hidden — it is still worth
   opening to reread the feedback. */

.sp-state:empty { display: none; }
.sp-state.practice { background: var(--ok-bg); color: var(--ok); border-color: transparent; }
.sp-state.review   { background: var(--surface-2); color: var(--muted); border-color: transparent; }
.sp-state.locked   { background: var(--surface-2); color: var(--muted); border-color: transparent; }

.card.sp-locked { opacity: .9; }
.card.sp-locked:hover { transform: none; border-color: var(--line); }
.card.sp-review { opacity: .82; }

.sp-summary { margin: 0 0 18px; }
.sp-sum {
  display: block; padding: 12px 15px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); font-size: .88rem; line-height: 1.7; color: var(--ink-2);
}
.sp-sum b { color: var(--ink); }
.sp-sum.pro { border-inline-start: 3px solid var(--signal-deep); }

.sp-gate { margin-bottom: 16px; padding: 18px; border-radius: var(--radius); background: var(--surface-2); }
.sp-gate h2 { margin: 0 0 8px; font-size: 1.05rem; font-weight: 800; }
.sp-gate p { margin: 0 0 12px; font-size: .9rem; line-height: 1.7; color: var(--ink-2); }
.sp-gate.locked { text-align: center; }
.sp-gate .locked-actions { display: flex; flex-wrap: wrap; gap: 9px; justify-content: center; }

.sp-review-panel { margin-bottom: 16px; }
.sp-review-head { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; margin-bottom: 14px; }
.sp-review-kicker { font-size: .74rem; font-weight: 700; color: var(--muted); }
.sp-review-score { display: flex; align-items: baseline; gap: 7px; }
.sp-review-score b { font-family: var(--font-de); font-size: 1.5rem; font-weight: 800; }
.sp-review-score.pass b { color: var(--ok); }
.sp-review-score.fail b { color: var(--bad); }
.sp-review-score span { font-size: .82rem; color: var(--muted); }
.sp-review-dq { padding: 10px 13px; border-radius: var(--radius-sm); background: var(--bad-bg); color: var(--bad); font-size: .86rem; }
.sp-review-crit { display: grid; gap: 9px; margin-bottom: 16px; }
.sp-rc { padding: 10px 13px; border: 1px solid var(--line); border-radius: var(--radius-sm); }
.sp-rc-l { font-size: .84rem; font-weight: 700; }
.sp-rc-p { float: inline-end; font-family: var(--font-de); font-size: .84rem; color: var(--muted); }
.sp-rc p { margin: 5px 0 0; font-size: .8rem; line-height: 1.65; color: var(--ink-3); }
.sp-review-h { margin: 0 0 10px; font-size: .95rem; font-weight: 700; }
.sp-review-talk { display: grid; gap: 9px; }
.sp-rt { padding: 10px 13px; border-radius: var(--radius-sm); background: var(--surface-2); }
.sp-rt.me { background: var(--brand-soft); }
.sp-rt-who { font-size: .7rem; font-weight: 700; color: var(--muted); }
.sp-rt p { margin: 3px 0 0; font-family: var(--font-de); font-size: .9rem; line-height: 1.6; }


/* On a phone the columns stack, and the free plan would otherwise push the
   recommended one below the fold. Lead with the recommendation; free is still
   one scroll away. */
@media (max-width: 900px) {
  .plan-grid.three .plan.featured { order: -1; }
}

/* Match yourself to a plan before reading any feature table. */
.plan-pick {
  margin: 0 0 26px; padding: 16px 18px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface);
}
.plan-pick-h { display: block; font-size: .8rem; font-weight: 800; color: var(--muted); margin-bottom: 10px; }
.plan-pick ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.plan-pick li { font-size: .88rem; line-height: 1.7; color: var(--ink-2); }
.plan-pick li b { color: var(--ink); }

/* The same card, carrying an ordered list instead of a set of choices: the
   numbers matter here because the steps only work in this order — the account
   has to exist before there is anything to activate. */
.plan-pick.steps ol {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 12px; counter-reset: step;
}
.plan-pick.steps li {
  counter-increment: step;
  position: relative; padding-inline-start: 34px;
  font-size: .88rem; line-height: 1.7; color: var(--ink-2);
}
.plan-pick.steps li::before {
  content: counter(step);
  position: absolute; inset-inline-start: 0; top: 1px;
  width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--font-de); font-size: .76rem; font-weight: 700;
  background: var(--signal-wash); color: var(--accent-ink);
}
.plan-pick.steps li b { display: block; color: var(--ink); }
.plan-steps-note {
  margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--line-soft);
  font-size: .78rem; line-height: 1.65; color: var(--ink-3);
}

/* ═══════════════════════════════════════════ pricing, ranked

   The card reads in decision order: who it is for, the price, the call to
   action, then what you get — the two or three things that matter set apart
   from the rest, and every line explained in one sentence. */

.plan-for {
  margin: 0 0 16px; padding: 8px 12px;
  border-radius: var(--radius-sm); background: var(--surface-2);
  font-size: .82rem; line-height: 1.55; color: var(--ink-2); text-align: center;
}

.plan-his { list-style: none; margin: 20px 0 4px; padding: 0; display: grid; gap: 11px; }
.plan-hi {
  padding: 11px 13px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface-2);
  border-inline-start: 3px solid var(--brand);
}
.plan-hi-t { display: block; font-size: .9rem; font-weight: 800; color: var(--ink); margin-bottom: 3px; }
.plan-hi-w { display: block; font-size: .8rem; line-height: 1.65; color: var(--ink-2); }
.plan.featured .plan-hi { border-inline-start-color: var(--signal-deep); }

.plan-feats .feat-body { display: block; }
.plan-feats .feat-body b { display: block; font-size: .87rem; font-weight: 700; line-height: 1.5; }
.plan-feats .feat-body em {
  display: block; margin-top: 2px;
  font-style: normal; font-size: .77rem; line-height: 1.6; color: var(--muted);
}
.plan-feats li.no .feat-body b { color: var(--muted); font-weight: 600; }
.plan-feats li.no .feat-body em { color: var(--ink-3); }

@media (max-width: 620px) {
  .plan-hi { padding: 10px 11px; }
  .plan-hi-t { font-size: .86rem; }
}


/* Says the listing is scoped to one level, and offers the way back. Without
   it a learner scoped to B2 sees no B1 and no reason why. */
.scope-note:empty { display: none; }
.scope-note {
  margin: 0 0 10px; padding: 9px 13px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: .82rem; line-height: 1.6; color: var(--ink-2);
}
.scope-note .link-btn {
  border: 0; background: none; padding: 0;
  font: inherit; font-weight: 700; color: var(--brand-ink);
  cursor: pointer; text-decoration: underline;
}


/* ═══════════════════════════════ marking a speaking exam

   Correcting takes a few seconds of real work. The steps shown are the ones
   actually being performed, so the wait reads as progress rather than as a
   page that has stopped responding. */

.sp-analyzing {
  padding: 34px 24px; text-align: center;
  border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--surface);
}
.sp-analyzing h3 { margin: 14px 0 6px; font-size: 1.1rem; font-weight: 800; color: var(--ink); }
.sp-analyzing-step { margin: 0; font-size: .88rem; color: var(--ink-2); min-height: 1.4em; }

.sp-spinner {
  width: 30px; height: 30px; margin: 0 auto;
  border: 3px solid var(--line);
  border-top-color: var(--brand);
  border-radius: 50%;
  animation: spSpin .8s linear infinite;
}
.sp-spinner.sm {
  width: 14px; height: 14px; border-width: 2px; margin: 0;
  display: inline-block; vertical-align: -2px; margin-inline-end: 7px;
}
@keyframes spSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .sp-spinner { animation-duration: 2.4s; }
}

.sp-analyzing-list {
  list-style: none; margin: 20px auto 0; padding: 0;
  max-width: 300px; text-align: start;
}
.sp-analyzing-list li {
  position: relative; padding-inline-start: 24px; margin-bottom: 9px;
  font-size: .82rem; color: var(--ink-3);
  transition: color .25s ease;
}
.sp-analyzing-list li::before {
  content: '○'; position: absolute; inset-inline-start: 0; color: var(--ink-3);
}
.sp-analyzing-list li.on { color: var(--ink); }
.sp-analyzing-list li.on::before { content: '●'; color: var(--brand-ink); }

.sp-refining {
  margin: 0 0 14px; padding: 9px 13px;
  border-radius: var(--radius-sm);
  background: var(--brand-soft); color: var(--brand-ink);
  font-size: .82rem; line-height: 1.5;
}

@media (max-width: 620px) {
  .sp-analyzing { padding: 26px 16px; }
}


/* ---------------------------------------------------------- locked preview

   Paid sections stay on screen. The learner sees the real thing — the set
   names, the counts, the exercise text — dimmed and inert, with the invitation
   above it. Hiding the feature entirely sells nothing; showing it and asking
   for the subscription is the whole point.

   The dimming is deliberately mild. Blur it too hard and the preview stops
   being evidence of anything. */
.locked-preview {
  position: relative;
  margin-top: 14px;
  /* Readable, not ghostly. The lock is communicated by the panel above and the
     🔒 badges — not by making the content too faint to evaluate. Someone
     deciding whether to pay has to be able to actually read what they would
     be paying for. */
  opacity: .92;
  pointer-events: none;      /* mouse; the keyboard is handled by inert */
  user-select: none;
  cursor: pointer;
}
.locked-preview > * { pointer-events: none; }
/* One door left open. A signed-out reader may press the start button — it asks
   for an account rather than starting anything — so the panel's blanket
   pointer-events rule is lifted for that button alone. */
.locked-preview.lock-live-start .actions,
.locked-preview.lock-live-start [data-sp-start] { pointer-events: auto; }
.locked-preview.lock-live-start [data-sp-start] { cursor: pointer; }

/* Said once, after three finished exercises, to an account that has shown it
   is here to work. Sits inside the result box so it reads as the next step
   rather than as an interruption of one. */
.plan-nudge {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 13px;
  border-top: 1px solid color-mix(in srgb, var(--ink) 12%, transparent);
}
.plan-nudge p { margin: 0; font-size: .88rem; line-height: 1.6; }
.plan-nudge .btn { margin-inline-start: auto; }
@media (max-width: 560px) {
  .plan-nudge .btn { margin-inline-start: 0; width: 100%; justify-content: center; }
}

.locked-cta-line { margin: 10px 0 0; font-size: .95rem; }

/* A single locked set inside an otherwise usable menu — the trial case, where
   Artikel and Redewendungen are open and the other two are not. */
.train-card.is-locked { opacity: .9; }
.train-lock {
  display: inline-block; margin-top: 8px;
  font-size: .74rem; font-weight: 600;
  color: var(--ink-2); white-space: nowrap;
}


/* The transcript handed back when marking fails. Selectable and scrollable:
   the learner has just spoken for ten minutes and the words are the one thing
   that must not be lost. */
.sp-raw {
  margin: 12px 0 0; padding: 12px 14px;
  max-height: 320px; overflow: auto;
  border-radius: var(--radius-sm);
  background: var(--surface-2, var(--surface));
  font-family: var(--font-de); font-size: .86rem; line-height: 1.7;
  white-space: pre-wrap; user-select: text;
}


/* --------------------------------------------- German characters bar

   Sits directly above the text box so the connection is obvious. Large enough
   to hit with a thumb — 40px is the usual floor for a touch target, and this
   is used most by learners typing on a phone with a French or Arabic layout. */
.umlaut-bar {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin: 0 0 8px;
}
.umlaut-key {
  min-width: 42px; min-height: 40px;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2, var(--surface));
  color: var(--ink);
  font-family: var(--font-de);
  font-size: 1.05rem; font-weight: 600; line-height: 1;
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
.umlaut-key:hover { border-color: var(--accent); }
.umlaut-key:active { background: var(--accent); color: #111; }
.umlaut-key:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }


/* ------------------------------------------------- mobile menu (top left)

   The bottom bar carries the four things opened daily; everything else lives
   here. On an RTL page the header's action group sits at the visual left, so
   the button placed last in it lands at the top-left corner, which is where
   this menu was asked for.

   The panel slides from the same side as its button rather than from the RTL
   start edge — a drawer that opens away from the control that summoned it
   reads as a different surface. */
.menu-btn { display: none; font-size: 1.15rem; }

.menu-sheet[hidden] { display: none; }
.menu-sheet {
  position: fixed; inset: 0; z-index: 200;
  display: flex;
  /* The document is RTL, so flex-END is the visual left — which is the side
     the button lives on and the side the panel must open from. flex-start
     here would put it on the right, under the brand. */
  justify-content: flex-end;
}
.menu-scrim {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, .45);
  animation: menuFade .16s ease-out;
}
.menu-panel {
  position: relative;
  width: min(84vw, 320px);
  height: 100%;
  overflow-y: auto;
  padding: 14px 14px calc(14px + env(safe-area-inset-bottom));
  background: var(--paper);
  border-inline-start: 1px solid var(--line);
  box-shadow: 0 0 40px rgba(0, 0, 0, .35);
  animation: menuIn .18s ease-out;
  display: flex; flex-direction: column; gap: 2px;
}
@keyframes menuFade { from { opacity: 0 } to { opacity: 1 } }
@keyframes menuIn { from { transform: translateX(-14px); opacity: .6 } to { transform: none; opacity: 1 } }

.menu-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 4px 6px 12px; margin-bottom: 6px;
  border-bottom: 1px solid var(--line);
}
.menu-panel a {
  display: flex; align-items: center; gap: 10px;
  min-height: 46px; padding: 8px 10px;
  border-radius: var(--radius-sm);
  color: var(--ink-2); text-decoration: none; font-size: .95rem;
}
.menu-panel a:hover, .menu-panel a:focus-visible {
  background: var(--surface-2, var(--surface)); color: var(--ink);
}
.menu-i { width: 20px; text-align: center; opacity: .75; }

@media (max-width: 940px) {
  .menu-btn { display: inline-flex; }
  /* The account link is a tab now; two routes to one page is one too many. */
  .site-header .acc-link,
  .site-header .cta-mini { display: none; }

  /* Push the action group to the far edge so the menu button — last in the
     group, and therefore leftmost in RTL — actually reaches the corner it was
     asked to sit in. Without this the level pill leaves it 58px short. */
  .site-header .header-actions { margin-inline-start: auto; }
  .site-header #levelPill { margin-inline-end: auto; }
}
@media (min-width: 941px) {
  /* Desktop keeps the full horizontal nav, so the sheet never opens. */
  .menu-sheet { display: none !important; }
}

/* Sprechen filters — the level and Teil questions, as chips over the results
   instead of two screens in front of them. */
.spn-filters {
  display: flex; flex-wrap: wrap; gap: 10px 18px;
  align-items: center; margin: 0 0 18px;
}
.spn-fgroup { display: flex; flex-wrap: wrap; gap: 8px; }
.spn-fgroup .chip { padding: 8px 14px; border-radius: 999px; }
.spn-c { opacity: .55; font-size: .82em; margin-inline-start: 3px; }
.chip.selected .spn-c { opacity: .7; }
.spn-count { margin: 0 0 14px; }
.spn-more { margin-top: 18px; text-align: center; }

@media (max-width: 560px) {
  .spn-filters { gap: 8px 10px; }
  .spn-fgroup .chip { padding: 7px 12px; font-size: .84rem; }
}

/* The line that says what Sprechen actually is — a spoken exam with a marked
   result — carried as a caption under the title. It is the argument for the
   whole section, so it is set as a statement: the same signal-coloured pill
   the Road section uses for its turn line, wrapped rather than clipped
   because this sentence is long. */
.sp-lede {
  display: inline-block; max-width: 62ch;
  margin: 10px 0 4px; padding: 12px 20px;
  border-radius: 18px;
  background: var(--signal-wash);
  border: 1px solid color-mix(in srgb, var(--signal) 40%, transparent);
  color: var(--accent-ink);
  font-size: .94rem; line-height: 1.75; font-weight: 600;
}
@media (max-width: 560px) {
  .sp-lede { padding: 11px 15px; font-size: .88rem; }
}

/* ────────────────────────────────────────────────────────── footer
   Two lines and nothing else. The link list is gone — the header, the tab bar
   and the pages themselves already carry the navigation, and repeating all
   fourteen destinations at the bottom of every page was the only thing making
   this area large. */
/* The footer as a sitemap, not a receipt.
   It used to be a mark, four links and two legal lines — which said nothing
   about what the site contains and gave a reader who had scrolled to the
   bottom nowhere to go. Now: who we are and how to reach us in the first
   column, then what there is to do, grouped the way the product is grouped.

   The wide column is 1.4fr, not 1fr. It carries a brand lockup, a sentence
   and a row of buttons; at equal width the tagline broke every three words
   while the link columns sat half empty. */
.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr repeat(3, 1fr);
  gap: 32px 28px;
  padding-bottom: 30px; margin-bottom: 22px;
  border-bottom: 1px solid var(--line-soft);
}

.footer-brand { flex: none; margin-bottom: 12px; }
.footer-tag {
  margin: 0 0 18px; max-width: 34ch;
  color: var(--ink-2); font-size: .9rem; line-height: 1.6;
}

/* The English line in the hero. Muted and small — it is not competing with
   the Arabic headline, it is answering "what is this site" for the readers
   and reviewers who cannot read the headline at all. */
.hero-en {
  margin: 12px 0 0; max-width: 54ch;
  color: rgba(247, 250, 252, .74); font-size: .88rem; line-height: 1.6;
}
@media (max-width: 720px) { .hero-en { font-size: .82rem; } }

/* The English one-liner. Quiet, but present on every page — it is what an
   English-speaking reviewer or visitor reads to learn what this site is. */
.footer-en { margin: 8px 0 18px; max-width: 46ch; color: var(--ink-3);
  font-size: .84rem; line-height: 1.6; }

.footer-col-t {
  margin: 0 0 12px;
  font-size: .82rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.footer-col ul { list-style: none; margin: 0; padding: 0; }
.footer-col li + li { margin-top: 9px; }
.footer-col a {
  color: var(--ink-2); text-decoration: none; font-size: .9rem;
  transition: color .15s var(--ease);
}
.footer-col a:hover { color: var(--ink); }
.footer-col a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }
.footer-col a[lang="de"] { font-family: var(--font-de); }

/* ── contact ────────────────────────────────────────────────────────────
   Icon buttons rather than pasted handles: three glyphs read as one group
   at a glance, where three lines of address text read as small print. Each
   carries an aria-label and a title, so neither a screen reader nor a
   hesitating pointer has to guess which is which. */
.footer-social-t {
  display: block; margin-bottom: 10px;
  font-size: .82rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
}
.fsoc-row { display: flex; gap: 10px; }
.fsoc {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px;          /* a comfortable touch target */
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink-2);
  transition: color .15s var(--ease), border-color .15s var(--ease),
              transform .15s var(--ease);
}
.fsoc svg { width: 20px; height: 20px; }
.fsoc:hover {
  color: var(--accent-ink); border-color: var(--accent);
  transform: translateY(-2px);
}
.fsoc:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (max-width: 900px) {
  /* Two columns before one: at 900px the four-across grid gives each link
     column less width than "Sprachbausteine" needs, and every German label
     wraps. */
  .footer-grid { grid-template-columns: 1fr 1fr; gap: 28px 24px; }
  .footer-about { grid-column: 1 / -1; }
}
@media (max-width: 520px) {
  .footer-grid { grid-template-columns: 1fr; gap: 26px; }
  .footer-tag { max-width: none; }
}

.footer-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px 20px; flex-wrap: wrap;
}
.footer-bar p { margin: 0; font-size: .85rem; color: var(--ink-3); }
/* `space-between` puts the first child at the start edge, which under RTL is
   the right — so the domain, written second, settles on the far left as asked,
   and the pair swaps correctly if the document direction ever changes. */
.footer-domain { font-family: var(--font-de); letter-spacing: .01em; }
@media (max-width: 520px) {
  .footer-bar { justify-content: center; text-align: center; gap: 6px; }
}

/* ──────────────────────────────────────────── highlighted notices
   One treatment, two uses: the line that explains what separates the plans,
   and the instruction that a subscription is activated by hand. Both are
   sentences a reader must not skim past, and neither is an error — so they
   are lifted with the site's own signal wash rather than shouted in red. */
.note-hl {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 20px 0 0; padding: 13px 16px;
  border: 1px solid color-mix(in srgb, var(--signal) 42%, transparent);
  border-radius: 14px;
  background: var(--signal-wash);
  color: var(--accent-ink);
  font-size: .88rem; line-height: 1.75; text-align: start;
}
.note-hl b { font-weight: 800; }
.note-hl a { font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }

/* The activation notice is an instruction with a consequence for getting it
   wrong, so it takes the warning colours and a marker. */
.note-hl.warn {
  border-color: var(--warn-line);
  background: var(--warn-bg);
  color: var(--warn);
}
.note-hl-i {
  flex: none; width: 20px; height: 20px; margin-top: 1px;
  border-radius: 50%; display: grid; place-items: center;
  background: var(--warn); color: var(--warn-bg);
  font-size: .74rem; font-weight: 900; line-height: 1;
}

/* On the plan card list the highlighted line replaces a plain footnote, so it
   keeps the divider that separated it from the features above. */
.pc-incl-foot.note-hl {
  display: block; margin-top: 18px; text-align: center;
}

/* The exercise index carries all 578 cards — 6,000 DOM nodes — because every
   one of them is a link a search engine should follow and a filter should be
   able to match without a round trip. Compressed the page is 23 KB, so the
   transfer was never the problem; the cost is laying out and painting cards
   nobody has scrolled to yet.

   content-visibility hands that decision to the browser: off-screen cards keep
   their markup and stay findable by in-page search and by the site's own
   filters, and simply are not rendered until they approach the viewport. The
   intrinsic size is the measured height of a real card, so the scrollbar does
   not lurch as they materialise. */
.ex-grid > .card,
.grid > .card {
  content-visibility: auto;
  contain-intrinsic-size: auto 132px;
}

/* ───────────────────────────────── Sprechen: what to say, and one example
   Two cards, both open. The first version folded the example behind a bare
   line of text and it read as a label rather than a control — the owner of the
   site looked at a theme and concluded the examples had never been written.
   Nothing is hidden here now.

   Both sit on the mint wash with a signal border, which is how the rest of the
   site marks something as help rather than as exam content: the same treatment
   the Redemittel box carries. They are told apart by their headers, not by
   inventing a second accent colour.

   Placement is sprechen.js's job, not a media query's — on a phone these live
   between the question and the record button, on a wide screen they move to
   the right-hand column. See placeGuidance(). */
.sp-guide-pair { display: grid; gap: 10px; margin: 12px 0 0; }

.sp-guide {
  border: 1px solid color-mix(in srgb, var(--signal) 45%, transparent);
  border-radius: var(--radius);
  background: var(--signal-wash);
  overflow: hidden;
}

/* ── card headers, which are also the toggle on a phone ─────────────────── */
.sp-guide-head {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 13px;
  cursor: pointer; list-style: none;
}
.sp-guide-head::-webkit-details-marker { display: none; }
.sp-guide-head::marker { content: ''; }

/* Drawn from two borders rather than set in a glyph: "⌄" renders at a
   different weight and baseline in every font that has it, and rotated 180°
   it reads as "<" instead of pointing up. */
.sp-guide-chev {
  flex: none; margin-inline-start: auto;
  width: 8px; height: 8px; margin-top: -4px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  border-radius: 1px;
  color: var(--ink-3);
  transform: rotate(45deg);
  transition: transform .18s ease, margin-top .18s ease;
}
.sp-guide[open] > .sp-guide-head .sp-guide-chev {
  transform: rotate(225deg); margin-top: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .sp-guide-chev { transition: none; }
}

/* On a wide screen these are not dropdowns at all. They sit in their own
   column, sprechen.js holds them open, and a chevron there would advertise a
   control that does nothing. */
@media (min-width: 961px) {
  .sp-guide-head { cursor: default; pointer-events: none; }
  .sp-guide-chev { display: none; }
}
.sp-guide-badge {
  flex: none; display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: .95rem; line-height: 1;
}
.sp-guide-title { display: grid; gap: 1px; min-width: 0; }
.sp-guide-title b { font-size: .92rem; color: var(--signal-deep); }
.sp-guide-title small { font-size: .75rem; color: var(--ink-2); }

/* ── the points ─────────────────────────────────────────────────────────── */
.sp-guide-list {
  margin: 0; padding: 0 13px 11px; list-style: none;
  display: grid; gap: 6px;
}
.sp-guide-list li {
  display: flex; gap: 9px; align-items: flex-start;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: .87rem; line-height: 1.6; color: var(--ink);
}

/* A number, because these are points to cover in order. A checkmark would
   claim they are already done. */
.sp-guide-n {
  flex: none; display: grid; place-items: center;
  width: 20px; height: 20px; margin-top: 1px;
  border-radius: 50%;
  background: var(--signal-wash); color: var(--signal-deep);
  /* In dark the wash and the card are near neighbours, so the badge needs an
     edge of its own or the number reads as painted straight onto the row. */
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--signal) 40%, transparent);
  font-size: .7rem; font-weight: 700; font-variant-numeric: tabular-nums;
}

/* ── the example ────────────────────────────────────────────────────────── */
/* One row per sentence: the German, and the same sentence in Darija under it.
   Paired line by line rather than as two blocks, so a learner can see which
   German clause carries which piece of the meaning. */
.sp-ex-lines {
  margin: 0 13px; padding: 0; list-style: none;
  display: grid; gap: 7px;
}
.sp-ex-lines li {
  padding: 9px 11px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  border-inline-start: 3px solid var(--signal);
}
.sp-ex-de {
  display: block;
  /* German inside an Arabic page: without its own direction the full stops and
     the "…" migrate to the wrong end of the line. */
  direction: ltr; text-align: left;
  font-size: .87rem; line-height: 1.6; color: var(--ink);
}
.sp-ex-ar {
  display: block; margin-top: 3px;
  padding-top: 3px;
  border-top: 1px dashed var(--line-soft);
  font-size: .79rem; line-height: 1.6; color: var(--ink-2);
}
.sp-guide-swap {
  margin: 0; padding: 8px 13px 11px;
  font-size: .76rem; color: var(--ink-2);
}

/* On a wide screen these are the top of the right-hand column, above the Teil
   list, and they scroll with it rather than being pinned. */
@media (min-width: 961px) {
  [data-sp-guide-slot]:not(:empty) { margin-bottom: 14px; }
  [data-sp-guide-slot] .sp-guide-pair { margin: 0; }
}

/* Half the card, for a visitor with no account. Legible as text, not as
   language — the same treatment the Redemittel teaser uses, and for the same
   reason: enough to show the points are specific to this theme, not enough to
   answer the question with. user-select stops a long press on a phone from
   lifting the words out from under the blur. */
.sp-guide .guide-locked {
  filter: blur(4.2px); opacity: .75;
  user-select: none; pointer-events: none;
}
.sp-guide .guide-locked * { user-select: none; }
.guide-more {
  margin: 0; padding: 2px 13px 11px;
  font-size: .76rem; font-weight: 700; color: var(--signal-deep);
}
/* Nobody should sit and wait for a blur to resolve. */
@media (prefers-reduced-motion: reduce) {
  .sp-guide .guide-locked { filter: blur(4.2px); }
}

@media (max-width: 560px) {
  .sp-guide-title small { font-size: .71rem; }
  .guide-more { padding: 2px 11px 10px; }
  .sp-guide-head { padding: 10px 11px; gap: 9px; }
  .sp-guide-list { padding: 0 11px 10px; }
  .sp-guide-list li { font-size: .83rem; gap: 8px; padding: 7px 9px; }
  .sp-ex-lines { margin: 0 11px; gap: 6px; }
  .sp-ex-lines li { padding: 8px 10px; }
  .sp-ex-de { font-size: .83rem; }
  .sp-ex-ar { font-size: .76rem; }
  .sp-guide-swap { padding: 8px 11px 10px; }
}

/* ─────────────────────────────────────────── Sprechen: the speaking toolbox
   Sits between the question and the microphone, which is the order the exam
   has: hear it, reach for the words, answer. Collapsed by default — on a
   phone the record button is the point of the screen and must not be pushed
   under the fold by a list of phrases nobody has asked for yet. */
.sp-rm {
  margin: 12px 0 14px; padding: 12px 14px;
  border: 1px solid color-mix(in srgb, var(--signal) 38%, transparent);
  border-radius: 14px;
  background: var(--signal-wash);
}
.sp-rm-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.sp-rm-head b { font-size: .92rem; color: var(--accent-ink); }
.sp-rm-i { font-size: .95rem; }
.sp-rm-hint { font-size: .74rem; color: var(--ink-3); }

.sp-rm-slots { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.sp-rm-slot { flex: 1 1 auto; min-width: 0; }

.sp-rm-btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 13px; border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--signal-deep) 30%, transparent);
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: .82rem; cursor: pointer;
  transition: background .14s var(--ease), border-color .14s var(--ease);
}
.sp-rm-btn:hover { border-color: var(--signal-deep); }
/* A chip is sized by its content, which is fine until the content is
   "Gegenargument" plus its Arabic gloss plus a lock: 155px of text in a 151px
   pill, spilling over the edge. Flex children do not shrink below their
   content unless told to, so they are told to. */
.sp-rm-btn { max-width: 100%; }
.sp-rm-btn > span { min-width: 0; overflow-wrap: anywhere; }
.sp-rm-btn:focus-visible { outline: 2px solid var(--signal-deep); outline-offset: 2px; }
.sp-rm-btn [lang="de"] { font-family: var(--font-de); font-weight: 600; }
.sp-rm-ar { color: var(--ink-3); font-size: .76rem; }
.sp-rm-chev { color: var(--signal-deep); font-weight: 800; font-size: .8rem; }
.sp-rm-btn[aria-expanded="true"] {
  background: var(--signal-deep); color: #fff; border-color: var(--signal-deep);
}
.sp-rm-btn[aria-expanded="true"] .sp-rm-ar,
.sp-rm-btn[aria-expanded="true"] .sp-rm-chev { color: #DCEBE8; }

.sp-rm-list {
  list-style: none; margin: 9px 0 2px; padding: 0;
  display: grid; gap: 6px;
}
/* `display: grid` above beats the UA rule that makes [hidden] display:none, so
   every group rendered open while its hidden attribute said otherwise — the
   DOM and the screen disagreed, and only the screen was telling the truth. */
.sp-rm-list[hidden] { display: none; }
/* German first and whole, Arabic under it — never over it, never instead of
   it. The two are separated by weight and direction rather than a rule, which
   keeps the row short enough to stay scannable on a phone. */
.sp-rm-list li {
  display: flex; flex-direction: column; gap: 3px;
  padding: 8px 12px; border-radius: 10px;
  background: var(--surface); border: 1px solid var(--line-soft);
  line-height: 1.6; text-align: start;
}
.sp-rm-list .rm-de {
  font-family: var(--font-de); font-size: .86rem; color: var(--ink);
}
.sp-rm-list .rm-ar {
  font-size: .78rem; color: var(--ink-3);
}
/* German compounds are long enough to outrun a 375px screen on their own. */
.sp-rm-list .rm-de, .sp-rm-list .rm-ar { overflow-wrap: anywhere; }

/* The exam, mocked, in front of a locked one. The demo inside is the home
   page's component; only the frame around it belongs to this page. */
.sp-preview { border-color: color-mix(in srgb, var(--signal) 38%, transparent); }
.sp-pv-head { display: flex; align-items: center; gap: 9px; margin-bottom: 12px; }
.sp-pv-kicker { font-size: .82rem; font-weight: 700; color: var(--accent-ink); }
.sp-pv-tag {
  font-size: .68rem; font-weight: 700; letter-spacing: .02em;
  padding: 2px 8px; border-radius: 999px;
  background: var(--paper-2); color: var(--ink-3);
}
.sp-pv-note {
  margin: 12px 0 0; font-size: .82rem; line-height: 1.7; color: var(--ink-2);
}

/* The first thing a new account sees: three ways in, one tap each. Cards
   rather than links because the target has to be obvious on a phone held in
   one hand, which is 82% of this audience. */
/* The welcome: what the site does, for someone who has just arrived. Four
   rows rather than a paragraph, because it is read in the two seconds before
   the reader decides whether to close it. */
.su-perks { list-style: none; margin: 10px 0 8px; padding: 0; display: grid; gap: 8px; }
.su-perks li { display: flex; gap: 11px; align-items: flex-start; }
/* The two that are the reason to be here rather than reading a PDF. Lifted
   with a tint and a rule on the leading edge — enough to be seen before the
   text is read, not so much that the other two look broken. */
.su-perks li.star {
  background: var(--signal-wash);
  border-inline-start: 2px solid var(--signal-deep);
  border-radius: 9px;
  padding: 6px 9px;
  margin-inline-start: -4px;
}
.su-perks li > span { flex: none; color: var(--signal-deep); font-size: 1rem; line-height: 1.35; }
.su-perks div { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.su-perks b { font-size: .88rem; }
.su-perks div span { font-size: .78rem; color: var(--ink-3); line-height: 1.55; }
@media (max-height: 700px) {
  /* A short phone must still reach the Google button without scrolling past
     the reason it is there. */
  .su-perks { gap: 7px; margin: 9px 0 8px; }
  .su-perks div span { display: none; }
}

/* Level first. Two buttons, thumb-sized, because this is the first thing a new
   account is asked and it is asked on a phone. */
.su-lvl { display: flex; gap: 8px; margin: 4px 0 16px; }
.su-lvl-b {
  flex: 0 0 auto; min-width: 62px; padding: 7px 16px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface);
  font: inherit; font-family: var(--font-de); font-weight: 700; font-size: .84rem;
  color: var(--ink); cursor: pointer;
  transition: background .14s var(--ease), border-color .14s var(--ease), color .14s var(--ease);
}
.su-lvl-b:hover { border-color: var(--signal-deep); }
.su-lvl-b:focus-visible { outline: 2px solid var(--signal-deep); outline-offset: 2px; }
.su-lvl-b.on { background: var(--signal-deep); border-color: var(--signal-deep); color: #fff; }
.su-start-cap { margin-bottom: 0; }

.su-start { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.su-start-card {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 14px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--surface);
  text-decoration: none; color: var(--ink);
  transition: border-color .14s var(--ease), background .14s var(--ease);
}
.su-start-card:hover, .su-start-card:focus-visible {
  border-color: var(--signal-deep); background: var(--signal-wash);
}
.su-start-i { font-size: 1.15rem; color: var(--signal-deep); flex: none; }
.su-start-t { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.su-start-t b { font-size: .93rem; }
.su-start-t span {
  font-size: .8rem; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.su-start-go { margin-inline-start: auto; color: var(--signal-deep); flex: none; }



   The toolbox in front of a locked exam. Same block, same chips, same colours
   — the point is that it is recognisably the thing they would be getting, not
   an advert for it. Everything in here is a button: the phrases are inert
   text, so a tap anywhere lands on the one action available.  */
.sp-rm-teaser { cursor: pointer; }
.sp-rm-teaser .sp-rm-btn { cursor: pointer; }
.sp-rm-teaser .sp-rm-chev { font-size: .74rem; }
/* Legible enough to be read as German, not enough to be read as a phrase. The
   user-select rule stops a long-press on a phone from lifting the text out of
   the blur.  */
.sp-rm-teaser .rm-locked {
  filter: blur(4.5px); opacity: .75; user-select: none;
  pointer-events: none;
}
.sp-rm-teaser .rm-more {
  display: block; padding: 4px 2px 0;
  background: none; border: 0;
  font-size: .76rem; color: var(--signal-deep); font-weight: 700;
  text-align: start;
}
/* Nobody should sit and wait for a blur to resolve. */
@media (prefers-reduced-motion: reduce) {
  .sp-rm-teaser .rm-locked { filter: blur(4.5px); }
}

@media (max-width: 560px) {
  .sp-rm { padding: 10px 12px; margin: 10px 0 12px; }
  .sp-rm-hint { display: none; }
  /* Two per row, not four stacked: full-width chips cost 235px of a 844px
     screen before a single phrase is shown, and the record button has to stay
     reachable without scrolling. */
  .sp-rm-slot { flex: 1 1 44%; }
  .sp-rm-btn {
    width: 100%; justify-content: center; gap: 5px; padding: 7px 9px; font-size: .78rem;
    /* Two lines inside the chip beats one line outside it. */
    flex-wrap: wrap; border-radius: 14px; line-height: 1.35;
  }
  .sp-rm-ar { font-size: .7rem; }
  .sp-rm-list li { font-size: .84rem; }
}

/* ------------------------------------------------- a recording that is paid */

/*
 * A paid recording has no src until it is asked for, so the player is replaced
 * by the asking. The wait is shown as a percentage because the whole file has
 * to arrive before it can start — a blob cannot stream.
 */
.ga-load {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 10px 0;
}
.ga-note { font-size: .84rem; color: var(--ink-3); }
.ga-note a { color: var(--signal-deep); font-weight: 700; }
html[data-theme="dark"] .ga-note a { color: var(--signal); }

/* ------------------------------------------------------------- sharing */

/*
 * Sharing is offered after a result, where the learner knows whether the thing
 * was worth a friend's time. Two buttons: the phone's own share sheet, which
 * is where WhatsApp lives, and a plain copy for a desktop.
 */
.sh-row {
  display: flex; flex-wrap: wrap; gap: 10px;
  margin-top: 16px; padding-top: 16px;
  border-top: 1px solid var(--line);
}
.sh-row .btn { flex: 1 1 auto; min-width: 0; }
@media (max-width: 460px) { .sh-row .btn { flex-basis: 100%; } }

/* ------------------------------------------- optional profile fields */

/*
 * Two fields nobody has to fill in, on the form where losing somebody is most
 * expensive. So "اختياري" is part of the label rather than a footnote, and the
 * whole group reads quieter than the required fields above it.
 */
/* The label is a grid, so a caption and its badge have to be one item or they
   stack into two rows. */
.acc-cap { display: block; }
.acc-opt {
  display: inline-block;
  font-size: .72rem; font-weight: 600; letter-spacing: .02em;
  color: var(--ink-3); background: var(--surface);
  border: 1px solid var(--line); border-radius: 5px;
  padding: 1px 6px; margin-inline-start: 6px;
}
.acc-lvl { border: 0; margin: 0; padding: 0; min-width: 0; }
.acc-lvl legend {
  padding: 0; margin-bottom: 7px;
  font-size: .88rem; font-weight: 600; color: var(--ink-2);
}
.acc-lvl-row { display: flex; gap: 10px; }
/* A tap target, not a radio dot: these are pressed on a phone. */
/* Outranks `.acc-form label { display: grid }`, which would otherwise stack the
   radio above its own label text. */
.acc-form .acc-lvl-row label,
.acc-lvl-row label {
  flex: 1 1 0; min-width: 0; margin: 0;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  padding: 11px 10px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface); color: var(--ink-2);
  font-family: var(--font-de); font-weight: 700; font-size: .95rem;
  transition: border-color .14s var(--ease), background .14s var(--ease), color .14s var(--ease);
}
.acc-lvl-row label:hover { border-color: var(--signal-deep); }
.acc-lvl-row input { accent-color: var(--signal-deep); margin: 0; }
.acc-lvl-row label:has(input:checked) {
  border-color: var(--signal-deep); background: var(--signal-wash); color: var(--accent-ink);
}
.acc-lvl-row label:focus-within { outline: 2px solid var(--signal-deep); outline-offset: 2px; }

/* The same pair on the account page, under a heading of their own. */
.acc-extras {
  margin-top: 22px; padding-top: 20px;
  border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 10px;
}
.acc-extras h3 { margin: 0; font-size: 1rem; }
.acc-extras .count-note { margin: 0; }

/* The next-question button, once an answer is recorded and waiting.
   A ring rather than an animation: this appears mid-exam, and something
   flashing while you are trying to think in German is not help. */
.btn.awaiting {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--signal) 45%, transparent);
}

/* ══════════════════════════════════════════ Übungen: sections before lists

   Übungen → section → Teil → exercise, with each step on screen instead of
   remembered. The tab strip is the load-bearing piece: it names every room in
   the building from inside any of them, which is what the old search box
   could never do. */

.uex { padding-bottom: 8px; }

/* ── the section selector ───────────────────────────────────────────────── */

/* Scrolls sideways rather than wrapping. Five items will not fit a 360px
   phone at a readable size, and a strip that wraps to two lines stops
   reading as one control. */
.uex-tabs {
  margin: 18px 0 26px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* text-align on a block, not justify-content on a flex row. Centring an
     overflowing flex row pushes its leading edge out of the scroll range and
     the first tab becomes unreachable; a centred inline box stays scrollable
     to both ends. Matters here because this strip does overflow on a phone. */
  text-align: center;
}
.uex-tabs::-webkit-scrollbar { display: none; }

.uex-tabs-in {
  display: inline-flex; gap: 4px;
  padding: 5px;
  background: var(--paper-2);
  border: 1px solid var(--line-soft);
  border-radius: 999px;
  min-width: max-content;
}

.uex-tab {
  display: inline-block; white-space: nowrap;
  padding: 9px 18px;
  border-radius: 999px;
  font-family: var(--font-de); font-size: .98rem; font-weight: 600;
  color: var(--ink-2); text-decoration: none;
  transition: background .15s var(--ease), color .15s var(--ease);
}
.uex-tab:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 6%, transparent); }

/* The active tab is a raised chip, not a colour swap: it has to read as
   "you are standing here" at a glance on a strip that scrolls. */
.uex-tab.is-on {
  background: var(--surface); color: var(--ink);
  box-shadow: var(--shadow-sm);
}
.uex-tab.is-on:hover { background: var(--surface); }
/* الكل is marked as a LINK, not as a filled chip.
   It is the one item in the strip that is not an exam section — it is the way
   out of the four into the whole list — so it has to stand out without
   claiming a state. An accent wash was tried first and read as "selected":
   inside a tab strip, any filled pill is the selected one, and colour alone
   does not undo that. So: no fill at all, accent ink, an underline and an
   arrow — the arrow being the one mark in this design that means "goes
   somewhere" rather than "you are here", which is exactly the difference
   being drawn. The underline that came with it is gone: between the accent
   ink and the arrow the label is already the odd one out, and the rule under
   a single word in a row of pills was noise.

   When it IS the current page it drops all of that and takes the raised chip
   like any other tab, because then "you are here" is the truth. */
.uex-tab-alt {
  font-family: var(--font-ar); font-weight: 700;
  color: var(--accent-ink); background: transparent;
  text-decoration: none;
}
.uex-tab-alt::after {
  content: "←"; margin-inline-start: 6px; font-size: .88em;
  /* The arrow is ornament on a label that already reads; keeping it out of the
     accessibility tree stops a screen reader saying "الكل left arrow". */
  speak: never;
}
.uex-tab-alt:hover {
  color: var(--accent-ink);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.uex-tab-alt.is-on, .uex-tab-alt.is-on:hover {
  color: var(--ink); background: var(--surface);
}
.uex-tab-alt.is-on::after { content: none; }
.uex-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── the heading ────────────────────────────────────────────────────────── */

.uex-head { margin: 0 0 22px; }

.uex-eyebrow {
  display: inline-flex; align-items: center; gap: 7px;
  margin: 0 0 14px; padding: 6px 14px;
  background: var(--accent-soft); border: 1px solid var(--accent-soft);
  border-radius: 999px;
  color: var(--accent-ink); font-size: .84rem; font-weight: 600;
}
.uex-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent); flex: none;
}

/* Large on purpose. The section name is the answer to "where am I", and on a
   page whose job is orientation that deserves the room. */
/* text-align: right, against the site's own [lang="de"] rule.
   That rule gives German islands direction:ltr and text-align:start, which
   puts a block-level German heading at the LEFT edge — correct for a line of
   German prose, wrong for a 4rem display word sitting above an Arabic eyebrow,
   an Arabic lede and a right-aligned tab strip. At this size the heading is
   not an island in a sentence, it is the page's own start marker, and it has
   to begin where everything under it begins. The shell is dir="rtl" with no
   LTR mode, so `right` is the start edge, full stop. */
.uex-h1 {
  margin: 0 0 6px;
  font-family: var(--font-de);
  font-size: clamp(2.4rem, 7vw, 4rem);
  line-height: 1.02; letter-spacing: -.035em;
  text-align: right;
}
.uex-lede { margin: 0; color: var(--ink-2); font-size: 1.02rem; max-width: 56ch; }
/* The badge above already carries the count on a wide screen. */
.uex-lede-n { display: none; }

/* ── the skill cards on /uebungen/ ──────────────────────────────────────── */

.uex-cards {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

.uex-card {
  display: flex; flex-direction: column; gap: 9px;
  padding: 20px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  text-decoration: none; color: inherit;
  transition: border-color .15s var(--ease), transform .15s var(--ease),
              box-shadow .15s var(--ease);
}
.uex-card:hover, .uex-card:focus-visible {
  border-color: var(--accent); transform: translateY(-2px);
  box-shadow: var(--shadow);
}
.uex-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.uex-card-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.uex-card-top b {
  font-family: var(--font-de); font-size: 1.42rem; font-weight: 700;
  letter-spacing: -.02em; line-height: 1.1;
}
.uex-card-ar { color: var(--ink-3); font-size: .92rem; }
.uex-card-blurb { color: var(--ink-2); font-size: .93rem; line-height: 1.55; flex: 1 1 auto; }

.uex-card-foot {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 4px; padding-top: 12px;
  border-top: 1px solid var(--line-soft);
  font-size: .82rem; color: var(--ink-3);
}
.uex-card-n { font-weight: 700; color: var(--ink); }
.uex-card-meta::before { content: "·"; margin-inline-end: 8px; color: var(--line); }

/* ── the level switch ───────────────────────────────────────────────────── */

.uex-lvlbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 0 0 18px;
}
.uex-lvl-label { color: var(--ink-3); font-size: .88rem; }

.uex-lvls {
  display: inline-flex; gap: 4px; padding: 4px;
  background: var(--paper-2);
  border: 1px solid var(--line-soft);
  border-radius: 999px;
}
.uex-lvl {
  appearance: none; border: 0; cursor: pointer;
  padding: 8px 24px; border-radius: 999px;
  background: transparent; color: var(--ink-2);
  font-family: var(--font-de); font-size: 1rem; font-weight: 700;
  transition: background .15s var(--ease), color .15s var(--ease);
}
.uex-lvl:hover { color: var(--ink); }
/* Filled, not outlined: this is the one control on the page that changes what
   is listed below it, so it carries the page's only strong colour.

   --signal with --signal-ink, which is the pair the rest of the site uses for
   a filled accent (.btn.accent, .road-chip.is-on). Pairing --signal-ink with
   --accent instead measured 2.71:1 in light mode — --signal-ink is the dark
   text meant to sit ON --signal, and --accent is already the dark end of that
   ramp, so the two were competing rather than contrasting. */
.uex-lvl.is-on { background: var(--signal); color: var(--signal-ink); }
.uex-lvl:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── the Teil tiles ─────────────────────────────────────────────────────── */

/* auto-fill, not auto-fit: Schreiben has a single Teil per level, and auto-fit
   collapses the empty tracks so that one card stretched the whole row and read
   as a banner rather than as one of a set. Empty tracks keep every tile the
   same size whether a section has one or six. */
.uex-teile {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
/* display:grid from the class above outranks the user-agent's
   [hidden]{display:none}, so the hidden level rendered too and both panels
   stacked. Say it here, where the display is set. */
.uex-teile[hidden] { display: none; }

.uex-teil {
  display: flex; flex-direction: column; gap: 8px;
  padding: 18px 20px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-decoration: none; color: inherit;
  transition: border-color .15s var(--ease), transform .15s var(--ease),
              box-shadow .15s var(--ease);
}
.uex-teil:hover, .uex-teil:focus-visible {
  border-color: var(--accent); transform: translateY(-2px);
  box-shadow: var(--shadow);
}
.uex-teil:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Same reason as .uex-h1: a stretched flex item, so text-align decides where
   "Teil 1" sits, and it belongs at the card's start edge with the rest. */
.uex-teil-n {
  font-family: var(--font-de); font-size: 1.22rem; font-weight: 700;
  letter-spacing: -.02em; line-height: 1.15;
  text-align: right;
}
.uex-teil-blurb { color: var(--ink-2); font-size: .9rem; line-height: 1.55; flex: 1 1 auto; }

.uex-teil-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-top: 4px; padding-top: 11px;
  border-top: 1px solid var(--line-soft);
  font-size: .85rem; color: var(--ink-2);
}
.uex-teil-foot b { font-weight: 700; color: var(--ink); }
.uex-go { color: var(--accent); font-size: 1.05rem; }

/* Phone-only; the tab strip carries this on every other width. */
.uex-alle { display: none; }

/* Without JavaScript nothing would switch the panels, so show every level
   rather than stranding the reader on the first one. */
@media (scripting: none) {
  .uex-teile[hidden] { display: grid !important; }
  .uex-lvlbar { display: none; }
}

/* ── phone ──────────────────────────────────────────────────────────────

   Desktop is untouched below this line.

   The strip stops scrolling and becomes a grid. A sideways strip works on a
   wide screen because the whole thing is visible at once; on a 375px phone it
   held 564px of tabs, so two of the five sections were off-screen behind a
   gesture with the scrollbar hidden. The entire point of this page is that a
   learner sees what there is to study without hunting — a section they cannot
   see is a section that does not exist to them. Two columns, because
   "Sprachbausteine" does not fit three across at a readable size, and الكل
   takes the last row on its own: it is the escape hatch, not a fifth skill. */
@media (max-width: 560px) {
  .uex-tabs {
    margin: 12px 0 20px;
    overflow-x: visible;
    text-align: initial;
  }
  .uex-tabs-in {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 5px;
    width: 100%;
    border-radius: var(--radius);
  }
  .uex-tab {
    /* 13px, so the tab measures 44px tall — the smallest comfortable touch
       target. At 11px it came out 40px, which is a miss often enough to be
       annoying on the one control this page is navigated by. */
    padding: 13px 8px;
    text-align: center;
    font-size: .92rem;
    white-space: normal;      /* Sprachbausteine may take two lines */
    line-height: 1.25;
    border-radius: calc(var(--radius) - 5px);
  }
  .uex-tab-alt { grid-column: 1 / -1; }

  /* Tighter head, so the Teile start near the fold rather than a scroll below
     it. The h1 keeps its size — it is the answer to "where am I".

     On a section page the badge and the descriptive half of the lede go: the
     badge's count moves inline, and every Teil tile below states its own task
     anyway, so the sentence was saying twice what the page was about. Worth
     ~75px, which is most of a Teil tile. The Übungen home keeps both — it has
     no level bar and nothing underneath repeating it. */
  .uex-eyebrow { margin-bottom: 10px; font-size: .8rem; padding: 5px 12px; }
  .uex-head { margin-bottom: 16px; }
  .uex-head-sec .uex-eyebrow { display: none; }
  .uex-head-sec .uex-lede-more { display: none; }
  .uex-head-sec .uex-lede-n { display: inline; }
  .uex-lvlbar { margin-bottom: 14px; }

  .uex-cards, .uex-teile { grid-template-columns: 1fr; gap: 10px; }
  .uex-card { padding: 16px; gap: 7px; }
  .uex-teil { padding: 14px 16px; gap: 6px; }
  .uex-teil-foot { padding-top: 9px; }

  /* The section cards ARE the selector on this page, so the strip above them
     was the same four words a second time inside one screen. */
  .uex-home .uex-tabs { display: none; }
  .uex-alle {
    display: block; margin-top: 14px; padding: 13px 16px;
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--surface); color: var(--ink-2);
    font-size: .94rem; text-align: center; text-decoration: none;
  }
  .uex-alle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
}
