/* Nektar General English: the design pass (Claude, 11 Oct 2026), loaded only for the new design.
   The design switch (src/design.js) asks at start which design to use; this file is switched on with
   the "Yeni tasarım" choice and stays off for the live one, so the live design is unchanged.
   One block per idea, in commit order; the ideas, their commits and where to look on the bench are
   in sandbox/design/NOTES.md. Keep the palette rule: only the key edge shade is new. */

/* ---------- Design pass (11 Oct): the waiting button ----------
   A primary button that waits for an answer looks asleep, not broken: plain paper and ink instead
   of a washed-out orange. When the answer is chosen it wakes: the orange comes in and one thin ring
   leaves it (engine.js wakePrimary). The button itself never moves. */
.actionbar .btn-primary { position: relative; transition: background-color 200ms var(--ease), color 200ms var(--ease), transform 180ms var(--ease); }
.actionbar .btn-primary:disabled { opacity: 1; background: var(--surface-2); color: var(--muted); }
.actionbar .btn-primary.is-waking::after { content: ""; position: absolute; inset: 0; border-radius: inherit; border: 2px solid var(--primary); pointer-events: none; animation: btn-wake 520ms var(--ease) forwards; }
@keyframes btn-wake { from { opacity: .75; transform: scale(1); } to { opacity: 0; transform: scale(1.04, 1.32); } }
@media (prefers-reduced-motion: reduce) { .actionbar .btn-primary.is-waking::after { display: none; } }

/* ---------- Design pass (11 Oct): answer options are keys ----------
   Text options, true/false, word cards and match cards share one shape: a paper key with a solid
   edge under it. A press sinks the key onto its edge; the chosen key settles into place in the
   learner's blue. Right and wrong keep their outline and small mark, never a fill. */
