/* Tikrar — one stylesheet. Mobile-first, calm, RTL.
 * Palette: ink #0B1B2B · teal #12A594 · mist #F5F8FA · line #E4EBF1
 *          muted #5B7286 · amber #F0A500 · coral #E4572E
 */

:root {
  --ink: #0B1B2B;
  --teal: #12A594;
  --teal-dark: #0E897B;
  --mist: #F5F8FA;
  --line: #E4EBF1;
  --muted: #5B7286;
  --amber: #F0A500;
  --coral: #E4572E;

  --card: #FFFFFF;
  --radius: 16px;
  --radius-sm: 10px;
  --shadow: 0 1px 2px rgba(11, 27, 43, .06), 0 6px 20px rgba(11, 27, 43, .06);
  --shadow-lg: 0 10px 40px rgba(11, 27, 43, .16);
  --tap: 44px;
  --font: system-ui, "Noto Naskh Arabic", "Segoe UI", Tahoma, sans-serif;
  --tabbar-h: 82px;          /* 56px pill + its 26px gutter: what the scroller and a toast clear */
  --appbar-h: 58px;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; height: 100%; overflow: hidden; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.65;
  color: var(--ink);
  background: var(--mist);
  -webkit-font-smoothing: antialiased;
  /* The frame is ONE full-height flex column: the app bar, the banner and the tab bar are real
     flow boxes glued to the screen edges, so nothing rides WebKit's sliding visual viewport.
     Only #view scrolls. */
  display: flex;
  flex-direction: column;
  height: 100%;                  /* fallback where dvh is unknown (html carries height: 100%) */
  min-height: 100%;              /* ICB-bounded floor: can only fill the shell up to the layout viewport,
                                    never grow it past the visible area or hide the flex:none tab bar */
  height: 100dvh;
  overflow: hidden;
  position: relative;            /* containing block for the .waiting / .modal scrims */
}

/* Installed web apps only: the large viewport (100lvh) IS the full screen and is never
   larger than it, so the shell reaches the real bottom edge. Scoped to standalone so a
   browser tab — where lvh can exceed the visible area as the URL bar hides — is untouched.
   One unit, no arithmetic, comparing nothing: it cannot overshoot. */
@media (display-mode: standalone) {
  body { min-height: 100lvh; }
}

