/* ═══════════════════════════════════════════════════════════════════
   ኤላም — app screens

   The shell and every screen inside it. Load after base.css.

   One rule shapes the layout: nothing here is a dashboard. There is no
   sidebar of destinations. A slim top bar carries study Home and the four tracks, and
   the moment you step into a course, a reading or a session it collapses
   to a back link and the thing's own name while the track's colour takes
   over the page.
   ═══════════════════════════════════════════════════════════════════ */

/* ═══════════════════ Shell ═══════════════════ */

/* overflow-x: clip, not hidden: clip does not create a scroll container,
   so the sticky top bar keeps working. Needed because the section blocks
   below bleed to 100vw, which is wider than the page on any browser with
   a classic scrollbar. */
/* On a wide monitor the app is a sheet of cream paper laid on a slightly
   darker mat, rather than cream stretched to 2560px — a reading column
   that wide is unusable, and the mat gives the page an edge to end at. */
body { background: var(--paper); }
.shell {
  min-height: 100vh;
  width: 100%;
  max-width: var(--frame-wide);
  margin-inline: auto;
  background: var(--app);
  overflow-x: clip;
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--session-chrome);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}
.topbar__in {
  max-width: var(--frame);
  margin: 0 auto;
  padding: 0 clamp(16px, 4vw, 40px);
  height: 70px;
  display: flex;
  align-items: center;
  gap: clamp(8px, 2vw, 24px);
}


/* ── Search ────────────────────────────────────────────────────────
   The widest thing in the bar, and the only one that grows with it. It
   is a button drawn as a field: the palette behind it has filters and a
   result list of its own, so there is one search implementation and this
   is its door, not a second input that would have to agree with it. */
.searchbar {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 520px;
  height: 44px;
  padding: 0 6px 0 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--line-soft);
  color: var(--ink-4);
  font: 400 14px/1.4 var(--ui);
  text-align: start;
  cursor: pointer;
  transition: background .16s var(--ease), border-color .16s var(--ease);
}
.searchbar:hover { background: var(--card); border-color: var(--line-3); }
.searchbar:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.searchbar__icon { width: 18px; height: 18px; flex: none; color: var(--ink-4); }
.searchbar__txt {
  min-width: 0;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The shortcut, said quietly. app.js binds both ⌘K and "/", so this is a
   promise the app keeps. Hidden on touch, where there is no key to press. */
.searchbar__key {
  flex: none;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-2);
  border-radius: 7px;
  background: var(--card);
  color: var(--ink-5);
  font: 600 12px/1 var(--ui);
}
@media (pointer: coarse) {
  .searchbar__key { display: none; }
}

/* Home is a real destination here, separate from the brand mark: the
   former returns to the learner's overview, while the latter returns to
   the public landing page. It sits to the right of search now rather than
   centred — a centred row cannot share a bar with a field that wide. */
.topnav {
  flex: none;
  display: flex;
  align-items: center;
  gap: 2px;
  min-width: 0;
}
.topnav__link {
  padding: 9px 14px;
  border-radius: 999px;
  font: 400 14.5px/1.5 var(--et);
  color: var(--ink-4);
  white-space: nowrap;
}
.topnav__link:hover { background: var(--hover); color: var(--ink); }
/* "You are here" is the one place the track's own colour is allowed to
   act as a label, so it gets the deep partner as ink on the pale tint. */
.topnav__link.is-on { background: var(--tint, var(--line-soft)); color: var(--tint-ink, var(--ink)); font-weight: 500; }
.topnav__link--home {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--ui);
  font-size: 13px;
  font-weight: 600;
}
.topnav__link--home svg {
  width: 15px;
  height: 15px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ── The tracks menu ───────────────────────────────────────────────
   One trigger whose width does not depend on how much curriculum
   exists. The panel is a menu, not a dialog: it does not claim
   aria-modal and does not hold Tab. */
.navmenu { position: relative; }
.navmenu__trigger {
  min-height: 44px;
  padding: 0 12px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-4);
  font: 600 13px/1.5 var(--ui);
  white-space: nowrap;
  cursor: pointer;
}
.navmenu__trigger:hover { background: var(--hover); color: var(--ink); }
/* Standing inside a ዘርፍ shows on the trigger, because the menu has put
   the track's own name out of sight. The tint is the track's, the same
   licence the pill row had — the weight and the chevron carry it too. */
.navmenu__trigger.is-on {
  background: var(--tint, var(--line-soft));
  color: var(--tint-ink, var(--ink));
  font-weight: 700;
}
.navmenu__chev {
  width: 15px;
  height: 15px;
  flex: none;
  transition: transform .16s var(--ease);
}
.navmenu.is-open .navmenu__chev { transform: rotate(180deg); }

.navmenu__panel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 8px);
  inset-inline-start: 0;
  width: max-content;
  min-width: 268px;
  max-width: min(92vw, 340px);
  max-height: min(70vh, 520px);
  padding: 8px;
  overflow-y: auto;
  border: 1px solid var(--line-2);
  border-radius: var(--r-lg);
  background: var(--card);
  box-shadow: var(--sh-2);
  display: grid;
  gap: 2px;
}
.navmenu__panel[hidden] { display: none; }
.navmenu__row {
  min-height: 56px;
  padding: 8px 10px;
  display: flex;
  align-items: center;
  gap: 12px;
  border-radius: var(--r-md);
  color: var(--ink-2);
}
.navmenu__row:hover { background: var(--hover); color: var(--ink); }
.navmenu__row.is-on { background: var(--tint, var(--line-soft)); color: var(--tint-ink, var(--ink)); }
/* The track's own emblem, the drawing its cards already carry — the same
   call the teacher rail makes, so a ዘርፍ looks like itself everywhere. */
.navmenu__art { width: 34px; height: 34px; flex: none; display: grid; place-items: center; }
.navmenu__art svg { width: 100%; height: 100%; display: block; }
.navmenu__body { min-width: 0; display: flex; flex-direction: column; }
.navmenu__title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font: 500 14.5px/1.45 var(--et);
}
.navmenu__sub {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-4);
  font: 500 12px/1.45 var(--ui);
}

.topbar__end {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
  margin-left: auto;
  margin-inline-start: auto;
}

.iconbtn {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: 999px;
  border: none;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
}
/* An icon button is the smallest target on the site and the one with no
   label, so its hover has to be unmistakable: a filled disc, a ring, and
   full-strength ink. */
.iconbtn:hover,
.iconbtn:focus-visible { background: var(--hover); box-shadow: inset 0 0 0 1px var(--line); color: var(--ink); }
.iconbtn.is-on { background: var(--accent-bg); color: var(--accent); }
.iconbtn svg { width: 20px; height: 20px; }

/* ── The ladder, explained in settings ── */
.panel--ladder { padding: 20px 22px; display: flex; flex-direction: column; gap: 14px; }
.panel--ladder p { margin: 0; font: 500 14.5px/1.75 var(--ui); color: var(--ink-3); text-wrap: pretty; }
.panel--ladder p b { color: var(--ink); font-weight: 700; }
.ladder {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  counter-reset: rung;
}
.ladder li {
  flex: 1 1 128px;
  padding: 11px 13px;
  border-radius: var(--r);
  background: var(--rail);
  border: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.ladder li b { font: 700 12.5px/1.35 var(--ui); color: var(--ink-2); }
.ladder li span { font: 600 12.5px/1.4 var(--ui); color: var(--accent-2); }

/* ── The account chip ──
   Standing evidence that signing in did something. An initial and one
   word: enough to answer "am I signed in, and is my work safe?" without
   spending any of the bar's attention on it. */
.acctchip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px 5px 5px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--ink-3);
  max-width: 190px;
}
.acctchip[hidden] { display: none; }
.acctchip:hover { border-color: var(--line-3); color: var(--ink); }
.acctchip__mark {
  flex: none;
  width: 26px; height: 26px;
  border-radius: 999px;
  display: grid; place-items: center;
  background: var(--ink);
  color: #fff;
  font: 800 12px/1 var(--ui);
}
.acctchip__txt {
  font: 700 12px/1.3 var(--ui);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.acctchip[data-state="syncing"] .acctchip__mark { background: var(--ink-4); }
.acctchip[data-state="error"] { border-color: var(--bad-line); color: var(--bad-2); }
.acctchip[data-state="error"] .acctchip__mark { background: var(--bad); }

/* On a phone the bar is already tight; the initial alone still answers
   the question, so the word goes.

   What is left is one of three circles in a row, not a fourth kind of
   object beside them: same 44px box as search and the menu, no ring of
   its own. It used to draw itself a 36px pill, which was both out of
   rhythm and under the minimum touch target. */
@media (max-width: 560px) {
  .acctchip {
    width: 44px; height: 44px;
    padding: 0;
    max-width: none;
    justify-content: center;
    border-color: transparent;
    background: transparent;
  }
  .acctchip__txt { display: none; }
  .acctchip__mark { width: 30px; height: 30px; font-size: 13px; }

  /* Except when the sync has failed. That is the one thing worth the
     bar's width — colour never carries meaning alone, and here the word
     is the only thing carrying it. */
  .acctchip[data-state="error"] { width: auto; padding: 0 11px 0 0; }
  .acctchip[data-state="error"] .acctchip__txt { display: block; }
}

/* ── The quiet bar ────────────────────────────────────────────────
   Inside a course, a reading or a result, the destinations disappear and
   the bar says only where you are and how to get back out. */
.topbar--quiet .topnav,
.topbar--quiet .brand__txt { display: none; }

/* Search does not disappear with them — a question you half remember is
   exactly the thing you go looking for from inside a course — but it
   stops being the widest object on a bar whose job is now the crumb, and
   drops back to the icon it used to be. Same shape below the tablet
   breakpoint, where the destinations move into the drawer. */
.topbar--quiet .searchbar {
  flex: none;
  width: 44px;
  max-width: 44px;
  padding: 0;
  justify-content: center;
  border-color: transparent;
  background: transparent;
  color: var(--ink-2);
}
.topbar--quiet .searchbar:hover { background: var(--hover); }
.topbar--quiet .searchbar__txt,
.topbar--quiet .searchbar__key { display: none; }

.topbar .brand,
.topbar .brand:hover { color: var(--ink); }
/* Ink, not terracotta. The terracotta is reserved for "you are here" and
   for links; a permanently-accented logo spends it on the one element
   nobody needs directed to. */
.topbar .brand__name { color: var(--ink); }
.topbar .brand__sub { color: var(--ink-4); }

/* [hidden] loses to display:flex, so it has to be restated. Without this
   the back link shows on the home page, where there is nothing to go back
   from. */
.crumb { display: flex; align-items: center; gap: 10px; min-width: 0; margin-inline-end: auto; }
.crumb[hidden] { display: none; }
.crumb__back {
  flex: none;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px 7px 11px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--hover);
  font: 600 13px/1.3 var(--ui);
  color: var(--ink-2);
  cursor: pointer;
}
.crumb__back:hover { background: var(--sunk); border-color: var(--line-2); color: var(--ink); }
.crumb__here {
  min-width: 0;
  font: 400 15px/1.4 var(--et);
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Navigation drawer ──────────────────────────────────────────────
   Opened from the hamburger next to Settings, on any screen size. It is
   the one place Home, every track, My challenges and Settings sit
   together — the pill nav above only ever carried the first two, and on
   a phone (where the pills hide below 900px) nothing carried the rest. */
.navdrawer { position: fixed; inset: 0; z-index: 50; display: flex; justify-content: flex-end; }
.navdrawer[hidden] { display: none; }
.navdrawer__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(24, 22, 19, .42);
}
.navdrawer__panel {
  position: relative;
  width: min(320px, 86vw);
  height: 100%;
  padding: 10px 10px calc(14px + env(safe-area-inset-bottom, 0px));
  background: var(--card);
  border-left: 1px solid var(--line);
  box-shadow: var(--sh-dialog);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}
.navdrawer__head { flex: none; display: flex; align-items: center; justify-content: space-between; padding: 6px 10px 10px; }
.navdrawer__title { font: 800 12.5px/1.4 var(--ui); letter-spacing: .07em; text-transform: uppercase; color: var(--ink-4); }
/* The account, at the top of the menu that now carries Settings. The bar's
   chip is an initial on a phone and nothing else; this says the name, the
   address and what the sync is doing, in words. */
