/* Lernbisschen — stylesheet.

   The previous version was built to the Apple HIG and ended up looking like the Settings app:
   correct, accessible and completely anonymous. This one keeps every accessibility rule and
   throws out the borrowed identity. The standard it is held to:

   - One brand colour, violet, because the app is called Lernbisschen and a generic system blue names
     nobody. Green and amber are spent exclusively on answer feedback and appear nowhere else,
     which is why the topic palette below is deliberately cool: no topic may look like "richtig".
   - No gradients. Depth is built from flat stacked surfaces and hard offset shadows. A soft
     purple gradient is the single most common tell of a generated interface.
   - No web font is loaded. The app promises that nothing is sent anywhere, and a font request
     is a request. The display face is whatever rounded or display cut the system already has.
   - Anything you can press is physically pressable: it sits on a hard edge and travels down onto
     it. Presses are :active in CSS so they land on pointer-down without waiting for a frame.
   - No state is signalled by colour alone; every coloured state also carries a glyph.
   - Interface icons are drawn on one grid at one stroke weight. No emoji.

   The ADHD rules from STUDIE.md are unchanged and still win where the two disagree: nothing red
   on a wrong answer, no state that can get worse, one thing per screen in a sprint, and every
   motion collapsible to nothing via Reizarm. */

/* ============================================================ tokens */

:root {
  --scale: 1;

  --bg:          #0b0a12;
  --surface:     #16141f;
  --surface-2:   #201d2d;
  --edge:        rgba(255, 255, 255, .07);
  --edge-strong: rgba(255, 255, 255, .13);
  --fill:        rgba(148, 140, 190, .16);
  --fill-strong: rgba(148, 140, 190, .26);
  --separator:   rgba(148, 140, 190, .22);

  --ink:         #f5f3ff;
  --ink-2:       rgba(233, 229, 255, .66);   /* 7.0:1 on a card */
  --ink-3:       rgba(233, 229, 255, .44);   /* icons and axis labels only */

  --brand:       #7a5af8;                    /* 4.5:1 against white text */
  --brand-deep:  #4c2fc4;                    /* the edge a brand button sits on */
  --brand-soft:  rgba(122, 90, 248, .18);
  --brand-ink:   #b9a5ff;                    /* brand as text, on dark */

  --green:       #22d07a;
  --green-edge:  #0f8a4f;
  --green-soft:  rgba(34, 208, 122, .15);
  --amber:       #ffb020;
  --amber-edge:  #b06d00;
  --amber-soft:  rgba(255, 176, 32, .15);
  --red:         #ff5a5a;

  /* What may be written on top of a filled green or amber surface. Both feedback colours are
     bright here and near-black in the light theme, so the ink flips with them — white on this
     green is 2.0:1 and unreadable. */
  --on-green:    #08170f;
  --on-amber:    #14121c;

  --press-edge:  #302c42;   /* the hard edge an unfilled control sits on */

  --chrome:      rgba(11, 10, 18, .72);
  --chrome-edge: rgba(255, 255, 255, .09);

  --shadow:      0 2px 10px rgba(0, 0, 0, .35);
  --shadow-lift: 0 10px 34px rgba(0, 0, 0, .5);

  /* The built-in CSS easings are too weak to read as intentional. */
  --ease-out:    cubic-bezier(.23, 1, .32, 1);
  --ease-drawer: cubic-bezier(.32, .72, 0, 1);

  --r:    16px;
  --r-lg: 20px;
  --r-xl: 26px;

  --drop: 4px;   /* how far a pressable control travels onto its edge */

  /* Topic identity. Eight hues, all cool, none within reach of green or amber. A topic colour
     is a name, not decoration: the same topic is the same colour on every screen. */
  --t-alltag:    #3b82f6;
  --t-arbeit:    #6366f1;
  --t-reisen:    #0284c7;   /* darkened from sky-500: the white check on it has to clear 3:1 */
  --t-smalltalk: #0891b2;   /* same reason */
  --t-gefuehle:  #ec4899;
  --t-essen:     #d946ef;
  --t-digital:   #a855f7;
  --t-phrasen:   #8b5cf6;
}

:root[data-theme="light"] {
  --bg:          #f4f2fa;
  --surface:     #ffffff;
  --surface-2:   #ffffff;
  --edge:        rgba(20, 18, 28, .09);
  --edge-strong: rgba(20, 18, 28, .16);
  --fill:        rgba(90, 84, 112, .09);
  --fill-strong: rgba(90, 84, 112, .17);
  --separator:   rgba(90, 84, 112, .18);

  --ink:         #14121c;
  --ink-2:       #5a5470;   /* 7.1:1 on white */
  --ink-3:       #8c86a0;   /* icons and axis labels only */

  --brand:       #6d28d9;   /* 7.1:1 against white text */
  --brand-deep:  #4c1d95;
  --brand-soft:  rgba(109, 40, 217, .10);
  --brand-ink:   #6d28d9;

  --green:       #0e7a45;
  --green-edge:  #0a5531;
  --green-soft:  rgba(14, 122, 69, .10);
  --amber:       #9a5b00;
  --amber-edge:  #6b3f00;
  --amber-soft:  rgba(154, 91, 0, .11);
  --red:         #c4132b;

  /* Here both feedback colours are dark, so the ink flips to white. */
  --on-green:    #ffffff;
  --on-amber:    #ffffff;

  --press-edge:  #d8d3e6;

  --chrome:      rgba(244, 242, 250, .8);
  --chrome-edge: rgba(20, 18, 28, .08);

  --shadow:      0 2px 10px rgba(43, 33, 78, .09);
  --shadow-lift: 0 10px 34px rgba(43, 33, 78, .16);

  --t-alltag:    #1d4ed8;
  --t-arbeit:    #4338ca;
  --t-reisen:    #0369a1;
  --t-smalltalk: #0e7490;
  --t-gefuehle:  #be185d;
  --t-essen:     #a21caf;
  --t-digital:   #7e22ce;
  --t-phrasen:   #6d28d9;
}

* { box-sizing: border-box; }