a { color: var(--teal-dark); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { line-height: 1.3; margin: 0 0 .4em; }
h1 { font-size: 1.5rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1.02rem; }
p { margin: 0 0 .8em; }

:focus-visible { outline: 3px solid var(--teal); outline-offset: 2px; border-radius: 6px; }

/* ── App bar ──────────────────────────────────────────────────────────── */
.appbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  height: calc(var(--appbar-h) + env(safe-area-inset-top));   /* 58px of content + the top inset */
  padding: 0 14px;
  padding-top: env(safe-area-inset-top);
  background: var(--ink);
  color: #fff;
  box-shadow: var(--shadow);
  flex: none;
}
.brand { display: inline-flex; align-items: center; gap: 9px; color: #fff; }
.brand:hover { text-decoration: none; }
.brand__mark img { display: block; border-radius: 8px; }
.brand__name { font-weight: 700; font-size: 1.18rem; letter-spacing: .3px; }
/* The app version beside the wordmark: 0.72rem against the name's 1.18rem, so it reads as a footnote to
   the name, not a second title. Baseline-aligned and nowrap so it can never wrap the name or grow the
   58px bar. Colour #8FA3B3 on the ink #0B1B2B bar = 6.68:1 contrast (AA for normal text). */
.brand__ver {
  align-self: baseline;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .3px;
  white-space: nowrap;
  color: #8FA3B3;
}
.brand__ver[hidden] { display: none; }
.appbar__end { display: flex; align-items: center; gap: 8px; min-width: 0; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: .74rem;
  font-weight: 600;
  white-space: nowrap;
}
.chip--offpeak { background: rgba(18, 165, 148, .18); color: #7FE6DA; }
.chip--peak { background: rgba(240, 165, 0, .18); color: #FFD27A; }
.chip--done { background: rgba(18, 165, 148, .14); color: var(--teal-dark); }
.chip--due { background: rgba(228, 87, 46, .14); color: var(--coral); }
.chip--muted { background: rgba(91, 114, 134, .14); color: var(--muted); }

/* The name IS the account link (an <a href="#/me">) — 44px tall so it is a real tap target. */
.usermenu__btn {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 4px 10px 4px 4px;
  background: rgba(255, 255, 255, .08);
  border: 0; border-radius: 999px; color: #fff; cursor: pointer;
  font: inherit; font-size: .9rem;
  min-width: 0;   /* the pill may shrink so the name truncates instead of overflowing the header */
}
.usermenu__btn:hover { text-decoration: none; background: rgba(255, 255, 255, .14); }
.usermenu__avatar {
  display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 999px;
  background: var(--teal); color: #fff; font-weight: 700;
}
/* Earned streak freezes beside the name — display only, never a control. The count is the signal (tabular
   digits so it never jitters); the emoji is decoration and the full meaning lives on the insights screen. */
.usermenu__freeze {
  display: inline-flex; align-items: center; gap: 2px;
  flex: 0 0 auto;   /* the badge keeps its box; a long name shrinks and truncates instead (T-071) */
  font-size: .9rem; font-variant-numeric: tabular-nums; opacity: .95;
}
.usermenu__freeze[hidden] { display: none; }
/* A fixed-height appbar carries ONE line of the learner's name, never two: never wrap — truncate with
   an ellipsis when there is genuinely no room. min-width:0 lets this flex item shrink below its
   content size (wrapping was the old failure); max-width stops a very long name from ever pushing
   the pill off the screen edge. */
.usermenu__name {
  min-width: 0; max-width: 128px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ── Layout ───────────────────────────────────────────────────────────── */
.view {
  width: 100%;          /* definite width: an auto-margin flex item is not stretched by the column
                           container, so #view used to size to max-content and overflow the screen. */
  max-width: 720px;
  margin: 0 auto;
  padding: 16px 14px calc(16px + var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
  /* the ONE scrolling region: it takes the space UNDER the floating bar and owns the scroll */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
/* In a session the scroller hands its padding to .review-body, so the session footer is flush.
   The flex column is scoped HERE, not on .view, so every other screen keeps its plain block flow.
   A review session must stay flex: a single-question card is SHORTER than the screen, so
   .review-body { flex: 1 1 auto } is what pushes the pinned .session-footer down to the real bottom
   edge; without it the ratings would float mid-screen with dead space under them — the exact
   "where do I tap" fail this ticket exists to kill. */
.view.is-session { padding: 0; display: flex; flex-direction: column; }

/* A running session owns the TOP edge too (T-031 Variant A). The app bar is static markup OUTSIDE
   #view (web/index.html), so the session's `#view.is-session` class can never style it — a sibling
   header has no descendant relationship — and setSessionChrome() toggles this body-level hook
   explicitly instead (deliberately not `:has()`). Wordmark, version badge, account pill and the
   app-bar off-peak chip all leave the screen while a card is open. */
body.is-session .appbar { display: none; }
/* The notch inset the bar used to carry has to go somewhere. T-034/T-112 sized the bar as
   `height: calc(var(--appbar-h) + env(safe-area-inset-top))` with `padding-top: env(safe-area-inset-top)`;
   with the bar hidden, THIS rule is what carries the inset in a session — the scroller takes the top
   safe area as its own padding, so the first row ("Card N of M") starts below the notch instead of
   sliding under it. `env()` resolves to 0px on a device with no notch, so nothing changes there. */
body.is-session .view.is-session { padding-top: env(safe-area-inset-top); }
@media (min-width: 900px) {
  .view { max-width: 880px; padding-top: 26px; }
}

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  margin: 0 0 14px;
  box-shadow: var(--shadow);
}
.page-title { margin: 2px 0 14px; }
.muted { color: var(--muted); }
.small { font-size: .86rem; }
.center { text-align: center; }
.row { display: flex; align-items: center; gap: 10px; }
.row--wrap { flex-wrap: wrap; }
.spread { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.stack > * + * { margin-top: 10px; }

/* ── Buttons ──────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: var(--tap); padding: 0 18px;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--card); color: var(--ink);
  font: inherit; font-weight: 600; cursor: pointer;
  transition: background .12s ease, transform .06s ease;
}
.btn:hover { background: var(--mist); }
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: .5; cursor: progress; }
.btn--primary { background: var(--teal); border-color: var(--teal); color: #fff; }
.btn--primary:hover { background: var(--teal-dark); }
.btn--block { width: 100%; }
.btn--lg { min-height: 56px; font-size: 1.08rem; border-radius: 14px; }
.btn--danger { color: var(--coral); border-color: rgba(228, 87, 46, .4); }
.btn--danger:hover { background: rgba(228, 87, 46, .08); }
.btn--ghost { border-color: transparent; background: transparent; }
.btn--sm { min-height: 38px; padding: 0 12px; font-size: .88rem; border-radius: 9px; }
/* T-101 — the deck screen's action row (Review · Practice · Edit · Scan). Small type like
   .btn--sm, but never a small target: the 44px floor holds, so the row is one line on a
   360 px phone without shrinking what the thumb has to hit. */
.btn--row { min-height: var(--tap); padding: 0 12px; font-size: .88rem; border-radius: 10px; }
.deck-actions { gap: 8px; }
/* The wrap-up's SECONDARY action (T-010): smaller type, no fill, no border — and still a full 44px tap
   target, so "small" never means "hard to hit" on a phone. */
.btn--quiet {
  min-height: var(--tap); padding: 0 12px;
  border-color: transparent; background: transparent;
  color: var(--muted); font-size: .92rem; border-radius: 10px;
}
.btn--quiet:hover { background: var(--mist); color: var(--ink); }

/* The bottom of the account screen: a hairline separator and one neutral, full-width Sign out.
   Signing out is deliberately NOT a tap away from the daily loop (it used to live in a menu on
   the bar). No red here — red is reserved for the one irreversible action. */
.account-footer { margin: 32px 0 14px; padding-top: 24px; border-top: 1px solid var(--line); }
.account-footer .btn { min-height: 48px; }

/* The account switch-off (D-25) — the one irreversible action, so it wears the reserved red and sits last.
   The red sentence is the only thing said about what happens: nothing about decks. */
.switch-off { margin: 18px 0 8px; }
.switch-off .btn { min-height: 48px; }
.switch-off__warn { margin: 10px 2px 0; text-align: center; color: var(--coral); font-size: .88rem; line-height: 1.4; }

/* ── Forms ────────────────────────────────────────────────────────────── */
.field { display: block; margin: 0 0 12px; }
.field__label { display: block; margin: 0 0 6px; font-size: .92rem; font-weight: 600; color: var(--ink); }
.input, .textarea, .select {
  width: 100%;
  min-height: var(--tap);
  padding: 10px 12px;
  font: inherit; font-size: 1rem;
  color: var(--ink); background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.textarea { min-height: 96px; resize: vertical; line-height: 1.6; }
.input:focus, .textarea:focus, .select:focus { border-color: var(--teal); outline: none; box-shadow: 0 0 0 3px rgba(18, 165, 148, .18); }
.inline-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.inline-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
@media (max-width: 420px) { .inline-3 { grid-template-columns: 1fr; } }

/* ── Stats / tiles ────────────────────────────────────────────────────── */
.tiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
@media (min-width: 640px) { .tiles { grid-template-columns: repeat(4, 1fr); } }
.tile { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px; text-align: center; }
.tile__num { font-size: 1.7rem; font-weight: 700; color: var(--teal-dark); line-height: 1.1; }
.tile__num--amber { color: var(--amber); }
.tile__lbl { font-size: .82rem; color: var(--muted); margin-top: 4px; }
/* ── The Home day tile (T-111 / D-T10) ────────────────────────────────────
   The number IS a fraction toward the next freeze, so it holds tabular digits and never wraps; the
   chain is a second, quieter line inside the same tile (the snowflake stays alone in the top bar). */
.tile--day .tile__num { font-size: 1.55rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tile__chain {
  margin-top: 5px; font-size: .78rem; line-height: 1.2;
  color: var(--muted); font-variant-numeric: tabular-nums;
}
/* Visually hidden, still spoken: the fraction's real words ("3 of 5 days") — a screen reader reads
   "3/5" as "three slash five". One rule, the standard clip, no display: none (which would silence it). */
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ── Deck list ────────────────────────────────────────────────────────── */
.deck {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px; margin-bottom: 10px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  color: inherit; box-shadow: var(--shadow);
}
.deck:hover { text-decoration: none; border-color: var(--teal); }
.deck__swatch { width: 12px; align-self: stretch; border-radius: 999px; background: var(--teal); flex: none; }
.deck__main { flex: 1 1 auto; min-width: 0; }
.deck__name { font-weight: 700; display: block; }
.deck__sub { font-size: .84rem; color: var(--muted); }
.deck__meta { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }

/* ── T-166: the decks tab carries TWO groups — "Your decks", then "Shared with you" ──────────
   The shelf reuses the existing .tiles grid (a rectangle card, no new component); the two columns
   it needs are its own modifier, like .tiles--5 / .tiles--6 elsewhere. */
.decks-heading { font-size: 1.05rem; margin: 18px 0 8px; }
.tiles--decks { grid-template-columns: 1fr; }
@media (min-width: 640px) { .tiles--decks { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px) { .tiles--decks { grid-template-columns: repeat(3, 1fr); } }
.shared-card { text-align: start; display: flex; flex-direction: column; gap: 6px; }
.shared-card__head { display: flex; align-items: center; gap: 10px; min-width: 0; }
.shared-card__swatch { align-self: auto; height: 18px; width: 10px; }
.shared-card__name { font-weight: 700; color: var(--ink); min-width: 0; overflow-wrap: anywhere; }
.shared-card__by { margin: 0; }
.shared-card__num { margin: 2px 0 0; font-size: 1.25rem; font-weight: 700; color: var(--teal-dark); }
.shared-card__hint { font-weight: 400; font-size: .8rem; }
.shared-card__actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: auto; padding-top: 4px; }
.shared-card__actions .btn { flex: 1 1 auto; }

/* ── Audience ("who is this deck for?") ───────────────────────────────── */
.chip--level { background: rgba(18, 165, 148, .14); color: var(--teal-dark); }
.audience-card h2 { margin-top: 0; }
.audience-current { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 2px 0 14px; }
.hint { font-size: .82rem; color: var(--muted); margin: 6px 0 0; }
/* T-354 — the source counter under a concept's textarea turns green at the length a question can be
   written from; below it the card sits in the deck's «Waiting for more text» fold instead of a round */
.hint.charcount.ok { color: #8FD96B; }

/* ── Review ───────────────────────────────────────────────────────────── */
.review-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
/* T-330 / D-T38 — the day's one line, coloured by the gate (coral → lime). No words, no badge: the
   colour moves card by card, and a short ease makes a rating feel like it moved something. */
.review-head__day { transition: color .28s ease; }
.progress { height: 6px; border-radius: 999px; background: var(--line); overflow: hidden; margin: 10px 0 16px; }
.progress__bar { height: 100%; background: var(--teal); width: 0; transition: width .25s ease; }

.qcard { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px; }
/* .qcard__meta / __deck / __type / __path are GONE: the card meta row no longer renders anywhere in
   the app (T-031 Variant A removed it from the session card and nothing else built one). */

/* T-033 · decision D-14 — the session card's ONE move: after a self-rating advances to the next
   question the INCOMING card enters (220 ms, inside the 250 ms entrance budget). The exit is
   deliberately NOT animated: the outgoing card is replaced the instant the write resolves, and
   holding it there would move a card the learner may still be reading (and could stall the loop if
   the write fails). Transform + opacity only, so the card's BOX never changes size, the pinned
   session footer cannot be pushed, and nothing loops. The class is applied by renderReviewCard()
   only when submitRating() raised review.advanceMotion — never inside the recall window. */
.qcard--enter { animation: qcard-in .22s ease-out; }
@keyframes qcard-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}
.qcard__prompt { font-size: 1.18rem; line-height: 1.75; white-space: pre-wrap; word-wrap: break-word; }
.qcard__choices { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 8px; }
.qcard__choices li { padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--mist); }
/* MCQ options are the answer surface: real one-shot buttons, green when correct / red when wrong. */
.qcard__choices--interactive li { padding: 0; border: 0; background: transparent; }
.choice {
  display: block; width: 100%; text-align: start; font: inherit; color: var(--ink);
  padding: 10px 12px; border: 2px solid var(--line); border-radius: var(--radius-sm);
  background: var(--mist); cursor: pointer;
}
.choice:hover { border-color: var(--teal); }
.choice[disabled] { cursor: default; }
.choice--correct { border-color: #1f9d55; background: rgba(31, 157, 85, .14); color: #14713d; }
.choice--wrong { border-color: var(--coral); background: rgba(228, 87, 46, .14); color: #a8331a; }
.choice--correct:hover, .choice--wrong:hover { border-color: inherit; }

.answer { margin-top: 16px; padding-top: 16px; border-top: 1px dashed var(--line); }
.answer__label { font-size: .8rem; font-weight: 700; color: var(--teal-dark); letter-spacing: .5px; margin-bottom: 4px; }
.answer__body { white-space: pre-wrap; word-wrap: break-word; }
.citations { margin: 12px 0 0; padding: 10px 12px; border-inline-start: 3px solid var(--amber); background: rgba(240, 165, 0, .07); border-radius: 8px; }
.citations__label { font-size: .78rem; font-weight: 700; color: #9a6b00; }
.citations q { display: block; margin-top: 4px; font-style: italic; }

/* ── Merged answer card: answer + explanation + memory hook + quoted sources, one block ── */
.merged { margin-top: 14px; display: grid; gap: 12px; }
.merged__label { font-size: .8rem; font-weight: 700; color: var(--teal-dark); letter-spacing: .5px; margin-bottom: 4px; }
.merged__label--hook { display: flex; align-items: center; gap: 6px; color: #9a6b00; }
.merged__hook-icon { font-size: 1rem; line-height: 1; }
.merged__answer { font-weight: 600; white-space: pre-wrap; word-wrap: break-word; }
.merged__body { white-space: pre-wrap; word-wrap: break-word; }
.merged__explanation { }
.merged__mnemonic { padding: 8px 12px; border-inline-start: 3px solid var(--amber);
  background: rgba(240, 165, 0, .10); border-radius: 8px; }
.merged .citations { margin-top: 0; }

/* Four equal columns at EVERY width — the four buttons are the scheduler's ONLY input, so a
   wrapped 2×2 row (a vertical mis-tap moving the interval ±2) is not allowed. The row never
   breaks; below ~420px the four TARGETS only slim the interval label, never themselves:
   min-height stays 62px, comfortably over the 44 CSS px a thumb needs (WCAG 2.2 SC 2.5.8 floor 24). */
.ratings { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 16px; }
/* T-139 — the rating buttons must declare their own text colour. Without it they inherit the UA's
   `ButtonText`, which flips with the OS theme because index.html declares `color-scheme: light dark`;
   the four labels then rendered WHITE on the white `--card` surface (computed rgb(255,255,255) on
   rgb(255,255,255) = 1.00:1 — invisible). Every other button here is fine because .btn sets `color`.
   `var(--ink)` is #0B1B2B, 17.41:1 on the card, and does not move the 87.5x62 target or the previews. */
.rate {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  min-width: 0; min-height: 62px; padding: 8px; border: 1px solid var(--line); border-radius: 12px;
  background: var(--card); color: var(--ink); font: inherit; cursor: pointer;
  position: relative;              /* T-033: the ✓ chosen cue is placed in the button's corner */
}
.rate:hover { border-color: var(--teal); background: var(--mist); }
.rate[disabled] { opacity: .5; cursor: progress; }
.rate__name { font-weight: 700; }
.rate--again { border-inline-start: 4px solid var(--coral); }
.rate--hard { border-inline-start: 4px solid var(--amber); }
.rate--good { border-inline-start: 4px solid var(--teal); }
.rate--easy { border-inline-start: 4px solid var(--teal-dark); }
/* T-033 · D-14 — the immediate answer to a rating tap: the state is set in the SAME tick, before the
   write leaves the phone, and it is NOT colour alone (the greyscale test). The tapped button keeps
   its FULL opacity while the other three dim (the row is locked, .rate[disabled] opacity), takes a
   2px inset ring, and shows a ✓ mark in its corner — so the chosen answer is still readable in
   greyscale, in monochrome and to a colour-blind learner. Only the surface colour eases, in 100 ms,
   well inside the "every tap answers within 100 ms" rule; the state itself appears instantly. */
.ratings.is-locked { cursor: progress; }
.rate.is-chosen {
  border-color: var(--teal); background: var(--mist);
  box-shadow: inset 0 0 0 2px var(--teal);
  transition: background .1s ease, box-shadow .1s ease;
}
.rate.is-chosen[disabled] { opacity: 1; }   /* the rated tap stays legible while the row is locked */
.rate__check { position: absolute; top: 3px; inset-inline-end: 5px; line-height: 1;
  font-size: .72rem; font-weight: 700; color: var(--teal-dark); }
@media (max-width: 420px) {
  .ratings { gap: 4px; }
  .rate { padding: 6px 2px; }
}

/* ── T-275 — the two taps that grade a card ────────────────────────────────────────────────────
   Certainty is asked BEFORE the answer, on every card: three words, one row, 44 pt targets, and on a
   recall card the tap is also the reveal. After a judged card there is ONE button (the reading time);
   after a reveal card there is the one outcome question — ✗ No · ½ Close · ✓ Yes, a glyph over its
   word so the red-amber-green ramp never has to be read as colour alone. */
.certainty, .outcome, .verdict-row { margin: 8px 14px 12px; }
.certainty__ask, .certainty__locked { margin: 0 0 6px; }
.certainty__locked { display: block; padding: 10px 2px; }
.certainty__row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 9px; }
.certainty__btn {
  min-height: var(--tap); padding: 10px 6px; border: 1px solid var(--line); border-radius: 12px;
  background: var(--card); color: var(--ink); font: inherit; font-weight: 600; cursor: pointer;
  min-width: 0;
}
.certainty__btn:hover { border-color: var(--teal); background: var(--mist); }
.certainty__btn[aria-pressed="true"] { border-color: var(--teal); box-shadow: inset 0 0 0 2px var(--teal); }
.outcome__ask { margin: 0 0 8px; text-align: center; }
.outcome__row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 9px; }
.outcome__btn {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  min-height: 62px; min-width: 0; padding: 8px; border: 1px solid var(--line); border-radius: 12px;
  background: var(--card); color: var(--ink); font: inherit; cursor: pointer;
}
.outcome__btn:hover { background: var(--mist); }
.outcome__btn[disabled] { opacity: .5; cursor: progress; }
.outcome__btn--no { border-inline-start: 4px solid var(--coral); }
.outcome__btn--close { border-inline-start: 4px solid var(--amber); }
.outcome__btn--yes { border-inline-start: 4px solid var(--teal); }
.outcome__glyph { font-size: 1.15rem; font-weight: 700; line-height: 1; }
.outcome__word { font-size: .78rem; color: var(--muted); }
@media (max-width: 420px) {
  .certainty__row, .outcome__row { gap: 4px; }
}

/* ── T-276 — the survey ────────────────────────────────────────────────────────────────────────
   Raised AFTER the answer exists — a reveal tap, or Send on a judged card — and never before it.
   A light card in the middle of the page on a frosted backdrop: the words are already on the card
   behind it and the blur is what keeps the prediction honest. */
.survey {
  position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; padding: 15px;
  background: rgba(10, 14, 14, .34);
  -webkit-backdrop-filter: blur(9px) saturate(115%);
  backdrop-filter: blur(9px) saturate(115%);
  animation: survey-in .16s ease-out;
}
.survey__card {
  width: min(380px, 100%); padding: 18px; text-align: center;
  background: var(--card); border: 1px solid var(--line); border-radius: 18px;
  box-shadow: 0 18px 50px rgba(16, 32, 32, .18);
}
.survey__ask { margin: 0 0 12px; font-weight: 700; font-size: 1.02rem; color: var(--ink); }
.survey__row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 9px; }
.survey__btn {
  min-height: var(--tap); min-width: 0; width: 100%; padding: 11px 6px; font-size: .97rem;
  border: 1px solid var(--line); border-radius: 12px; background: var(--mist);
  color: var(--ink); font: inherit; font-weight: 600; cursor: pointer;
}
.survey__btn:hover { border-color: var(--teal); background: var(--card); }
.survey__btn:active { transform: scale(.98); }
@keyframes survey-in { from { opacity: 0 } to { opacity: 1 } }

/* ── the certainty scale — one track, three stops, three shapes ──────────────────────────────────
   The owner's picture, 30.10 evening: one pill holding three stops, the glyph above the word, the
   chosen stop filled in mint with a soft halo. A single object with three positions reads as a scale,
   not as three buttons: the hand slides rather than hunts. Filled circle, half circle, diamond carry
   the order, so the words are read once and never again. Mint (not the lime action) because this is
   a reading of himself, not a "go" button. */

.survey__row {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0;
  padding: 5px; background: #101413; border: 1px solid var(--line); border-radius: 999px;
}
.survey__btn {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  min-width: 0; min-height: 64px; padding: 8px 2px;
  background: transparent; border: 0; border-radius: 999px; color: var(--muted);
  transition: background .14s ease, color .14s ease, box-shadow .14s ease;
  touch-action: manipulation;
}
.survey__btn:hover { background: rgba(255, 255, 255, .05); color: #C9D2CE; }
.survey__btn:active,
.survey__btn[aria-checked="true"] {
  background: var(--teal-dark); color: #0A1410;
  box-shadow: 0 0 0 3px rgba(91, 224, 176, .18), 0 8px 20px rgba(91, 224, 176, .28);
}
.survey__glyph { font-size: 17px; line-height: 1; }
.survey__label {
  font-size: 10px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  white-space: nowrap;
}
.survey__btn:focus-visible { outline: 3px solid var(--teal-dark); outline-offset: 3px; }

/* ── T-359 · the finish screen — one block, one row of three ways out ────────────────────────────
   His word (30.10.2026 night): «card is totally chaos. The header is from all design. There is
   messages different messages everywhere I need a unified design with the app and one seamless block
   of text with three horizontal buttons … the footer will be the same». So: the app's own card, left
   aligned like every other screen, one paragraph under the heading, the coach's note as that same
   block's last sentence behind a hairline, and three equal buttons in one row, each with a forward
   arrow. No colour does the ranking any more — the row is one texture, three labels. */
.finish { display: block; padding: 6px 12px 0; }
.finish__block { padding: 18px 16px 16px; }
.finish__title {
  margin: 0 0 10px; color: var(--ink); font-size: 21px; line-height: 1.25; font-weight: 800;
  letter-spacing: -0.01em; text-align: start;
}
.finish__line {
  margin: 0 0 5px; color: var(--muted); font-size: 15px; line-height: 1.5; text-align: start;
}
.finish__line:last-of-type { margin-bottom: 0; }
.finish__line .num { color: var(--ink); font-weight: 700; }
.finish__note {
  margin: 14px 0 0; padding-top: 13px; border-top: 1px solid var(--line);
  color: var(--ink); font-size: 15px; line-height: 1.62; text-align: start;
}
.finish__note:empty { display: none; }
.finish__acts {
  display: flex; align-items: center; justify-content: center;
  width: max-content; margin: 22px auto 0;
}
/* T-359 · the ways out ARE the floating footer bar: same 56 px pill, same 28 px ends, same shadow,
   icon slots inside it, and the way on drawn with the footer's own play triangle. */
.finish__bar {
  display: flex; align-items: center; gap: 2px; height: 56px; padding: 0 10px;
  background: var(--raised); border-radius: 28px;
  box-shadow: 0 6px 20px rgba(11, 27, 43, .14);
}
.act {
  display: grid; place-items: center;
  width: 56px; height: 56px; min-height: var(--tap);
  padding: 0; border: 0; background: transparent; color: var(--muted);
  border-radius: 50%; font: inherit; cursor: pointer;
  transition: color .15s ease, transform .1s ease;
}
.act:hover { color: var(--ink); }
.act:active { transform: translateY(1px); }
.act svg { display: block; width: 22px; height: 22px; }
.act--go { color: var(--teal); }
.act--go svg { width: 26px; height: 26px; }
.act--go:hover { color: var(--teal-dark); }
.act:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; }

/* ── T-275 — the coach ─────────────────────────────────────────────────────────────────────────
   The note at the end of a sitting, and the page on the Insights tab. A tinted card, the two numbers
   the app can prove, then sentences — never a second dashboard. */
.coach-note { max-width: 420px; margin: 18px auto 0; }
.coach-note__card, .coach-page__card {
  text-align: start; background: var(--mist); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px;
}
.coach-note__who {
  margin: 0 0 6px; text-transform: uppercase; letter-spacing: .08em; font-weight: 700;
}
.coach-note__strip { margin: 0 0 8px; }
.coach-note__text { margin: 0; line-height: 1.55; color: var(--ink); }
.coach-page { margin-bottom: 14px; }
.coach-page__action { margin: 10px 0 0; color: var(--teal-dark); font-weight: 600; }
/* T-400 — the weekly page: a headline, short paragraphs, the week as seven bars. */
.coach-week__head { margin: 0 0 8px; font-weight: 700; line-height: 1.45; color: var(--ink); }
.coach-week__para { margin: 0 0 8px; line-height: 1.55; color: var(--ink); }

/* ── Blurred "secret text" reveal (answer / explanation) ───────────────────
   Cosmetic obfuscation on the learner's own device: the text is already in the
   payload, it is blurred until tapped. The blur IS the retrieval cue, so it stays;
   the dot texture that used to sit over it is gone (decoration, not a cue). The
   masked surface carries a faint brand tint and a teal border so it reads as a live
   "tap to reveal", never as plain disabled grey text. */
.reveal { margin-top: 14px; }
.reveal__btn {
  position: relative; display: block; width: 100%; text-align: start; font: inherit;
  color: inherit; cursor: pointer; padding: 12px 14px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--mist);
}
.reveal__btn:hover { border-color: var(--teal); }
.reveal.is-revealed .reveal__btn { background: var(--card); border-color: var(--teal); }
/* Masked: a live, tappable surface — faint teal wash, teal border, no dot texture. */
.reveal:not(.is-revealed) .reveal__btn { background: rgba(18, 165, 148, .06); border-color: rgba(18, 165, 148, .35); }
.reveal:not(.is-revealed) .reveal__btn:hover { border-color: var(--teal); }
.reveal__label { display: block; font-size: .8rem; font-weight: 700; color: var(--teal-dark);
  letter-spacing: .5px; margin-bottom: 4px; }
.reveal__content { display: block; white-space: pre-wrap; word-wrap: break-word;
  transition: filter .18s ease, opacity .18s ease; }
.reveal:not(.is-revealed) .reveal__content { filter: blur(6px); opacity: .55; user-select: none; pointer-events: none; }
.reveal__hint { display: inline-block; margin-top: 8px; font-size: .78rem; font-weight: 700;
  color: var(--teal-dark); letter-spacing: .3px; }
.reveal__hide {
  margin-top: 6px; padding: 3px 10px; font: inherit; font-size: .78rem; font-weight: 600;
  color: var(--muted); background: transparent; border: 1px solid var(--line);
  border-radius: 999px; cursor: pointer;
}
.reveal__hide:hover { color: var(--ink); border-color: var(--teal); }

/* ── Multi-blank cloze: one tappable chip per blank, each revealed on its own tap ── */
.blank-tools { margin-top: 10px; }
.blank {
  display: inline-block; vertical-align: baseline; margin: 0 2px; padding: 2px 10px;
  font: inherit; line-height: 1.3; cursor: pointer; border-radius: 8px;
  border: 1px solid var(--teal); background: rgba(18, 165, 148, .12); color: var(--teal-dark);
}
.blank:hover { background: rgba(18, 165, 148, .22); }
.blank__mask { letter-spacing: 2px; font-weight: 700; }
.blank.is-revealed { background: rgba(31, 157, 85, .14); border-style: solid; border-color: #1f9d55; color: #14713d; }
.blank__answer { font-weight: 600; }

/* ── True/False answer buttons — two, coloured on choice; never the rating row ── */
.tf { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-top: 14px; }
.tf__btn {
  min-height: 48px; padding: 10px 12px; font: inherit; font-weight: 700; cursor: pointer;
  border: 2px solid var(--line); border-radius: 12px; background: var(--card); color: var(--ink);
}
.tf__btn:hover { border-color: var(--teal); }
.tf__btn--correct { border-color: #1f9d55; background: rgba(31, 157, 85, .14); color: #14713d; }
.tf__btn--wrong { border-color: var(--coral); background: rgba(228, 87, 46, .14); color: #a8331a; }
.tf__btn--correct:hover, .tf__btn--wrong:hover { border-color: inherit; }
.tf__verdict { margin: 8px 0 0; font-weight: 700; }
.tf__verdict--ok { color: #14713d; }
.tf__verdict--no { color: var(--coral); }

@media (prefers-reduced-motion: reduce) {
  .reveal__content { transition: none; }
  .psources__body { animation: none; }
  /* T-033 · D-14 — both new pieces of motion are decoration: with reduced motion asked for, the next
     card is simply THERE and the rating tap is instant. Nothing else about the card changes. */
  .qcard--enter { animation: none; }
  .rate.is-chosen { transition: none; }
  .survey { animation: none; }
  .survey__btn:active { transform: none; }
  .survey__btn { transition: none; }
}

/* ── Waiting frame ─────────────────────────────────────────────────────────
   T-323 — the app has ONE waiting visual: the T-313 ring. It replaces the old 28 px .spinner and
   the onboarding card's SVG arc, so no screen shows a different kind of circle. */
.waiting {
  position: absolute; inset: 0; z-index: 60;
  display: grid; place-items: center;
  background: rgba(245, 248, 250, .72);
}
.waiting__card {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 20px 24px; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.waiting__card .scanring { margin: 0; }
.waiting__line { margin: 0; color: var(--ink); font-weight: 600; }
/* The one way out of the frame: a plain, calm secondary action (44px target via .btn), no colour. */
.waiting__cancel { margin-top: 4px; }

/* T-323 — the bare waiting screen (review preparing, home, stats, editor): the ring in the middle
   of the free area, its line under it, nothing else. `min-height: 100%` fills the scroller's content
   box, whose bottom padding already reserves the floating tab bar — so the ring settles on the
   centre of the space the learner can actually see, never under the bar. */
.empty--wait {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 16px; min-height: 100%; padding: 0 18px; margin: 0;
  box-sizing: border-box; text-align: center;
}
.view.is-session .empty--wait { flex: 1 1 auto; }
.empty--wait .scanring { margin: 0; flex: none; }
.empty__line { margin: 0; color: var(--ink); font-weight: 600; font-size: 16px; line-height: 1.45; }

.empty { text-align: center; padding: 40px 18px; color: var(--muted); }
.empty h2 { color: var(--ink); }
/* The end-of-session line that says when the next cards come (T-010): ink, not muted — it is the one new
   fact on the screen — and its changing digits sit in monospace so the sentence keeps its shape. */
.next-cards { margin: 6px 0 0; color: var(--ink); font-weight: 600; }
.num { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; font-variant-numeric: tabular-nums; }

/* ── Tree / topics ────────────────────────────────────────────────────── */
.topic { margin: 0 0 6px; }
.topic__name { font-weight: 700; display: flex; align-items: center; gap: 8px; margin: 16px 0 8px; }
.topic__name::before { content: ""; width: 8px; height: 8px; border-radius: 2px; background: var(--teal); flex: none; }
.concept {
  display: flex; align-items: flex-start; gap: 10px; justify-content: space-between;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius-sm); margin-bottom: 8px; background: var(--card);
}

/* ── T-129 — a concept is ONE dense line, and its editor is the same line opened in place ──────────
   Owner, 18.10.2026: "No seperations no blocks no wide spaces. Goal is compaction". No card, no chip
   row, no confidence bar: a bold title, the concept's own text in regular type, one muted number line. */
.concept-groups .concept { border: 0; background: none; box-shadow: none; padding: 2px 0;
  border-radius: 0; margin-bottom: 0; gap: 8px; align-items: center; }
.concept__open { flex: 1; min-width: 0; cursor: pointer; padding: 6px 0; }
.concept__title { font-weight: 700; font-size: .96rem; line-height: 1.25; color: var(--ink); }
.concept__text { font-size: .82rem; line-height: 1.35; color: var(--muted); margin-top: 1px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.concept__stats { font-size: .7rem; color: var(--muted); margin-top: 2px; letter-spacing: .01em; }
.concept-groups .concept__actions { gap: 2px; }
/* Bank is a quiet word, not a pill: the row is a line of text, and two stacked buttons made it tall. */
.concept-groups .concept__actions .btn { border: 0; background: none; color: var(--muted);
  font-size: .72rem; padding: 4px 2px; min-height: 28px; }

/* the editor: same width, no frame, no stacked labels */
.edit-panel { margin: 0; padding: 2px 0 10px; width: 100%; }
/* the row BECOMES the editor: its line and its handle step aside, its place on the screen never moves */
.concept.is-editing { flex-direction: column; align-items: stretch; }
.concept.is-editing .concept__open, .concept.is-editing .concept__actions { display: none; }
.cx { display: flex; flex-direction: column; gap: 6px; }
.cx__title, .cx__source { border: 0; background: none; width: 100%; padding: 4px 0; font: inherit;
  color: var(--ink); outline: none; }
.cx__title { font-weight: 700; font-size: .96rem; }
.cx__source { font-size: .82rem; line-height: 1.4; color: var(--muted); resize: none; }
.cx__title:focus, .cx__source:focus { box-shadow: 0 1px 0 var(--teal); }
.cx__vals { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.cx__val { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; padding: 5px 8px;
  border: 1px solid var(--line); border-radius: 9px; background: var(--card); cursor: pointer;
  min-height: 40px; font: inherit; }
.cx__val-label { font-size: .62rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.cx__val-num { font-size: .9rem; font-weight: 700; color: var(--ink); }
.cx__wheel { max-height: 132px; overflow-y: auto; scroll-snap-type: y mandatory;
  border: 1px solid var(--line); border-radius: 10px; background: var(--card); }
.cx__wheel-col { display: flex; flex-direction: column; }
.cx__wheel-item { scroll-snap-align: center; min-height: 44px; border: 0; background: none;
  font: inherit; font-size: .9rem; color: var(--muted); cursor: pointer; }
.cx__wheel-item.is-on { color: var(--teal-dark); font-weight: 700; }
.cx__row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.cx__chips { display: flex; flex-wrap: wrap; gap: 4px; }
.cx__chip { border: 1px solid var(--line); background: var(--card); color: var(--muted);
  border-radius: 999px; padding: 5px 9px; font: inherit; font-size: .76rem; cursor: pointer; min-height: 32px; }
.cx__chip.is-on { border-color: var(--teal); color: var(--teal-dark); background: rgba(18, 165, 148, .08); font-weight: 600; }
.cx__langs { border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.cx__lang { display: block; width: 100%; text-align: start; border: 0; background: var(--card);
  padding: 9px 10px; font: inherit; font-size: .84rem; color: var(--ink); cursor: pointer; }
.cx__lang.is-on { color: var(--teal-dark); font-weight: 600; }
.cx__actions { display: flex; align-items: center; gap: 10px; padding-top: 2px; }
.cx__del { border: 0; background: none; color: var(--coral); font: inherit; font-size: .84rem;
  font-weight: 600; padding: 8px 4px; cursor: pointer; }
.cx__close { border: 0; background: none; color: var(--muted); font: inherit; font-size: .84rem;
  padding: 8px 4px; cursor: pointer; margin-inline-start: auto; }
/* the row's title/stats/tag rules moved into the T-129 block above: one dense line, no chip row.
   .conf-bar stays — the Stats screen still draws confidence with it. */
.concept__actions { display: flex; flex-direction: column; gap: 6px; flex: none; }
.conf-bar { height: 5px; border-radius: 999px; background: var(--line); overflow: hidden; width: 72px; margin-top: 5px; }
.conf-bar--wide { width: 100%; margin-top: 6px; }
.conf-bar__fill { height: 100%; background: var(--teal); }

details.formbox { border: 1px solid var(--line); border-radius: var(--radius); background: var(--card); margin-bottom: 12px; overflow: hidden; }
details.formbox > summary { padding: 14px 16px; font-weight: 700; cursor: pointer; list-style: none; display: flex; justify-content: space-between; }
details.formbox > summary::-webkit-details-marker { display: none; }
/* "+" and "−", not the fullwidth forms: U+FF0B renders as a tofu box on a device whose font lacks it
   (seen in this container's render, 18.10) and the sign is the only mark the summary carries. */
details.formbox > summary::after { content: "+"; color: var(--teal); font-weight: 700; }
details.formbox[open] > summary::after { content: "\2212"; }
details.formbox > .formbox__body { padding: 0 16px 16px; }

/* Bank item */
.item { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 12px; margin-bottom: 10px; background: var(--mist); }
.item--flagged { border-color: var(--coral); background: rgba(228, 87, 46, .05); }
.item__head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; font-size: .8rem; }
.item__q { font-weight: 600; }
.item__a { color: var(--teal-dark); }
.item__flag { display: flex; align-items: center; gap: 6px; margin-top: 8px; }

/* ── Toasts & banner ──────────────────────────────────────────────────── */
.toasts {
  position: fixed; inset-inline: 0; bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 12px);
  display: flex; flex-direction: column; align-items: center; gap: 8px; z-index: 80; pointer-events: none; padding: 0 14px;
}
.toast {
  pointer-events: auto;
  max-width: 460px; width: 100%;
  padding: 12px 14px; border-radius: 12px;
  background: var(--ink); color: #fff; box-shadow: var(--shadow-lg);
  font-size: .92rem; animation: toast-in .18s ease;
}
.toast--error { background: var(--coral); }
.toast--ok { background: var(--teal-dark); }
.toast button { background: none; border: 0; color: inherit; font: inherit; font-weight: 700; cursor: pointer; text-decoration: underline; }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.banner {
  position: sticky; top: 0; z-index: 30;
  padding: 10px 16px; background: rgba(228, 87, 46, .12); color: #8f3016;
  border-bottom: 1px solid rgba(228, 87, 46, .3); font-size: .9rem; text-align: center;
}

/* ── Bottom tabs (T-113) ────────────────────────────────────────────────
   A floating pill: 56px tall, 26px off the bottom edge, 23px in from each side, every corner
   rounded. ICONS ONLY — no words are painted under them (the founder's word); each link keeps its
   word as an aria-label, so the bar is still nameable and the active tab is marked aria-current.
   The middle slot is the raised +: a 64px teal disc that starts TODAY'S QUEUE and nothing else.

   The bar floats OVER the scroller — `position: absolute`, NOT fixed (the shell is already
   `position: relative`, so it is the containing block and the bar can never ride WebKit's sliding
   visual viewport away from its column). The plate around it is the page itself, not a strip of
   chrome: deck rows pass visibly BEHIND the pill and out at either side. `#view` reserves the bar's
   footprint (`--tabbar-h`) as bottom padding, so no last row can END underneath it. */
.tabbar {
  position: absolute; inset-inline: 0; bottom: 0;   /* over the scroller; the shell is the containing
                                     block — and the bar still anchors the raised + */
  z-index: 45;
  display: flex; align-items: center; justify-content: space-between;
  height: 56px;
  margin: 0 23px calc(26px + env(safe-area-inset-bottom, 0px));
  padding: 0 20px;
  background: var(--card);
  border-radius: 28px;
  box-shadow: 0 6px 20px rgba(11, 27, 43, .14);
  overflow: visible;                   /* the raised + is never clipped */
}
.tabbar__item {
  display: flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; min-height: var(--tap);
  color: var(--muted);
}
.tabbar__item:hover { text-decoration: none; }
.tabbar__item.is-active { color: var(--teal-dark); }
.tabbar__icon { display: grid; place-items: center; line-height: 0; }
.tabbar__icon svg { display: block; width: 22px; height: 22px; }
.tabbar__gap { width: 56px; height: 1px; }   /* the hole the raised + sits in */

.tabbar__fab {
  position: absolute; left: 50%; bottom: 30px; transform: translateX(-50%);
  width: 64px; height: 64px;
  border: 0; border-radius: 50%;
  background: var(--teal); color: var(--card);
  display: grid; place-items: center;
  box-shadow: 0 6px 16px rgba(18, 165, 148, .45);
  cursor: pointer;
}
.tabbar__fab:hover { background: var(--teal-dark); }
.tabbar__fab svg { display: block; width: 26px; height: 26px; }

/* ── In-session footer ──────────────────────────────────────────────────
   Inside a review session the tab bar steps aside and this bar owns the bottom edge: the one exit
   (End session, on the muted strip) above the four ratings — the scheduler's ONLY input — with the
   bottom inset applied here. It is the last box of the scroller and sticks to its bottom edge, so
   the four targets are never a scroll away. */
.review-body { flex: 1 1 auto; padding: 16px 14px; }
.session-footer {
  position: sticky; bottom: 0; z-index: 35; flex: none;
  background: var(--card); border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
}
.session-footer__exit {
  display: flex; align-items: center; justify-content: center;
  min-height: var(--tap);                /* 44px — the exit is a real target, never a text link */
  background: var(--mist); border-bottom: 1px solid var(--line);
}
.session-footer .ratings { margin: 8px 14px 12px; }
/* The footer stands taller than the tab bar it replaces, so a toast must clear it (the stack is a
   fixed overlay offset by the bar's height and would otherwise cover the exit and the ratings). */
.view.is-session ~ .toasts { margin-bottom: 64px; }

/* Login / centered auth */
.auth { max-width: 420px; margin: 6vh auto 0; }
.auth .brand--big { text-align: center; margin-bottom: 18px; }
.auth .brand--big img { border-radius: 18px; }
.auth__title { font-size: 1.4rem; text-align: center; }
.form-error {
  padding: 10px 12px; border-radius: 10px;
  background: rgba(228, 87, 46, .1); color: #8f3016;
  border: 1px solid rgba(228, 87, 46, .3);
  font-size: .9rem; text-align: start;
}

/* Utilities */
.hidden, [hidden] { display: none !important; }
.pill-row { display: flex; gap: 6px; flex-wrap: wrap; }
.js-json { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: .8rem; white-space: pre-wrap; word-break: break-word; background: var(--mist); border: 1px solid var(--line); border-radius: 8px; padding: 10px; max-height: 260px; overflow: auto; direction: ltr; text-align: left; }
.table { width: 100%; border-collapse: collapse; font-size: .88rem; }
.table th, .table td { text-align: start; padding: 8px 6px; border-bottom: 1px solid var(--line); }
.table th { color: var(--muted); font-weight: 600; }

@media (min-width: 760px) {
  /* The pill is the same object at every width — centred and capped on a tablet or a desktop,
     never glued edge to edge, and the bottom gutter survives. */
  .tabbar {
    width: calc(100% - 46px);
    max-width: 620px;
    margin-inline: auto;
  }
}

/* ── Item content: own language + direction inside the English LTR shell ── */
.qcard__prompt, .qcard__choices li, .answer__body, .citations q,
.item__q, .item__a, .deck__name { text-align: start; }

/* ── Question-type chips (multi-select) ───────────────────────────────── */
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chipchip {
  min-height: 36px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--card); color: var(--ink);
  font: inherit; font-size: .86rem; cursor: pointer;
}
.chipchip:hover { border-color: var(--teal); }
.chipchip.is-on { background: var(--teal); border-color: var(--teal); color: #fff; font-weight: 600; }

/* ── Confirm dialog ───────────────────────────────────────────────────── */
.modal {
  position: absolute; inset: 0; z-index: 100; padding: 18px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(11, 27, 43, .5);
}
.modal__card { width: 100%; max-width: 420px; background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: 18px; }
.modal__title { margin: 0 0 8px; font-size: 1.05rem; }
.modal__msg { margin: 0 0 16px; }
.modal__actions { display: flex; gap: 10px; justify-content: flex-end; }
/* Two decisions side by side in a popup: equal halves, each a 44 px target on a phone. */
.modal__actions--pair .btn { flex: 1 1 0; min-height: 44px; justify-content: center; }

/* ── Scan popup progress bar ──────────────────────────────────────────── */
.scan-progress { margin: 0 0 12px; }
.scan-progress__bar { width: 100%; height: 6px; background: var(--line); border-radius: 3px; overflow: hidden; }
.scan-progress__fill { height: 100%; width: 0; background: var(--teal); border-radius: 3px; transition: width .2s ease; }
.scan-progress__fill.indeterminate { width: 30% !important; animation: scan-sweep 1.2s ease-in-out infinite; }
.scan-progress__fill.complete { width: 100% !important; animation: none; }
@keyframes scan-sweep {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(300%); }
}
@media (prefers-reduced-motion: reduce) {
  .scan-progress__fill.indeterminate { animation: none; width: 100% !important; opacity: .6; }
}

/* ── Stats: tiles, heatmap, bars, per-deck, type mix ──────────────────── */
.home-heat { margin: 4px 0 10px; }
.home-heat h3 { font-size: .95rem; margin: 0; }
.tiles--5 { grid-template-columns: repeat(2, 1fr); }
@media (min-width: 640px) { .tiles--5 { grid-template-columns: repeat(5, 1fr); } }

.heatmap { display: grid; grid-template-columns: auto repeat(7, 1fr); gap: 3px; align-items: center; }
.heatmap__rowlbl { font-size: .72rem; color: var(--muted); white-space: nowrap; padding-inline-end: 4px; }
.heatmap__wd { font-size: .68rem; color: var(--muted); text-align: center; }
.heat { height: 15px; border-radius: 3px; background: var(--line); }
.heat--empty { background: transparent; }
.heat--0 { background: var(--line); }
.heat--1 { background: rgba(18, 165, 148, .25); }
.heat--2 { background: rgba(18, 165, 148, .45); }
.heat--3 { background: rgba(18, 165, 148, .70); }
.heat--4 { background: var(--teal-dark); }
.heatmap__legend { display: flex; align-items: center; gap: 4px; margin-top: 10px; }
.heatmap__legend .heat { width: 15px; }

.bar { height: 10px; border-radius: 999px; background: var(--line); overflow: hidden; }
.bar__fill { height: 100%; background: var(--teal); border-radius: 999px; }

.statdeck { padding: 12px 0; border-bottom: 1px solid var(--line); }
.statdeck:last-child { border-bottom: 0; }
.statdeck__head { display: flex; align-items: center; gap: 10px; }
.statdeck__head .deck__swatch { align-self: auto; height: 18px; width: 10px; }
.statdeck__name { font-weight: 700; flex: 1 1 auto; min-width: 0; }
.statdeck__nums { font-size: .84rem; color: var(--muted); margin-top: 4px; }

.typerow { display: grid; grid-template-columns: 1fr auto; grid-template-areas: "label count" "bar bar"; gap: 3px 8px; margin-bottom: 10px; }
.typerow__label { grid-area: label; font-size: .88rem; }
.typerow__count { grid-area: count; font-size: .82rem; color: var(--muted); }
.typerow__bar { grid-area: bar; height: 10px; border-radius: 999px; background: var(--line); overflow: hidden; }
.typerow__fill { display: block; height: 100%; background: var(--teal); border-radius: 999px; }

/* ── Topic hierarchy (tree + controls) ────────────────────────────────── */
.topic-tree { display: flex; flex-direction: column; gap: 6px; }
.topic-node__head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; }
.topic-node__name { font-weight: 600; }
.topic-form { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 6px; margin-inline-start: 8px; }
.concept-groups .topic__name { margin-top: 14px; }

/* T-124 — the concept tree FOLDS: one <details> per topic, the header is the handle, everything shut
   on arrival. The chevron replaces the topic square and turns when the fold opens; 44 px of tap height
   so a thumb hits it (owner, 18.10.2026). */
.concept-groups .cg { margin: 0; }
.concept-groups .cg__head { cursor: pointer; list-style: none; user-select: none;
  padding: 10px 0; min-height: 44px; margin: 2px 0 4px; }
.concept-groups .cg__head::-webkit-details-marker { display: none; }
.concept-groups .cg__head::before { content: "\25B8"; width: auto; height: auto; background: none;
  border-radius: 0; color: var(--teal); font-size: .95rem; line-height: 1; }
.concept-groups .cg[open] > .cg__head::before { content: "\25BE"; }
.concept-groups .cg__body { padding-inline-start: 2px; }
/* Chrome puts closed <details> content behind content-visibility instead of display:none, so the shut body
   still RESERVES its height and a collapsed fold leaves a blank block the size of its rows (measured:
   193 px of empty card). Hide it ourselves — this is the one rule that makes a shut fold cost nothing. */
details:not([open]) > :not(summary) { display: none; }

/* ── T-127 — parent and child read differently, the topic's card and the drag live in the tree ─────── */
.concept-groups .cg--parent > .cg__head { font-size: 1rem; font-weight: 700; color: var(--ink); }
.concept-groups .cg--child { border-inline-start: 2px solid var(--line); padding-inline-start: 8px; }
.concept-groups .cg--child > .cg__head { font-size: .92rem; font-weight: 600; color: var(--muted); }
.concept-groups .cg--child > .cg__head::before { font-size: .75rem; }
.concept-groups .cg__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.concept-groups .cg__edit { flex: none; border: 0; background: none; color: var(--muted); font: inherit;
  font-size: .95rem; line-height: 1; padding: 6px 8px; min-height: 32px; cursor: pointer; border-radius: 8px; }
.concept-groups .cg__edit:hover { background: var(--mist); color: var(--ink); }
.concept-groups .cg__card { padding: 8px 0 12px; }
.topic-card { display: flex; flex-direction: column; gap: 8px; border: 1px solid var(--line);
  border-radius: 12px; padding: 12px; background: var(--mist); }
.topic-card .row { gap: 8px; }

/* the move handle on a concept row — the only thing that starts a drag */
.drag-handle { flex: none; border: 1px solid var(--line); background: var(--card); color: var(--muted);
  border-radius: 8px; min-width: 34px; min-height: 34px; font-size: 1rem; line-height: 1; cursor: grab;
  touch-action: none; }
.drag-handle:active { cursor: grabbing; }
.drag-ghost { position: fixed; top: 0; left: 0; z-index: 9999; pointer-events: none; max-width: 260px;
  padding: 8px 12px; border: 1px solid var(--teal); border-radius: 10px; background: var(--card);
  box-shadow: var(--shadow-lg); font-size: .85rem; color: var(--ink); }
body.is-dragging { user-select: none; -webkit-user-select: none; }
.cg.is-drop > .cg__head { background: rgba(18, 165, 148, .12); box-shadow: inset 0 0 0 2px var(--teal);
  border-radius: 10px; color: var(--teal-dark); }

/* ── Bulk concept editor (line-based) ─────────────────────────────────── */
.ed-help { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; margin-bottom: 10px; }
.ed-help__body { margin-top: 8px; }
.ed-help__body ul { margin: 6px 0 0; padding-inline-start: 18px; }
.ed-help__body li { margin-bottom: 4px; }
.ed-newlang-field { max-width: 280px; margin-bottom: 10px; }
.ed-lines { width: 100%; min-height: 320px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  font-size: .82rem; line-height: 1.5; white-space: pre; overflow-wrap: normal; overflow-x: auto; }
.ed-count { margin: 8px 0; }
.ed-errors { background: rgba(230, 90, 90, .06); border: 1px solid var(--coral); border-radius: 10px; padding: 8px 12px; margin-bottom: 10px; }
.ed-error { color: var(--coral); font-size: .8rem; margin: 2px 0; }
.ed-toolbar { margin-bottom: 10px; }
.scan-control { display: flex; flex-direction: column; gap: 6px; flex: 1 1 220px; }
/* T-102 — a card title may carry a ⓘ: the card's own explanation, opened in place under the title.
   A tooltip needs a hover and a phone has none; the button keeps the 44 px target, and the note is
   `hidden` (never `display:` in CSS, or the attribute would stop working). */
.card-title { display: flex; align-items: center; gap: 4px; }
.info-btn { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px;
  margin: -10px 0 -10px -6px; padding: 0; border: 0; border-radius: 22px; background: transparent;
  color: var(--ink); cursor: pointer; }
.info-btn:hover { background: var(--mist); }
.info-btn[aria-expanded="true"] { color: var(--teal); }
.card-note { margin: 4px 0 12px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px;
  background: var(--mist); color: var(--muted); font-size: .92rem; line-height: 1.55; }

.dropzone { border: 1px dashed var(--line); border-radius: 10px; padding: 8px 10px; text-align: center; }
.dropzone.is-over { border-color: var(--teal); background: rgba(18, 165, 148, .06); }
/* T-101 — a drag target is a mouse gesture. On a touch screen the box is a 44 px hole in the
   page that says "drop a photo here" to a thumb that cannot drag: 44 of the 186 px of controls
   above the first card. It stays on a mouse, never on a phone. */
@media (max-width: 700px) { .dropzone { display: none; } }

.ed-bar { position: sticky; bottom: 0; z-index: 20; display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 12px; padding: 10px 12px; background: var(--ink); color: #fff; border-radius: 12px; box-shadow: var(--shadow-lg); }
.ed-bar__text { font-weight: 700; }
.ed-bar__actions { display: flex; gap: 8px; }


/* ══════════════════════════════════════════════════════════════════════════
 * PRIMER — the interactive teaching card for a brand-new concept.
 * ══════════════════════════════════════════════════════════════════════════ */
.primer { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px; display: grid; gap: 16px; }
.primer__head { display: grid; gap: 4px; }
.primer__title { font-size: 1.35rem; margin: 0; }
.primer__crumb { font-size: .82rem; color: var(--muted); }
.primer__tags { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.primer__lead { font-size: 1.12rem; line-height: 1.6; font-weight: 600; margin: 0; padding: 12px 14px;
  background: var(--mist); border-inline-start: 4px solid var(--teal); border-radius: 10px; }
.primer__block-title { font-size: .8rem; font-weight: 700; color: var(--teal-dark); letter-spacing: .6px;
  text-transform: uppercase; margin: 0 0 8px; }

/* Mechanism: numbered, connected step chips (tap to expand). */
.psteps { list-style: none; margin: 0; padding: 0; position: relative; display: grid; gap: 8px; }
.psteps::before { content: ""; position: absolute; inset-inline-start: 17px; top: 12px; bottom: 12px; width: 2px; background: var(--line); }
.pstep { position: relative; }
.pstep__head { position: relative; display: flex; align-items: flex-start; gap: 12px; width: 100%; text-align: start;
  padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--card); }
.pstep__num { flex: none; display: grid; place-items: center; width: 24px; height: 24px; border-radius: 999px;
  background: var(--teal); color: #fff; font-size: .82rem; font-weight: 700; z-index: 1; }
.pstep__text { font-weight: 600; }
.psteps > .pstep:not(:last-child)::after { content: ""; }

/* Scale bar with a marked value and an optional value2 band. */
.pscale { display: grid; gap: 6px; }
.pscale__label { font-weight: 600; }
.pscale__bar { position: relative; height: 14px; border-radius: 999px; background: var(--line); overflow: hidden; }
.pscale__band { position: absolute; top: 0; bottom: 0; background: rgba(18, 165, 148, .30); }
.pscale__mark { position: absolute; top: -3px; bottom: -3px; width: 4px; margin-inline-start: -2px; border-radius: 2px;
  background: var(--teal-dark); box-shadow: 0 0 0 2px #fff; }
.pscale__ends { display: flex; justify-content: space-between; font-size: .78rem; color: var(--muted); }
.pscale__value { font-weight: 700; color: var(--teal-dark); }
.pscale__value-range { font-weight: 600; }

/* Trap = a distinct caution block. */
.primer__trap { padding: 12px 14px; border-inline-start: 4px solid var(--coral); background: rgba(228, 87, 46, .07); border-radius: 10px; }
.primer__trap-label { font-size: .78rem; font-weight: 700; color: var(--coral); letter-spacing: .4px; margin-bottom: 4px; }
.primer__trap-body { font-weight: 500; }
.primer__where { font-size: .9rem; color: var(--muted); margin: 0; }

/* Source quote — collapsed by default. */
.primer__quote { border: 1px solid var(--line); border-radius: 10px; background: var(--mist); padding: 10px 12px; }
.primer__quote-summary { font-size: .82rem; font-weight: 700; color: var(--amber); cursor: pointer; list-style: none; }
.primer__quote-summary::-webkit-details-marker { display: none; }
.primer__quote-summary::after { content: " ▾"; }
.primer__quote[open] .primer__quote-summary::after { content: " ▴"; }
.primer__quote-body { margin: 8px 0 0; padding-inline-start: 10px; border-inline-start: 3px solid var(--amber); }
.primer__quote-body q { font-style: italic; }
.primer__quote-url { display: block; margin-top: 6px; font-size: .8rem; word-break: break-all; }

.primer--empty { gap: 10px; }

/* The compact, skippable pre-question strip for a brand-new concept. */
.prestrip { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 12px;
  padding: 8px 10px; border: 1px dashed var(--teal); border-radius: var(--radius-sm);
  background: rgba(18, 165, 148, .06); }
.prestrip__show { flex: 1 1 auto; text-align: start; font: inherit; font-weight: 600; color: var(--teal-dark);
  cursor: pointer; padding: 8px 10px; border: 0; border-radius: var(--radius-sm); background: transparent; }
.prestrip__show:hover { background: rgba(18, 165, 148, .13); }
.prestrip__skip { flex: none; font: inherit; font-size: .84rem; color: var(--muted); cursor: pointer;
  padding: 8px 10px; border: 0; border-radius: var(--radius-sm); background: transparent; }
.prestrip__skip:hover { color: var(--ink); background: rgba(11, 27, 43, .05); }

/* ── The collapsed "Primer & sources" panel under every question ───────────── */
.psources { margin: 14px 0 0; }
.psources__head { display: block; }
.psources__toggle { display: flex; align-items: center; gap: 8px; width: 100%; text-align: start;
  font: inherit; font-weight: 600; color: var(--teal-dark); cursor: pointer; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--mist); }
.psources__toggle:hover { border-color: var(--teal); background: rgba(18, 165, 148, .09); }
.psources__icon { flex: none; font-size: 1rem; line-height: 1; }
.psources__label { flex: none; }
.psources__state { flex: 1 1 auto; text-align: end; font-weight: 500; font-size: .84rem; color: var(--muted); }
.psources__body { display: grid; gap: 12px; margin-top: 10px; animation: psources-in .16s ease; }
@keyframes psources-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.psources__actions { display: grid; }
.psources__error { margin: 0; }
.psources .primer { box-shadow: none; }

.citations__item { margin-top: 6px; }
.citations__url { display: block; margin-top: 3px; font-size: .8rem; word-break: break-all; dir: ltr; }
/* The concept's door (founder, 30.10): the source as a green link, the quote as plain text —
   no amber box, no "Source" heading. A link that is green says "this opens"; a box that is amber
   says "read this first", and the card already told him what to read. */
.src-card__links { display: grid; gap: 6px; margin-top: 8px; }
.src-card__link { display: block; font-size: .85rem; color: var(--teal); word-break: break-all; dir: ltr;
  text-decoration: underline; text-underline-offset: 2px; }
.src-card__quote { margin: 0; font-size: .82rem; line-height: 1.5; color: #9FB3AA; border-inline-start: 2px solid #2A332F; padding-inline-start: 10px; }

/* ══════════════════════════════════════════════════════════════════════════
 * Account toggle (a real switch) + sub-tabs
 * ══════════════════════════════════════════════════════════════════════════ */
.priming-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 6px 0 4px; }
.priming-row__label { font-weight: 600; }
.switch { position: relative; flex: none; width: 52px; height: 30px; padding: 0; border: 1px solid var(--line);
  border-radius: 999px; background: var(--line); cursor: pointer; transition: background .15s ease; }
.switch__knob { position: absolute; top: 3px; inset-inline-start: 3px; width: 22px; height: 22px; border-radius: 999px;
  background: #fff; box-shadow: var(--shadow); transition: inset-inline-start .15s ease; }
.switch.is-on { background: var(--teal); border-color: var(--teal); }
.switch.is-on .switch__knob { inset-inline-start: 25px; }
.switch[disabled] { opacity: .6; cursor: progress; }

.subtabs { display: inline-flex; gap: 4px; padding: 4px; background: var(--mist); border: 1px solid var(--line);
  border-radius: 999px; margin: 0 0 14px; }
.subtab { border: 0; background: transparent; font: inherit; font-weight: 600; color: var(--muted); cursor: pointer;
  padding: 7px 16px; border-radius: 999px; }
.subtab.is-active { background: var(--card); color: var(--teal-dark); box-shadow: var(--shadow); }

/* ══════════════════════════════════════════════════════════════════════════
 * INSIGHTS — weekday strip, concept lists, topics, gaps, latency. T-408: the hour
 * bars and the six overview tiles are gone — the coach speaks for those.
 * ══════════════════════════════════════════════════════════════════════════ */

/* minmax(0, 1fr) + min-width: 0 on the item: a 1fr track keeps an automatic min-content floor, so at
   360px the weekday cell's acc figure ("82%" at 1.05rem) pushed the 7-column strip 3.3px past the
   screen edge. Measured on untouched main — a PRE-EXISTING defect the T-031 probe run surfaced, not a
   T-031 regression. The standard fix: let the track and the item shrink below their content. */
.iweek { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; }
.iweek__day { min-width: 0; }
.iweek__day { text-align: center; padding: 10px 4px; background: var(--mist); border-radius: 10px; }
.iweek__name { font-size: .76rem; font-weight: 700; color: var(--muted); }
.iweek__acc { font-size: 1.05rem; font-weight: 700; color: var(--teal-dark); }
.iweek__n { margin-top: 2px; }

.iconcepts { display: grid; gap: 8px; }
.iconcept { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--mist); }
.iconcept__title { font-weight: 600; flex: 1 1 auto; min-width: 0; word-break: break-word; }
.iconcept__meta { font-size: .82rem; color: var(--muted); }

.itable-wrap { overflow-x: auto; }

.igaps { display: grid; gap: 10px; }
.igaps__list { display: grid; gap: 8px; }
/* The chain's current state, said once: at risk / freeze used / reset. The words carry the meaning;
   colour only reinforces it. */
.igaps__state { margin: 0; font-size: .9rem; font-weight: 600; }
.igaps__state--risk { color: var(--amber); }
.igap { padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--mist); }
.igap__range { font-weight: 600; }
.igap__meta { margin-top: 2px; }

.ilat { display: grid; gap: 8px; }
.ilat__head { display: flex; gap: 6px; flex-wrap: wrap; }
.ilat__row { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 12px; border: 1px solid var(--line); border-radius: 8px; }
.ilat__label { font-weight: 600; }
.ilat__val { color: var(--teal-dark); font-weight: 700; }

/* ══════════════════════════════════════════════════════════════════════════
 * DUPLICATES panel on the deck page
 * ══════════════════════════════════════════════════════════════════════════ */
.dupes { display: grid; gap: 12px; margin-top: 10px; }
.dupes__msg { margin: 8px 0 0; }
.dupe { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 12px; background: var(--mist); }
.dupe__head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dupe__score { font-weight: 700; color: var(--teal-dark); }
.dupe__reason { margin: 6px 0; }
.dupe__grid { display: grid; grid-template-columns: 1fr; gap: 10px; margin: 10px 0; }
@media (min-width: 560px) { .dupe__grid { grid-template-columns: 1fr auto 1fr; align-items: center; } }
.dupe__side { padding: 10px 12px; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm); display: grid; gap: 6px; }
.dupe__title { font-weight: 600; }
.dupe__topic { }
.dupe__actions { display: flex; justify-content: flex-end; }

/* ══════════════════════════════════════════════════════════════════════════
 * SHARE & IMPORT + onboarding wizard
 * ══════════════════════════════════════════════════════════════════════════ */
.deck-line { position: relative; }
.deck-line__actions { display: flex; justify-content: flex-end; gap: 8px; margin: -6px 0 12px; }
.deck__export { }

.import-box { display: grid; gap: 10px; }
.import-status { margin: 0; }
.import-warnings { display: grid; gap: 4px; }
.import-warn { margin: 0; color: var(--amber); }

.wizard { display: grid; gap: 14px; }
.wizard-grid { display: grid; grid-template-columns: 1fr; gap: 12px; }
@media (min-width: 620px) { .wizard-grid { grid-template-columns: 1fr 1fr; } }
.wizard-card { display: grid; gap: 8px; align-content: start; padding: 16px; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.wizard-card__title { margin: 0; }
.wizard-card__desc { margin: 0; }
.wizard-file { margin-top: 4px; }

/* ─────────────────────────────────────────────────────────────────────────
 * ONBOARDING — four tender cards (T-260)
 * The cards own the screen: no app bar, no tab bar. Centered, max-width card.
 * ═══════════════════════════════════════════════════════════════════════════ */
body.is-onboard .appbar { display: none; }
body.is-onboard .tabbar { display: none; }
body.is-onboard .view { padding: 24px 16px calc(24px + env(safe-area-inset-bottom, 0px)); max-width: 420px; margin: 0 auto; }

.onboard { display: grid; gap: 16px; width: 100%; }
.onboard__progress { display: flex; justify-content: center; font-size: 12px; font-weight: 600; color: var(--muted); letter-spacing: .5px; text-transform: uppercase; }
.onboard__card { display: grid; gap: 16px; padding: 24px; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.onboard__card--grid { gap: 12px; }
.onboard__card--account { gap: 16px; }

.onboard__title { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -.3px; }
.onboard__lead { margin: 0; font-size: 15px; line-height: 1.5; }
.onboard__desc { margin: 0; font-size: 13px; line-height: 1.4; }

.onboard__doors { display: grid; gap: 10px; margin-top: 8px; }
.onboard__door { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 18px 16px; text-align: center; border: 1px solid var(--line); border-radius: var(--radius); background: var(--card); transition: border-color .15s, background .15s; }
.onboard__door:hover { border-color: var(--ink); background: var(--mist); }
.onboard__door--primary { border-color: var(--ink); background: var(--ink); color: var(--card); }
.onboard__door--primary:hover { border-color: var(--teal); background: var(--teal); }
.onboard__door-title { font-size: 15px; font-weight: 700; }
.onboard__door-desc { font-size: 12px; line-height: 1.3; opacity: .8; }

.onboard__grid { display: grid; grid-template-columns: 1fr; gap: 12px; }
@media (min-width: 620px) { .onboard__grid { grid-template-columns: 1fr 1fr; } }

.onboard__questions { display: grid; gap: 12px; margin-top: 8px; }
.onboard__q { display: grid; gap: 6px; }
.onboard__q-label { font-size: 11px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase; color: var(--muted); }
.onboard__q .input { font-size: 15px; padding: 12px 14px; }

.onboard__actions { margin-top: 8px; }
.onboard__next { font-size: 15px; font-weight: 600; padding: 14px 16px; }

.onboard__account-fields { display: grid; gap: 14px; margin-top: 4px; }
.onboard__field { display: grid; gap: 6px; }
.onboard__field-label { font-size: 12px; font-weight: 600; color: var(--muted); }
.onboard__field-hint { margin-top: -2px; }
.onboard__field-wrap { display: grid; gap: 10px; }
.onboard__photo-label { position: relative; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.onboard__photo { width: 88px; height: 88px; border-radius: 50%; background: var(--mist); color: var(--ink-muted); display: flex; align-items: center; justify-content: center; font-size: 32px; font-weight: 700; overflow: hidden; border: 2px dashed var(--line); transition: border-color .15s; }
.onboard__photo img { width: 100%; height: 100%; object-fit: cover; }
.onboard__photo-label:hover .onboard__photo { border-color: var(--ink); }
.onboard__photo-hint { font-size: 12px; }
.onboard__photo-input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.onboard__field .input { font-size: 15px; padding: 12px 14px; }
.onboard__field .select { font-size: 15px; padding: 12px 14px; }


/* ══ HOME — the rings-and-sheet screen (T-113 / D-T11) ═════════════════════
   Every size, gap and radius below is the pixel spec's
   (evidence/T-113-2026-10-17/I-30days-and-deck-rings.html). No new palette token: ink, teal,
   teal-dark, amber, muted, line, card, mist — the translucent whites are the spec's own alpha
   over the ink panel, not a colour of their own.

   Home owns the top edge: the shell's app bar steps aside (body.is-home, set by the router, the
   same explicit hook a session uses) and the hero bar carries the wordmark instead.
   ──────────────────────────────────────────────────────────────────────── */
body.is-home .appbar { display: none; }
/* T-195 — the VIEW is no longer capped. Home paints its own top edge (.home__bar, .home__hero), so
   capping the scroller at 640 also capped the INK: on a tablet the dark band stopped 52–192px short
   of each screen edge and a --mist strip ran down both sides — a phone column standing on a page.
   The width now belongs to the three surfaces; the ink bleeds, the content does not (see
   --home-pad below). At 390 `100%` is 390, so the phone is the screen that already ships. */
body.is-home .view { padding: 0 0 calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px)); max-width: none; }

/* A desktop browser with classic scrollbars reserves ~15px INSIDE the scroller — and the ink lives
   inside it, so once the sheet is taller than the window the dark bar stopped 15px short of the
   right edge: the same light strip this ticket exists to remove, one scrollbar wide. Home therefore
   shows no scrollbar: the page still scrolls by touch, wheel, arrow keys and PageDown, and iPadOS
   never had a layout-taking scrollbar to lose. Scoped to home — every other screen keeps its own. */
body.is-home .view { scrollbar-width: none; }
body.is-home .view::-webkit-scrollbar { width: 0; height: 0; }

/* One gutter, three surfaces. `max()` lets the column grow with the screen — 24px gutters on a
   phone — and then holds it at 620px, which is not a new number: it is the cap the floating tab bar
   already declares for a tablet (`.tabbar` max-width 620px, centred, from 760px up). So the sheet's
   deck pill and the nav pill below it are the SAME width on the SAME line at every width where the
   bar is capped, and the pill never overhangs the nav it sits above. Below 668px the `calc()` term
   underflows and `max()` resolves to the 24px gutter that has always been there: at 390px every box
   on this screen measures exactly what it measured before. The token is declared on the BODY hook,
   not on .home, so it cannot disappear if the wrapper is ever renamed; `100%` inside it resolves at
   each use site, and all three users share .home as their containing block, so the brand, the
   greeting, the month grid and the deck pill stay on ONE vertical line at every width. */
body.is-home { --home-pad: max(24px, calc((100% - 620px) / 2)); }

.home { background: var(--mist); padding-bottom: 8px; }

/* The bar — sticky, so the sheet slides UNDER it and the wordmark never leaves. It owns the TOP
   edge, so it carries the notch inset inside its own sticky box: `height` and `padding-top` both
   grow by `env(safe-area-inset-top)`, which keeps the 58px of chrome below the status bar once the
   bar is pinned (a parent's padding or a `top` offset would let it slide back under). At inset 0
   both `calc()`s resolve to the 58px/10px it always had — nothing shifts. */
.home__bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  height: calc(58px + env(safe-area-inset-top));
  padding: calc(10px + env(safe-area-inset-top)) var(--home-pad) 0;
  background: var(--ink); color: var(--card);
}
.home__brand { font-size: 15px; font-weight: 700; color: var(--card); opacity: .95; }
.home__brand:hover { text-decoration: none; }
.home__stats { display: flex; align-items: center; gap: 16px;
  font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; }
.home__stat { display: inline-flex; align-items: center; gap: 3px; color: var(--card); }
.home__stat--chain svg { fill: var(--amber); }
.home__stat--freeze svg { fill: none; stroke: var(--teal); stroke-width: 2.2; stroke-linecap: round; }
.home__who {
  font-size: 13px; font-weight: 600; color: var(--card);
  background: rgba(255, 255, 255, .12); padding: 6px 10px; border-radius: 999px;
  max-width: 132px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.home__who:hover { text-decoration: none; background: rgba(255, 255, 255, .18); }

/* The welcome half. The 14px the greeting used to carry as a `margin` lives here as the hero's own
   PADDING: a first-child margin collapses through the dark panel and paints the page's mist in the
   14px strip under the bar (a hairline seam); as ink it is the panel itself. Same 14px, and at inset
   0 the greeting does not move a pixel. */
.home__hero { background: var(--ink); border-radius: 0 0 24px 24px; padding: 14px var(--home-pad) 24px; }
.home__greet { margin: 0; font-size: 24px; font-weight: 700; letter-spacing: -.3px;
  color: var(--card); }

.home__rings { display: flex; justify-content: center; gap: 40px; margin: 18px 0 0; }
.home__ring { display: flex; flex-direction: column; align-items: center; gap: 8px; width: 112px; }
.home__ring svg { display: block; }
.home__ring svg circle { fill: none; stroke: rgba(255, 255, 255, .14); stroke-width: 10; }
.home__ring svg circle + circle { stroke: var(--teal); stroke-linecap: round; }
.home__ring--new svg circle + circle { stroke: var(--amber); }
.home__ring svg text { fill: var(--card); font-weight: 700; text-anchor: middle;
  font-variant-numeric: tabular-nums; }
.home__ring svg text:nth-of-type(1) { font-size: 30px; }
.home__ring svg text:nth-of-type(2) { font-size: 11px; font-weight: 600; fill: rgba(255, 255, 255, .6); }
.home__ring-lbl { font-size: 14px; font-weight: 600; color: rgba(255, 255, 255, .85); }

/* Five rising bars, the amber rule, the two words. */
.home__freeze { margin: 18px 0 0; padding: 16px 16px 12px;
  background: rgba(255, 255, 255, .07); border-radius: 16px;
  display: flex; flex-direction: column; align-items: center; gap: 10px; }
.home__bars { display: flex; align-items: flex-end; gap: 8px; height: 56px; }
.home__bar-fill { width: 14px; border-radius: 4px; background: rgba(255, 255, 255, .16); }
.home__bar-fill:nth-child(1) { height: 22px; }
.home__bar-fill:nth-child(2) { height: 30px; }
.home__bar-fill:nth-child(3) { height: 38px; }
.home__bar-fill:nth-child(4) { height: 46px; }
.home__bar-fill:nth-child(5) { height: 56px; }
.home__bar-fill.is-on { background: var(--teal); }
.home__rule { width: 96px; height: 3px; border-radius: 2px; background: var(--amber); margin-top: 2px; }
.home__freeze-lbl { font-size: 14px; font-weight: 600; color: rgba(255, 255, 255, .85); }

/* The sheet — it slides up over the welcome half and carries the rolling month and the deck rows.
   The top edge is FLAT: the overlap (-24px) equals the hero's own corner radius, so the ink's rounded
   foot finishes exactly ON the sheet's edge — two curves can no longer cross and leave a claw. */
.home__sheet { position: relative; z-index: 1; margin-top: -24px;
  background: var(--mist); border-radius: 0; padding: 12px var(--home-pad) 56px; }
.home__grip { width: 40px; height: 4px; border-radius: 2px; background: var(--line); margin: 0 auto 4px; }

/* The Statistics grid, at the size it has on a phone. 328px is that grid's own width inside the
   Statistics card at 390, so each cell stays 40 by 15 with the same 3px corner. max-width keeps a
   narrower phone from overflowing; a wider window does not stretch it. */
.home__sheet .heatmap { width: 328px; max-width: 100%; }
.home__sheet .heatmap__legend { margin-top: 6px; }
.home__sheet > h2 { margin: 0 0 2px; font-size: 1.2rem; }
.home__sheet > p.muted { margin: 0 0 6px; }

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

/* The deck row — a 72px pill. Scoped to the sheet: the Decks tab keeps its own card row. */
.home__decks .deck {
  display: flex; align-items: center; gap: 0;
  height: 72px; margin: 0; padding: 0 12px 0 16px;
  background: var(--card); border: 0; border-radius: 36px;
  box-shadow: 0 1px 2px rgba(11, 27, 43, .05);
}
.home__decks .deck:hover { border: 0; }
.deck__start {
  display: flex; align-items: center; gap: 12px; flex: 1 1 auto; min-width: 0;
  height: 72px; padding: 0; border: 0; background: none; font: inherit;
  color: inherit; text-align: start; cursor: pointer;
}
.deck__due { position: relative; width: 40px; height: 40px; flex: none;
  display: grid; place-items: center; }
.deck__due svg { position: absolute; inset: 0; }
.deck__due svg circle { fill: none; stroke: var(--line); }
.deck__due svg circle + circle { stroke: var(--teal); stroke-linecap: round; }
.deck__due-n { position: relative; font-size: 12px; font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums; }
.deck__txt { display: flex; flex-direction: column; min-width: 0; }
.home__decks .deck__name { display: block; font-size: 16px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.home__decks .deck__meta { display: block; margin-top: 2px; font-size: 13px; font-weight: 500;
  color: var(--muted); }

/* The arrow: the ONLY way into the deck itself. No divider before it (the founder's word — the
   mock's separator span is gone). 44px, so it is a target and not a decoration. */
.deck__go {
  width: 44px; height: 44px; flex: none; border-radius: 50%;
  border: 1.5px solid var(--teal); color: var(--teal-dark);
  display: grid; place-items: center;
}
.deck__go:hover { text-decoration: none; background: var(--mist); }

/* ══════════════════════════════════════════════════════════════════════════
 * T-125 — THE ACCOUNT SCREEN ("Me") and its one-field wizards.
 *
 * Taken verbatim from the Designer's ship layer
 * (phontary/projects/tikrar/evidence/T-125-2026-10-18/mock.css §2): every colour,
 * radius, type size and bar height resolves from the tokens already in this file.
 * One selector differs, deliberately: the mock hides the shell bar with
 * `.is-me .appbar`, which in the real page would also hide a WIZARD's own bar —
 * that bar is the same .appbar, inside #view, per the mock's own markup. The shell
 * bar is the one element with the id, so the hook is scoped to it:
 * `body.is-me > #appbar`.
 * ══════════════════════════════════════════════════════════════════════════ */

/* The screen owns its top half the way Home does: the shell's app bar steps aside
   (body.is-me, the same explicit hook a session and Home use) and the hero carries
   the wordmark instead. That is what removes the duplicate pill: the account link
   has no business on the account screen, and the hero's disc is the only identity
   the eye needs. */
body.is-me > #appbar { display: none; }

.me__bar {
  display: flex; align-items: center; justify-content: space-between;
  /* the bar owns the TOP edge, so it carries the notch inset inside its own box —
     exactly what .home__bar does (T-113). At inset 0 it resolves to the 44px. */
  height: calc(44px + env(safe-area-inset-top));
  padding-top: env(safe-area-inset-top);
  margin: 0;
}
.me__bar .home__brand { font-size: 15px; display: inline-flex; align-items: center; min-height: 44px; }

.is-me .view {
  padding: 0 0 calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
  max-width: 640px;              /* Home's own column width: the page is wider, not different */
}

/* ── the welcome half: the one thing the eye lands on ──────────────────── */
.me__head {
  background: var(--ink);
  border-radius: 0 0 24px 24px;   /* the hero's foot; the sheet below has a FLAT top edge */
  padding: 0 24px 36px;     /* 36 = the sheet's 24 px overlap + 12 px of air under the email */
  text-align: center;
}

/* The photo control is ONE target: the disc AND the words under it are inside
   the button, so a thumb aiming at the caption is not told "nothing here".
   80 x 101 — more than double the 44 px floor. */
.me__id {
  display: grid; justify-items: center; gap: 4px;
  margin: 0 auto; padding: 0; border: 0; background: none;
  font: inherit; color: #fff; cursor: pointer;
}
.me__avatar {
  display: grid; place-items: center;
  width: 80px; height: 80px; margin: 0; padding: 0;
  border: 0; border-radius: 50%;
  background: var(--teal); color: #fff;
  font: inherit; font-size: 30px; font-weight: 700; letter-spacing: .5px;
  cursor: pointer; overflow: hidden;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .18);
}
.me__avatar img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* 12 px is the smallest type on the screen and it is a LABEL for a control,
   not body copy — body copy never goes below 16 px. */
.me__avatar-lbl {
  display: block; margin: 0;
  font-size: 13px; font-weight: 600; line-height: 1.35;
  color: rgba(255, 255, 255, .78);
}

.me__name {
  margin: 8px 0 0;
  font-size: 22px; font-weight: 700; line-height: 1.55;   /* Naskh descenders need the depth */
  color: #fff;
  /* ONE line, ellipsis. A wrapped name looks kinder, but it grows the head by
     34 px and on a 390 px phone that pushes the last row behind the floating +.
     The whole name is one tap away in the Name wizard, which holds it entire. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  unicode-bidi: plaintext;        /* an Arabic name is laid out RTL inside a centred LTR block */
}
.me__mail {
  margin: 4px 0 0;
  font-size: 13px; font-weight: 400; line-height: 1.35;
  color: rgba(255, 255, 255, .78);
  direction: ltr;                 /* an address never mirrors */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ── the sheet: flat top edge, overlap = the hero's radius (no crossing arcs) */
.me__sheet {
  position: relative; z-index: 1;
  margin-top: -24px;
  background: var(--mist);
  border-radius: 0;
  /* 24 px inline is Home's own sheet padding, and it is what makes a row pass
     behind the floating pill WITHOUT peeking out at its sides: the rows land on
     24..366, inside the pill's 23..367. 56 px at the foot clears the bar. */
  padding: 16px 24px 56px;
}

.me__list { display: flex; flex-direction: column; gap: 8px; }
.me__list + .me__list { margin-top: 8px; }   /* the toggle is a row like the others, not a new group */

/* ── one row: the Home pill, 72 px, arrow at the inline end ────────────── */
.me-row {
  display: flex; align-items: center; gap: 12px;
  width: 100%; min-height: 72px; margin: 0;
  padding: 10px 0; padding-inline: 16px 12px;   /* logical: the pill mirrors with the reading direction */
  background: var(--card);
  border: 0; border-radius: 36px;
  box-shadow: 0 1px 2px rgba(11, 27, 43, .05);
  font: inherit; color: inherit; text-align: start;
  cursor: pointer;
}
.me-row:focus-visible { outline: 3px solid var(--teal); outline-offset: 2px; }
.me-row__txt { flex: 1 1 auto; min-width: 0; }
.me-row__t {
  display: block;
  font-size: 16px; font-weight: 600; line-height: 1.3;
  color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.me-row__v {
  display: block; margin-top: 1px;
  font-size: 13px; font-weight: 600; line-height: 1.35;
  color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  unicode-bidi: plaintext;        /* a user-written value keeps its own direction */
}
/* the same arrow the Home deck row uses, same 44 px disc, same border */
.me-row__go {
  width: 44px; height: 44px; flex: none;
  border-radius: 50%; border: 1.5px solid var(--teal);
  color: var(--teal-dark);
  display: grid; place-items: center;
}
.me-row__go svg { display: block; width: 20px; height: 20px; }
/* the arrow points at the reading direction's end, never at "right" */
[dir="rtl"] .me-row__go svg { transform: scaleX(-1); }

/* the one row that acts in place: the row is the switch, the pill shows the state */
.me-row--switch .switch { pointer-events: none; }

/* ── the bottom of the screen: today's blocks, untouched ───────────────── */
.is-me .account-footer { margin: 32px 0 14px; }
.is-me .switch-off { margin: 18px 0 8px; }

/* ══════════════════════════════════════════════════════════════════════════
 * ONE FIELD, ONE SCREEN — the wizard
 * The bar is .appbar's own geometry (58 px + top inset, ink); it gains a
 * back arrow, a title and Cancel, because a wizard with no visible way out
 * is the one thing this screen may never be.
 * ══════════════════════════════════════════════════════════════════════════ */
.view--wiz { padding: 16px 14px calc(24px + env(safe-area-inset-bottom, 0px)); }
/* .is-me .view owns the account screen's padding; a wizard inside the same body hook
   takes it back — one step more specific so the order cannot matter. */
body.is-me .view--wiz { padding: 16px 14px calc(24px + env(safe-area-inset-bottom, 0px)); }

.wizbar__back {
  flex: none; width: 44px; height: 44px; margin-inline-start: -6px;
  display: grid; place-items: center;
  border: 0; border-radius: 12px; background: transparent;
  color: #fff; cursor: pointer;
  font: inherit; font-size: 20px; line-height: 1;
}
.wizbar__title {
  flex: 1 1 auto; min-width: 0; margin: 0;
  font-size: 17px; font-weight: 700; text-align: center; color: #fff;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wizbar__cancel {
  flex: none; min-width: 44px; min-height: 44px; padding: 0 6px;
  border: 0; border-radius: 12px; background: transparent;
  color: #fff; font: inherit; font-size: 15px; font-weight: 600; cursor: pointer;
}

/* the wizard card's own rhythm: 16 px of air between the blocks it holds */
.wizard-card { gap: 10px; }
.wizard-card .field { margin: 0; }
.wizard-card .btn--block { margin-top: 4px; }
.wizard-card .form-error { margin: 0; }
.wizard-card .hint { margin: 0; }

/* THREE SIZES, TWO WEIGHTS on a wizard: 17 (bar title) / 16 (label, input,
   button) / 13 (description, hint, error). The app's .field__label is .92rem
   (14.72 px) and .small is .86rem (13.76 px); both are pinned to 13 px here so
   the form reads as three steps and not as four sizes a hair apart. */
.wizard .field__label { font-size: 13px; line-height: 1.35; }
.wizard .wizard-card__desc { font-size: 13px; font-weight: 400; line-height: 1.4; }
.wizard .hint { font-size: 13px; font-weight: 400; line-height: 1.4; }
.wizard .input::placeholder { color: var(--muted); opacity: 1; }
.wizard .btn--quiet { font-size: 16px; }
.wizard .form-error { font-size: 13px; font-weight: 400; line-height: 1.4; }

/* the photo step: a preview disc in the sheet, initials until there is a photo */
.me__photo {
  display: grid; place-items: center;
  width: 120px; height: 120px; margin: 4px auto 0;
  border-radius: 50%; background: var(--teal); color: #fff;
  font-size: 40px; font-weight: 700; letter-spacing: 1px;
  overflow: hidden;
}
.me__photo img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* A wizard is the whole screen: the floating tab bar steps aside while one is open (the mock's
   wizard frames carry no tab bar, and a third exit mid-edit invites a lost keystroke — back and
   Cancel are the two ways out, as drawn). */
body.is-me-wiz .tabbar { display: none; }

/* ══════════════════════════════════════════════════════════════════════════
 * T-221 — THE REPORT ENTRY AND ITS SHEET
 *
 * PART A (below, down to "the sheet") is the WHOLE entry: the mark's look and its corner, the
 * room the two top bars must leave for it, and the phone-only concessions. The founder is
 * choosing the final entry point, so this part is deliberately ONE replaceable block: replacing
 * it means rewriting these rules + `buildReportMark()` in app.js and nothing else. The id
 * (#report-btn), the aria-label (the sheet's heading), the sheet below and the capture are NOT
 * part of the replaceable look — they are the contract.
 *
 * The corner here is the provisional one (spec'd before the founder's second look): a 44 px
 * target, a 28 px chip, 7 px under the notch inset, 12 px from the inline end. Never red, no
 * badge, no count; two skins for one meaning — a translucent white chip on the ink app bar,
 * Home's ink hero and the Account head, a white chip on the mist surface of a study session.
 * ══════════════════════════════════════════════════════════════════════════ */
/* ── PART A — the entry: one quiet word (the founder's pick, 22.10) ────── */
/* Not a sign, not a chip, not a corner: the word sits inside whatever bar the screen already
   owns, so it reads as the page's own furniture. 44 px tall, one meaning, never red. */
.report-mark {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 6px;
  margin: 0;
  border: 0;
  background: none;
  font-family: inherit;
  font-size: .84rem;
  font-weight: 600;
  letter-spacing: .2px;
  white-space: nowrap;
  color: var(--muted);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color .1s ease;
}
.report-mark:hover, .report-mark:focus-visible { color: var(--ink); }
.report-mark[hidden] { display: none !important; }
.report-mark__word { display: inline-block; }

/* The one fallback (a screen with no bar of its own keeps the word on screen). */
.report-mark--float {
  position: fixed;
  top: calc(env(safe-area-inset-top) + 7px);
  inset-inline-end: 10px;
  z-index: 46;
}

/* Four surfaces, one word: the ink bars take the light ink, the mist ones the muted grey. */
.appbar .report-mark, .home__bar .report-mark, .me__bar .report-mark { color: rgba(255, 255, 255, .72); }
.appbar .report-mark:hover, .home__bar .report-mark:hover, .me__bar .report-mark:hover,
.appbar .report-mark:focus-visible, .home__bar .report-mark:focus-visible, .me__bar .report-mark:focus-visible { color: #fff; }
.review-head .report-mark { margin-inline-start: auto; }
.home__bar .report-mark { margin-inline-end: 2px; }

/* 390 px: the name and the version are what give way — the avatar initial carries identity. */
@media (max-width: 430px) {
  .brand__ver { display: none !important; }
  .usermenu__name { display: none; }
}

/* ── PART B — the pop-up (contract: role, focus, states, the frozen words) ─ */
/* The founder's shape (22.10): a pop-up over a blurred page, so the learner never loses the
   screen he was working on. The blur is the padding; the card is small enough to feel temporary. */
.report {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(11, 27, 43, .24);
  -webkit-backdrop-filter: blur(7px) saturate(1.04);
  backdrop-filter: blur(7px) saturate(1.04);
}
/* No blur in the engine? Say the same thing with a heavier scrim rather than nothing. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .report { background: rgba(11, 27, 43, .55); }
}
.report__sheet {
  width: min(100% - 24px, 420px);
  max-height: min(86dvh, 640px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px 16px calc(16px + env(safe-area-inset-bottom, 0px));
  margin: 0 0 12px;
  background: var(--card);
  border-radius: 20px;
  box-shadow: var(--shadow-lg);
}
/* Above 600 px it is a centred 480 px dialog, not a bottom card. */
@media (min-width: 600px) {
  .report { align-items: center; padding: 18px; }
  .report__sheet {
    width: 480px;
    max-height: 88vh;
    border-radius: var(--radius);
    padding: 22px 20px 18px;
    margin: 0;
  }
}
.report__title { margin: 0 0 2px; font-size: 1.18rem; }
.report__label { font-size: .92rem; font-weight: 600; color: var(--ink); }
.report__words {
  width: 100%;
  min-height: 96px;
  padding: 10px 12px;
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--mist);
  border: 1px solid var(--line);
  border-radius: 12px;
  resize: vertical;
}
.report__words::placeholder { color: var(--muted); opacity: 1; }
.report__block-title {
  margin: 8px 0 0;
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: .4px;
  text-transform: uppercase;
  color: var(--muted);
}
.report__line { margin: 0; font-size: .86rem; color: var(--muted); }
.report__note { margin: 4px 0 0; font-size: .92rem; font-weight: 600; }
.report__note--ok { color: var(--teal-dark); }
.report__note--error { color: var(--coral); }
/* Refused is not an error: the same ink, quieter — the learner did nothing wrong. */
.report__note--refused { color: var(--ink); font-weight: 600; }
.report__actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  margin-top: auto;
  padding-top: 14px;
}
.report__actions .btn { min-height: var(--tap); padding: 0 18px; }
@media (min-width: 600px) {
  .report__actions { margin-top: 0; }
}
.report.is-sending .report__cancel { opacity: 1; }   /* Cancel stays live while Send locks */

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


/* ══════════════════════════════════════════════════════════════════════
 * T-288: CARD MARKS — concept line, source card, note box, flag popup
 * ══════════════════════════════════════════════════════════════════════ */

/* ── card marks container ────────────────────────────────────────────── */
.card-marks { margin-top: 12px; }

/* ── concept line at card head ───────────────────────────────────────── */
.card-marks__head { border-bottom: 1px solid #1E2522; padding-bottom: 11px; margin-bottom: 13px; }
.card-marks__concept { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; min-height: 44px; padding: 0; background: transparent; border: 0; color: inherit;
  font: inherit; text-align: start; cursor: pointer; }
.card-marks__concept[disabled] { cursor: default; }
.card-marks__concept svg { width: 17px; height: 17px; color: var(--muted); flex: 0 0 auto; }
.card-marks__concept:hover svg { color: var(--teal); }
.card-marks__kicker { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card-marks__kicker b { color: var(--ink); font-weight: 700; letter-spacing: .02em; text-transform: none; font-size: 12px; }


/* ── source card (opens in place) ────────────────────────────────────── */
.src-card { margin-top: 14px; border: 1px solid #2A332F; border-radius: 14px; padding: 13px; background: #0F1413; }
.src-card__field { font-size: 13px; line-height: 1.6; border-inline-start: 2px solid var(--teal); padding-inline-start: 9px; position: relative; min-height: 1.6em; white-space: pre-wrap; }
.src-card__field[contenteditable="true"] { cursor: text; outline: none; }
.src-card__field[contenteditable="true"]:focus { background: #121816; border-radius: 0 8px 8px 0; }
.src-card__field:empty::before { content: attr(data-placeholder); color: var(--muted); }
.src-card__caret { display: inline-block; width: 1.5px; height: 14px; background: var(--teal); vertical-align: -2px; margin-inline-start: 2px; animation: blink 1s infinite; }
@keyframes blink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } }
.src-card__quotes { margin-top: 11px; }
.src-card__label { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--mint); font-weight: 700; margin-bottom: 6px; }
.src-card__quote { display: block; font-size: 12px; line-height: 1.55; color: var(--muted); margin-bottom: 6px; }
.src-card__quote::before { content: "« "; color: #C6D2CD; }
.src-card__quote::after { content: " »"; color: #C6D2CD; }
.src-card__warn { margin-top: 11px; font-size: 11px; color: var(--amber); line-height: 1.5; }
.src-card__acts { display: flex; gap: 8px; margin-top: 12px; }
.src-card__btn { flex: 1; height: 36px; border-radius: 11px; border: 1px solid #2A332F; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; background: #101513; color: var(--ink); cursor: pointer; }
.src-card__btn:hover { background: #141917; border-color: #3A443F; }
.src-card__btn--go { background: var(--teal); color: var(--mist); border-color: var(--teal); }
.src-card__btn--go:hover { filter: brightness(0.95); }

/* ── note box ────────────────────────────────────────────────────────── */
.note-box { margin-top: 12px; border: 1px solid #2A332F; border-radius: 14px; padding: 12px; background: #0F1413; }
.note-box__field { width: 100%; min-height: 60px; font: inherit; font-size: 12.5px; color: var(--ink); background: transparent; border: none; resize: vertical; outline: none; }
.note-box__field::placeholder { color: var(--muted); }
.note-box__hint { margin-top: 8px; font-size: 10.5px; color: #6D7A74; }
.note-box__acts { display: flex; gap: 8px; margin-top: 12px; }
.note-box__btn { flex: 1; height: 36px; border-radius: 11px; border: 1px solid #2A332F; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; background: #101513; color: var(--ink); cursor: pointer; }
.note-box__btn:hover { background: #141917; border-color: #3A443F; }
.note-box__btn--go { background: var(--teal); color: var(--mist); border-color: var(--teal); }
.note-box__btn--go:hover { filter: brightness(0.95); }

/* ── flag popup (centred over blurred page) ──────────────────────────── */
.flag-scrim { position: fixed; inset: 0; background: rgba(6,8,7,.45); backdrop-filter: blur(7px); z-index: 100; }
.flag-pop { position: fixed; z-index: 101; left: 50%; top: 50%; transform: translate(-50%,-50%); width: 330px; background: #131716; border: 1px solid #2A332F; border-radius: 18px; padding: 16px; }
.flag-pop__head { margin-bottom: 4px; }
.flag-pop__title { font-size: 14px; font-weight: 700; margin: 0; }
.flag-shell { display: contents; }
.flag-pop__label { font-size: 12.5px; }
.flag-pop__subtitle { font-size: 11px; color: var(--muted); margin: 4px 0 0; }
.flag-pop__chips { display: flex; flex-direction: column; gap: 7px; margin-top: 12px; }
.flag-pop__chip { display: flex; align-items: center; gap: 9px; border: 1px solid #2A332F; border-radius: 11px; padding: 10px 11px;
  font: inherit; font-size: 12.5px; background: transparent; color: var(--ink); text-align: start; cursor: pointer; }
.flag-pop__chip:hover { background: #141A0F; border-color: var(--teal); }
.flag-pop__bx { width: 16px; height: 16px; border-radius: 5px; border: 1.5px solid #3A453F; flex: 0 0 auto; }
.flag-pop__chip.is-on { border-color: var(--teal); background: #141A0F; color: var(--ink); }
.flag-pop__chip.is-on .flag-pop__bx { background: var(--teal); border-color: var(--teal); }
.flag-pop__acts { display: flex; gap: 8px; margin-top: 13px; }
.flag-pop__btn { flex: 1; height: 38px; border-radius: 11px; border: 1px solid #2A332F; display: flex; align-items: center; justify-content: center; font-size: 12.5px; font-weight: 700; background: #101513; color: var(--ink); cursor: pointer; }
.flag-pop__btn:hover { background: #141917; border-color: #3A443F; }
.flag-pop__btn--go { background: var(--teal); color: var(--mist); border-color: var(--teal); }
.flag-pop__btn--go:hover { filter: brightness(0.95); }

/* ── quiet foot row ──────────────────────────────────────────────────── */
.card-marks__foot { display: flex; align-items: center; justify-content: space-between; border-top: 1px solid #1E2522; margin-top: 15px; padding-top: 12px; }
.card-marks__foot-btn { display: flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 600; color: var(--muted); background: transparent; border: none; cursor: pointer; padding: 0; }
.card-marks__foot-btn:hover { color: var(--ink); }
.card-marks__foot-btn svg { width: 16px; height: 16px; }


/* ══ T-313 — the preparing ring ════════════════════════════════════════════
   132 px box, band 12 px (outer radius 61, inner 49). Light drifting inside the
   stroke: one turn in 7 s clockwise over a dimmer turn in 9 s the other way,
   both breathing on 4.5 s — no dash, no hard leading edge, no telling where it
   started. Colours are the live tokens (bevel.css); the mask cuts the band so
   the light never spills into the hole. Numbers frozen in
   projects/tikrar/evidence/T-313-2026-10-26/spec.md.                          */
.scanring { position: relative; width: 132px; height: 132px; margin: 2px auto 10px; }
.scanring.scanring--sm { width: 84px; height: 84px; }
.scanring.scanring--xs { width: 64px; height: 64px; }
.scanring > div { position: absolute; inset: 5px; border-radius: 50%; }
.scanring__track { border: 12px solid var(--line, #242B28); }
.scanring__spin {
  background: conic-gradient(from 0deg,
    rgba(201,244,90,0) 0deg, rgba(201,244,90,.06) 30deg, rgba(201,244,90,.26) 60deg,
    rgba(201,244,90,.62) 90deg, rgba(201,244,90,1) 120deg, rgba(201,244,90,.62) 150deg,
    rgba(201,244,90,.26) 180deg, rgba(201,244,90,.06) 210deg, rgba(201,244,90,0) 240deg,
    rgba(201,244,90,0) 360deg);
  -webkit-mask: radial-gradient(closest-side, transparent 0 79%, #000 80% 100%);
          mask: radial-gradient(closest-side, transparent 0 79%, #000 80% 100%);
  animation: tikscan-turn 7s linear infinite, tikscan-breathe 4.5s ease-in-out infinite;
}
.scanring__spin.ccw { animation: tikscan-turn-back 9s linear infinite, tikscan-breathe-dim 4.5s ease-in-out infinite; }
@keyframes tikscan-turn { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes tikscan-turn-back { from { transform: rotate(0deg); } to { transform: rotate(-360deg); } }
@keyframes tikscan-breathe { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
@keyframes tikscan-breathe-dim { 0%, 100% { opacity: .35; } 50% { opacity: .16; } }
.scanring.rf .scanring__spin, .scanring.re .scanring__spin,
.scanring.rx .scanring__spin, .scanring.ri .scanring__spin { display: none; }
.scanring.rf .scanring__track { border-color: var(--teal, #C9F45A); }
.scanring.re .scanring__track { border-color: var(--amber, #FFB347); }
.scanring.rx .scanring__track { border-color: var(--coral, #FF6B57); }
/* A still ring for a person who asked the system not to move: the light parks. */
@media (prefers-reduced-motion: reduce) {
  .scanring__spin { animation: none !important; transform: rotate(-30deg); }
  .scanring__spin.ccw { display: none; }
}
/* the scan popup's own lines, mounted inside the sheet instead of a dialog */
.scanhost { display: block; margin: 0 0 12px; }
.scanhost .modal__title { font-size: 15px; margin: 0 0 2px; color: var(--ink, #F2F5F3); }
.scanhost .modal__msg { margin: 0; font-size: 13px; color: var(--muted, #8D9A94); }
.scanhost .modal__actions { justify-content: flex-start; margin-top: 10px; }
.scanhost .modal__actions .btn { flex: 0 0 auto; }

/* the sheet's own scan layout: the ring and the phase line in one row, the deck
   form underneath in its own scroll area so the details never push the ring away */
/* the theme's sheet card already scrolls inside 84vh — the scan sheet only narrows the ring */
/* 84vh would tuck the sheet's foot under the floating bar: stop it short of the bar */
.sheetcard.sheetcard--scan { display: block; max-height: 76vh; overflow-y: auto; }
.sheetcard.sheetcard--scan .sheetbody--form { padding: 0 16px 4px; }
.sheetcard.sheetcard--scan .sheetclose { margin-top: 6px; }
.scanrow { display: flex; gap: 14px; align-items: center; padding: 0 16px 10px; }
.scanrow .scanring { flex: none; margin: 0; }
.scanhost { flex: 1; min-width: 0; }
.scanhost .modal__title { margin: 0 0 2px; font: inherit; font-size: 16px; font-weight: 700; color: var(--ink, #EAF2EE); }
.scanhost .modal__msg { margin: 0; font-size: 13px; line-height: 1.35; color: var(--muted, #8EA39A); }
.scanhost .modal__actions { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.scanhost .modal__actions .btn { min-height: 36px; padding: 0 10px; flex: 1 1 0; min-width: 0; }
.sheetbody--form { padding: 0 16px 4px; }
.scanring--xs > div { inset: 2px; }
.scanring--xs .scanring__track { border-width: 6px; }
.scanring--sm > div { inset: 3px; }
.scanring--sm .scanring__track { border-width: 8px; }
/* T-323 — the 28 px ring that stands inside a button while it saves (the onboarding account card).
   The band scales with the box: a 3 px stroke and a 12 px box, so the light stays visible. */
.scanring--xxs { width: 28px; height: 28px; }
.scanring--xxs > div { inset: 1px; }
.scanring--xxs .scanring__track { border-width: 3px; }
.onboard-preparing { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; }

/* the phase buttons share the narrow column beside the ring: two even halves, never clipped */
.scanhost .modal__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.scanhost .modal__actions .btn { flex: 1 1 0; min-width: 0; padding: 0 10px; min-height: 36px; }

/* ── T-353 — one label, one size, one shade ────────────────────────────────────────────────────
   Founder, 30.10: "All card 10 of X, concept, answer, explanation, hide/reveal, note, flag, end
   session, war das, before u look: all should be all cap, same size, same color shade except ones
   inside the answer block/box." So every label on the card wears the same caps, the same 10.5px and
   the one muted shade; the answer's own prose is content and keeps its own type. The day's gate keeps
   its colour as a dot instead of colouring the words. */
.review-head__left { display: flex; align-items: center; gap: 10px; min-width: 0; }
.review-head__count,
.card-marks__kicker,
.reveal__label,
.reveal__hint,
.reveal__hide,
.merged__label:not(.merged__label--hook),
.card-marks__foot-btn,
.review-head__exit,
.outcome__ask,
.survey__ask {
  text-transform: uppercase;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .14em;
  color: var(--muted);
  line-height: 1.3;
}
.review-head__dot { width: 6px; height: 6px; border-radius: 999px; flex: 0 0 auto; }
/* The way out: the far right edge, the size of a thumb, a quiet pill so it still reads as a target.
   The counter keeps the far left — the two ends of one line, nothing between them. */
.review-head__exit {
  display: inline-flex; align-items: center; min-height: var(--tap); padding: 0 12px;
  background: transparent; border: 1px solid var(--line); border-radius: 999px; cursor: pointer;
  font-family: inherit;
}
.review-head__exit:hover { border-color: var(--muted); }
/* A footer with nothing in it is not a footer. */
.session-footer--empty { display: none; }