.navacct {
  flex: none;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 60px;
  margin: 0 0 8px;
  padding: 8px 12px;
  border-radius: var(--r);
  background: var(--rail);
  border: 1px solid var(--line);
  color: var(--ink-2);
}
.navacct[hidden] { display: none; }
.navacct:hover,
.navacct:focus-visible { background: var(--hover); border-color: var(--line-3); }
.navacct__mark {
  flex: none;
  width: 34px; height: 34px;
  border-radius: 999px;
  display: grid; place-items: center;
  background: var(--ink);
  color: #fff;
  font: 800 14px/1 var(--ui);
}
.navacct__txt { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.navacct__name {
  font: 700 13.5px/1.35 var(--ui);
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.navacct__state { font: 600 12.5px/1.3 var(--ui); color: var(--ink-4); }
.navacct[data-state="syncing"] .navacct__mark { background: var(--ink-4); }
.navacct[data-state="error"] { border-color: var(--bad-line); }
.navacct[data-state="error"] .navacct__mark { background: var(--bad); }
.navacct[data-state="error"] .navacct__state { color: var(--bad-2); }

.navdrawer__links { display: flex; flex-direction: column; gap: 2px; }
.navdrawer__link {
  min-height: 52px;
  padding: 0 12px;
  border-radius: var(--r);
  display: flex;
  align-items: center;
  gap: 14px;
  color: var(--ink-2);
  font: 600 15px/1.4 var(--ui);
}
.navdrawer__link svg { flex: none; width: 21px; height: 21px; color: var(--ink-4); }
.navdrawer__link:hover,
.navdrawer__link:focus-visible { background: var(--hover); color: var(--ink); }
.navdrawer__link.is-on { background: var(--tint, var(--line-soft)); color: var(--tint-ink, var(--ink)); font-weight: 700; }
.navdrawer__link.is-on svg { color: inherit; }
.navdrawer__divider { height: 1px; margin: 10px 12px; background: var(--line); }
.navdrawer__eyebrow {
  padding: 2px 12px 6px;
  font: 800 11.5px/1.4 var(--ui);
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-4);
}

.page {
  max-width: var(--frame);
  margin: 0 auto;
  padding: 30px clamp(16px, 4vw, 40px) 80px;
}
.page--narrow { max-width: 46rem; }

.stack { display: flex; flex-direction: column; gap: 12px; }
.section { display: flex; flex-direction: column; gap: 14px; }
.section + .section { margin-top: 34px; }

/* The bottom tab bar was replaced by the drawer. The rule stayed and
   nothing ever re-enabled it, so the markup under it was dead — it has
   been removed from app.html, and this keeps any cached copy quiet. */
.tabbar { display: none; }

/* ── Section blocks ───────────────────────────────────────────────
   These used to bleed to the window edge in bands of colour — sand for
   one section, a pink tint for the next. On the cream page that reads as
   three different pages stacked on top of each other, and the seams land
   in arbitrary places because the bleed is measured against the viewport
   while everything else is measured against the frame.

   They are now pure rhythm: space and an eyebrow. The page is one sheet
   of paper from the top bar to the footer, and the white cards on it are
   the only thing that changes value. */
.block {
  margin-top: 38px;
  padding: 0;
  width: auto;
  background: none;
}
.block__in {
  max-width: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* ═══════════════════ Home ═══════════════════
   One column, full width, stacked. The old two-column layout left a hole
   in the bottom-right corner at every size; a single column ending in a
   figures strip has no corner to leave empty. */

/* 42px was a landing-page headline on a working screen. The design set
   puts the greeting at 30px — big enough to own the top of the page,
   small enough that the daily review card under it is still the loudest
   thing there, which is the point of the whole screen. */
.greet { display: flex; flex-direction: column; gap: 6px; margin-bottom: 26px; }
.greet h1 { margin: 0; font: 800 clamp(26px, 3.2vw, 30px)/1.25 var(--ui); letter-spacing: -.025em; color: var(--ink); }
.greet p  { margin: 0; font: 500 14.5px/1.6 var(--ui); color: var(--ink-5); max-width: 48ch; }

.hero {
  border-radius: var(--r-2xl);
  padding: clamp(22px, 3.4vw, 34px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 20px 28px;
}
.hero__body { flex: 1 1 280px; min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.hero__body h2 { margin: 0; font: 800 clamp(21px, 2.6vw, 27px)/1.25 var(--ui); letter-spacing: -.02em; color: var(--ink); }
.hero__body p  { margin: 0; font: 500 15px/1.65 var(--ui); color: var(--ink-2); max-width: 52ch; text-wrap: pretty; }
.hero .tag { align-self: flex-start; }
.hero .btn { flex: 0 1 auto; min-width: 0; }
.hero__art { flex: none; width: 92px; height: 92px; color: var(--tint-ink, var(--accent)); }

.hero--first { background: var(--card); border: 1px solid var(--line); box-shadow: var(--sh-2); }
.hero--done  { background: var(--card); border: 1px solid var(--line); box-shadow: var(--sh-1); }

/* The one dark surface on the site. It is the thing you came here to do. */
.hero--due { background: var(--ink-block); box-shadow: var(--sh-dark); }
.hero--due .hero__count { flex: none; font: 400 clamp(46px, 6vw, 64px)/1 var(--et); color: #fff; }
.hero--due .hero__body h2 { color: #fff; }
.hero--due .hero__body p  { color: #a8a099; }
.hero--due .num-alt { color: rgba(255,255,255,.5); }

.resume {
  text-align: start;
  background: var(--card);
  border: 1px solid var(--line);
  box-shadow: var(--sh-1);
  border-radius: var(--r-lg);
  padding: 16px 18px;
  display: flex;
  align-items: center;
  gap: 14px;
  cursor: pointer;
  width: 100%;
  color: inherit;
  transition: box-shadow .12s var(--ease);
}
.resume:hover { box-shadow: var(--sh-2); color: inherit; }
.resume__icon {
  flex: none;
  width: 38px; height: 38px;
  border-radius: 999px;
  background: var(--tint, var(--accent-bg));
  display: grid; place-items: center;
  color: var(--tint-ink, var(--accent));
  font-size: 15px;
}
.resume__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.resume__eyebrow {
  font: 700 11px/1.4 var(--ui);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--tint-ink, var(--accent));
}
.resume__title { font: 400 14.5px/1.7 var(--et); color: var(--ink); text-wrap: pretty; }
.resume__go { flex: none; color: var(--ink-5); font-size: 18px; }

/* ── Track cards ──────────────────────────────────────────────────
   A block of the track's colour with its emblem drawn into it. This is
   where the site stops being a list of words. */
.grid { display: grid; gap: 16px; }
/* 200px sits four across on a laptop and two across on a tablet — never
   three with an orphan alone on the next row. Written when there were
   exactly four tracks; the live curriculum now carries a fifth (የመጽሐፍ
   ቅዱስ ጥናት) and can carry more, so the orphan row it was tuned to avoid
   is reachable again at some widths. Worth looking at on a real laptop
   before changing the number. */
.grid--tracks  { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.grid--courses { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

/* ── First paint ──────────────────────────────────────────────────
   The half-second the live curriculum takes to arrive. The blocks carry
   the real hero and track-card geometry so the page does not resize when
   the content lands in their place — that resize is the whole reason
   this exists.

   No text, no percentages, no spinner. It says a shape is coming and
   nothing more; anything readable here would be a claim that has to be
   taken back a moment later. */
.skel { padding-top: 34px; }
.skel__block {
  display: block;
  background: var(--card);
  border: 1px solid var(--line);
}
.skel__hero {
  border-radius: var(--r-2xl);
  min-height: 152px;
  margin-bottom: 38px;
}
.skel__tracks {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.skel__tcard { border-radius: var(--r-xl); min-height: 178px; }

/* A slow breath, and a shallow one. The design system has no gradients in
   it, so no sweep; and the page is quiet enough that a blinking rectangle
   would be the loudest thing on it. */
@media (prefers-reduced-motion: no-preference) {
  .skel__block { animation: skel-breathe 1.8s var(--ease, ease) infinite; }
  @keyframes skel-breathe {
    0%, 100% { opacity: 1; }
    50%      { opacity: .55; }
  }
}

/* ─── A series: one book, several days ───────────────────────────────
   Drawn as a heading and a rule rather than a box. The days inside are
   still ordinary course cards — boxing them would make the group look
   like a single thing you enter, when what you actually pick is one
   day. The rule is the track's own colour, so a series belongs to its
   ዘርፍ without needing to be labelled twice. */
.series { margin-bottom: 28px; }
.series:last-child { margin-bottom: 0; }
.series__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 14px;
  padding-inline-start: 12px;
  border-inline-start: 3px solid var(--tint-ink, var(--line-3));
  margin-bottom: 14px;
}
.series__title {
  margin: 0;
  font: 600 var(--t-lg)/1.5 var(--et);
  color: var(--ink);
}
.series__meta {
  font: 600 var(--t-xs)/1.5 var(--ui);
  color: var(--ink-4);
  letter-spacing: .01em;
}

.tcard {
  position: relative;
  overflow: hidden;
  text-align: start;
  background: var(--tint, var(--card));
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  padding: 20px;
  min-height: 178px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  cursor: pointer;
  color: inherit;
  transition: transform .14s var(--ease), box-shadow .14s var(--ease);
}
.tcard:hover { transform: translateY(-2px); box-shadow: var(--sh-lift); color: inherit; }
/* A watermark, so it has to stay behind the meta line rather than
   underneath it. It was 128px hanging off two edges, which put the
   thickest part of the drawing directly under "1 course · 45 questions". */
.tcard__art {
  position: absolute;
  right: -14px; bottom: -14px;
  width: 96px; height: 96px;
  color: var(--tint-ink);
  opacity: .13;
  pointer-events: none;
}
.tcard__title { font: 500 19px/1.55 var(--et); color: var(--ink); text-wrap: pretty; position: relative; }
.tcard .cmeta { position: relative; }
.tcard .mstat { margin-top: auto; position: relative; }

.ccard {
  text-align: start;
  background: var(--card);
  border: 1px solid var(--line);
  box-shadow: var(--sh-1);
  border-radius: var(--r-xl);
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  cursor: pointer;
  color: inherit;
  transition: transform .12s var(--ease), box-shadow .12s var(--ease);
}
.ccard:hover { box-shadow: var(--sh-2); transform: translateY(-2px); color: inherit; }
.ccard__title { font: 500 19px/1.6 var(--et); color: var(--ink); text-wrap: pretty; }
.ccard__desc  { font: 400 14px/1.8 var(--et); color: var(--ink-2); text-wrap: pretty; }
.cmeta { font: 600 12.5px/1.5 var(--ui); color: var(--ink-3); }
.cmeta .num-alt { color: var(--ink-5); }

/* ── Study plan ───────────────────────────────────────────────────
   A cadence, not a streak. A streak punishes one missed day; three
   sessions a week is something a nine-year-old can actually keep and a
   parent can actually check. */
.plan {
  background: var(--card);
  border: 1px solid var(--line);
  box-shadow: var(--sh-1);
  border-radius: var(--r-xl);
  padding: 20px 24px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 26px;
}
.plan__body { flex: 1 1 240px; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.plan__title { font: 800 18px/1.3 var(--ui); letter-spacing: -.01em; color: var(--ink); }
.plan__line  { font: 500 13.5px/1.6 var(--ui); color: var(--ink-3); text-wrap: pretty; }
.plan__pips { display: flex; gap: 8px; flex: none; }
.plan__pip {
  width: 32px; height: 32px;
  border-radius: 999px;
  border: 2px solid var(--line-2);
  display: grid; place-items: center;
  font: 700 11px/1 var(--ui);
  color: var(--ink-5);
}
.plan__pip.is-done { background: var(--good); border-color: var(--good); color: #fff; }

/* ── Figures ──────────────────────────────────────────────────────
   A strip, not a column. Four numbers do not deserve a whole rail. */
.figures {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  overflow: hidden;
  box-shadow: var(--sh-1);
}
.figrow {
  padding: 18px 20px;
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.figrow:last-child { border-right: 0; }
.figrow dt { font: 600 12px/1.5 var(--ui); color: var(--ink-3); }
.figrow dd { margin: 0; font: 400 26px/1.2 var(--et); color: var(--ink); }

/* ═══════════════════ Track and course ═══════════════════
   Both open with a band of the track's own colour carrying its emblem,
   so the page says where you are before a word is read. */

.band {
  background: var(--tint, var(--paper));
  border-radius: var(--r-2xl);
  padding: clamp(24px, 3.6vw, 38px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 20px 28px;
  margin-bottom: 24px;
}
.band__body { flex: 1 1 320px; min-width: 0; display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
.band__eyebrow {
  font: 700 11.5px/1.4 var(--ui);
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--tint-ink, var(--ink-3));
}
.band h1 { margin: 0; font: 600 clamp(25px, 3.4vw, 36px)/1.4 var(--et); color: var(--ink); text-wrap: pretty; }
.band p  { margin: 0; max-width: 60ch; font: 400 15.5px/1.85 var(--et); color: var(--ink-2); text-wrap: pretty; }
.band__art { flex: none; width: clamp(84px, 11vw, 124px); color: var(--tint-ink); }

.runbar { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.runbar .btn { padding-inline-end: 12px; }

/* The count rides in a chip rather than trailing the label after a
   middot: it is a different kind of thing from the words, and at a
   glance the row should read as four sizes to choose between. */
.btn__n {
  flex: none;
  min-width: 26px;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--rail);
  color: var(--ink-3);
  font: 800 12px/1.4 var(--ui);
  font-variant-numeric: tabular-nums;
}
.btn--dark .btn__n { background: rgba(255, 255, 255, .16); color: var(--on-dark); }
.btn:hover .btn__n { background: var(--sunk); }
.btn--dark:hover .btn__n { background: rgba(255, 255, 255, .22); }

.runbar__note {
  margin: 0 0 24px;
  font: 400 14px/1.7 var(--ui);
  color: var(--ink-4);
  max-width: 62ch;
  text-wrap: pretty;
}

@media (max-width: 560px) {
  /* Four full-width rows beat four cramped ones that wrap mid-label. */
  .runbar { flex-direction: column; gap: 8px; }
  .runbar .btn { width: 100%; justify-content: space-between; }
}

.draftbar {
  background: var(--warn-bg);
  border-radius: 16px;
  padding: 15px 18px;
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 22px;
}
.draftbar__icon {
  flex: none;
  width: 26px; height: 26px;
  border-radius: 999px;
  background: var(--warn-line);
  display: grid; place-items: center;
  color: var(--warn-ink);
  font: 700 14px/1 var(--ui);
}
.draftbar p { flex: 1; min-width: 0; margin: 0; font: 500 13.5px/1.65 var(--ui); color: var(--warn-ink); }
.draftbar b { font-weight: 700; }

.mstrip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 18px;
  padding: 16px 20px;
  background: var(--card);
  box-shadow: var(--sh-1);
  border-radius: var(--r-lg);
  margin-bottom: 22px;
}
.mstrip__label { font: 800 17px/1.3 var(--ui); letter-spacing: -.01em; color: var(--mc, var(--m0)); }
.mstrip__pct   { font: 700 14px/1.4 var(--ui); color: var(--ink-2); }
.mbar { flex: 1 1 160px; height: 8px; border-radius: 999px; background: var(--sunk); overflow: hidden; }
.mbar > span {
  display: block; height: 100%;
  border-radius: 999px;
  background: var(--mc, var(--m0));
  transition: width .4s var(--ease);
}

.urow {
  text-align: start;
  width: 100%;
  background: var(--card);
  border: none;
  border-bottom: 1px solid var(--line-soft);
  padding: 18px 20px;
  display: flex;
  gap: 16px;
  align-items: center;
  cursor: pointer;
  color: inherit;
}
.urow:hover { background: var(--tint, var(--hover)); color: inherit; }
.urow__num {
  flex: none;
  min-width: 38px; height: 38px;
  padding: 0 7px;
  display: grid; place-items: center;
  background: var(--paper);
  border-radius: var(--r-sm);
  font: 400 16px/1 var(--et);
  color: var(--ink-2);
}
.urow__num .num-alt { display: none; }
.urow__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.urow__title { font: 500 16px/1.7 var(--et); color: var(--ink); text-wrap: pretty; }
.urow__meta  { font: 600 12px/1.5 var(--ui); color: var(--ink-3); }
.urow__meta .num-alt { color: var(--ink-5); }
.urow__side {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* ── The unit on a phone ──────────────────────────────────────────
   One flex line put the title and the mastery cluster in competition
   for the same 430px, and the cluster won: a chip, four dots and a word
   hold their intrinsic width whatever happens, so the title — the only
   part that says what the unit *is* — was squeezed under 160px and
   wrapped to five lines of Ethiopic while "Beginning" sat on one.
   The title takes the full measure here and the mastery drops beneath
   it, which is also its true rank: you pick a unit by its name, never
   by its level. */
@media (max-width: 640px) {
  .urow {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "num  body"
      "num  side";
    align-items: start;
    gap: 9px 14px;
  }
  .urow__num  { grid-area: num; }
  .urow__body { grid-area: body; }
  .urow__side {
    grid-area: side;
    justify-content: flex-start;
    gap: 6px 9px;
  }
  /* Tighter than the desktop tracking, so the four dots read as one
     mark beside the word instead of a row of their own. */
  .urow__side .dots { font-size: 11px; letter-spacing: .26em; }

  /* "2 due" is sitting directly underneath saying it already. */
  .urow--due .urow__when { display: none; }

  /* A locked unit holds its chip and its chevron directly — there is no
     .urow__side on that row to put them in. */
  .urow--locked {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "num  body  go"
      "num  chip  go";
  }
  .urow--locked > .chip     { grid-area: chip; justify-self: start; }
  .urow--locked > .rrow__go { grid-area: go;   align-self: center; }
}

.empty {
  background: var(--card);
  border: 1px dashed var(--line-2);
  border-radius: var(--r-xl);
  padding: 56px 24px;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.empty h2 { margin: 0; font: 800 20px/1.35 var(--ui); letter-spacing: -.01em; color: var(--ink); }
.empty p  { margin: 0 auto; max-width: 46ch; font: 500 14.5px/1.7 var(--ui); color: var(--ink-3); text-wrap: pretty; }

/* ═══════════════════ Reading ═══════════════════
   Read first, then practise. The passage's own typography — the measure,
   the leading, ግእዝ beside its ትርጉም — lives in `assets/css/reading.css`,
   because /teacher's full preview draws the same passage and a second copy
   of those rules would drift. What stays here is the furniture around it:
   the foot, the mark, the practice buttons, the player's frame. */

.reading__foot {
  margin-top: 40px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}
.reading__done { font: 600 13.5px/1.6 var(--ui); color: var(--ink-3); margin-inline-end: auto; }
.reading__need { display: block; font: 600 12.5px/1.6 var(--ui); color: var(--ink-3); margin-top: 6px; }

/* The teacher's recording under the paragraph it speaks: quieter than the
   exercise player — this is a reading page, and the text leads. */
.player--reading {
  margin: 4px 0 24px;
  padding: 12px 16px;
  box-shadow: none;
  border: 1px solid var(--line-soft);
}
.player--reading .player__note { font-weight: 500; color: var(--ink-3); }

/* A unit held by its reading: the row is the road to that reading, and the
   words say so — the softened title alone never carries it. */
.urow--locked .urow__title { color: var(--ink-2); }
.urow--locked .chip { flex: none; }

.rrow {
  text-align: start;
  width: 100%;
  background: var(--card);
  border: none;
  border-bottom: 1px solid var(--line-soft);
  padding: 18px 20px;
  display: flex;
  gap: 16px;
  align-items: center;
  cursor: pointer;
  color: inherit;
}
.rrow:hover { background: var(--tint, var(--hover)); color: inherit; }
.rrow__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.rrow__title { font: 500 16px/1.7 var(--et); color: var(--ink); }
.rrow__meta  { font: 600 12px/1.5 var(--ui); color: var(--ink-3); }
.rrow__go { flex: none; color: var(--ink-5); font-size: 18px; }

/* ═══════════════════ Session ═══════════════════ */


/* The one screen you sit on for twenty minutes, so it takes the warm
   off-white rather than the page's white. It also says, without a word,
   that you are inside something rather than browsing. */
.session {
  position: fixed;
  inset: 0;
  background: var(--cream);
  z-index: 15;
  display: flex;
  flex-direction: column;
}
.session[hidden] { display: none; }

/* Practice becomes a quiet, warm-paper study stage. Results keep the paper
   shell above, so reflection still feels like part of the library. */
#ov-practice { background: var(--session-bg); }
#ov-practice .session__top,
#ov-practice .session__foot {
  background: var(--session-chrome);
  border-color: var(--session-line);
}
#ov-practice .exitbtn {
  background: var(--session-card);
  border-color: var(--session-card-line);
  color: var(--ink-2);
}
#ov-practice .exitbtn:hover {
  background: var(--session-key);
  border-color: var(--line-2);
  color: var(--session-ink);
}
#ov-practice .session__pos,
#ov-practice .session__pos .num-alt,
#ov-practice .qnum,
#ov-practice .qnum .num-alt,
#ov-practice .hint,
#ov-practice .deferred-note { color: var(--session-muted); }
#ov-practice .pbar { background: var(--session-line); }
#ov-practice .pbar__fill { background: var(--ink-2); }
#ov-practice .session__count[data-mode="deferred"] {
  background: var(--session-key);
  color: var(--session-muted);
}
#ov-practice .qkind { background: var(--warn-bg); color: var(--warn); }
#ov-practice .qstem { color: var(--session-ink); }
/* The session surface repaints resting cards, and only resting ones.
   An id beats the state classes on specificity, so a tile that has been
   paired, marked right or marked wrong has to be excused by name —
   otherwise the practice screen quietly erases every colour the
   exercise just took the trouble to apply. */
#ov-practice .opt:not(.is-right):not(.is-wrong):not(.is-picked),
#ov-practice .mtile--l:not([data-pair]):not(.is-right):not(.is-wrong),
#ov-practice .mtile--r:not([data-pair]):not(.is-right):not(.is-wrong),
#ov-practice .match:not(.is-armed) .match__bank,
#ov-practice .player {
  background: var(--session-card);
  border-color: var(--session-card-line);
  box-shadow: none;
}
/* …and the armed bank keeps its ring here too, for the same reason. */
#ov-practice .match.is-armed .match__bank {
  background: var(--session-card);
  border-color: var(--session-card-line);
}
#ov-practice .opt:hover:not(:disabled) {
  background: var(--session-card);
  border-color: var(--line-2);
  box-shadow: 0 0 0 2px rgba(28, 26, 23, .06);
}
#ov-practice .opt__key { background: var(--session-key); color: var(--ink-5); }
/* Deliberately no background here: the base .opt.is-picked fill applies,
   and restating it was how this state ended up with two owners and one
   of them silently winning. */
#ov-practice .opt.is-picked { border-color: var(--accent); }
#ov-practice .qfig img { border-color: var(--session-card-line); background: var(--session-key); }
#ov-practice .qfig figcaption { color: var(--session-muted); }
#ov-practice .session__foot .btn { background: var(--ink-block); color: var(--on-dark); }
#ov-practice .session__foot .btn:disabled { background: var(--session-disabled); color: var(--session-muted); }
#ov-practice .session__foot .btn:hover:not(:disabled) { background: var(--ink); }

.session__top { border-bottom: 1px solid var(--line); background: var(--session-chrome); }
.session__top-in {
  max-width: 900px;
  margin: 0 auto;
  padding: 16px clamp(16px, 3vw, 32px);
  display: flex;
  align-items: center;
  gap: 16px;
}
.exitbtn {
  flex: none;
  min-height: 44px;
  padding: 9px 16px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 999px;
  font: 600 13px/1.3 var(--ui);
  color: var(--ink-2);
  cursor: pointer;
}
.exitbtn:hover { background: var(--hover); border-color: var(--line-2); color: var(--ink); }

.session__meter { flex: 1; display: flex; align-items: center; gap: 14px; min-width: 0; }
.session__pos { flex: none; font: 700 13px/1.4 var(--ui); color: var(--ink-2); white-space: nowrap; }
.session__pos .num-alt { color: var(--ink-4); }
.pbar {
  flex: 1;
  height: 6px;
  border-radius: 999px;
  background: var(--sunk);
  overflow: hidden;
  display: block;
  min-width: 40px;
}
.pbar__fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--ink);
  transition: width .25s var(--ease);
  width: 0;
}
.session__count {
  flex: none;
  display: flex;
  align-items: center;
  gap: 6px;
  border-radius: 999px;
  padding: 7px 13px;
  font: 400 13px/1.3 var(--et);
  background: var(--good-bg);
  color: var(--good);
  white-space: nowrap;
}
.session__count[data-mode="deferred"] { background: var(--line-soft); color: var(--ink-2); }
.session__count i { font: 700 11px/1 var(--ui); font-style: normal; }
.session__count[data-mode="deferred"] i { display: none; }
.session__count .num-alt { color: inherit; opacity: .65; }

/* A question that fits should not scroll. The footer is a flex sibling
   rather than an overlay, so the scroller only ever holds the question
   itself — the old 140px of bottom padding was reserving room for a bar
   that is not on top of it, and that padding alone was enough to put a
   scrollbar on a four-line true/false. */
.session__scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
/* The result screen reuses the page shell, so cap it like the app frame */
.session__scroll > .page { max-width: var(--frame); margin: 0 auto; }
.session__body {
  max-width: 760px;
  margin: 0 auto;
  padding: 40px clamp(16px, 3vw, 32px) 40px;
  display: flex;
  flex-direction: column;
  gap: 26px;
  /* Centre a short question in the space instead of stranding it under
     the meter with a gulf beneath — but never push a long one up out of
     reach, which is what `justify-content: center` alone would do. */
  min-height: 100%;
  justify-content: center;
}

.qhead { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.qkind {
  font: 700 11px/1.4 var(--ui);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--warn);
  background: var(--warn-bg);
  border-radius: 999px;
  padding: 5px 12px;
}
.qnum { font: 600 12px/1.4 var(--ui); color: var(--ink-5); }
.qnum .num-alt { color: var(--ink-4); }

.qstem {
  margin: 0;
  font: 500 27px/1.8 var(--et);
  color: var(--ink);
  text-wrap: pretty;
}
/* Negations — *ያልሆነው* — must not be misread as their opposite */
.qstem .neg {
  font-style: normal;
  color: var(--bad);
  font-weight: 600;
  border-bottom: 2px solid var(--bad-soft);
}

/* ─── Text options ─── */
.options { display: flex; flex-direction: column; gap: 11px; }

.opt {
  position: relative;
  width: 100%;
  text-align: start;
  min-height: 64px;
  padding: 16px 20px;
  border-radius: var(--r-lg);
  cursor: pointer;
  display: flex;
  gap: 14px;
  align-items: center;
  background: var(--card);
  border: 1px solid var(--line);
  transition: transform .1s var(--ease), background .12s var(--ease), border-color .12s var(--ease);
}
.opt:hover:not(:disabled) { transform: translateY(-1px); }
.opt:disabled { cursor: default; }

.opt__key {
  flex: none;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  border-radius: 999px;
  background: var(--app);
  font: 400 13px/1 var(--et);
  color: var(--ink-3);
}
.opt__text { flex: 1; min-width: 0; font: 400 18px/1.75 var(--et); color: var(--ink); text-wrap: pretty; }
.opt__hot  { flex: none; font: 600 11px/1 var(--ui); color: var(--ink-4); }
.opt__mark { flex: none; font: 700 14px/1.6 var(--ui); color: var(--ink-3); min-width: 12px; }

.opt.is-right {
  background: var(--good-fill);
  border: 2px solid var(--good);
  padding: 15px 19px;
}
.opt.is-right .opt__key  { background: #d6e5db; color: var(--good-2); }
.opt.is-right .opt__mark { color: var(--good-2); }

.opt.is-wrong {
  background: var(--bad-fill);
  border: 2px solid var(--bad);
  padding: 15px 19px;
}
.opt.is-wrong .opt__key  { background: #f0d3cc; color: var(--bad-2); }
.opt.is-wrong .opt__mark { color: var(--bad-2); }

.opt.is-muted { opacity: .55; }

/* Chosen but not yet committed. Deliberately a different visual language
   from is-right / is-wrong — this is a pencil mark, so it reads as
   "selected", never as "correct". Colour alone doesn't carry it: the
   border thickens and the key fills in too. */
/* Chosen, not yet marked. With feedback deferred this is the only record
   of the decision until the end of the session, so it says so three ways
   — a fill you can see across a room, a 2px rule, and the word "Chosen"
   rather than a dot somebody has to interpret. */
.opt.is-picked {
  background: var(--pick-bg);
  border: 2px solid var(--accent);
  padding: 15px 19px;
}
.opt.is-picked .opt__key  { background: var(--accent); color: #fff; }
.opt.is-picked .opt__mark {
  color: var(--accent-2);
  font: 700 11px/1 var(--ui);
  letter-spacing: .04em;
  text-transform: uppercase;
  white-space: nowrap;
}
.opt.is-picked .opt__mark::after { content: "Chosen"; }

/* ─── True or false ───
   Two targets, side by side on anything wider than a phone, with the
   letter key dropped — ሀ/ለ tells a student nothing when the options are
   እውነት and ሐሰት. The tint is a whisper, not a hint: both sides get one,
   so neither looks like the safe answer. */
.options--tf {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
.opt[data-side] {
  min-height: 108px;
  flex-direction: column;
  justify-content: center;
  gap: 8px;
  text-align: center;
}
.opt[data-side] .opt__key { display: none; }
.opt[data-side] .opt__text {
  flex: none;
  font-size: 30px;
  line-height: 1.35;
  text-align: center;
}
/* The keyboard hint used to be `position: absolute` with no offset,
   which put "1" and "2" on top of the words እውነት and ሐሰት. It belongs in
   the corner, quietly, and only where a keyboard exists at all. */
.opt[data-side] .opt__hot {
  position: absolute;
  top: 10px;
  inset-inline-end: 12px;
  font-size: 11.5px;
  color: var(--ink-5);
}
@media (hover: none) and (pointer: coarse) {
  .opt__hot { display: none; }
}
.opt[data-side="true"]  { border-color: var(--good-line); }
.opt[data-side="false"] { border-color: var(--bad-line); }
.opt[data-side].is-picked { border-color: var(--accent); }

/* ─── Picture options ─── */
.options--img {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
}
.options--img .opt {
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  padding: 12px;
  min-height: 0;
}
.options--img .opt.is-picked,
.options--img .opt.is-right,
.options--img .opt.is-wrong,
.options--img .opt.is-chosen { padding: 11px; }
.options--img .opt__key {
  position: absolute;
  margin: 6px;
  background: rgba(255, 255, 255, .92);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .18);
}
.opt__img {
  display: block;
  border-radius: var(--r);
  overflow: hidden;
  background: var(--paper);
}
.opt__img img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}
.options--img .opt__text {
  flex: none;
  font-size: 16px;
  line-height: 1.6;
  text-align: center;
}

/* ─── A picture belonging to the question ───
   Capped by height rather than width so a tall manuscript page and a wide
   diagram both leave room for the options below without scrolling. */
.qfig {
  margin: 18px 0 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-start;
}
.qfig img {
  display: block;
  max-width: 100%;
  max-height: 320px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--paper);
}
.qfig figcaption { font: 400 15px/1.7 var(--et); color: var(--ink-4); }

/* ─── Character options ─── */
.options--glyph {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 14px;
}
.opt--glyph {
  min-height: 150px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: var(--r-lg);
  padding: 12px;
}
.opt--glyph.is-chosen, .opt--glyph.is-right, .opt--glyph.is-wrong { padding: 11px; }
.opt--glyph .opt__key { display: none; }
.opt--glyph .opt__text { flex: none; font-size: 62px; line-height: 1.2; text-align: center; }
.opt--glyph .opt__mark { min-height: 13px; font-size: 13px; }

/* ─── Matching ───────────────────────────────────────────────────────
   The hard part of a matching question is not making the pair; it is
   seeing, afterwards, which two things you joined. So a completed pair
   is stated three times over — both halves take the same wash, the same
   rule down the side, and the same number — and the left tile repeats
   its partner's words in a chip, so the pairing survives even when the
   bank has scrolled out of sight on a phone. */
.match { display: flex; flex-wrap: wrap; gap: 20px; align-items: flex-start; }
.match__col { flex: 1 1 320px; min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.match__bank {
  flex: 1 1 260px;
  min-width: 200px;
  max-width: 380px;
  background: var(--card);
  box-shadow: var(--sh-1);
  border-radius: var(--r-lg);
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-self: stretch;
  transition: box-shadow .2s var(--ease);
}
/* While a left tile is held, the bank is the only place worth tapping.
   The ring is a shadow rather than an outline, because `outline` means
   keyboard focus everywhere else in this app and should keep meaning
   only that. */
.match.is-armed .match__bank { box-shadow: var(--sh-lift), 0 0 0 2px var(--ink); }
.match.is-armed .mtile--r:not(.is-done) { border-color: var(--line-3); background: var(--card); }
.match__hint {
  font: 600 12px/1.6 var(--ui);
  color: var(--ink-3);
  text-wrap: pretty;
  min-height: 2.4em;   /* the line changes as you go; don't let it jump */
}
.match.is-armed .match__hint { color: var(--ink); }
.match__pills { display: flex; flex-wrap: wrap; gap: 9px; align-content: flex-start; }
.match__col.is-nudge { animation: nudge .4s var(--ease); }

.mtile {
  position: relative;
  transition: background .18s var(--ease), border-color .18s var(--ease),
              box-shadow .18s var(--ease);
}
.mtile--l {
  width: 100%;
  text-align: start;
  min-height: 62px;
  padding: 14px 18px;
  border-radius: var(--r-md);
  cursor: pointer;
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  background: var(--card);
  border: 1px solid var(--line);
  border-inline-start: 4px solid var(--line-2);
}
.mtile__text { flex: 1; min-width: 0; font: 500 17px/1.75 var(--et); color: var(--ink); }

/* The pair number — the thing that actually says "these two go together".
   A solid disc with a white numeral, not a tinted outline: it has to be
   findable across the gap between the column and the bank at a glance,
   on a cheap phone screen, by someone who cannot separate the colours.
   Empty until a pair is made, so it costs no room on an untouched tile
   and appears exactly when it means something. */
.mtile__no {
  flex: none;
  display: none;
  min-width: 28px;
  height: 28px;
  border-radius: 999px;
  align-items: center;
  justify-content: center;
  font: 800 14px/1 var(--ui);
  font-variant-numeric: tabular-nums;
  background: var(--ink-4);
  color: #fff;
}
.mtile[data-pair] .mtile__no { display: inline-flex; }

/* The chip on the left tile that repeats the partner's words. */
.mtile__pin {
  flex: none;
  max-width: 100%;
  text-align: center;
  padding: 5px 12px;
  border-radius: 999px;
  background: transparent;
  font: 400 15px/1.6 var(--et);
  color: var(--ink-4);
}
.mtile--l.is-done .mtile__pin { background: var(--card); }

.mtile--l.is-active {
  background: var(--line-soft);
  border-color: var(--ink);
  border-inline-start-color: var(--ink);
  box-shadow: var(--sh-lift);
}
.mtile--l.is-right { background: var(--good-fill); border-color: var(--good); border-inline-start-color: var(--good); }
.mtile--l.is-wrong { background: var(--bad-fill);  border-color: var(--bad);  border-inline-start-color: var(--bad); }

/* What it should have been, said where the mistake is. */
.mtile__fix {
  flex-basis: 100%;
  font: 500 14px/1.7 var(--et);
  color: var(--good-2);
}
.mtile__fix::before {
  content: "→ ";
  font-family: var(--ui);
}

.mtile--r {
  min-height: 46px;
  padding: 10px 16px;
  border-radius: 999px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  max-width: 100%;
  font: 400 17px/1.6 var(--et);
  background: var(--card);
  border: 1px solid var(--line);
  color: var(--ink);
}
.mtile--r .mtile__pin { display: none; }
.mtile--r .mtile__text { font-size: 17px; font-weight: 400; }
.mtile--r.is-done { border-style: solid; }
.mtile--r.is-right { background: var(--good-fill); border-color: var(--good); color: var(--good-2); }
.mtile--r.is-wrong { background: var(--bad-fill);  border-color: var(--bad); color: var(--bad-2); }

/* ── The six pair washes ──
   One rule per pair rather than six near-identical blocks would be
   nicer, but custom properties cannot be selected on, and this stays
   readable next to the token file it mirrors. */
/* A paired tile is stated loudly: filled wash, a 2px rule all round in
   the pair's ink, a 6px slab down the leading edge, and the numbered
   disc filled in the same ink. The resting palette elsewhere is quiet
   because it is being *read*; this is being *matched*, and a pairing you
   have to hunt for is the same as no pairing at all. */
.mtile[data-pair] {
  border-width: 2px;
  border-style: solid;
}
.mtile--l[data-pair] { border-inline-start-width: 6px; }

.mtile[data-pair="1"] { background: var(--p1); border-color: var(--p1-ink); }
.mtile[data-pair="2"] { background: var(--p2); border-color: var(--p2-ink); }
.mtile[data-pair="3"] { background: var(--p3); border-color: var(--p3-ink); }
.mtile[data-pair="4"] { background: var(--p4); border-color: var(--p4-ink); }
.mtile[data-pair="5"] { background: var(--p5); border-color: var(--p5-ink); }
.mtile[data-pair="6"] { background: var(--p6); border-color: var(--p6-ink); }
.mtile[data-pair="1"] .mtile__no { background: var(--p1-ink); }
.mtile[data-pair="2"] .mtile__no { background: var(--p2-ink); }
.mtile[data-pair="3"] .mtile__no { background: var(--p3-ink); }
.mtile[data-pair="4"] .mtile__no { background: var(--p4-ink); }
.mtile[data-pair="5"] .mtile__no { background: var(--p5-ink); }
.mtile[data-pair="6"] .mtile__no { background: var(--p6-ink); }

/* The chip echoing the partner's words takes the same ink, so the left
   tile alone tells you what it is joined to without looking away. */
.mtile[data-pair="1"] .mtile__pin { border: 1.5px solid var(--p1-ink); color: var(--p1-ink); }
.mtile[data-pair="2"] .mtile__pin { border: 1.5px solid var(--p2-ink); color: var(--p2-ink); }
.mtile[data-pair="3"] .mtile__pin { border: 1.5px solid var(--p3-ink); color: var(--p3-ink); }
.mtile[data-pair="4"] .mtile__pin { border: 1.5px solid var(--p4-ink); color: var(--p4-ink); }
.mtile[data-pair="5"] .mtile__pin { border: 1.5px solid var(--p5-ink); color: var(--p5-ink); }
.mtile[data-pair="6"] .mtile__pin { border: 1.5px solid var(--p6-ink); color: var(--p6-ink); }

/* The teacher's recording of the question, under the stem on any card. */
.qaudio { margin: 0 0 18px; }
.qaudio audio { width: 100%; max-width: 460px; }

/* An option with its own recording: the play control is a sibling of the
   answer button, never inside it — nested buttons are unreachable. */
.optrow { display: flex; gap: 10px; align-items: stretch; }
.optrow .opt { flex: 1 1 auto; min-width: 0; }
.optrow__play {
  flex: none;
  min-width: 48px;
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  background: var(--card);
  color: var(--ink);
  font-size: 15px;
  cursor: pointer;
}
.optrow__play:hover { background: var(--tint, var(--hover)); }

/* ─── Listening ─── */
.player {
  background: var(--card);
  box-shadow: var(--sh-1);
  border-radius: var(--r-lg);
  padding: 18px 20px;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}
.player__btn {
  flex: none;
  width: 56px; height: 56px;
  border-radius: 999px;
  background: var(--ink);
  border: none;
  color: #fff;
  font-size: 18px;
  cursor: pointer;
  display: grid; place-items: center;
}
.player--empty .player__btn {
  background: var(--line-soft);
  border: 1px dashed var(--line-2);
  color: var(--ink-5);
  cursor: default;
}
.player__note { flex: 1 1 200px; min-width: 0; margin: 0; font: 600 13.5px/1.6 var(--ui); color: var(--ink-2); }
.player--empty .player__note { color: var(--bad); }
.player audio { flex: 1 1 200px; min-width: 0; max-width: 100%; }

/* ─── Feedback ─── */
.fb {
  border-radius: var(--r-lg);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 11px;
  animation: fadeUp .18s ease-out;
  background: var(--good-bg);
}
.fb[hidden] { display: none; }
.fb.is-bad { background: var(--bad-bg); }

.fb__head { display: flex; align-items: center; gap: 10px; }
.fb__icon {
  flex: none;
  width: 24px; height: 24px;
  border-radius: 999px;
  background: var(--good);
  color: #fff;
  display: grid; place-items: center;
  font: 700 12px/1 var(--ui);
}
.fb.is-bad .fb__icon { background: var(--bad); }
.fb__title { font: 800 17px/1.4 var(--ui); letter-spacing: -.01em; color: var(--good); }
.fb.is-bad .fb__title { color: var(--bad); }

.fb__answer { font: 400 16px/1.8 var(--et); color: var(--ink); text-wrap: pretty; }
.fb__answer .lab {
  font: 700 11px/1.4 var(--ui);
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--good-line);
  margin-inline-end: .5em;
}
.fb.is-bad .fb__answer .lab { color: var(--bad-soft); }

.fb__explain {
  font: 400 14.5px/1.85 var(--et);
  color: var(--ink-2);
  background: rgba(255,255,255,.82);
  border-radius: var(--r);
  padding: 13px 16px;
  text-wrap: pretty;
}
.fb__explain[hidden] { display: none; }

.deferred-note { font: 600 13px/1.7 var(--ui); color: var(--ink-3); }
.deferred-note[hidden] { display: none; }

/* ─── Session footer ─── */
.session__foot { border-top: 1px solid var(--line); background: var(--rail); }
.session__foot-in {
  max-width: 760px;
  margin: 0 auto;
  padding: 16px clamp(16px, 3vw, 32px);
  display: flex;
  align-items: center;
  gap: 16px;
}
.hint { flex: 1; font: 600 12.5px/1.5 var(--ui); color: var(--ink-4); }
.session__foot .btn {
  flex: none;
  min-height: 52px;
  padding: 0 34px;
  border: none;
  border-radius: 15px;
  font: 700 16px/1.4 var(--ui);
  background: var(--ink);
  color: #fff;
}
.session__foot .btn:disabled { background: var(--sunk); color: var(--ink-4); }
.session__foot .btn:hover:not(:disabled) { background: #2b2823; }

/* ═══════════════════ Results ═══════════════════ */


.res-hero {
  background: var(--card);
  border-radius: var(--r-xl);
  padding: 30px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px 28px;
  animation: pop .22s ease-out;
  box-shadow: var(--sh-2);
}
.res-hero__pct { flex: none; font: 400 62px/1 var(--et); color: var(--good); }
.res-hero.is-low .res-hero__pct { color: var(--bad); }
.res-hero__body { flex: 1 1 260px; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.res-hero__raw     { font: 600 13px/1.5 var(--ui); color: var(--ink-3); }
.res-hero__verdict { margin: 0; font: 800 22px/1.35 var(--ui); letter-spacing: -.02em; color: var(--ink); text-wrap: pretty; }
.res-hero__best    { font: 700 12.5px/1.6 var(--ui); color: var(--warn); }
.res-hero__best[hidden] { display: none; }

/* Results actions sit in a row under the score, not in a rail */
/* `.actions` from base.css carries the stacking and the order; the results
   page reads left to right off its own hero, so the row packs to the start
   rather than the end. */
.res-actions { justify-content: flex-start; gap: 10px; margin: 26px 0 0; }
.res-actions .btn { flex: 0 1 auto; }
/* Where to go next, one step quieter than what to do with this session, and
   behind a rule so the two are read as two questions rather than one menu
   of five equal answers. */
.res-onward {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 20px 0 34px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.res-onward .btn { flex: 0 1 auto; min-height: 46px; padding: 0 16px; font-size: 13.5px; }
.res-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; margin-bottom: 30px; }

.rev {
  background: var(--card);
  border: 1px solid var(--bad-line);
  border-radius: var(--r-md);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.rev__head {
  font: 700 11px/1.4 var(--ui);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--bad);
}
.rev__q { font: 500 17px/1.8 var(--et); color: var(--ink); text-wrap: pretty; }
.rev__q .neg { font-style: normal; color: var(--bad); font-weight: 600; }
.rev__lines { display: flex; gap: 28px; flex-wrap: wrap; }
.rev__line { font: 400 14.5px/1.75 var(--et); }
.rev__line span {
  font: 700 11px/1.4 var(--ui);
  letter-spacing: .06em;
  text-transform: uppercase;
  margin-inline-end: .5em;
}
.rev__line--yours { color: var(--bad); }
.rev__line--yours span { color: var(--bad-soft); }
.rev__line--right { color: var(--good); }
.rev__line--right span { color: var(--good-line); }
.rev__explain {
  font: 400 14px/1.85 var(--et);
  color: var(--ink-2);
  background: var(--paper);
  border-radius: var(--r-sm);
  padding: 12px 14px;
  text-wrap: pretty;
}

.rev--ok {
  background: var(--card);
  box-shadow: var(--sh-1);
  border-radius: var(--r);
  padding: 13px 16px;
  display: flex;
  gap: 11px;
  align-items: center;
}
.rev--ok .tick {
  flex: none;
  width: 20px; height: 20px;
  border-radius: 999px;
  background: var(--good-bg);
  color: var(--good);
  display: grid; place-items: center;
  font-size: 11px;
}
.rev--ok .rev__q { flex: 1; min-width: 0; font: 400 14px/1.75 var(--et); color: var(--ink-2); }

.move {
  background: var(--card);
  box-shadow: var(--sh-1);
  border-radius: var(--r-md);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.move__title { font: 500 14px/1.7 var(--et); color: var(--ink); text-wrap: pretty; }
.move__row { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.move__was  { color: var(--ink-5); }
.move__arrow { color: var(--ink-5); font-size: 13px; }
.move__now  { animation: pop .32s ease-out both; }
.move__line {
  font: 700 12px/1.5 var(--ui);
  color: var(--mc, var(--m0));
  animation: fadeUp .32s ease-out both;
}

.nextdue {
  margin: 0;
  background: var(--good-bg);
  border-radius: 16px;
  padding: 14px 16px;
  font: 600 13px/1.65 var(--ui);
  color: var(--good);
  text-wrap: pretty;
}
.nextdue[hidden] { display: none; }

.brow {
  padding: 13px 16px;
  display: flex;
  gap: 12px;
  align-items: center;
  border-bottom: 1px solid var(--line-soft);
}
.brow__name  { flex: 1; min-width: 0; font: 400 13.5px/1.7 var(--et); color: var(--ink); text-wrap: pretty; }
.brow__score { flex: none; font: 400 13.5px/1.5 var(--et); color: var(--ink-2); }
.brow[data-band="hi"]  .brow__score { color: var(--good); }
.brow[data-band="mid"] .brow__score { color: var(--warn); }
.brow[data-band="lo"]  .brow__score { color: var(--bad); }

/* ═══════════════════ Settings ═══════════════════ */


/* ═══════════════════ Profile ═══════════════════
   A sticky card of who you are beside a tabbed column of how it is going.
   Settings used to be a page of its own and the only place any of this
   lived, so a learner could practise for a month and never meet a figure
   that was not on the home hero.

   One column on a phone — the card first, because "your streak is eleven"
   is the reason to open this page at all. ───────────────────────────── */
.page--me { max-width: 1180px; }
.melayout { display: grid; gap: 28px; align-items: start; }

.mecard {
  min-width: 0;
  padding: 28px 24px;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--card);
  display: flex;
  flex-direction: column;
  gap: 4px;
  box-shadow: var(--sh-1);
}
.mecard__avatar {
  width: 72px;
  height: 72px;
  margin-bottom: 14px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--accent-bg);
  color: var(--accent-2);
  font: 700 28px/1 var(--ui);
}
.mecard__name {
  margin: 0;
  overflow: hidden;
  color: var(--ink);
  font: 800 26px/1.2 var(--ui);
  letter-spacing: -.03em;
  text-overflow: ellipsis;
}
.mecard__sub {
  margin: 4px 0 0;
  overflow: hidden;
  color: var(--ink-4);
  font: 500 13px/1.6 var(--ui);
  text-overflow: ellipsis;
}
/* Three figures, hairline-separated. The same numbers the dashboard says
   at full size — this is the glance, that is the page. */
.mecard__figs {
  margin: 20px 0 0;
  padding: 16px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px;
}
.mecard__figs > div { min-width: 0; display: flex; flex-direction: column-reverse; gap: 2px; }
.mecard__figs dt { color: var(--ink-4); font: 600 11px/1.4 var(--ui); }
.mecard__figs dd { margin: 0; color: var(--ink); font: 750 22px/1.2 var(--ui); letter-spacing: -.02em; }

.mecard__acts { margin-top: 18px; display: flex; flex-direction: column; gap: 8px; }
.mecard__acts .btn { width: 100%; justify-content: center; }

/* The settings rail rides in this column on the tab it belongs to, where
   it can stay beside a panel a screen and a half long. .settings-jump
   brings its own rules — including staying hidden until there is a column
   for it to stand in. */
.merail { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }
.merail > strong { display: block; color: var(--ink); font: 750 17px/1.3 var(--ui); letter-spacing: -.02em; }
.merail > span { display: block; margin-top: 2px; color: var(--accent-2); font: 700 12px/1.4 var(--ui); }
.merail > p { margin: 8px 0 0; color: var(--ink-3); font: 500 12.5px/1.6 var(--ui); text-wrap: pretty; }

.memain { min-width: 0; display: flex; flex-direction: column; gap: 24px; }

/* Underline tabs. The rule under the row is the thing that makes a tab a
   tab; the active one sits on a solid terracotta segment of it, and says
   so in weight as well, because colour never carries this alone. */
.metabs {
  display: flex;
  gap: 4px;
  overflow-x: auto;
  scrollbar-width: none;
  border-bottom: 1px solid var(--line);
}
.metabs::-webkit-scrollbar { display: none; }
.metab {
  min-height: 48px;
  padding: 0 14px;
  display: inline-flex;
  align-items: center;
  flex: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  color: var(--ink-4);
  font: 600 14px/1.4 var(--ui);
  white-space: nowrap;
}
.metab:hover { color: var(--ink); }
.metab.is-on { border-bottom-color: var(--accent); color: var(--ink); font-weight: 750; }

.mepanel-host { min-width: 0; display: flex; flex-direction: column; gap: 28px; }
.mepanel { min-width: 0; display: flex; flex-direction: column; gap: 14px; }
.mepanel__head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.mepanel__head h2 { margin: 0; color: var(--ink); font: 750 17px/1.35 var(--ui); letter-spacing: -.015em; }
.mepanel__head p { margin: 0; color: var(--ink-4); font: 500 12.5px/1.5 var(--ui); }

/* Thirty squares. A shape for the month, with the count in words beside
   it — the strip is the rhythm, the number is the fact. */
.daystrip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14px, 1fr));
  gap: 4px;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--card);
}
.daystrip__cell {
  aspect-ratio: 1;
  border-radius: 4px;
  background: var(--line-soft);
}
.daystrip__cell.is-done { background: var(--accent); }
/* Today keeps a ring whether or not it has been practised yet, so the
   strip has a "you are here" that does not depend on having studied. */
.daystrip__cell.is-today { outline: 2px solid var(--ink-4); outline-offset: 1px; }

.melist { display: flex; flex-direction: column; gap: 6px; }
.merow {
  min-height: 64px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--card);
  display: flex;
  align-items: center;
  gap: 14px;
  color: var(--ink-2);
}
.merow:hover { border-color: var(--line-3); background: var(--hover); color: var(--ink); }
.merow__art { width: 38px; height: 38px; flex: none; display: grid; place-items: center; }
.merow__art svg { width: 100%; height: 100%; display: block; }
.merow__body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.merow__title { overflow: hidden; color: var(--ink); font: 550 15px/1.5 var(--et); text-overflow: ellipsis; white-space: nowrap; }
.merow__meta { overflow: hidden; color: var(--ink-4); font: 500 12px/1.5 var(--ui); text-overflow: ellipsis; white-space: nowrap; }
.merow__done {
  flex: none;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  background: var(--good-bg);
  color: var(--good);
  font: 700 11.5px/1.5 var(--ui);
}

.page--settings { max-width: 1080px; display: flex; flex-direction: column; gap: 32px; }
.page--settings h1 { margin: 4px 0 0; font: 800 32px/1.2 var(--ui); letter-spacing: -.035em; color: var(--ink); }
.settings-heading > p:not(.eyebrow) { max-width: 62ch; margin: 10px 0 0; color: var(--ink-3); font: 500 14px/1.7 var(--ui); text-wrap: pretty; }
.settings-layout { display: grid; gap: 32px; align-items: start; }
.settings-summary { padding: 24px 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); display: flex; flex-direction: column; gap: 8px; }
/* The section rail. Phones scroll a page this short comfortably, so it
   earns its place only where the summary column already stands beside
   the sections. Buttons, not anchors — the router owns the hash. */
.settings-jump { display: none; }
.setblock { scroll-margin-top: 84px; }
.settings-summary > strong { font: 750 20px/1.3 var(--ui); letter-spacing: -.02em; color: var(--ink); }
.settings-summary > span { color: var(--accent-2); font: 700 12px/1.4 var(--ui); }
.settings-summary > p:last-child { max-width: 38ch; margin: 6px 0 0; color: var(--ink-3); font: 500 12.5px/1.65 var(--ui); text-wrap: pretty; }
.settings-sections { min-width: 0; display: flex; flex-direction: column; gap: 40px; }
.setblock { display: flex; flex-direction: column; gap: 12px; }
.setblock__heading h2 { margin: 0; color: var(--ink); font: 750 18px/1.35 var(--ui); letter-spacing: -.015em; }
.setblock__heading p { margin: 4px 0 0; color: var(--ink-3); font: 500 12.5px/1.6 var(--ui); }
.learning-profile { padding: 24px; border: 1px solid var(--line); border-radius: var(--r-xl); background: color-mix(in srgb, var(--t-books) 20%, var(--card)); display: flex; flex-direction: column; gap: 24px; }
.settings-field { max-width: 360px; display: flex; flex-direction: column; gap: 8px; }
.settings-field > span,
.track-focus legend { color: var(--ink-2); font: 700 12px/1.45 var(--ui); }
.settings-field select { min-height: 50px; padding: 0 14px; border: 1px solid var(--line-2); border-radius: var(--r); background: var(--card); color: var(--ink); font: 600 14px/1.4 var(--ui); }
.settings-field select:focus { border-color: var(--accent); outline: 3px solid var(--accent-bg); }
.settings-field small { color: var(--ink-3); font: 500 11.5px/1.55 var(--ui); }
.track-focus { min-width: 0; margin: 0; padding: 0; border: 0; }
.track-focus > p { margin: 4px 0 12px; color: var(--ink-3); font: 500 11.5px/1.55 var(--ui); }
.track-focus__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: 8px; }
.track-choice { min-width: 0; min-height: 64px; padding: 12px; border: 1px solid var(--line); border-radius: var(--r); background: var(--card); display: flex; align-items: center; gap: 12px; text-align: start; cursor: pointer; }
.track-choice.is-on { border-color: var(--ink); background: var(--rail); }
.track-choice__mark { width: 24px; height: 24px; flex: none; border: 1px solid var(--line-2); border-radius: 50%; display: grid; place-items: center; color: var(--on-dark); font: 800 11px/1 var(--ui); }
.track-choice.is-on .track-choice__mark { border-color: var(--ink); background: var(--ink); }
.track-choice > span:last-child { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.track-choice b { overflow: hidden; color: var(--ink); font: 550 14px/1.55 var(--et); text-overflow: ellipsis; white-space: nowrap; }
.track-choice small { color: var(--ink-3); font: 500 12.5px/1.45 var(--ui); }
.review-explainer { border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--card); overflow: hidden; }
.review-explainer summary { min-height: 72px; padding: 16px; display: flex; align-items: center; justify-content: space-between; gap: 16px; cursor: pointer; list-style: none; }
.review-explainer summary::-webkit-details-marker { display: none; }
.review-explainer summary > span:first-child { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.review-explainer summary b { color: var(--ink); font: 700 14px/1.4 var(--ui); }
.review-explainer summary small { color: var(--ink-3); font: 500 11.5px/1.5 var(--ui); }
.review-explainer summary > span:last-child { color: var(--ink-3); font: 500 22px/1 var(--ui); transition: transform .16s var(--ease); }
.review-explainer[open] summary > span:last-child { transform: rotate(45deg); }
.review-explainer .panel--ladder { border-top: 1px solid var(--line); }
.setblock--danger { padding-top: 24px; border-top: 1px solid var(--line); }
.setblock--danger .btn { align-self: flex-start; }

@media (min-width: 880px) {
  .settings-layout { grid-template-columns: minmax(180px, 240px) minmax(0, 700px); gap: clamp(42px, 6vw, 76px); }
  .settings-summary { position: sticky; top: 88px; }
  /* The profile's two columns, and the card that stays put beside them.
     max-height plus its own scroll, or a long settings rail on a short
     laptop screen would push its own bottom off the viewport with no way
     to reach it. */
  .melayout { grid-template-columns: minmax(240px, 300px) minmax(0, 1fr); gap: clamp(28px, 3.5vw, 48px); }
  .mecard {
    position: sticky;
    top: 88px;
    max-height: calc(100vh - 108px);
    overflow: hidden auto;
  }
  .settings-jump { display: flex; flex-direction: column; gap: 2px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); }
  .settings-jump button {
    min-height: 44px;
    padding: 0 10px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--ink-3);
    text-align: start;
    font: 600 13px/1.4 var(--ui);
    cursor: pointer;
  }
  .settings-jump button:hover { background: var(--rail); color: var(--ink); }
}