/* ============================================================ type

   Two stacks. The display stack asks for whatever rounded or display cut the system has —
   SF Pro Rounded on Apple, Segoe UI Variable Display on Windows — because a display cut is the
   cheapest way to stop looking like a settings screen. The text stack stays legible at 15px.
   Hierarchy is carried by scale and weight, never by letterspaced capitals. */

:root {
  --font:    ui-rounded, "SF Pro Rounded", "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, Roboto, sans-serif;
  --font-dp: ui-rounded, "SF Pro Rounded", "Segoe UI Variable Display", "Segoe UI", system-ui, -apple-system, Roboto, sans-serif;
}

html { font-size: calc(16px * var(--scale)); -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-optical-sizing: auto;
  font-synthesis-weight: none;
  font-size: 1.0625rem;
  line-height: 1.42;
  letter-spacing: -.01em;
  min-height: 100vh;
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
}

.display, .largetitle, .title2, .title3, .num, .btn, .grouphead {
  font-family: var(--font-dp);
}

.display    { font-size: clamp(3.5rem, 16vw, 4.75rem); line-height: .96; letter-spacing: -.045em; font-weight: 800; }
.largetitle { font-size: clamp(2.125rem, 8vw, 2.5rem); line-height: 1.08; letter-spacing: -.032em; font-weight: 800; margin: 0 0 .3rem; }
.title2     { font-size: 1.5rem;   line-height: 1.2;  letter-spacing: -.024em; font-weight: 800; }
.title3     { font-size: 1.25rem;  line-height: 1.24; letter-spacing: -.02em;  font-weight: 700; }
.headline   { font-size: 1.0625rem;line-height: 1.29; letter-spacing: -.012em; font-weight: 700; }
.subhead    { font-size: .9375rem; line-height: 1.34; letter-spacing: -.005em; }
.footnote   { font-size: .8125rem; line-height: 1.38; letter-spacing: 0; }
.num        { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

button, input, select, textarea { font: inherit; color: inherit; letter-spacing: inherit; }
button { -webkit-tap-highlight-color: transparent; touch-action: manipulation; cursor: pointer; }

:focus-visible { outline: 3px solid var(--brand-ink); outline-offset: 3px; border-radius: 10px; }

/* ============================================================ glyphs */

#glyphs { display: none; }
.glyph {
  width: 1.375rem; height: 1.375rem; flex: none; display: block;
  fill: none; stroke: currentColor; stroke-width: 1.85;
  stroke-linecap: round; stroke-linejoin: round;
}
.glyph.solid { fill: currentColor; stroke: none; }
.glyph.chev  { width: 1.0625rem; height: 1.0625rem; color: var(--ink-3); stroke-width: 2.2; }
.glyph.sm    { width: 1.1875rem; height: 1.1875rem; }

/* ============================================================ chrome */

#topbar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  padding: .55rem clamp(1rem, 4vw, 1.5rem);
  background: var(--chrome);
  -webkit-backdrop-filter: saturate(180%) blur(22px);
  backdrop-filter: saturate(180%) blur(22px);
  border-bottom: 1px solid var(--chrome-edge);
}
body.in-sprint #topbar, body.in-auth #topbar { display: none; }

.brand {
  display: flex; align-items: center; gap: .45rem;
  background: none; border: 0; padding: .25rem .25rem;
  font-family: var(--font-dp); font-size: 1.1875rem; font-weight: 800; letter-spacing: -.028em;
  color: var(--ink);
}
.brandmark {
  display: grid; place-items: center; width: 1.75rem; height: 1.75rem; flex: none;
  border-radius: 9px; background: var(--brand); color: #fff;
  box-shadow: 0 2px 0 var(--brand-deep);
}
.brandmark .glyph { width: 1.0625rem; height: 1.0625rem; }

.topright { display: flex; align-items: center; gap: .4rem; }

/* Two counters, both of which can only ever go up. That is the whole point: there is no streak
   here to break, so the number that replaces it counts days you turned up, not days in a row. */
.chip {
  display: inline-flex; align-items: center; gap: .3rem;
  font-family: var(--font-dp); font-size: .875rem; font-weight: 800; letter-spacing: -.01em;
  padding: .3rem .6rem .3rem .45rem; border-radius: 999px;
  background: var(--fill); color: var(--ink); white-space: nowrap;
}
.chip .glyph { width: 1rem; height: 1rem; }
.chip.xp { color: var(--brand-ink); background: var(--brand-soft); }
.chip .unit { font-weight: 700; opacity: .6; font-size: .8125rem; }

/* ---- bottom tab bar: a floating pill, because navigation on a phone belongs under the thumb */