:root { --key-edge: #d9d0c2; }
:root[data-theme="dark"] { --key-edge: #0c131c; }
.choices:not(.tiles) > .choice, .match-item, .build-bank .token, .sort .token, .tf-btn {
  border-style: solid; border-width: 1.5px; border-color: var(--line); background: var(--surface); color: var(--text);
  box-shadow: 0 2px 0 var(--key-edge);
  transition: transform 140ms var(--ease), box-shadow 140ms var(--ease), border-color 160ms ease, background-color 160ms ease, color 160ms ease, opacity 250ms ease;
}
.choices:not(.tiles) > .choice { border-radius: 16px; font-weight: 600; }
/* Size only where no step sets its own (gap, comic and speak keep their tighter keys). */
:where(.choices:not(.tiles)) > .choice { min-height: 56px; padding: 0.85rem 1.1rem; font-size: 1.05rem; }
.match-item { border-radius: 16px; min-height: 60px; font-weight: 600; }
.match-item.match-l { font-weight: 500; }
.build-bank .token, .sort .token { border-radius: 12px; }
.tf-btn { box-shadow: 0 2px 0 var(--key-edge); }
:is(.choices:not(.is-locked) > .choice, .match-item:not(.is-matched), .build-bank .token, .sort .token, .tf-btn):active { transform: translateY(1px); box-shadow: 0 1px 0 var(--key-edge); }
.choices:not(.is-locked) > .choice.is-selected, .match-item.is-selected, .sort .token.is-selected, .tf-list:not(.is-locked) .tf-btn.is-selected {
  border-color: var(--select); background: var(--accent-soft); color: var(--accent-ink); outline: 0;
  box-shadow: 0 2px 0 color-mix(in srgb, var(--select) 55%, var(--key-edge)); transform: none;
  animation: key-settle 280ms var(--ease);
}
@keyframes key-settle { 0% { transform: translateY(2px) scale(0.97); } 55% { transform: translateY(-1px) scale(1.01); } 100% { transform: none; } }
/* Locked: the right key keeps its outline and mark, the others lie flat. */
.choices.is-locked > .choice { box-shadow: none; }
.choices.is-locked > .choice.is-correct { box-shadow: 0 2px 0 color-mix(in srgb, var(--right) 45%, var(--key-edge)); }
.match-item.is-matched { background: var(--surface); border-color: color-mix(in srgb, var(--right) 60%, var(--line)); box-shadow: none; opacity: 0.6; }
.match-item.is-wrong { border-color: var(--bad); background: var(--surface); }
@media (prefers-reduced-motion: reduce) { .choices > .choice.is-selected, .match-item.is-selected, .sort .token.is-selected, .tf-btn.is-selected { animation: none; } }

/* ---------- Design pass (11 Oct): the feedback sheet never hides the answer ----------
   The sheet lies over the step, so the options under it disappeared just when the learner wants to
   see which one was right. While it is open the body gets room under the step and the answer
   scrolls up above the sheet (engine.js revealAnswer). Pictures keep their size. */
.lesson.has-sheet .lesson-body { padding-bottom: calc(var(--sheet-h, 0px) + 1rem); }
.lesson.has-sheet .lesson-body > .step { flex-shrink: 0; }

/* ---------- Design pass (11 Oct): picture options are square cards ----------
   Picture options were tall white boxes with a small object in the middle, and a third option sat
   alone under two. Now every picture option is a square card the picture fills: two or four in a
   2-column grid, three (or six) in one row. In pick and bridge the cards sit at the bottom, in
   the thumb's reach, and the listening bar stands in the middle of the free height. */
.choices.tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.choices.tiles:has(> :nth-child(3):last-child), .choices.tiles:has(> :nth-child(6):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.lesson-body .choices.tiles > .choice:last-child:nth-child(odd) { grid-column: auto; justify-self: stretch; width: auto; }
.choices.tiles > .choice { aspect-ratio: 1; min-height: 0; padding: 4px; border: 1.5px solid var(--line); border-radius: 18px; background: var(--surface); box-shadow: 0 2px 0 var(--key-edge, var(--line)); transition: transform 140ms var(--ease), box-shadow 140ms var(--ease), border-color 160ms ease, background-color 160ms ease, opacity 250ms ease; }
.choices.tiles > .choice .tile { display: block; width: 100%; height: 100%; }
.lesson-body .choices.tiles .media-sm { width: 100%; height: 100%; max-height: none; aspect-ratio: auto; margin: 0; }
.choices.tiles .media img { padding: 7%; }
.choices.tiles:not(.is-locked) > .choice:active { transform: translateY(1px); box-shadow: 0 1px 0 var(--key-edge, var(--line)); }
.choices.tiles:not(.is-locked) > .choice.is-selected { border-color: var(--select); background: var(--accent-soft); box-shadow: 0 2px 0 color-mix(in srgb, var(--select) 55%, var(--line)); animation: tile-settle 300ms var(--ease); }
.choices.tiles:not(.is-locked) > .choice.is-selected img { animation: tile-lift 300ms var(--ease); }
@keyframes tile-settle { 0% { transform: translateY(2px) scale(0.96); } 55% { transform: translateY(-1px) scale(1.015); } 100% { transform: none; } }
@keyframes tile-lift { 0% { transform: scale(0.94); } 60% { transform: scale(1.04); } 100% { transform: none; } }
.choices.tiles.is-locked > .choice { box-shadow: none; }
/* Pick and bridge: the cards at the bottom, the listening bar in the middle of the free height. */
.lesson-body .step-pick .choices.tiles, .lesson-body .step-bridge .choices.tiles { flex: none; grid-auto-rows: auto; margin: 0; }
.lesson-body .step-pick .audio-hero, .lesson-body .step-bridge .audio-hero { margin: auto 0; padding: 1rem 0; }
@media (prefers-reduced-motion: reduce) { .choices.tiles > .choice.is-selected, .choices.tiles > .choice.is-selected img { animation: none; } }

/* ---------- Design pass (11 Oct): in a listening check the voice is the centrepiece ----------
   Pick, bridge and catch ask one thing: listen. The player stands in the middle of the screen as
   one large round button with its wave under it and the slow voice beside; while the voice plays,
   two soft rings leave the button. The answers wait at the bottom. */
.lesson-body > .step-catch .audio-hero { margin: auto 0; padding: 1rem 0; }
.lesson-body > .step-catch .choices { margin-bottom: 0; grid-template-columns: repeat(auto-fit, minmax(84px, 1fr)); }
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar { flex-direction: column; align-items: center; gap: 12px; width: auto; height: auto; border: 0; background: transparent; overflow: visible; }
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar-play { flex: none; flex-direction: column; gap: 16px; padding: 0; }
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar-icon { position: relative; width: 92px; height: 92px; transition: transform 160ms var(--ease); }
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar-play:active .abar-icon { transform: scale(0.95); }
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar-icon .icon { width: 30px; height: 30px; margin-left: 5px; }
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar-wave { height: 34px; gap: 4px; }
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar-wave span { width: 4px; height: var(--h); }
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar-speed { width: 52px; height: 40px; border: 1.5px solid var(--line); border-radius: 999px; background: var(--surface); }
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar.is-playing .abar-icon::before,
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar.is-playing .abar-icon::after { content: ""; position: absolute; inset: 0; border-radius: 50%; border: 2px solid var(--navy); pointer-events: none; animation: listen-ring 1.8s ease-out infinite; }
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar.is-playing .abar-icon::after { animation-delay: 0.9s; }
:root[data-theme="dark"] :is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar-icon::before,
:root[data-theme="dark"] :is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar-icon::after { border-color: var(--accent); }
@keyframes listen-ring { from { opacity: 0.45; transform: scale(1); } to { opacity: 0; transform: scale(1.55); } }
@media (prefers-reduced-motion: reduce) { :is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar-icon::before, :is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar-icon::after { display: none; } }

/* ---------- Design pass (11 Oct): the answer sits in the thumb zone ----------
   Most steps put everything in the top third and left the middle empty. Now a step takes the
   screen: what it is about (text, picture, pairs) stands in the middle of the free height, and
   what the learner does (options, word cards, the composer) sits at the bottom, near the thumb and
   the button. Nothing is hidden: a long step still scrolls. */
.lesson-body > :is(.step-read-mcq, .step-read-tf, .step-match, .step-shadow, .step-chat) { flex: 1 0 auto; display: flex; flex-direction: column; }
/* Reading: the text in the middle, the question and the answers under it. */
:is(.step-read-mcq, .step-read-tf) > .instr + * { margin-top: auto; margin-bottom: auto; }
:is(.step-read-mcq, .step-read-tf) > :is(.choices, .tf-list) { margin-top: 1rem; }
.step-read-mcq > .question { margin-top: 1.25rem; }
/* Pairs and repeating: one group in the middle. */
.step-match > .match { margin-block: auto; }
.step-shadow > .shadow-card { margin-top: auto; }
.step-shadow > :last-child { margin-bottom: auto; }
/* Chat: the thread from the top, the composer at the bottom, like a messaging app. */
.step-chat > .composer { margin-top: auto; padding-top: 0.75rem; }
/* Build and speak: the picture may grow; the question and the answer go down together. */
.lesson-body > :is(.step-build, .step-speak) > .media-md { flex: 1 1 210px; max-height: 300px; }
.step-build > .bubble, .step-build > .media-md + .build, .step-speak > .context { margin-top: auto; }
.step-build > .bubble + .build { margin-top: 0.9rem; }
/* Gap: the picture on top, the sentence and its options at the bottom. */
.step-gap > .audio-hero { margin-top: auto; }

/* ---------- Design pass (11 Oct): the progress line pulses as it fills ----------
   Each step forward fills the line a little slower and softer, and one small pulse of the accent
   leaves its tip (engine.js drawProgress sets --share and .is-advancing). */
.chain .link { position: relative; }
.chain .link .link-fill { transition: transform 460ms var(--ease); }
.chain .link::after { content: ""; position: absolute; top: 50%; left: calc(var(--share, 0) * 100%); width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 50%; background: var(--primary); opacity: 0; pointer-events: none; }
.chain .link.is-advancing::after { animation: progress-pulse 700ms var(--ease) 260ms; }
.chain .link.is-done::after { background: var(--ok); }
@keyframes progress-pulse { 0% { opacity: 0.6; transform: scale(0.45); } 100% { opacity: 0; transform: scale(2.1); } }
@media (prefers-reduced-motion: reduce) { .chain .link::after { display: none; } }

/* ---------- Design pass (11 Oct): each step arrives in reading order ----------
   A new step slides in a little from the right (forward), and its parts come in one after another
   in the order they are read: instruction, subject, answers. About 0.4 s in all. The selectors carry
   no weight (:where), so any part with its own entrance keeps it. */
.lesson:not(.cefr) > .lesson-body > .step { animation: step-forward 280ms var(--ease) both; }
:where(.lesson:not(.cefr) > .lesson-body > .step) > :where(*) { animation: step-part 340ms var(--ease) both; }
:where(.lesson:not(.cefr) > .lesson-body > .step) > :where(:nth-child(2)) { animation-delay: 50ms; }
:where(.lesson:not(.cefr) > .lesson-body > .step) > :where(:nth-child(3)) { animation-delay: 100ms; }
:where(.lesson:not(.cefr) > .lesson-body > .step) > :where(:nth-child(4)) { animation-delay: 150ms; }
:where(.lesson:not(.cefr) > .lesson-body > .step) > :where(:nth-child(5)) { animation-delay: 190ms; }
:where(.lesson:not(.cefr) > .lesson-body > .step) > :where(:nth-child(n+6)) { animation-delay: 220ms; }
@keyframes step-forward { from { opacity: 0; transform: translateX(18px); } to { opacity: 1; transform: none; } }
@keyframes step-part { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ---------- Design pass (11 Oct): the next stop invites the tap ----------
   When the map opens, the next stop's marker sends out a soft ring three times and then rests (no
   endless motion), and "Sıradaki" carries a small arrow that leans forward with it. A press sinks
   any open stop's marker a little. */
.stop.is-current .stop-dot::before { content: ""; position: absolute; inset: -4px; border-radius: 50%; border: 2px solid var(--primary); opacity: 0; pointer-events: none; animation: stop-invite 2.6s var(--ease) 0.8s 3; }
@keyframes stop-invite { 0% { opacity: 0.55; transform: scale(1); } 45% { opacity: 0; transform: scale(1.5); } 100% { opacity: 0; transform: scale(1.5); } }
.stop.is-current .stop-status { display: inline-flex; align-items: center; gap: 0.3rem; }
.stop.is-current .stop-status::after { content: ""; width: 0.95em; height: 0.95em; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat; animation: stop-lean 2.6s var(--ease) 0.8s 3; }
@keyframes stop-lean { 0%, 100% { transform: none; } 20% { transform: translateX(3px); } 40% { transform: none; } }
a.stop .stop-dot { transition: transform 160ms var(--ease); }
a.stop:active .stop-dot { transform: scale(0.94); }
@media (prefers-reduced-motion: reduce) { .stop.is-current .stop-dot::before, .stop.is-current .stop-status::after { animation: none; } }

/* ---------- Design pass (11 Oct): a finished stop is stamped, the rope tugs ----------
   Back on the map after a stop: its marker comes down like a stamp (a little large and turned,
   then pressed flat), a ring of the green leaves it like ink, and the check is drawn in from the
   left. Then the rope to the next stop is pulled and tugs once (journey.js tug) as the next marker
   opens. */
.stop.is-just-done .stop-dot { animation: stop-stamp 520ms var(--ease) 150ms both; }
.stop.is-just-done .stop-dot::before { content: ""; position: absolute; inset: -2px; border-radius: 50%; border: 2px solid var(--ok); opacity: 0; pointer-events: none; animation: stop-ink 640ms var(--ease) 470ms; }
.stop.is-just-done .stop-dot .icon { animation: stop-check 380ms ease-out 520ms both; }
@keyframes stop-stamp { 0% { opacity: 0; transform: scale(1.55) rotate(-14deg); } 55% { opacity: 1; transform: scale(0.93) rotate(3deg); } 100% { opacity: 1; transform: none; } }
@keyframes stop-ink { from { opacity: 0.6; transform: scale(0.95); } to { opacity: 0; transform: scale(1.7); } }
@keyframes stop-check { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@media (prefers-reduced-motion: reduce) { .stop.is-just-done .stop-dot, .stop.is-just-done .stop-dot::before, .stop.is-just-done .stop-dot .icon { animation: none; } }

/* ---------- Design pass (11 Oct): the stop entry's route reads like the map ----------
   The knots under the cover speak the map's language: a finished stop is the green stamp with its
   check, the next one sends out a soft ring three times. The pin of the chosen stop drops onto its
   knot when the page opens. Başla no longer slides in: it fades in where it stays. */
.intro-knot.is-done .intro-knot-mark { background: var(--ok); border-color: var(--ok); color: var(--bg); }
.intro-knot.is-done .intro-knot-mark .icon { width: 13px; height: 13px; }
.intro-knot.is-next:not(.is-selected) .intro-knot-mark { position: relative; border-color: var(--primary); color: var(--primary); }
.intro-knot.is-next:not(.is-selected) .intro-knot-mark::after { content: ""; position: absolute; inset: -2px; border-radius: 50%; border: 2px solid var(--primary); opacity: 0; pointer-events: none; animation: stop-invite-knot 2.6s var(--ease) 0.9s 3; }
@keyframes stop-invite-knot { 0% { opacity: 0.55; transform: scale(1); } 45% { opacity: 0; transform: scale(1.8); } 100% { opacity: 0; transform: scale(1.8); } }
.intro-selection .icon { animation: pin-drop 460ms var(--ease) 420ms both; }
@keyframes pin-drop { 0% { opacity: 0; transform: translateY(-16px); } 60% { opacity: 1; transform: translateY(2px); } 100% { transform: none; } }
.stop-intro .intro-action > .btn { animation: intro-fade 300ms ease-out 280ms both; }
@keyframes intro-fade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .intro-knot.is-next .intro-knot-mark::after, .intro-selection .icon { animation: none; } }

/* ---------- Design pass (11 Oct): the summary counts up what was learned ----------
   The end of a stop is a small ceremony, kept quiet: a green ring is drawn around the badge and
   its check is drawn in, the lines come in one after another, the pictures of the new words pop
   into the strip and the numbers count up (motion.js countUp). "Sıradaki" leans toward the next
   stop. The page holds the screen: the content in the middle, Tamam fixed at the bottom. */
.page.summary { min-height: 100dvh; display: flex; flex-direction: column; }
.page.summary > .summary-badge { margin-top: auto; }
.page.summary > .summary-actions { margin-top: auto; position: sticky; bottom: 0; padding: 1rem 0 0.25rem; background: var(--bg); z-index: 1; }
.summary-badge { position: relative; overflow: visible; }
.summary-badge .badge-ring { position: absolute; inset: -8px; width: calc(100% + 16px); height: calc(100% + 16px); transform: rotate(-90deg); pointer-events: none; }
.summary-badge .badge-ring circle { fill: none; stroke: var(--ok); stroke-width: 2.5; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; animation: badge-ring 720ms var(--ease) 260ms forwards; }
.summary-badge > .icon { animation: badge-check 380ms ease-out 700ms both; }
@keyframes badge-ring { to { stroke-dashoffset: 0; } }
@keyframes badge-check { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
.page.summary > :not(.summary-badge):not(.summary-actions) { animation: summary-rise 380ms var(--ease) both; }
.page.summary > :nth-child(2) { animation-delay: 160ms; }
.page.summary > :nth-child(3) { animation-delay: 240ms; }
.page.summary > :nth-child(4) { animation-delay: 320ms; }
.page.summary > :nth-child(5) { animation-delay: 400ms; }
.page.summary > :nth-child(n+6) { animation-delay: 470ms; }
@keyframes summary-rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.summary .reveal-thumbs img { animation: thumb-pop 380ms var(--ease) both; animation-delay: 620ms; }
.summary .reveal-thumbs img:nth-child(2) { animation-delay: 710ms; }
.summary .reveal-thumbs img:nth-child(3) { animation-delay: 800ms; }
@keyframes thumb-pop { 0% { opacity: 0; transform: scale(0.5) rotate(-10deg); } 65% { opacity: 1; transform: scale(1.08); } 100% { transform: none; } }
.summary .count-up { font-variant-numeric: tabular-nums; }
.summary-next { align-items: center; }
.summary-next strong { margin-left: auto; }
.summary-next .summary-next-go { width: 18px; height: 18px; color: var(--primary); animation: stop-lean-next 2.4s var(--ease) 1.2s 3; }
@keyframes stop-lean-next { 0%, 100% { transform: none; } 20% { transform: translateX(4px); } 40% { transform: none; } }
@media (prefers-reduced-motion: reduce) { .summary-badge .badge-ring circle { stroke-dashoffset: 0; } }

/* ---------- Design pass, round 3 (11 Oct): orange and teal ----------
   Round 2 was too orange (user, 11 Oct). Now: an almost white paper with a touch of warm brown, the
   orange kept for the action only, and its complement on the colour wheel, teal, for the learner's
   choice and the small moments (instruction dot, progress pulse, the next stop's ring, the active
   tab, Maya's and the other speakers' bubbles). Right and done are a clear green, apart from the
   teal. Each lesson stage has a quiet chip. Edges are 2 px. All text pairs pass 4.5:1 in light and
   dark (checked). */
:root {
  --bg: #fcfaf7; --surface: #ffffff; --surface-2: #f3efe9; --line: #e8e1d7; --paper-rule: #eee8df; --sky: #d7ebe8; --sky-2: #eef7f5;
  --muted: #5c6168;
  --primary-soft: #fdf0ea; --primary-edge: #b93d1f;
  --teal: #13807e; --teal-soft: #e0f2f0; --teal-ink: #0a5c5b;
  --select: #13807e; --accent: #13807e; --blue: #13807e; --accent-soft: #e0f2f0; --accent-ink: #0b6563;
  --right: #2e8540; --right-soft: #e3f1e6; --ok: #2e8540; --ok-soft: #e3f1e6;
  --key-edge: #ddd4c7; --bubble-bg: #eaf5f3; --bubble-line: #c5e3df;
  --chip-warm: #f1ece4; --chip-warm-ink: #6b5b45; --chip-intro: #e0f2f0; --chip-intro-ink: #0a5c5b;
  --chip-listen: #e0f2f0; --chip-listen-ink: #0a5c5b; --chip-read: #e3f1e6; --chip-read-ink: #22663a;
  --chip-speak: #fde9e1; --chip-speak-ink: #a3351a; --chip-write: #e8ecf3; --chip-write-ink: #2c3e5c;
}
:root[data-theme="dark"] {
  --bg: #111517; --surface: #191f22; --surface-2: #22292d; --line: #343e44; --paper-rule: #2a3236; --sky: #1d3536; --sky-2: #15292a;
  --teal: #5cc8c2; --teal-soft: #12302f; --teal-ink: #8adbd6;
  --select: #5cc8c2; --accent: #5cc8c2; --blue: #5cc8c2; --accent-soft: #143232; --accent-ink: #8adbd6;
  --right: #6fcf8a; --right-soft: #173022; --ok: #6fcf8a; --ok-soft: #173022;
  --primary-soft: #3a221b; --primary-edge: #a63a20; --key-edge: #0b0e10; --bubble-bg: #16292a; --bubble-line: #2a4a49;
  --chip-warm: #2e2a22; --chip-warm-ink: #e2cfa9; --chip-intro: #12302f; --chip-intro-ink: #8adbd6;
  --chip-listen: #12302f; --chip-listen-ink: #8adbd6; --chip-read: #173022; --chip-read-ink: #9ad8ab;
  --chip-speak: #3a221b; --chip-speak-ink: #f6a68c; --chip-write: #222b3b; --chip-write-ink: #b9c6e0;
}
/* Primary buttons share the keys' edge: a solid darker orange under them, pressed flat. */
.btn-primary:not(:disabled) { box-shadow: 0 2px 0 var(--primary-edge); }
.btn-primary:not(:disabled):active { transform: translateY(1px); box-shadow: 0 1px 0 var(--primary-edge); }
/* The lesson's top line: the stage as a small coloured chip, a quiet track, a teal pulse. */
.stage-label strong { padding: 0.05rem 0.5rem; border-radius: 999px; background: var(--chip-bg, var(--surface-2)); color: var(--chip-ink, var(--text)); font-size: 0.74rem; letter-spacing: 0.01em; }
.stage-label[data-stage="warm"], .stage-label[data-stage="use"], .stage-label[data-stage="fix"] { --chip-bg: var(--chip-warm); --chip-ink: var(--chip-warm-ink); }
.stage-label[data-stage="intro"] { --chip-bg: var(--chip-intro); --chip-ink: var(--chip-intro-ink); }
.stage-label[data-stage="listen"] { --chip-bg: var(--chip-listen); --chip-ink: var(--chip-listen-ink); }
.stage-label[data-stage="read"] { --chip-bg: var(--chip-read); --chip-ink: var(--chip-read-ink); }
.stage-label[data-stage="speak"] { --chip-bg: var(--chip-speak); --chip-ink: var(--chip-speak-ink); }
.stage-label[data-stage="write"] { --chip-bg: var(--chip-write); --chip-ink: var(--chip-write-ink); }
.link-bar { background: var(--surface-2); }
.chain .link::after { background: var(--teal); }
/* The instruction opens with a small teal dot. */
.lesson:not(.cefr) .instr-en::before { content: ""; display: inline-block; width: 7px; height: 7px; margin-right: 0.5rem; border-radius: 50%; background: var(--teal); vertical-align: 0.12em; }
/* The listening button wears the navy; its rings and the wave while playing take the teal. */
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar.is-playing .abar-icon::before,
:is(.step-pick, .step-bridge, .step-catch) .audio-hero .abar.is-playing .abar-icon::after { border-color: var(--teal); }
.abar.is-playing .abar-wave span { background: var(--teal); }
/* Speech bubbles in the teal paper, whoever speaks; the learner's own stay navy. */
.bubble-npc .bubble-body { background: var(--bubble-bg); border-color: var(--bubble-line); }
.message-thread .voice-message { background: var(--bubble-bg); border-color: var(--bubble-line); }
.message-thread .voice-message.is-right { background: var(--surface); border-color: var(--line); }
.message-thread .voice-message.is-playing { border-color: var(--teal); }
.message-thread .voice-message.is-playing .voice-wave span, .message-thread .voice-message.is-paused .voice-wave span { background: var(--teal); }
.story-bubble:not(.is-learner) { background: var(--bubble-bg); border-color: var(--bubble-line); }
.msg-bubble { background: var(--bubble-bg); }
.tut-coach { background: var(--teal-soft); color: var(--teal-ink); }
.tut-coach::before { border-bottom-color: var(--teal-soft); }
/* Home and map: the next activity on a white card, teal for the invitation, green for done. */
.now { background: var(--surface); }
.now .now-label { color: var(--stamp); font-weight: 600; }
.stop.is-current .stop-dot::before, .intro-knot.is-next:not(.is-selected) .intro-knot-mark::after { border-color: var(--teal); }
.unit-group.is-current-unit > summary .unit-code { border-color: var(--primary); color: var(--stamp); }
.app-tab[aria-current="page"] { position: relative; color: var(--primary); }
.app-tab[aria-current="page"]::before { content: ""; position: absolute; top: 4px; width: 18px; height: 3px; border-radius: 2px; background: var(--teal); }
/* Summary: the strip of new words on teal paper, the badge on green. */
.learned-reveal { background: var(--teal-soft); }
.learned-reveal .reveal-go { color: var(--teal-ink); }
.summary-badge { background: var(--right-soft); color: var(--right); }
/* Maya's level check speaks in the same colours (sandbox/cefr). */
.cefr { --bubble: var(--bubble-bg); }

/* ---------- Design pass, round 2 (11 Oct): the level check and its result ----------
   Questions: the letters are cobalt chips, the answers the same keys as in lessons, Maya's bubbles
   in the learner-blue paper. Result: the level is stamped into its rope loop, its sentence sits on a
   card, and the five levels stand as stairs (sandbox/cefr/src/run.js levelStairs): climbed up to
   the result, "Sen" on the result, "Başla" on the suggested start. The replies are keys. */
.cefr-letter { background: var(--chip-listen); color: var(--chip-listen-ink); }
.cefr-choices .choice.is-selected .cefr-letter { background: var(--select); color: var(--surface); }
.cefr-rope-traveller { box-shadow: 0 2px 0 var(--primary-edge); }
.cefr-rope.is-sure .cefr-rope-traveller { box-shadow: 0 2px 0 color-mix(in srgb, var(--ok) 60%, #000); }
.cefr-kicker { padding: 0.15rem 0.7rem; border-radius: 999px; background: var(--teal-soft); color: var(--teal-ink); font: 600 0.8rem/1.4 var(--font); font-style: normal; letter-spacing: 0.02em; }
.cefr-seal { animation: cefr-stamp 560ms var(--ease) 180ms both; }
.cefr-level { color: var(--text); }
.cefr-loop path { stroke: var(--primary); }
.cefr-loop-dot { fill: var(--teal); }
@keyframes cefr-stamp { 0% { opacity: 0; transform: scale(1.35) rotate(-7deg); } 60% { opacity: 1; transform: scale(0.96) rotate(1.5deg); } 100% { opacity: 1; transform: none; } }
.cefr-level-note { max-width: 34ch; padding: 0.7rem 0.95rem; border-radius: 16px; background: var(--surface); border: 1.5px solid var(--line); color: var(--text); }
.cefr-stairs { list-style: none; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); align-items: end; gap: 6px; width: min(100%, 19rem); margin: 0.6rem 0 0; padding: 0; }
.cefr-stair { display: grid; justify-items: center; gap: 4px; }
.cefr-stair-step { display: block; width: 100%; height: calc(10px + var(--i) * 9px); border-radius: 6px 6px 3px 3px; background: var(--surface-2); transform-origin: 50% 100%; animation: cefr-stair-rise 420ms var(--ease) both; animation-delay: calc(500ms + var(--i) * 70ms); }
.cefr-stair.is-reached .cefr-stair-step { background: color-mix(in srgb, var(--navy) 70%, var(--surface)); }
:root[data-theme="dark"] .cefr-stair.is-reached .cefr-stair-step { background: color-mix(in srgb, var(--accent) 55%, var(--surface)); }
.cefr-stair.is-found .cefr-stair-step { background: var(--primary); box-shadow: 0 2px 0 var(--primary-edge); }
.cefr-stair.is-start .cefr-stair-step { outline: 2px solid var(--right); outline-offset: 2px; }
.cefr-stair strong { font: 600 0.82rem/1 var(--font); color: var(--muted); }
.cefr-stair.is-found strong { color: var(--stamp); }
.cefr-stair.is-start strong { color: var(--right); }
.cefr-stair small { min-height: 1.1em; font-size: 0.7rem; font-weight: 700; color: var(--muted); }
.cefr-stair.is-found small { color: var(--stamp); }
.cefr-stair.is-start small { color: var(--right); }
@keyframes cefr-stair-rise { from { transform: scaleY(0); } to { transform: none; } }
.cefr-reply { border: 1.5px solid var(--line); box-shadow: 0 2px 0 var(--key-edge); transition: transform 140ms var(--ease), box-shadow 140ms var(--ease), border-color 160ms ease; }
.cefr-reply:active { transform: translateY(1px); box-shadow: 0 1px 0 var(--key-edge); }
.cefr-reply.is-selected { border-color: var(--select); background: var(--accent-soft); color: var(--accent-ink); }
@media (prefers-reduced-motion: reduce) { .cefr-seal, .cefr-stair-step { animation: none; } }

/* ---------- Design pass, round 3 (11 Oct): the unit cover as a magazine ----------
   src/meet.js magazine(): the title is set line by line, each line as large as it can be, so every
   title has its own shape ("My / bag", "What / time / is it?"); the picture stands on a field in its
   own hue, as a pastel field; a swipe moves the field, the picture and the words at three speeds. The floating
   object is left out until covers are drawn in layers (see README). */
.meet-scene.is-magazine { gap: 0; }
.is-magazine .meet-copy { position: relative; z-index: 2; align-self: stretch; text-align: left; }
.is-magazine.align-end .meet-copy { text-align: right; }
.is-magazine .meet-eyebrow { max-width: none; margin: 0 0 12px; padding: 7px 0 6px; border-top: 2px solid var(--text); border-bottom: 1px solid var(--line); color: var(--text); font-size: .8rem; font-weight: 600; }
.is-magazine .meet-title { font-size: 48px; line-height: .92; letter-spacing: -.045em; text-wrap: initial; overflow-wrap: normal; }
.meet-title-line { display: block; white-space: nowrap; line-height: .92; letter-spacing: -.045em; translate: calc(var(--drag, 0) * 1.3px) 0; transition: translate .3s var(--ease); animation: mag-line 560ms var(--ease) both; animation-delay: calc(60ms + var(--i) * 90ms); }
.meet-title-line:nth-child(even) { color: var(--teal-ink, var(--text)); }
@keyframes mag-line { from { opacity: 0; transform: translateX(28px); } to { opacity: 1; transform: none; } }
.is-magazine .meet-art { flex: 1 1 0; min-height: 0; margin: 16px 0 0; container-type: size; }
.is-magazine .meet-art::before { content: ""; position: absolute; left: 0; right: 0; bottom: 0; top: min(25cqw, 50cqh); border-radius: 32px 32px 0 0; background: var(--cover-field, var(--teal-soft)); translate: calc(var(--drag, 0) * .2px) 0; transition: translate .3s var(--ease); transform-origin: 50% 100%; animation: mag-field 640ms var(--ease) both; }
.is-magazine .meet-art img { z-index: 1; object-position: center top; translate: calc(var(--drag, 0) * .55px) 0; transition: translate .3s var(--ease); animation: mag-art 620ms var(--ease) 120ms both; }
@keyframes mag-field { from { transform: scaleY(.6); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes mag-art { from { opacity: 0; transform: translateY(18px) scale(.97); } to { opacity: 1; transform: none; } }
.is-magazine .meet-obj { display: none; }
:root[data-theme="dark"] .is-magazine .meet-art::before { background: var(--cover-field-dark, var(--teal-soft)); }
.is-magazine .meet-known-row { position: relative; z-index: 2; margin-top: -54px; padding: 0 14px 14px; }

/* ---------- Design pass, round 3 (11 Oct): a picture keeps its size when the answers come ----------
   In speak, build, write and type the picture has a steady height; the question and the answers
   rise over its foot, where the picture fades into the paper. When even that does not fit, the step
   scrolls (user, 11 Oct: a picture must never shrink to a dot). */
.lesson:not(.cefr) .lesson-body > :is(.step-speak, .step-build, .step-write, .step-type) > .media-md { flex: 0 0 auto; height: clamp(150px, 34dvh, 280px); min-height: 0; max-height: none; margin-bottom: -36px; -webkit-mask-image: linear-gradient(to bottom, #000 70%, transparent); mask-image: linear-gradient(to bottom, #000 70%, transparent); }
.lesson:not(.cefr) .lesson-body > :is(.step-speak, .step-build, .step-write, .step-type) > .media-md + * { position: relative; z-index: 1; }

/* ---------- Unit cover (11 Oct, after the vertical and layered tries): picture, calm title, words ----------
   src/meet.js heroCover(). The unit's own cover picture edge to edge, a calm title above it (one size
   for all its words, 56 px down to 40, no giant word), and a few of the unit's new words as pictures
   only along its foot, each at its own depth: a swipe moves them at their own speed, and on the next
   slide they ease out the way the finger went. Only transform and opacity move. */
.meet-scene.meet-poster { gap: 0; overflow: visible; }
.meet-poster .meet-copy { position: relative; z-index: 2; }
.meet-poster .meet-eyebrow { max-width: 34ch; margin: 0 0 10px; color: var(--teal-ink, var(--muted)); font-size: .82rem; font-weight: 600; }
.meet-poster .meet-title { z-index: 2; font-size: var(--poster-size, 48px); font-weight: 600; line-height: 1.02; letter-spacing: -.02em; text-wrap: initial; overflow-wrap: normal; }
.poster-line { display: block; white-space: nowrap; translate: calc(var(--drag, 0) * .15px) 0; transition: translate .3s var(--ease); animation: poster-line 320ms var(--ease) both; animation-delay: calc(40ms + var(--i) * 50ms); }
@keyframes poster-line { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.meet-hero-art { position: absolute; inset: 0 -1.25rem; margin: 0; overflow: visible; pointer-events: none; }
.meet-hero-art::before { content: ""; position: absolute; inset: 0; background: radial-gradient(60% 30% at 50% 50%, var(--cover-field, var(--teal-soft)) 0%, transparent 100%); opacity: .8; }
:root[data-theme="dark"] .meet-hero-art::before { background: radial-gradient(60% 30% at 50% 50%, var(--cover-field-dark, var(--teal-soft)) 0%, transparent 100%); }
.meet-hero-art img { position: absolute; inset: auto; max-width: none; object-fit: contain; translate: calc(var(--drag, 0) * .1px) 0; transition: translate .3s var(--ease); }
.meet-poster .meet-known-row { position: absolute; left: 0; right: 0; z-index: 2; margin: 0; padding: 0; animation: poster-line 480ms var(--ease) 420ms both; }
@media (max-width: 360px) { .meet-hero-art { inset: 0 -16px; } }
@media (prefers-reduced-motion: reduce) {
  .poster-line, .meet-poster .meet-known-row { animation: none; }
  .poster-line, .meet-hero-art img { transition: none; translate: none; }
}

/* ---------- Phone test 11 Oct: options and the feedback sheet ----------
   When the options open (speaking refused or "Şimdi konuşamam"), the picture gives up some room and
   the options scroll into view (steps.js bringIntoView): the last one never waits behind the button.
   The feedback sheet is set apart from the options under it: a tint of its verdict and a deeper
   shadow, so the two never blend. */
.lesson:not(.cefr) .lesson-body > :is(.step-speak, .step-build, .step-write, .step-type).has-choices { flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; }
.lesson:not(.cefr) .lesson-body > :is(.step-speak, .step-build, .step-write, .step-type).has-choices > * { flex: none; }
.lesson:not(.cefr) .lesson-body > :is(.step-speak, .step-build, .step-write, .step-type).has-choices > .media-md { flex: 1 1 0; height: auto; min-height: 96px; max-height: 200px; margin-bottom: 0; -webkit-mask-image: none; mask-image: none; }
.lesson:not(.cefr) .lesson-body > .has-choices .mic-row { margin: 4px 0 0; }
.lesson:not(.cefr) .lesson-body > .has-choices .mic-info { display: none; }
.lesson:not(.cefr) .lesson-body > .has-choices > .media-md img { padding: 2%; }
.lesson:not(.cefr) .lesson-body > .has-choices > .toolbar:empty, .lesson:not(.cefr) .lesson-body > .has-choices > [hidden] { display: none; }
.lesson:not(.cefr) .lesson-body > .has-choices > .task-context { padding-top: 0; padding-bottom: 0; margin-bottom: 8px; }
.sheet.is-open { box-shadow: 0 -16px 36px rgb(15 25 40 / .16), 0 -1px 0 var(--line), inset 0 3px 0 var(--sheet-c, var(--line)); }
.sheet-ok { background: color-mix(in srgb, var(--right) 7%, var(--surface)); }
.sheet-near { background: color-mix(in srgb, var(--near) 8%, var(--surface)); }
.sheet-bad { background: color-mix(in srgb, var(--bad) 7%, var(--surface)); }
:root[data-theme="dark"] .sheet.is-open { box-shadow: 0 -16px 36px rgb(0 0 0 / .5), 0 -1px 0 var(--line), inset 0 3px 0 var(--sheet-c, var(--line)); }

/* The cover title is the magazine title again, held to a band (meet.js heroTitle); calm entry, little swipe. */
.meet-hero .meet-title-line { translate: calc(var(--drag, 0) * .2px) 0; animation: poster-line 340ms var(--ease) both; animation-delay: calc(40ms + var(--i) * 60ms); }
@media (prefers-reduced-motion: reduce) { .meet-hero .meet-title-line { animation: none; translate: none; } }

/* ---------- Phone test 11 Oct: answering without speaking, and the sandbox skip ----------
   "Konuşmadan cevapla" is the second button in the bar, beside the main one: always in sight, one
   name everywhere (design.js offerNoSpeech). "Geç" in the top corner shows the expected answer and
   moves on, for reading the content through (sandbox only, nothing is recorded). */
/* Speaking comes first (user, 23:46: the way round must not tempt): the microphone is the big, warm
   button, with a soft halo; "Konuşmadan cevapla" is a quiet underlined line above the main button,
   easy to find, never a second big button. */
.actionbar:has(> .btn-ghost:not([hidden])) { flex-wrap: wrap; row-gap: 2px; }
.actionbar .btn-ghost:not([hidden]) { flex: 1 0 100%; min-height: 44px; padding: 0 12px; border: 0; background: transparent; color: var(--muted); font-size: .88rem; font-weight: 600; text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--muted) 45%, transparent); text-underline-offset: 4px; }
.lesson:not(.cefr) .mic-row .btn-mic:not(.is-recording) { min-height: 64px; padding: 0 30px; border-radius: 999px; font-size: 1.12rem; box-shadow: 0 0 0 8px color-mix(in srgb, var(--teal) 14%, transparent), 0 3px 0 color-mix(in srgb, var(--navy, #1b2d46) 60%, black); }
.lesson:not(.cefr) .mic-row .btn-mic .icon { width: 22px; height: 22px; }
.dev-skip { flex: none; min-width: 44px; min-height: 32px; margin-left: 4px; padding: 0 12px; border: 1px dashed var(--line); border-radius: 999px; background: transparent; color: var(--muted); font-size: .8rem; font-weight: 700; }

/* ---------- Phone test 11 Oct: the phrase of the day as a card ----------
   One centred card in a soft teal: a large quiet quote mark behind the words, the phrase in the
   display serif, its Turkish under it on a tap, a dashed fold before the note, and one clear Dinle. */
.phrase-end { justify-items: center; text-align: center; gap: 16px; }
.phrase-end .culture-kicker { padding: 6px 14px 6px 10px; border-radius: 999px; background: var(--teal-soft); color: var(--teal-ink, var(--text)); font-size: .82rem; }
.phrase-end .culture-kicker .icon { width: 16px; height: 16px; color: var(--teal); }
.phrase-end .meet-saying { width: 100%; box-sizing: border-box; flex: none; margin: 0; justify-items: center; gap: 14px; padding: 40px 22px 22px; overflow: hidden; border-radius: 28px;
  background: linear-gradient(165deg, color-mix(in srgb, var(--teal-soft) 90%, var(--bg)) 0%, var(--surface) 78%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--teal) 16%, transparent), 0 22px 44px -30px rgb(10 60 60 / .45); animation: poster-line 360ms var(--ease) both; }
.phrase-end .meet-saying-mark { position: absolute; top: -6px; left: 14px; height: auto; font-size: 170px; line-height: 1; color: color-mix(in srgb, var(--teal) 20%, transparent); pointer-events: none; }
.phrase-end .meet-saying-text { position: relative; font-size: clamp(36px, 11vw, 54px); font-weight: 600; letter-spacing: -.02em; text-wrap: balance; }
.phrase-end .meet-saying .tr-reveal { position: relative; font-size: 1.05rem; }
.phrase-end .meet-saying-note { width: 100%; justify-content: center; padding-top: 14px; border-top: 1.5px dashed color-mix(in srgb, var(--teal) 28%, transparent); font-size: .84rem; text-align: left; }
.phrase-end .meet-saying-play { justify-self: center; min-height: 48px; margin: 2px 0 0; padding: 0 24px; border: 0; border-radius: 999px; background: var(--teal); color: var(--bg); font-weight: 700; }
.phrase-end .meet-saying-play .icon { color: currentColor; }
@media (prefers-reduced-motion: reduce) { .phrase-end .meet-saying { animation: none; } }

/* ---------- Phone test 11 Oct: sorting cards into two groups ----------
   One line says what to do; the first card leans once to each side; a second card peeks from under
   it, so it reads as a pile to deal; the two groups are bins at the screen's two sides, each arrow on
   its own outer edge, both neutral (user: no right/wrong feel), with its count in a small pill. */
.sort-deck-hint { margin: 0; text-align: center; color: var(--text); font-size: .95rem; font-weight: 600; }
.sort-deck-stage { position: relative; overflow: visible; padding-bottom: 8px; }
.sort-deck-stage::before { content: ""; position: absolute; inset: 10px 14px 0; border-radius: 24px; background: var(--surface-2, var(--surface)); border: 1px solid var(--line); z-index: 0; }
.sort-deck-card { position: relative; z-index: 1; box-shadow: 0 14px 30px -20px rgb(15 30 45 / .35); cursor: grab; }
.sort-deck-controls { gap: 12px; }
.sort-direction { min-height: 64px; padding: 10px 14px; border-width: 1.5px; border-radius: 18px; gap: 10px; }
.sort-direction { border-color: var(--line); background: var(--surface); }
.sort-direction[data-sort-side="1"] { flex-direction: row-reverse; text-align: right; }
.sort-direction > .icon { width: 22px; height: 22px; color: var(--text); }
.sort-direction strong { font-size: 1rem; }
.sort-direction .sort-deck-count { min-width: 26px; padding: 2px 8px; border-radius: 999px; background: var(--bg); color: var(--muted); text-align: center; font-weight: 700; }
.sort-direction[data-sort-side="1"] .sort-deck-count { margin-left: 0; margin-right: auto; }
.sort-direction.is-aimed { border-color: var(--text); background: var(--surface-2, var(--surface)); }

/* A word without a picture shows its Turkish as the picture (phone test 12 Oct: "şey" was tiny in a
   big tile): the size follows the tile, in the display serif. Small tiles (options) stay small. */
.media-md.is-word, .media-lg.is-word { container-type: inline-size; }
.media-md.is-word .media-word, .media-lg.is-word .media-word { font-family: var(--font-display); font-weight: 600; font-size: clamp(32px, 19cqw, 56px); line-height: 1.1; letter-spacing: -.01em; padding: 12px 16px; text-wrap: balance; }