.radio-row {
  text-align: start;
  width: 100%;
  min-height: 58px;
  background: var(--card);
  border: none;
  border-bottom: 1px solid var(--line-soft);
  padding: 16px 18px;
  display: flex;
  gap: 13px;
  align-items: center;
  cursor: pointer;
}
.radio-row.is-on { background: var(--app); }
.radio-row__dot {
  flex: none;
  width: 20px; height: 20px;
  border-radius: 999px;
  border: 2px solid var(--line-2);
  background: transparent;
}
.radio-row.is-on .radio-row__dot {
  border-color: var(--ink);
  background: var(--ink);
  box-shadow: inset 0 0 0 3px #fff;
}
.radio-row__label  { flex: 1; min-width: 0; font: 600 15px/1.5 var(--ui); color: var(--ink); }
.radio-row__sample { flex: none; font: 400 15px/1.5 var(--et); color: var(--ink-3); }

.switch-row {
  text-align: start;
  width: 100%;
  min-height: 68px;
  background: var(--card);
  border: none;
  border-bottom: 1px solid var(--line-soft);
  padding: 16px 18px;
  display: flex;
  gap: 16px;
  align-items: center;
  cursor: pointer;
}
.switch-row__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.switch-row__label { font: 600 15px/1.5 var(--ui); color: var(--ink); }
.switch-row__hint  { font: 500 12.5px/1.6 var(--ui); color: var(--ink-3); text-wrap: pretty; }
.switchel {
  flex: none;
  width: 52px; height: 31px;
  border-radius: 999px;
  background: var(--line-2);
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 3px;
  transition: background .18s var(--ease);
}
.switch-row.is-on .switchel { background: var(--ink); justify-content: flex-end; }
.switchel > span {
  width: 25px; height: 25px;
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 1px 3px rgba(22,24,29,.32);
}
.setnote { margin: 0; max-width: 56ch; font: 500 13px/1.7 var(--ui); color: var(--ink-3); text-wrap: pretty; }