.tabbar {
  position: fixed; z-index: 45;
  left: 50%; bottom: calc(.9rem + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  display: flex; gap: .15rem; padding: .3rem;
  border-radius: 999px;
  background: var(--chrome);
  -webkit-backdrop-filter: saturate(180%) blur(22px);
  backdrop-filter: saturate(180%) blur(22px);
  border: 1px solid var(--chrome-edge);
  box-shadow: var(--shadow-lift);
  max-width: calc(100vw - 1.5rem);
}
body.in-sprint .tabbar, body.in-auth .tabbar { display: none; }

.navbtn {
  display: flex; flex-direction: column; align-items: center; gap: .12rem;
  min-width: 4.25rem; padding: .45rem .5rem .4rem;
  background: none; border: 0; border-radius: 999px; color: var(--ink-2);
  font-size: .6875rem; font-weight: 700; letter-spacing: -.005em;
  transition: color .16s ease, background-color .16s ease;
}
.navbtn .glyph { width: 1.3125rem; height: 1.3125rem; }
.navbtn.is-on { color: #fff; background: var(--brand); }

/* Scroll edge instead of a hard divider under floating chrome. */
main::before {
  content: ""; position: fixed; left: 0; right: 0; top: 0; height: 3.6rem; z-index: 25;
  pointer-events: none; opacity: .75;
  background: linear-gradient(to bottom, var(--bg), transparent);
}
body.in-sprint main::before, body.in-auth main::before { display: none; }

/* ============================================================ page structure */

.screen { display: none; max-width: 40rem; margin: 0 auto; padding: 1.5rem clamp(1rem, 4vw, 1.5rem) 7.5rem; }
.screen.is-active { display: block; }
#screen-sprint.is-active {
  display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh;
  max-width: 34rem; padding: .9rem clamp(1rem, 4vw, 1.5rem) 1rem;
}

.pagelead { color: var(--ink-2); margin: 0 0 1.5rem; font-size: .9375rem; line-height: 1.45; }

.grouphead {
  font-size: .8125rem; font-weight: 800; color: var(--ink-2);
  letter-spacing: -.005em;
  margin: 1.85rem 0 .5rem; padding: 0 .25rem;
}
.groupfoot {
  font-size: .8125rem; line-height: 1.45; color: var(--ink-2);
  margin: .55rem 0 0; padding: 0 .25rem;
}
.groupfoot.end { margin-top: 1.2rem; }
.link { background: none; border: 0; padding: 0; color: var(--brand-ink); font: inherit; font-weight: 600; }

code { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: .92em; background: var(--fill); padding: .1rem .35rem; border-radius: 6px; }

/* ============================================================ pressables

   Every control that can be pressed sits on a hard edge and travels down onto it. The travel is
   :active rather than a scripted spring, so it lands on pointer-down with no frame of delay —
   and Reizarm collapses the transition to nothing while the pressed state still shows. */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  border: 0; border-radius: var(--r); padding: 0 1.35rem; min-height: 3.25rem;
  font-family: var(--font-dp); font-size: 1.0625rem; font-weight: 800; letter-spacing: -.014em;
  background: var(--surface-2); color: var(--ink);
  box-shadow: 0 var(--drop) 0 var(--press-edge);
  transition: transform .07s ease, box-shadow .07s ease, background-color .16s ease;
}
.btn:active:not(:disabled) { transform: translateY(var(--drop)); box-shadow: 0 0 0 var(--press-edge); }