.panel--account { padding: 18px; display: flex; flex-direction: column; gap: 14px; }

.acct-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.acct-email  { font: 700 15px/1.4 var(--ui); color: var(--ink); word-break: break-all; }
.acct-status { margin-top: 2px; font: 600 12.5px/1.6 var(--ui); color: var(--ink-3); }
.acct-status[data-state="synced"]  { color: var(--good); }
.acct-status[data-state="error"]   { color: var(--bad); }
.acct-status[data-state="syncing"] { color: var(--warn); }

/* ─── Continue with Google ───
   Google's own guidance: white surface, thin grey border, their mark at
   full colour, and nothing decorative added to it. It is now the only
   way in, so it is also the only button in this panel. */
.gbtn {
  width: 100%;
  min-height: 54px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 11px;
  padding: 14px 20px;
  border-radius: var(--r-lg);
  background: #fff;
  border: 1px solid var(--line-2);
  box-shadow: var(--sh-1);
  font: 700 15.5px/1.4 var(--ui);
  color: var(--ink);
  cursor: pointer;
  transition: border-color .14s var(--ease), box-shadow .14s var(--ease), transform .12s var(--ease);
}
.gbtn:hover:not(:disabled) { border-color: var(--line-3); box-shadow: var(--sh-lift); transform: translateY(-1px); }
.gbtn:disabled { opacity: .6; cursor: default; }
.gbtn__mark { display: grid; place-items: center; flex: none; }