.btn.filled { background: var(--brand); color: #fff; box-shadow: 0 var(--drop) 0 var(--brand-deep); }
.btn.filled:active:not(:disabled) { box-shadow: 0 0 0 var(--brand-deep); }
.btn.filled .glyph { color: #fff; }

.btn.large { width: 100%; min-height: 3.75rem; border-radius: var(--r-lg); font-size: 1.1875rem; --drop: 5px; }
.btn.plain { background: none; color: var(--brand-ink); box-shadow: none; font-weight: 700; min-height: 2.75rem; }
.btn.plain:active:not(:disabled) { transform: none; box-shadow: none; opacity: .6; }
.btn:disabled { opacity: .4; }

.iconbtn {
  width: 2.5rem; height: 2.5rem; flex: none; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--fill); border: 0; color: var(--ink-2);
  transition: color .16s ease, background-color .16s ease;
}
.iconbtn .glyph { width: 1.1875rem; height: 1.1875rem; stroke-width: 2.1; }

/* ============================================================ grouped list

   Kept for settings and other genuinely list-shaped content. It is the wrong shape for a home
   screen, which is why the home screen no longer uses it. */

.group { background: var(--surface); border-radius: var(--r); overflow: hidden; border: 1px solid var(--edge); }

.row {
  position: relative; display: flex; align-items: center; gap: .8rem;
  width: 100%; min-height: 3.4rem; padding: .75rem 1rem;
  background: transparent; border: 0; text-align: left; color: var(--ink);
  transition: background-color .16s ease;
}
.row + .row::before {
  content: ""; position: absolute; left: 1rem; right: 0; top: 0;
  height: 1px; background: var(--separator); transform: scaleY(.5); transform-origin: top;
}
/* Separators start where the text starts, not where the row starts. */
.row.has-icon + .row::before { left: 3.9rem; }
.row.static { cursor: default; }

.rowicon {
  width: 2rem; height: 2rem; border-radius: 9px; flex: none;
  display: grid; place-items: center;
  background: var(--fill-strong); color: var(--ink-2);
  transition: background-color .18s ease, color .18s ease;
}
.rowicon .glyph { width: 1.1875rem; height: 1.1875rem; stroke-width: 1.9; }
.rowicon.tint-brand { background: var(--brand); color: #fff; }
.rowicon.tint-sky   { background: var(--t-reisen); color: #fff; }
.rowicon.tint-slate { background: var(--fill-strong); color: var(--ink); }
.row.is-on .rowicon { background: var(--brand); color: #fff; }

.rowtext { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .08rem; }
.rowtitle { font-size: 1.0625rem; line-height: 1.29; font-weight: 600; }
.rowsub { font-size: .8125rem; line-height: 1.34; color: var(--ink-2); font-weight: 400; }
.rowtrail { color: var(--ink-2); font-size: .9375rem; font-weight: 600; flex: none; }
.row .checkmark { color: var(--brand-ink); opacity: 0; flex: none; transition: opacity .16s var(--ease-out); }
.row.is-on .checkmark { opacity: 1; }

.row.action .rowtitle { color: var(--brand-ink); font-weight: 700; }
.row.action.destructive .rowtitle { color: var(--red); }

.row select {
  background: none; border: 0; color: var(--ink-2); text-align: right;
  font-size: .9375rem; font-weight: 600; padding: .2rem 0;
  max-width: 13rem; text-overflow: ellipsis;
}
.row input[type="range"] { width: 8.5rem; accent-color: var(--brand); background: none; border: 0; flex: none; }

.switch {
  width: 3.25rem; height: 2rem; flex: none; appearance: none; -webkit-appearance: none;
  background: var(--fill-strong); border-radius: 999px; position: relative; border: 0;
  transition: background-color .2s ease;
}
.switch::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 1.75rem; height: 1.75rem; border-radius: 50%;
  background: #fff; box-shadow: 0 2px 5px rgba(0, 0, 0, .25);
  transition: transform .22s var(--ease-drawer);
}
.switch:checked { background: var(--brand); }
.switch:checked::after { transform: translateX(1.25rem); }

/* ============================================================ home */

.startcard {
  background: var(--surface); border: 1px solid var(--edge); border-radius: var(--r-xl);
  padding: .85rem .85rem 1rem; box-shadow: var(--shadow);
}

.segmented {
  position: relative; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  background: var(--fill); border-radius: 999px; padding: 4px; margin-bottom: .85rem;
}
.segthumb {
  position: absolute; top: 4px; bottom: 4px; left: 4px;
  width: calc((100% - 8px) / 3); border-radius: 999px;
  background: var(--brand); box-shadow: 0 2px 0 var(--brand-deep);
  will-change: transform;
}
.lenbtn {
  position: relative; z-index: 1; background: none; border: 0;
  padding: .55rem 0; font-family: var(--font-dp);
  font-size: .9375rem; font-weight: 700; color: var(--ink-2);
  transition: color .18s ease;
}
.lenbtn.is-on { font-weight: 800; color: #fff; }

.startsub { text-align: center; color: var(--ink-2); font-size: .8125rem; font-weight: 600; margin: .7rem 0 0; }

/* ---- topic tiles. A grid of objects, not a list of settings. */

.packgrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: .6rem; }

.packtile {
  --tint: var(--brand);
  position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: .1rem;
  padding: .85rem .85rem 1.1rem; border: 1px solid var(--edge); border-radius: var(--r-lg);
  background: var(--surface); color: var(--ink); text-align: left; overflow: hidden;
  box-shadow: 0 var(--drop) 0 var(--press-edge);
  transition: transform .07s ease, box-shadow .07s ease, border-color .18s ease, background-color .18s ease;
}
.packtile:active { transform: translateY(var(--drop)); box-shadow: 0 0 0 var(--press-edge); }

.packtile[data-pack="alltag"]    { --tint: var(--t-alltag); }
.packtile[data-pack="arbeit"]    { --tint: var(--t-arbeit); }
.packtile[data-pack="reisen"]    { --tint: var(--t-reisen); }
.packtile[data-pack="smalltalk"] { --tint: var(--t-smalltalk); }
.packtile[data-pack="gefuehle"]  { --tint: var(--t-gefuehle); }
.packtile[data-pack="essen"]     { --tint: var(--t-essen); }
.packtile[data-pack="digital"]   { --tint: var(--t-digital); }
.packtile[data-pack="phrasen"]   { --tint: var(--t-phrasen); }

.ptileicon {
  display: grid; place-items: center; width: 2.375rem; height: 2.375rem; margin-bottom: .45rem;
  border-radius: 11px; background: var(--fill-strong); color: var(--ink-2);
  transition: background-color .18s ease, color .18s ease;
}
.ptileicon .glyph { width: 1.375rem; height: 1.375rem; }
.ptilename { font-size: .9375rem; font-weight: 700; line-height: 1.22; letter-spacing: -.012em; }
.ptilemeta { font-size: .75rem; font-weight: 600; color: var(--ink-2); margin-top: .15rem; }

/* Selected topics carry their colour; unselected ones sit back and go grey. Selection is never
   colour alone — the check badge appears with it. */
.packtile.is-on { border-color: var(--tint); background: color-mix(in srgb, var(--tint) 10%, var(--surface)); }
.packtile.is-on .ptileicon { background: var(--tint); color: #fff; }
/* Deselected topics step back, but not so far that their labels stop being readable — measured:
   below .85 the meta line drops under 4.5:1 in the light theme. Selection is carried by the tint,
   the border and the check badge anyway, not by this. */
.packtile:not(.is-on) { opacity: .85; }

.ptilecheck {
  position: absolute; top: .7rem; right: .7rem;
  display: grid; place-items: center; width: 1.375rem; height: 1.375rem; border-radius: 50%;
  background: var(--tint); color: #fff; opacity: 0; transform: scale(.6);
  transition: opacity .16s var(--ease-out), transform .16s var(--ease-out);
}
.ptilecheck .glyph { width: .875rem; height: .875rem; stroke-width: 3; }
.packtile.is-on .ptilecheck { opacity: 1; transform: scale(1); }

/* Mastery, along the bottom edge. It can only ever grow. */
.ptilebar { position: absolute; left: 0; right: 0; bottom: 0; height: 4px; background: var(--fill); }
.ptilebar > i { display: block; height: 100%; background: var(--tint); transform-origin: left; }

/* ============================================================ sprint */

.sprintbar { display: flex; align-items: center; gap: .7rem; flex: none; }

.stepwrap { flex: 1; display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.stepbar { height: .625rem; border-radius: 999px; background: var(--fill-strong); overflow: hidden; }
.stepbar > div {
  height: 100%; width: 100%; border-radius: 999px; background: var(--brand);
  transform: scaleX(0); transform-origin: left; will-change: transform;
}
.stepcount { color: var(--ink-2); font-size: .6875rem; font-weight: 700; }

/* The clock. Deliberately the one thing with no spring anywhere near it. */
.timepill {
  display: flex; align-items: center; gap: .4rem; flex: none;
  padding: .3rem .7rem .3rem .35rem; border-radius: 999px; background: var(--fill);
}
.ring { position: relative; width: 1.625rem; height: 1.625rem; flex: none; }
.ring svg { width: 100%; height: 100%; transform: rotate(-90deg); display: block; }
.ring circle { fill: none; stroke-width: 4; }
.ring-bg { stroke: var(--fill-strong); }
.ring-fg { stroke: var(--brand-ink); stroke-linecap: round; stroke-dasharray: 106.8; transition: stroke-dashoffset 1s linear; }
.timetext { font-family: var(--font-dp); font-size: .875rem; font-weight: 800; letter-spacing: -.01em; }

.grabzone { flex: none; display: grid; place-items: center; height: 1.6rem; cursor: grab; touch-action: none; }
.grabzone:active { cursor: grabbing; }
.grabpill { display: block; width: 2.5rem; height: .3125rem; border-radius: 999px; background: var(--fill-strong); }

/* The stage keeps permanent room for the feedback sheet, so nothing reflows when it arrives. */
.taskstage { position: relative; flex: 1; display: flex; padding-bottom: 9.5rem; }
.cardlayer { position: absolute; inset: 0 0 9.5rem; display: flex; flex-direction: column; justify-content: center; }
#taskExit { pointer-events: none; }
.card { width: 100%; will-change: transform, opacity; }

.prompt { text-align: center; margin-bottom: 1.6rem; }
.plabel {
  display: inline-block; font-size: .75rem; font-weight: 800; color: var(--brand-ink);
  background: var(--brand-soft); padding: .3rem .7rem; border-radius: 999px;
}
.pword {
  font-family: var(--font-dp);
  font-size: clamp(2rem, 8vw, 2.75rem); line-height: 1.08; letter-spacing: -.035em;
  font-weight: 800; margin: .75rem 0 0;
}
.pword.sentence { font-size: clamp(1.375rem, 5.2vw, 1.75rem); line-height: 1.24; letter-spacing: -.024em; }
.psub { color: var(--ink-2); margin: .45rem 0 0; font-size: .9375rem; font-weight: 500; }

.opts { display: grid; gap: .55rem; }
.opt {
  --edgecol: var(--press-edge);
  display: flex; align-items: center; gap: .7rem;
  width: 100%; min-height: 3.5rem; padding: .75rem 1rem;
  background: var(--surface); border: 1.5px solid var(--edge); border-radius: var(--r);
  text-align: left; font-size: 1.0625rem; font-weight: 600; color: var(--ink);
  box-shadow: 0 var(--drop) 0 var(--edgecol);
  transition: transform .07s ease, box-shadow .07s ease, background-color .16s ease, border-color .16s ease;
}
.opt:active:not(:disabled) { transform: translateY(var(--drop)); box-shadow: 0 0 0 var(--edgecol); }

/* The number that answers this option. Shown only where a keyboard exists — the shortcut is
   already in the app, it was simply never mentioned anywhere. */
.optkey {
  display: none; place-items: center; flex: none;
  width: 1.5rem; height: 1.5rem; border-radius: 7px;
  background: var(--fill); color: var(--ink-3);
  font-size: .75rem; font-weight: 800;
}
.opt .optlabel { flex: 1; min-width: 0; }
.opt .optmark { flex: none; opacity: 0; transition: opacity .16s var(--ease-out); }
.opt:disabled { cursor: default; }

/* State is never colour alone — each coloured state also shows its glyph. */
.opt.state-good, .opt.state-reveal {
  --edgecol: var(--green-edge);
  background: var(--green-soft); border-color: var(--green);
}
.opt.state-good .optmark, .opt.state-reveal .optmark { opacity: 1; color: var(--green); }
.opt.state-wait { --edgecol: var(--amber-edge); background: var(--amber-soft); border-color: var(--amber); }
.opt.state-wait .optmark { opacity: 1; color: var(--amber); }
.opt.state-good .optkey, .opt.state-wait .optkey, .opt.state-reveal .optkey { opacity: .35; }

/* Eine Antwort, die nach dem ersten Fehlgriff als Hinweis weggenommen wurde. Sie verblasst und
   legt sich flach, mehr nicht: keine Farbe, kein Symbol, kein Rot. Sie ist keine Fehlermeldung,
   sondern eine kleiner gewordene Auswahl. */
.opt.state-gone { opacity: .3; box-shadow: none; transform: translateY(var(--drop)); }
.opt.state-gone .optlabel { text-decoration: line-through; text-decoration-thickness: 1px; }

.answerbox { display: flex; gap: .5rem; }
.answerbox input {
  flex: 1; min-width: 0; padding: .9rem 1rem; border-radius: var(--r);
  font-size: 1.0625rem; font-weight: 600; background: var(--surface);
  border: 2px solid var(--edge); color: var(--ink);
  transition: border-color .14s ease;
}
.answerbox input:focus { border-color: var(--brand); outline: none; }
.answerbox .btn { min-height: 3.5rem; padding: 0 1.25rem; }

.speakbtn {
  display: inline-flex; align-items: center; gap: .5rem; margin: 0 auto 1.1rem;
  padding: .7rem 1.2rem; border-radius: 999px;
  font-family: var(--font-dp); font-size: .9375rem; font-weight: 800;
  background: var(--surface); border: 1px solid var(--edge); color: var(--ink);
  box-shadow: 0 3px 0 var(--press-edge);
  transition: transform .07s ease, box-shadow .07s ease;
}
.speakbtn:active { transform: translateY(3px); box-shadow: 0 0 0 var(--press-edge); }
.speakbtn.big { font-size: 1.0625rem; padding: 1rem 1.75rem; }
.speakbtn .glyph { color: var(--brand-ink); }
.center { display: flex; justify-content: center; }

.tiles { display: flex; flex-wrap: wrap; gap: .45rem; justify-content: center; }
.tile {
  padding: .55rem .85rem; border-radius: 11px; font-size: 1rem; font-weight: 600;
  background: var(--surface); border: 1px solid var(--edge); color: var(--ink);
  box-shadow: 0 3px 0 var(--press-edge);
  transition: transform .07s ease, box-shadow .07s ease, opacity .16s var(--ease-out);
}
.tile:active:not(:disabled) { transform: translateY(3px); box-shadow: 0 0 0 var(--press-edge); }
.tile:disabled { opacity: .22; cursor: default; box-shadow: none; }
.slot {
  min-height: 3.5rem; display: flex; flex-wrap: wrap; gap: .45rem; align-content: flex-start;
  padding: .55rem; border-radius: var(--r); margin-bottom: .9rem;
  background: var(--fill); border: 0;
}
.slot:empty::before { content: attr(data-empty); color: var(--ink-3); font-size: .875rem; font-weight: 600; padding: .5rem; }
/* Gelegte Wörter sind keine Schaltflächen mehr: Da nie ein falsches Wort liegen kann, gibt es
   nichts zurückzunehmen — und damit auch keinen Grund, eine Rücknahme anzubieten. */
.slot .tile { background: var(--surface-2); }
.slot .tile.placed { display: inline-block; box-shadow: none; cursor: default; }

.gapline {
  font-family: var(--font-dp);
  font-size: clamp(1.375rem, 5.2vw, 1.75rem); font-weight: 800; line-height: 1.35; letter-spacing: -.024em;
}
.gapline .blank {
  display: inline-block; min-width: 3.5rem; color: var(--brand-ink);
  border-bottom: 3px solid var(--brand); margin: 0 .25rem;
}
.hintchip {
  display: inline-block; margin-top: .8rem; padding: .3rem .7rem; border-radius: 999px;
  background: var(--fill); color: var(--ink-2); font-size: .75rem; font-weight: 700;
}

.movecard { text-align: center; }
.movecard .moveglyph {
  display: grid; place-items: center; width: 4.5rem; height: 4.5rem; margin: 0 auto 1rem;
  border-radius: 50%; background: var(--brand-soft); color: var(--brand-ink);
}
.movecard .moveglyph .glyph { width: 2.5rem; height: 2.5rem; stroke-width: 1.6; }
.movecard h2 { margin: 0 0 .5rem; }
.movecard p { color: var(--ink-2); max-width: 24rem; margin: 0 auto 1.2rem; font-size: 1rem; }
.movetimer { font-family: var(--font-dp); font-size: 4rem; font-weight: 800; letter-spacing: -.045em; line-height: 1; }

/* ============================================================ feedback sheet

   The verdict arrives as a sheet from the bottom edge rather than a card in the flow. It puts
   the answer and the way onward in the same place every single time, which is worth more than
   any amount of visual novelty when attention is the scarce resource.

   The slide is a CSS transition, not a spring: nothing here is draggable, and a transition is
   what Reizarm and prefers-reduced-motion already know how to collapse. */

.fbsheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  padding: 1.1rem clamp(1rem, 4vw, 1.5rem) calc(1.1rem + env(safe-area-inset-bottom, 0px));
  background: var(--surface); border-top: 2px solid var(--edge);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  transform: translateY(102%);
  transition: transform .26s var(--ease-out);
  box-shadow: var(--shadow-lift);
}
.fbsheet.is-up { transform: translateY(0); }
/* It lives outside main, so nothing but the sprint may show it. */
body:not(.in-sprint) .fbsheet { display: none; }
.fbinner { max-width: 34rem; margin: 0 auto; }

/* Mixed into the surface rather than laid over it as a translucent wash: the sheet covers the
   lower part of the stage, and a see-through panel would let the card bleed through the verdict. */
.fbsheet.good { background: color-mix(in srgb, var(--green) 14%, var(--surface)); border-top-color: var(--green); }
.fbsheet.wait { background: color-mix(in srgb, var(--amber) 14%, var(--surface)); border-top-color: var(--amber); }

/* A level-up rides along on the sheet that is already coming up, rather than interrupting with
   anything of its own. Reaching a level is never bad news, so it needs no dismissal. */
.levelup {
  display: flex; align-items: center; gap: .45rem;
  margin-bottom: .75rem; padding: .4rem .75rem; border-radius: 999px;
  background: var(--brand); color: #fff;
  font-family: var(--font-dp); font-size: .875rem; font-weight: 800; letter-spacing: -.01em;
}

.fb { display: flex; align-items: flex-start; gap: .75rem; margin-bottom: .9rem; }
.fb .fbglyph {
  display: grid; place-items: center; width: 2.25rem; height: 2.25rem; flex: none; border-radius: 50%;
}
.fbsheet.good .fbglyph { background: var(--green); color: var(--on-green); }
.fbsheet.wait .fbglyph { background: var(--amber); color: var(--on-amber); }
.fb .fbtext { flex: 1; min-width: 0; padding-top: .1rem; }
/* 19px rather than 18: the green and amber titles land at 4.4:1 on their own sheet in the light
   theme, which clears the bar for large bold text but not for body text. The size is the fix. */
.fb .fbtitle { display: block; font-family: var(--font-dp); font-size: 1.1875rem; font-weight: 800; letter-spacing: -.02em; }
.fbsheet.good .fbtitle { color: var(--green); }
.fbsheet.wait .fbtitle { color: var(--amber); }
.fb .fbanswer { color: var(--ink); }
.fb .fbsub { display: block; color: var(--ink-2); font-size: .875rem; font-weight: 500; margin-top: .2rem; }
.fb .fbxp {
  flex: none; font-family: var(--font-dp); font-size: 1.0625rem; font-weight: 800;
  padding: .25rem .55rem; border-radius: 999px; background: var(--fill); color: var(--ink-2);
}
.fbsheet.good .fbxp { background: var(--green); color: var(--on-green); }
.fb.crit .fbxp { font-size: 1.25rem; }
.nextbtn { width: 100%; }
.card .nextbtn { margin-top: 1rem; }
.fbsheet.good .nextbtn { background: var(--green); color: var(--on-green); box-shadow: 0 var(--drop) 0 var(--green-edge); }
.fbsheet.good .nextbtn:active { box-shadow: 0 0 0 var(--green-edge); }
.fbsheet.wait .nextbtn { background: var(--amber); color: var(--on-amber); box-shadow: 0 var(--drop) 0 var(--amber-edge); }
.fbsheet.wait .nextbtn:active { box-shadow: 0 0 0 var(--amber-edge); }

/* ============================================================ done */

.donewrap { padding-top: 1.5rem; text-align: center; }
.donemark {
  display: grid; place-items: center; width: 4.5rem; height: 4.5rem; margin: 0 auto;
  border-radius: 50%; background: var(--green); color: var(--on-green);
  box-shadow: 0 0 0 10px var(--green-soft);
}
.donemark .glyph { width: 2.5rem; height: 2.5rem; stroke-width: 2.6; }
.donexp { color: var(--brand-ink); margin: 1.4rem 0 .2rem; }
.donexp .unit { font-size: 1.375rem; font-weight: 800; color: var(--ink-2); margin-left: .4rem; letter-spacing: -.02em; }
.donetitle { color: var(--ink-2); font-size: 1rem; font-weight: 600; margin: 0 0 1.75rem; max-width: 22rem; margin-inline: auto; }

.statrow { display: grid; grid-template-columns: repeat(3, 1fr); gap: .55rem; }
.stattile {
  background: var(--surface); border: 1px solid var(--edge); border-radius: var(--r);
  padding: .9rem .5rem; display: flex; flex-direction: column; align-items: center; gap: .1rem;
}
.stattile .sv { font-family: var(--font-dp); font-size: 1.625rem; font-weight: 800; letter-spacing: -.03em; line-height: 1.1; }
.stattile .sl { font-size: .75rem; font-weight: 600; color: var(--ink-2); }

/* Level line under the XP total. It states the level either way; when one was just reached it
   fills in and says so instead. */
.donelevel {
  display: inline-flex; align-items: center; gap: .4rem;
  margin: 0 0 1.1rem; padding: .35rem .8rem; border-radius: 999px;
  font-family: var(--font-dp); font-size: .875rem; font-weight: 800;
  background: var(--fill); color: var(--ink-2);
}
.donelevel .glyph { width: 1rem; height: 1rem; }
.donelevel.is-new { background: var(--brand); color: #fff; }

.donewrap .grouphead { text-align: left; }
.donelist .dl { display: flex; align-items: center; gap: .5rem; }
.donelist .dl .en { font-weight: 700; }
.donelist .dl .de { color: var(--ink-2); }
.donebtns { display: grid; gap: .5rem; margin-top: 1.75rem; }

/* ============================================================ stats */

.levelcard {
  background: var(--surface); border: 1px solid var(--edge); border-radius: var(--r-lg);
  padding: 1rem; margin-bottom: .6rem; box-shadow: var(--shadow);
}
.lvtop { display: flex; align-items: center; gap: .75rem; margin-bottom: .75rem; }
.lvbadge {
  display: grid; place-items: center; width: 2.75rem; height: 2.75rem; flex: none;
  border-radius: 14px; background: var(--brand); color: #fff;
  font-family: var(--font-dp); font-size: 1.375rem; font-weight: 800; letter-spacing: -.02em;
  box-shadow: 0 3px 0 var(--brand-deep);
}
.lvtext { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.lvname { font-family: var(--font-dp); font-size: 1.125rem; font-weight: 800; letter-spacing: -.02em; }
.lvsub { font-size: .8125rem; font-weight: 600; color: var(--ink-2); }

.statgrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: .6rem; }
.statgrid .stattile { align-items: flex-start; padding: 1rem; }
.statgrid .stattile .sv { font-size: 1.875rem; }
.statgrid .stattile .sl { font-size: .8125rem; }

.chartcard { background: var(--surface); border: 1px solid var(--edge); border-radius: var(--r); padding: 1rem .9rem .75rem; }
.daychart { display: flex; align-items: flex-end; gap: .28rem; height: 7.5rem; }
.daybar { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: .3rem; height: 100%; }
.daybar i { display: block; width: 100%; min-height: 4px; border-radius: 5px; background: var(--fill-strong); transform-origin: bottom; }
.daybar.has i { background: var(--brand); }
.daybar em { font-style: normal; font-size: .625rem; font-weight: 700; color: var(--ink-3); }
.daybar .dv { font-family: var(--font-dp); font-size: .625rem; font-weight: 800; color: var(--ink-2); height: .8rem; }
.daybar.today em { color: var(--brand-ink); }

.packrow { display: block; padding-top: .9rem; padding-bottom: .95rem; }
.packrow .ptop { display: flex; align-items: center; gap: .55rem; margin-bottom: .5rem; }
.packrow .ptop .pdot {
  display: grid; place-items: center; width: 1.625rem; height: 1.625rem; flex: none;
  border-radius: 8px; background: var(--tint, var(--brand)); color: #fff;
}
.packrow .ptop .pdot .glyph { width: 1rem; height: 1rem; stroke-width: 2; }
.packrow .ptop .pname { font-size: 1rem; font-weight: 700; }
.packrow .ptop .pmeta { margin-left: auto; color: var(--ink-2); font-size: .75rem; font-weight: 600; text-align: right; }
.bar { height: .375rem; border-radius: 999px; background: var(--fill-strong); overflow: hidden; }
.bar > i { display: block; height: 100%; width: 100%; border-radius: 999px; background: var(--tint, var(--brand)); transform-origin: left; }

.packrow[data-pack="alltag"]    { --tint: var(--t-alltag); }
.packrow[data-pack="arbeit"]    { --tint: var(--t-arbeit); }
.packrow[data-pack="reisen"]    { --tint: var(--t-reisen); }
.packrow[data-pack="smalltalk"] { --tint: var(--t-smalltalk); }
.packrow[data-pack="gefuehle"]  { --tint: var(--t-gefuehle); }
.packrow[data-pack="essen"]     { --tint: var(--t-essen); }
.packrow[data-pack="digital"]   { --tint: var(--t-digital); }
.packrow[data-pack="phrasen"]   { --tint: var(--t-phrasen); }

/* ============================================================ why */

.whycard {
  background: var(--surface); border: 1px solid var(--edge); border-radius: var(--r);
  padding: 1rem 1.1rem; margin-bottom: .55rem;
}
.whycard .wnum {
  display: inline-grid; place-items: center; width: 1.625rem; height: 1.625rem; margin-bottom: .55rem;
  border-radius: 8px; background: var(--brand-soft); color: var(--brand-ink);
  font-family: var(--font-dp); font-size: .75rem; font-weight: 800;
}
.whycard h3 { margin: 0 0 .3rem; font-size: 1.0625rem; font-weight: 800; letter-spacing: -.016em; }
.whycard p { margin: 0; color: var(--ink-2); font-size: .9375rem; line-height: 1.48; }
.whycard .src { display: block; margin-top: .55rem; font-size: .75rem; font-weight: 600; color: var(--ink-3); }

/* ============================================================ anmelden */

#screen-auth.is-active { display: grid; place-items: center; min-height: 100vh; min-height: 100dvh; padding-bottom: 1.5rem; }
.authwrap { width: 100%; max-width: 24rem; text-align: center; }
.authmark {
  display: grid; place-items: center; width: 4rem; height: 4rem; margin: 0 auto 1.2rem;
  border-radius: 20px; background: var(--brand); color: #fff;
  box-shadow: 0 6px 0 var(--brand-deep);
}
.authmark .glyph { width: 2.25rem; height: 2.25rem; }
.authwrap .largetitle { margin-bottom: .4rem; }
.authwrap .pagelead { margin-bottom: 1.6rem; }
.authwrap .groupfoot { text-align: left; padding: 0; margin-top: 1rem; }

.authform { display: grid; gap: .55rem; }
.authform input {
  width: 100%; padding: 1rem; border-radius: var(--r);
  font-size: 1.0625rem; font-weight: 600; background: var(--surface);
  border: 2px solid var(--edge); color: var(--ink);
  transition: border-color .14s ease;
}
.authform input:focus { border-color: var(--brand); outline: none; }
.authform input:disabled { opacity: .5; }

.inlineinput {
  width: 100%; background: none; border: 0; color: var(--ink);
  font-size: 1.0625rem; font-weight: 600; padding: .2rem 0;
}
.inlineinput:focus { outline: none; }

/* ============================================================ notices, read aloud, toast */

.notice {
  padding: .95rem 1.1rem; border-radius: var(--r); text-align: left;
  background: var(--surface); border: 1px solid var(--edge); border-left: 4px solid var(--amber);
  font-size: .875rem; line-height: 1.5; color: var(--ink-2);
}
.notice[hidden] { display: none; }
.notice strong { color: var(--ink); font-weight: 700; }
.notice ol { margin: .55rem 0 0; padding-left: 1.15rem; }
.notice li { margin-bottom: .25rem; }
.notice.ok { border-left-color: var(--green); }

.readbtn { color: var(--brand-ink); }
.readbtn.is-playing { background: var(--brand); color: #fff; }
.readbtn[hidden] { display: none; }

/* In Vorlesen-Modus every non-interactive text block can be tapped to hear just that block.
   Interactive rows keep their own action — the page button reads those. */
body.reading [data-read]:not(button [data-read]):not(label [data-read]) { cursor: pointer; }
@media (hover: hover) and (pointer: fine) {
  body.reading [data-read]:not(button [data-read]):not(label [data-read]):hover {
    background: var(--fill); box-shadow: 0 0 0 5px var(--fill); border-radius: 6px;
  }
}
/* Highlight without moving anything: the spread shadow paints outside the box. */
.is-reading {
  background: var(--brand-soft);
  box-shadow: 0 0 0 5px var(--brand-soft);
  border-radius: 6px;
}

.toast {
  position: fixed; left: 50%; bottom: 6rem; z-index: 60;
  padding: .7rem 1.1rem; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--edge-strong);
  box-shadow: var(--shadow-lift);
  font-size: .875rem; font-weight: 600; opacity: 0; pointer-events: none;
  max-width: calc(100vw - 2rem);
  transform: translate(-50%, 1.5rem);
  will-change: transform, opacity;
}
body.in-sprint .toast { bottom: 11rem; }

/* ============================================================ accessibility */

/* Reduced motion means fewer and gentler animations, not none: opacity and colour still help
   comprehension and cause no vestibular trouble, so only transforms are dropped. Reizarm is an
   explicit choice by the user and does mean none. Both leave the pressed state of a control
   intact — it simply arrives instantly, which is if anything more direct. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition-property: opacity, color, background-color, border-color !important; }
  .switch::after { transition: none !important; }
}
body.calm *, body.calm *::before, body.calm *::after { animation: none !important; transition-duration: .001ms !important; }

@media (prefers-reduced-transparency: reduce) {
  #topbar, .tabbar { background: var(--bg); -webkit-backdrop-filter: none; backdrop-filter: none; }
  main::before { display: none; }
}
body.solid #topbar, body.solid .tabbar { background: var(--bg); -webkit-backdrop-filter: none; backdrop-filter: none; }
body.solid main::before { display: none; }

@media (prefers-contrast: more) {
  :root { --separator: rgba(233,229,255,.5); --ink-2: rgba(233,229,255,.88); --ink-3: rgba(233,229,255,.7); --edge: rgba(255,255,255,.24); }
  :root[data-theme="light"] { --separator: rgba(20,18,28,.42); --ink-2: #3a3550; --ink-3: #55506a; --edge: rgba(20,18,28,.28); }
  .opt, .packtile, .group, .stattile { border-color: var(--edge-strong); }
}

/* In rem, so it also catches a normal phone once the font scale is turned up — which is exactly
   when the two counters stop fitting next to the wordmark. */
/* 30rem rather than 26: "Lernbisschen" is a long wordmark and the two counters need the room
   before it does. Below this the lightning mark carries the brand on its own. */
@media (max-width: 30rem) {
  .brandname { display: none; }
}

@media (max-width: 26rem) {
  .navbtn { min-width: 3.6rem; padding: .45rem .35rem .4rem; font-size: .625rem; }
  .packgrid { gap: .5rem; }
  .statrow { gap: .4rem; }
}

/* Hover motion and hover-only affordances are gated: on touch devices a tap fires hover,
   which leaves controls stuck in a hovered state after the finger is gone. */
@media (hover: hover) and (pointer: fine) {
  .optkey { display: grid; }
  .navbtn:hover:not(.is-on) { color: var(--ink); background: var(--fill); }
  .row:not(.static):hover { background: var(--fill); }
  .iconbtn:hover { color: var(--ink); background: var(--fill-strong); }
  .opt:hover:not(:disabled) { border-color: var(--edge-strong); background: var(--surface-2); }
  .packtile:hover:not(.is-on) { opacity: .85; }
  .tile:hover:not(:disabled) { background: var(--surface-2); }
  .link:hover { text-decoration: underline; }
}