.setnote--tight { margin-top: -4px; }

#acct-msg:empty { display: none; }
#acct-msg[data-bad="true"] { color: var(--bad); }

/* ═══════════════════ Dialog ═══════════════════ */


.dialog {
  position: fixed;
  inset: 0;
  background: rgba(28,26,23,.55);
  backdrop-filter: blur(3px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 20;
  padding: 24px;
}
.dialog[hidden] { display: none; }
.dialog__card {
  width: 100%;
  max-width: 430px;
  background: var(--card);
  border-radius: var(--r-xl);
  padding: 28px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  animation: fadeUp .18s ease-out;
  box-shadow: var(--sh-dialog);
}
.dialog__card h2 { margin: 0; font: 800 21px/1.35 var(--ui); letter-spacing: -.02em; color: var(--ink); }
.dialog__card p  { margin: 0 0 6px; font: 500 14.5px/1.65 var(--ui); color: var(--ink-2); text-wrap: pretty; }
.dialog__acts { display: flex; gap: 10px; justify-content: flex-end; }
.dialog__acts .btn { min-height: 48px; padding: 0 20px; font-size: 15px; }
.dialog__cancel  { background: var(--app); color: var(--ink-2); border: none; font-weight: 600; }
.dialog__cancel:hover { background: var(--line-soft); }
.dialog__confirm { background: var(--bad); color: #fff; border: none; padding: 0 22px; }
.dialog__confirm:hover { background: var(--bad-2); }

/* ═══════════════════ Phones ═══════════════════
   Everything stacks. The destinations go to the drawer at 720px rather
   than 900px: the bar used to carry one pill per ዘርፍ, which is what
   needed the extra 180px, and two fixed words fit on a tablet where five
   growing pills did not. Below 720px the bar is the brand and three
   controls — search, the account and the menu — which is the rule it has
   always kept on a phone.
   ───────────────────────────────────────────────────────────────────── */
@media (max-width: 720px) {
  .topnav { display: none; }
  .searchbar {
    flex: none;
    width: 44px;
    max-width: 44px;
    margin-inline-start: auto;
    padding: 0;
    justify-content: center;
    border-color: transparent;
    background: transparent;
    color: var(--ink-2);
  }
  .searchbar__txt,
  .searchbar__key { display: none; }
  /* .topbar__end already claims the end of the bar with its own auto
     margin; two of them would split the gap between the two clusters. */
  .topbar__end { margin-inline-start: 0; }
}

@media (max-width: 900px) {
  body { background: var(--app); }
  .topbar__in { height: 58px; }

  .page { padding: 20px 16px calc(28px + env(safe-area-inset-bottom, 0px)); }
  .band { padding: 22px; border-radius: var(--r-xl); }
  .band__art { width: 72px; }

  .greet h1 { font-size: 27px; }
  .hero { padding: 22px; border-radius: var(--r-xl); }
  .hero .btn { width: 100%; }
  .hero__art { display: none; }

  .figures { grid-template-columns: 1fr 1fr; }
  .figrow:nth-child(2n) { border-right: 0; }
  .figrow:nth-child(-n+2) { border-bottom: 1px solid var(--line-soft); }


  .qstem { font-size: 21px; line-height: 1.75; }
  .opt { min-height: 58px; padding: 14px 16px; }
  .opt.is-chosen, .opt.is-right, .opt.is-wrong { padding: 13px 15px; }
  .opt__text { font-size: 16.5px; }
  .opt__hot { display: none; }
  .options--glyph { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .opt--glyph { min-height: 116px; }
  .opt--glyph .opt__text { font-size: 48px; }

  /* On a phone the bank sits under the tiles rather than beside them,
     so it gets the full width and the pills get room to breathe. */
  .match { gap: 14px; }
  .match__bank { max-width: none; padding: 16px; }
  .mtile--l { min-height: 56px; padding: 12px 14px; }
  .mtile--l .mtile__text { font-size: 16.5px; }
  .mtile--r { min-height: 44px; font-size: 16.5px; }
  .mtile__pin { font-size: 14px; padding: 4px 10px; }

  .session__body { padding: 24px 16px 40px; }
  .session__top-in { padding: 12px 16px; gap: 10px; }
  .exitbtn { padding: 8px 13px; }
  .session__pos { font-size: 12px; }
  .session__count { padding: 6px 10px; font-size: 12px; }
  .session__foot-in { padding: 12px 16px; gap: 10px; }
  .session__foot { padding-bottom: env(safe-area-inset-bottom, 0px); }
  .session__foot .btn { padding: 0 22px; min-height: 50px; font-size: 15px; }
  .hint { font-size: 11.5px; }

  .res-hero { padding: 22px; }
  .res-hero__pct { font-size: 48px; }
  /* Full width for the two that decide what happens to this session; the
     three onward routes stay chips and wrap, because five full-width bars
     is a wall and the way out was at the bottom of it. */
  .res-actions .btn { flex: 1 1 100%; }
  .res-onward .btn { flex: 1 1 auto; }
  .page--settings h1 { font-size: 24px; }
}

/* ═══════════════════ Print ═══════════════════
   Cmd+P on a result page gives a clean handout for group study. */
@media print {
  .topbar, .tabbar, .session__top, .session__foot,
  .dialog, .res-actions, .res-onward { display: none !important; }
  body, .shell { background: #fff; }
  .session, .session__scroll { position: static; overflow: visible; }
  .card, .panel, .rev, .res-hero, .band { box-shadow: none; break-inside: avoid; }
}
/* A result is also an invitation: keep the sharing action distinct without
   making it louder than the learner's actual score. */
.challenge-action { border-color: var(--accent); color: var(--accent); }

/* The share panel. Each app gets its own target because a single share sheet
   drops half the message on some of them, and because a named button is
   faster to hit than a sheet you have to read. */
.share-panel {
  margin: 0 0 30px;
  padding: 20px 22px 18px;
  border: 1px solid var(--line-2);
  border-radius: var(--r-lg);
  background: #fff;
  box-shadow: var(--sh-2);
}
.share-panel__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.share-panel__title { margin: 0; font: 800 15px/1.4 var(--ui); }
/* The ring stays 30px — a close on a panel this small would otherwise
   read as a second action — but the thing a thumb has to land on is
   44px, thrown out past the ring by a pseudo-element. */
.share-panel__close {
  position: relative;
  flex: none; width: 30px; height: 30px; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 50%; background: none;
  color: var(--ink-4); font-size: 12px; cursor: pointer;
}
.share-panel__close::after { content: ""; position: absolute; inset: -7px; border-radius: 50%; }
.share-panel__close:hover { background: var(--rail); color: var(--ink); }
.share-name { margin-top: 14px; }
.share-name label { display: block; margin-bottom: 7px; color: var(--ink-4); font: 700 12.5px/1.4 var(--ui); }
.share-name__row { display: flex; flex-wrap: wrap; gap: 8px; }
.share-name input {
  flex: 1 1 200px; min-width: 0; min-height: 46px; padding: 0 13px;
  border: 1px solid var(--line-2); border-radius: var(--r); font-size: 16px;
}
.share-name__row .btn { flex: none; min-height: 46px; }
.share-send__lead { margin: 14px 0 12px; color: var(--ink-3); font-size: 13.5px; line-height: 1.55; }
.share-targets { display: flex; flex-wrap: wrap; gap: 8px; }
.share-target {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 15px;
  border: 1px solid var(--line-2); border-radius: var(--r-pill);
  background: var(--rail); color: var(--ink);
  font: 800 13px/1.4 var(--ui); cursor: pointer;
}
.share-target:hover { border-color: var(--accent); background: var(--pick-bg); color: var(--ink); }
.share-target__mark {
  flex: none; width: 22px; height: 22px; display: grid; place-items: center;
  border-radius: 50%; background: var(--ink); color: #fff; font-size: 11px; line-height: 1;
}
.share-target--more .share-target__mark { background: var(--ink-5); }
.share-link { display: flex; gap: 8px; margin-top: 14px; }
.share-link input {
  flex: 1; min-width: 0; min-height: 44px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--rail); color: var(--ink-3); font: 500 13px/1.4 var(--ui);
}
.share-link .btn { flex: none; min-height: 44px; }
.share-panel__mine { display: inline-block; margin-top: 14px; font-weight: 800; font-size: 13px; }
.challenge-share-status:empty { min-height: 0; margin: 0; }
.challenge-share-status { min-height: 22px; margin: 12px 0 0; color: var(--ink-4); font-size: 13px; line-height: 1.5; }
.challenge-share-status a { font-weight: 800; }
@media (max-width: 560px) {
  .share-panel { padding: 17px 15px 15px; }
  .share-name__row .btn, .share-name input { flex: 1 1 100%; }
  .share-target { flex: 1 1 calc(50% - 4px); justify-content: center; }
}


/* ═══════════════════════════════════════════════════════════════════
   Search modal — command-palette opened by ⌘K / Ctrl+K / "/"
   ═══════════════════════════════════════════════════════════════════ */

.search-modal {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: flex-start; justify-content: center;
  padding-top: min(12vh, 100px);
}
.search-modal[hidden] { display: none; }

.search-modal__backdrop {
  position: fixed; inset: 0;
  background: rgba(28,26,23,.55);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

.search-modal__card {
  position: relative;
  width: 94vw; max-width: 580px;
  max-height: 72vh;
  max-height: 72dvh;
  display: flex; flex-direction: column;
  animation: pop .18s var(--ease);
}

/* ── Head: pill search bar ────────────────────────────── */

.search-modal__head {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 6px 6px 20px;
  background: var(--card);
  border: 1px solid var(--line, #e5e2dc);
  border-radius: 999px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
  flex-shrink: 0;
}

.search-modal__head svg {
  flex: none; width: 22px; height: 22px;
  color: var(--ink-4); stroke-width: 1.5;
}

/* Desktop can close with Escape or a click on the backdrop framing the
   card, both of which a touch keyboard lacks — a visible X carries the
   whole job below 600px. Hidden here; the mobile block below swaps it in
   for the decorative glass icon. */
/* This one only ever exists on a touch screen, so it is sized for one:
   it was the single control on the site whose 40px was never once
   offered to a mouse. */
.search-modal__close {
  display: none;
  flex: none;
  width: 44px; height: 44px;
  align-items: center; justify-content: center;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
}
.search-modal__close svg { width: 20px; height: 20px; color: inherit; stroke-width: 2; }
.search-modal__close:hover,
.search-modal__close:focus-visible { background: var(--rail); color: var(--ink); }

#search-input {
  flex: 1 1 auto;
  border: none; outline: none; background: transparent;
  font: 400 17px/1.4 var(--ui);
  color: var(--ink);
  caret-color: var(--accent);
}
#search-input::placeholder { color: var(--ink-4); }

.search-modal__submit {
  flex: none;
  padding: 0 24px;
  height: 44px;
  font: 500 15px/44px var(--ui);
  color: #fff;
  background: #000;
  border: none;
  border-radius: 999px;
  cursor: pointer;
}

.search-modal__body {
  margin-top: 12px;
  background: var(--card);
  border: 1px solid var(--line, #e5e2dc);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-dialog);
  display: flex; flex-direction: column;
  overflow: hidden;
  min-height: 0;
}

/* ── Filters: trigger + collapsible panel ─────────────────────────
   Eleven pills (4 track + 3 kind + 4 mastery) used to sit in one
   horizontally-scrolling row with no hint anything scrolled off screen —
   cramped on desktop, worse on a phone where most of the row was never
   seen at all. They now live behind one "Filters" trigger, grouped and
   wrapped with room to breathe once opened. */

.search-modal__filters {
  flex: none;
  border-bottom: 1px solid var(--line, #e5e2dc);
}

.sf-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 18px;
}

.sf-trigger {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px;
  min-height: 44px;
  border: 1px solid var(--line, #e5e2dc);
  border-radius: var(--r-pill);
  background: transparent;
  font: 600 13px/1.4 var(--ui);
  color: var(--ink-3);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease);
}
.sf-trigger:hover { background: var(--rail); color: var(--ink-2); }
.sf-trigger.is-open { background: var(--rail); border-color: var(--ink-5); color: var(--ink-2); }
.sf-trigger__icon { flex: none; width: 15px; height: 15px; }
.sf-trigger__chevron {
  flex: none; width: 14px; height: 14px;
  transition: transform .15s var(--ease);
}
.sf-trigger.is-open .sf-trigger__chevron { transform: rotate(180deg); }

.sf-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font: 700 11px/1 var(--ui);
}

.sf-clear {
  border: none;
  background: transparent;
  padding: 7px 8px;
  min-height: 44px;
  font: 600 13px/1.4 var(--ui);
  color: var(--ink-4);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.sf-clear:hover { color: var(--ink-2); }

/* The panel pushes the results down rather than floating over them — a
   popover here would either get clipped by .search-modal__results' own
   scroll (an ancestor overflow: auto clips any absolutely-positioned
   child that pokes past it) or need its own escape hatch from the
   card's bounds. Pushing the layout is simpler and cannot misbehave on
   a small screen the way an anchored floating panel can. */
.sf-panel {
  display: flex; flex-direction: column; gap: 14px;
  padding: 2px 18px 16px;
  max-height: 38vh;
  overflow-y: auto;
}
.sf-panel[hidden] { display: none; }

.sf-section__label {
  margin-bottom: 7px;
  font: 700 11px/1.4 var(--ui);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-5);
}

.sf-section__pills {
  display: flex; flex-wrap: wrap; gap: 7px;
}

.sf-pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 11px;
  border: 1px solid var(--line, #e5e2dc);
  border-radius: var(--r-pill);
  background: transparent;
  font: 600 12px/1.5 var(--ui);
  color: var(--ink-4);
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease);
}
.sf-pill:hover { background: var(--rail); color: var(--ink-2); }
.sf-pill.is-on {
  background: var(--accent-bg);
  color: var(--accent);
  border-color: var(--accent-lt);
}

/* Track-coloured dot inside track filter pills. */
.sf-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--tint-ink);
}

/* Mastery pill colour hints. */
.sf-pill--m0.is-on { background: var(--rail); color: var(--ink-3); border-color: var(--ink-6); }
.sf-pill--m1.is-on { background: var(--warn-bg); color: var(--warn-ink); border-color: var(--warn-line); }
.sf-pill--m2.is-on { background: var(--good-bg); color: var(--good); border-color: var(--good-line); }
.sf-pill--m3.is-on { background: var(--good-bg); color: var(--good-2); border-color: var(--good-line); }

/* ── Result cards ──────────────────────────────────────────────
   Each result is a card carrying its track's colour on a left rail.
   Colour never carries the meaning on its own: the kind is written out
   beside the icon, and the course the result came from is named. */

.search-modal__results {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
}

.sr-card {
  position: relative;
  display: flex;
  align-items: stretch;
  flex-shrink: 0;
  gap: 14px;
  width: 100%;
  min-height: 44px;
  padding: 13px 16px 13px 0;
  border: 1px solid var(--line, #e5e2dc);
  border-radius: var(--r);
  background: var(--card);
  font: inherit;
  text-align: start;
  cursor: pointer;
  transition: border-color .14s var(--ease), background .14s var(--ease),
              transform .14s var(--ease);
}
/* .search-modal__results is a flex column that scrolls; a card is one of
   its flex items. An *explicit* min-height on a flex item (the 44px touch
   target floor) disables the browser's automatic "never shrink below
   content" protection, per spec — so once enough real results overflow
   the modal's height, every card gets flex-shrunk toward that 44px floor
   and a long Ethiopic title spills silently past the card's border
   (overflow stays visible). flex-shrink:0 is the actual fix: it keeps the
   44px floor for short cards while stopping the container from ever
   shrinking a card below its own content. Only shows up with enough real
   results to force shrinking — short local test fixtures never trigger it,
   which is why this was invisible until tested against the live bank. */
.sr-card:hover { background: var(--rail); }
.sr-card.is-active {
  border-color: var(--tint-ink, var(--ink-4));
  background: var(--tint, var(--rail));
  transform: translateX(2px);
}
.sr-card:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* The track's colour, as a rail rather than a wash — a 1.08:1 tint over
   a whole card is the mistake the mastery work already made once. */
.sr-card__rail {
  flex: none;
  width: 4px;
  border-radius: var(--r) 0 0 var(--r);
  background: var(--tint-ink, var(--ink-5));
  margin: -13px 0;
}

.sr-card__body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

/* Each row keeps its natural height. Without flex-shrink:0, a column
   flex container squeezes its children to fit whatever cross size the
   row above (.sr-card) settles on, instead of the reverse. Belt and
   braces alongside the unclamped title above: this is what stops a
   long row being squashed even if something upstream miscalculates. */
.sr-card__top,
.sr-card__title {
  flex-shrink: 0;
}

.sr-card__top {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.sr-card__kind {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--tint-ink, var(--ink-4));
  font: 700 11.5px/1.4 var(--ui);
  letter-spacing: .07em;
  text-transform: uppercase;
}
.sr-card__kind svg { width: 13px; height: 13px; }

.sr-card__where {
  min-width: 0;
  color: var(--ink-5);
  font-family: var(--et), var(--ui);
  font-weight: 500;
  font-size: 12px;
  line-height: 1.6;
  padding-bottom: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A question stem is a full sentence, and truncating it to force every
   card to the same height is what made the list unreadable in the first
   place — and unreadable in a worse way the second time: clamping to a
   fixed number of lines inside a flex column depends on every ancestor's
   height math agreeing with the clamp, and one real (long, two-line)
   title was enough to break that agreement and print the title sliced
   across two cards. Nothing here is clamped or clipped any more — the
   title wraps to however many lines it needs and the card grows to
   match, which cannot desync because there is no shared budget left to
   disagree about.
   line-height must not be "normal": Ethiopic glyphs run taller than the
   font's own metrics assume, so a tight line box clips and overlaps
   consecutive lines instead of wrapping them cleanly. 1.7 matches every
   other Ethiopic title in the app (.urow__title, .rrow__title). */
.sr-card__title {
  color: var(--ink);
  font-family: var(--et), var(--ui);
  font-weight: 600;
  font-size: 15px;
  line-height: 1.7;
  padding-bottom: 4px;
}

/* Highlight matched text. */
.search-hl {
  background: #fef08a;
  color: #713f12;
  border-radius: 4px;
  padding: 0 4px;
  font-weight: 600;
}

/* ── Empty state ───────────────────────────────────────────────── */

.search-modal__empty {
  padding: 36px 18px;
  text-align: center;
  color: var(--ink-5);
  font: 500 14px/1.5 var(--ui);
}

/* ── Footer keyboard hints ─────────────────────────────────────── */

.search-modal__footer {
  display: flex; align-items: center; gap: 16px;
  padding: 10px 18px;
  border-top: 1px solid var(--line, #e5e2dc);
  color: var(--ink-4);
  font: 500 11.5px/1 var(--ui);
}
.search-modal__footer kbd {
  display: inline-block;
  padding: 2px 5px;
  font: 600 11.5px/1.4 var(--ui);
  background: var(--rail);
  border: 1px solid var(--line, #e5e2dc);
  border-radius: 4px;
  margin-right: 3px;
}

/* ── Responsive ────────────────────────────────────────────────── */

@media (max-width: 600px) {
  /* Same centered-card pattern as desktop, not a fullscreen takeover: a
     fullscreen sheet (padding-top:0, height:100dvh, no visible backdrop)
     pinned the bar to the literal top of the screen and left nothing to
     tap to get back out. A smaller top offset keeps the card reachable
     with a thumb on a short phone without gluing it to the status bar,
     and the backdrop stays visible on every side so tapping outside the
     card — same gesture as any other dialog in the app — dismisses it. */
  .search-modal { padding-top: min(8vh, 64px); padding-left: 14px; padding-right: 14px; }
  .search-modal__card {
    width: 100%;
    max-width: none;
    max-height: 80dvh;
  }
  .search-modal__results {
    padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px));
  }
  .search-modal__footer { display: none; }

  /* Keyboard hints in the footer (↑↓, esc) don't apply to touch, so that
     row is hidden above — replace it with an explicit, always-visible
     close control instead of relying on the backdrop tap alone. */
  .search-modal__head { padding-left: 6px; }
  .search-modal__close { display: flex; }
  .search-modal__glass { display: none; }
  .search-modal__submit { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .search-modal__card { animation-duration: .001ms !important; }
}
/* ── Highlight animation for units ─────────────────────────────── */

/* Fill + rule, not a tint that fades from the first frame — a wash that
   starts dissolving the instant it appears reads as "already gone" by
   the time the eye lands on it after the scroll-into-view. This holds
   at full strength through the scroll, then eases out. */
@keyframes flash-hl {
  0%   { transform: scale(1.025); }
  8%   { background: var(--warn-bg); box-shadow: 0 0 0 3px var(--warn-line), 0 8px 20px rgba(28,26,23,.1); transform: scale(1.025); }
  55%  { background: var(--warn-bg); box-shadow: 0 0 0 3px var(--warn-line), 0 8px 20px rgba(28,26,23,.1); transform: scale(1); }
  100% { background: var(--card); box-shadow: 0 0 0 0 transparent; transform: scale(1); }
}
.urow.is-highlighted {
  animation: flash-hl 1.8s cubic-bezier(.16, 1, .3, 1) forwards;
  z-index: 10;
  position: relative;
}

@media (prefers-reduced-motion: reduce) {
  .urow.is-highlighted { animation-duration: .001ms; }
}

/* ══════════════════ Classes ══════════════════
   The learner's side of enrollment: the Class section in Settings and
   the "From your class" assignment list on home. Colour never carries
   the state alone — a finished assignment says Done in words, and the
   tick only echoes it. */
.classcard {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
}
.classcard + .classcard { border-top: 1px solid var(--line); }
.classcard__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.classcard__title { font: 400 15.5px/1.6 var(--et); color: var(--ink); }
.classcard__body p { margin: 0; font: 500 12.5px/1.6 var(--ui); color: var(--ink-3); }
.classcard__body small { font: 500 12.5px/1.6 var(--ui); color: var(--ink-3); }

.class-join { display: flex; align-items: flex-start; gap: 12px; padding: 14px 16px 10px; }
.class-join .settings-field { margin: 0; }
.class-join input {
  text-transform: uppercase;
  letter-spacing: .12em;
  font-weight: 700;
}
.class-join .btn { margin-top: 22px; flex: none; }
#class-join-msg { padding: 0 16px 12px; }
#class-join-msg[data-bad] { color: var(--bad); }

.assignlist {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  overflow: hidden;
}
.assign {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 16px;
  min-height: 44px;
  color: inherit;
}
.assign + .assign, .assignfold .assign { border-top: 1px solid var(--line); }
.assign:hover { background: var(--rail); color: inherit; }
.assign__mark {
  flex: none;
  width: 26px; height: 26px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  display: grid; place-items: center;
  font: 800 12px/1 var(--ui);
  color: var(--ink-3);
}
.assign.is-done .assign__mark { background: var(--good-bg); border-color: var(--good-line); color: var(--good); }
.assign__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.assign__what { font: 400 14.5px/1.6 var(--et); color: var(--ink); }
.assign.is-done .assign__what { color: var(--ink-3); }
.assign__meta { font: 500 12.5px/1.5 var(--ui); color: var(--ink-3); }
.assign__due { flex: none; font: 700 12.5px/1.4 var(--ui); color: var(--ink-3); }

.assignfold summary {
  padding: 11px 16px;
  border-top: 1px solid var(--line);
  font: 600 12.5px/1.5 var(--ui);
  color: var(--ink-3);
  cursor: pointer;
  min-height: 44px;
  display: flex;
  align-items: center;
}

@media (max-width: 640px) {
  .class-join { flex-direction: column; align-items: stretch; }
  .class-join .btn { margin-top: 0; }
}
