/* ══════════════════════════════════════════════════════════════════════════
   saved.css — Mock Matrix Hub, Saved Questions
   Stage 1: fixed header, folder navigation, question cards, palette.

   Layout contract
     .exam-page-container  position:fixed frame   (design.css)
     .screen-header        flex-shrink:0 — never scrolls
     .screen-scroll        the ONLY scrolling region
     .screen-inner         full window width, no max-width cap (design.css)

   So on a big screen the content genuinely runs side to side; nothing sits in
   a narrow centred column with dead space either side. Individual folder
   cards are still capped so a tile never stretches to 400px of emptiness.
   ══════════════════════════════════════════════════════════════════════════ */

body {
  background: var(--bg);
  color: var(--text);
  font-family: 'Inter', 'Noto Sans Devanagari', system-ui, -apple-system, sans-serif;
  margin: 0;
  overscroll-behavior: none;
}

/* ── header extras ─────────────────────────────────────────────────────── */
.lang-select {
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  border-radius: var(--r-btn);
  font: 600 12px/1 'Inter', sans-serif;
  padding: 8px 24px 8px 10px;
  cursor: pointer;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235c6580' stroke-width='2.4' stroke-linecap='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat;
  background-position: right 6px center;
  background-size: 12px;
}
.lang-select:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }

.icon-circle-btn {
  width: 34px; height: 34px; flex: 0 0 auto;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-2);
  cursor: pointer;
  font-size: 14px;
  transition: transform .12s, background .15s, color .15s;
}
.icon-circle-btn:hover { color: var(--primary); background: var(--primary-soft); }
.icon-circle-btn:active { transform: scale(.9); }

/* Breadcrumb sits under the appbar, inside the fixed header */
.crumb-bar {
  display: flex; align-items: center; gap: 4px;
  padding: 0;
  font-size: 12.5px; font-weight: 600;
  color: var(--text-3);
  min-height: 22px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.crumb-bar::-webkit-scrollbar { display: none; }
.crumb-bar:empty { display: none; }
.crumb-sep { font-size: 10px; opacity: .55; margin: 0 2px; flex: 0 0 auto; }
.crumb-btn {
  border: 0; background: none; padding: 3px 6px; cursor: pointer;
  font: inherit; color: var(--primary); border-radius: 7px; white-space: nowrap;
}
.crumb-btn:hover { background: var(--primary-soft); }
.crumb-now { color: var(--text); padding: 3px 6px; white-space: nowrap; }
.crumb-label { max-width: 46vw; overflow: hidden; text-overflow: ellipsis; display: inline-block; vertical-align: bottom; }

.btn-solid {
  border: 0; cursor: pointer;
  background: var(--grad-primary); color: #fff;
  font: 700 13.5px/1 'Inter', sans-serif;
  padding: 11px 20px; border-radius: var(--r-btn);
  box-shadow: var(--shadow-card);
}
.btn-solid:active { transform: scale(.97); }

/* ── section heading ───────────────────────────────────────────────────── */
/* v29: the in-body heading is plain text. It carries no surface, no border and
   no shadow, and it is stepped down from 19px/800 to 15.5px/700 so it reads as
   a line of body copy introducing the list — not as another header competing
   with the appbar above it. */
.sec-head {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin: 0 0 12px;
  background: transparent; border: 0; box-shadow: none;
}
.sec-title {
  margin: 0; font-size: 15.5px; font-weight: 700; letter-spacing: -.1px;
  color: var(--text-2);
}
.sec-sub { font-size: 12px; font-weight: 600; color: var(--text-3); }

/* ── folder grid ─────────────────────────────────────────────────────────
   Two tiles per row on a phone, three from 640px, four from 1000px — and the
   grid itself always spans the full width, starting at one edge. Each tile is
   capped so it can never become a stretched-out slab on a wide monitor.    */
/* One tile per row on a phone — two-up squeezed the name and the counts into
   unreadable stubs. Each step up only happens once that many 340px-capped tiles
   genuinely fit, so the count follows the screen instead of a fixed guess. */
.folder-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  width: 100%;
}
.folder-grid > * { max-width: 340px; }
@media (min-width: 600px)  { .folder-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 980px)  { .folder-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; } }
@media (min-width: 1300px) { .folder-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* ── topic search ────────────────────────────────────────────────────────────
   Sits between the section heading and the tile grid. It filters tiles that are
   already on screen, so it is deliberately not part of the grid: a grid item
   would be re-flowed by the very filtering it drives. */
.folder-search {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 12px;
  padding: 0 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: var(--shadow-card);
  transition: border-color .15s, box-shadow .15s;
}
.folder-search:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.folder-search > .fa-magnifying-glass { font-size: 13px; color: var(--text-3); flex: 0 0 auto; }
.folder-search input {
  flex: 1 1 auto; min-width: 0;
  border: 0; background: none; outline: none;
  font: 500 13.5px/1 'Inter', sans-serif; color: var(--text);
  padding: 11px 0;
  -webkit-appearance: none; appearance: none;
}
.folder-search input::placeholder { color: var(--text-3); font-weight: 500; }
/* Safari/iOS draw their own clear button; we render one so it looks the same
   everywhere and can be hidden until there is something to clear. */
.folder-search input::-webkit-search-cancel-button,
.folder-search input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
.folder-search-x {
  flex: 0 0 auto; border: 0; background: none; cursor: pointer;
  color: var(--text-3); font-size: 12.5px; padding: 5px 4px; border-radius: 50%;
}
.folder-search-x:hover { color: var(--text); background: var(--surface-2); }
.folder-search-x[hidden] { display: none; }
/* Both of these set display: themselves, which beats the UA's [hidden] rule, so
   the search filter's card.hidden = true would silently do nothing without an
   explicit override. */
.folder-card[hidden], .empty-state[hidden] { display: none !important; }
body.dark-mode .folder-search { background: var(--surface); }

.folder-card {
  display: flex; align-items: center; gap: 12px;
  width: 100%;
  text-align: left;
  padding: 14px 13px;
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  background: var(--surface);
  box-shadow: var(--shadow-card);
  cursor: pointer;
  font-family: inherit;
  transition: transform .13s, box-shadow .18s, border-color .18s;
  position: relative;
  overflow: hidden;
}
.folder-card::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--grad-primary); opacity: 0; transition: opacity .18s;
}
.folder-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-pop); transform: translateY(-2px); }
.folder-card:hover::before { opacity: 1; }
.folder-card:active { transform: scale(.985); }

.folder-ico {
  flex: 0 0 auto;
  width: 46px; height: 46px;
  border-radius: 14px;
  display: grid; place-items: center;
  font-size: 19px;
}
.folder-body { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; gap: 5px; }
.folder-name {
  font-size: 14.5px; font-weight: 700; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  letter-spacing: -.1px;
}
.folder-meta { display: flex; flex-wrap: wrap; gap: 4px 8px; }
.folder-stat {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 600; color: var(--text-2);
}
/* v29: .folder-go (the small right-pointing chevron) is REMOVED. It sat where
   the three-dot menu also lands, so a tile showed two affordances stacked and
   the chevron read as the menu's own arrow. The three-dot is now the only
   control on the tile's right edge, vertically centred. */
.folder-go { display: none !important; }

/* The "everything" folder spans the whole row — it is not one subject among
   many, and a full-width banner reads as the shortcut it is. */
.folder-wide { grid-column: 1 / -1; max-width: none; }
.folder-wide .folder-ico { width: 50px; height: 50px; font-size: 21px; }
.folder-wide .folder-name { font-size: 15.5px; }

/* ── empty state ───────────────────────────────────────────────────────── */
.empty-state {
  text-align: center; padding: 64px 22px;
  color: var(--text-3);
}
.empty-ico { font-size: 44px; opacity: .22; display: block; margin-bottom: 16px; }
.empty-state h3 { margin: 0 0 8px; font-size: 17px; font-weight: 700; color: var(--text-2); }
.empty-state p { margin: 0 auto; max-width: 420px; font-size: 13.5px; line-height: 1.6; }

/* ── loader / fatal ────────────────────────────────────────────────────── */
.loader-box {
  position: fixed; inset: 0; z-index: 900;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 14px; padding: 24px;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(3px);
}
.spinner {
  width: 38px; height: 38px;
  border: 3px solid var(--border-strong);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: savedSpin .75s linear infinite;
}
@keyframes savedSpin { to { transform: rotate(360deg); } }
.loader-text { margin: 0; font-size: 13.5px; font-weight: 600; color: var(--text-2); }
.loader-bar {
  width: min(280px, 72vw); height: 5px;
  border-radius: 99px; background: var(--border); overflow: hidden;
}
.loader-fill {
  height: 100%; width: 0%;
  background: var(--grad-primary);
  border-radius: 99px;
  transition: width .22s ease;
}
.loader-pct { margin: 0; font-size: 11.5px; font-weight: 700; color: var(--text-3); font-variant-numeric: tabular-nums; }

.fatal-box {
  position: fixed; inset: 0; z-index: 950;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 14px; padding: 26px; text-align: center;
  background: var(--bg);
}
.fatal-ico { font-size: 34px; color: var(--red); }
.fatal-msg { margin: 0; max-width: 400px; font-size: 14px; line-height: 1.6; color: var(--text-2); }

/* ── toast ─────────────────────────────────────────────────────────────── */
.mmh-toast {
  position: fixed; left: 50%; bottom: 26px; z-index: 2000;
  transform: translate(-50%, 18px);
  background: #1f2937; color: #fff;
  font-size: 13px; font-weight: 600;
  padding: 11px 18px; border-radius: 99px;
  box-shadow: var(--shadow-pop);
  opacity: 0; pointer-events: none;
  transition: opacity .2s, transform .2s;
  max-width: min(92vw, 520px); text-align: center;
}
.mmh-toast.show { opacity: 1; transform: translate(-50%, 0); }
body.dark-mode .mmh-toast { background: #e5e7eb; color: #111827; }

/* ══════════════════════════════════════════════════════════════════════════
   QUESTIONS VIEW
   ══════════════════════════════════════════════════════════════════════════ */
.qview {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
  align-items: start;
  width: 100%;
}
.qmain { min-width: 0; }

/* List view is intentionally one question per row. The test-page palette is
   the second desktop column; putting two cards beside each other makes long
   question text, images and solution boxes look like a cramped dashboard. */
.q-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
}

.q-cell { min-width: 0; border-radius: var(--r-card); }
.q-cell-flash { animation: cellFlash 1.15s ease; }
@keyframes cellFlash {
  0%, 100% { box-shadow: none; }
  22%      { box-shadow: 0 0 0 3px var(--primary), var(--shadow-pop); }
}

/* ── the card shell ────────────────────────────────────────────────────────
   The INSIDE of the card (.qtext, .exam-tag, .opt, .custom-radio,
   .explanation) is lifted verbatim from test.html by q-render.css, so a saved
   question reads exactly like it did in the test. Only this outer shell is
   new: a numbered head strip, a hairline border, and a soft card shadow.   */
.mmh-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  position: relative;
  min-width: 0;
}
.mmh-card-head {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 13px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.mmh-card-num::before{ content:"Question: "; font-weight:800; }
.mmh-card-num {
  flex: 0 0 auto;
  min-width: 27px; height: 27px; padding: 0 8px;
  display: inline-flex; align-items:center; justify-content:center; gap:2px;
  border-radius: 9px;
  background: var(--grad-primary); color: #fff;
  font-size: 12.5px; font-weight: 800;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 1px 3px rgba(48, 80, 232, .35);
}
.mmh-card-head-extra { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.mmh-direct-actions{ display:inline-flex; align-items:center; gap:5px; }
.mmh-direct-btn{
  display:inline-flex; align-items:center; justify-content:center; gap:5px;
  min-height:26px; padding:5px 8px; border:1px solid var(--border-strong);
  border-radius:7px; background:var(--surface); color:var(--text-2);
  font-family:inherit; font-size:11px; font-weight:700; line-height:1; cursor:pointer; white-space:nowrap;
  transition:background .12s,color .12s,border-color .12s,transform .1s;
}
.mmh-direct-btn:hover{ color:var(--primary); border-color:var(--primary); background:var(--primary-soft); }
.mmh-direct-btn:active{ transform:scale(.94); }
.mmh-direct-danger{ color:var(--red); }
.mmh-direct-danger:hover{ color:var(--red); border-color:var(--red); background:var(--red-soft,rgba(225,29,72,.1)); }

.mmh-card-marking{
  /* Legacy scoring metadata stays in the DOM for compatibility, but the
     requested QCard meta row exposes only number + Delete + Move + menu. */
  display:none !important;
}
.mk-pos{ color:var(--emerald-strong); font-weight:700; }
.mk-neg{ color:var(--red); font-weight:700; }

/* Per-card solution toggle: a revision page should never hide the explanation
   behind a mode switch, but it must not typeset 300 solutions nobody opened. */
.mmh-sol-btn {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--text-2);
  font: 700 11.5px/1 'Inter', sans-serif;
  padding: 6px 10px; border-radius: 99px; cursor: pointer;
  transition: background .15s, color .15s, border-color .15s, transform .12s;
  white-space: nowrap;
}
.mmh-sol-btn i { font-size: 11px; }
.mmh-sol-btn:hover { border-color: var(--amber-strong); color: var(--amber-strong); background: var(--amber-soft); }
.mmh-sol-btn:active { transform: scale(.94); }
.mmh-sol-btn[aria-expanded="true"] {
  background: var(--amber-soft); border-color: var(--amber-strong); color: var(--amber-strong);
}
.mmh-card .explanation { border-top: 1px solid var(--border); }

/* the lifted .qtext expects to sit inside a positioned card for its exam tag */
.mmh-card .qtext { position: relative; }
.mmh-card .question-image { padding: 0 10px; }
.mmh-card .question-image:empty { display: none; }
.img-fail { color: var(--red); font-size: 12.5px; padding: 4px 0; }
.no-sol { color: var(--text-3); font-style: italic; }

/* Focus mode: a single card, comfortable to read, with the nav pinned below */
.q-focus-stage { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

/* ══ v29: focus-mode bottom bar ════════════════════════════════════════════
   One fixed bar. PREV is pinned to the LEFT edge, NEXT to the RIGHT edge, and
   the Reattempt switch sits centred between them. The two buttons are capped
   (max-width) and pushed apart with margin-left:auto, so a wide monitor gets
   two normal buttons at the two ends instead of one enormous slab each.

   On ≥992px the bar stops 332px short of the right edge — the palette owns a
   real 320px column plus a 12px gap there — so it can never run underneath or
   override the palette. Same technique exams/test.html uses for its
   #practiceFixedBar (right:360px against a 360px palette). ══════════════ */
.focus-nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 1100;
  display: flex; align-items: center; gap: 12px;
  padding: 9px 14px calc(9px + env(safe-area-inset-bottom, 0px));
  background: var(--surface);
  border-top: 1px solid var(--border);
  box-shadow: 0 -10px 28px rgba(15,23,42,.12);
}
.focus-nav[hidden] { display: none !important; }
.focus-nav-btn {
  /* capped, and never allowed to grow into the middle of the bar */
  flex: 0 1 auto;
  max-width: 190px;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  /* The same solid blue the exam interface uses for its action row, so the
     saved paper's controls read as the same family as test.html's. */
  border: 0;
  background: #0b5ed7; color: #fff;
  font: 700 12.5px/1 'Inter', sans-serif;
  padding: 13px 20px; border-radius: var(--r-btn);
  cursor: pointer; transition: transform .12s, filter .15s, opacity .15s;
}
.focus-nav-btn:hover:not(:disabled) { filter: brightness(1.08); }
.focus-nav-btn:active:not(:disabled) { transform: scale(.97); }
.focus-nav-btn:disabled { background: #adb5bd; color: #fff; opacity: .75; cursor: not-allowed; }
/* NEXT is the one that travels to the right-hand end. */
#focusNext { margin-left: auto; }
.focus-pos {
  flex: 0 0 auto; font-size: 12px; font-weight: 700; color: var(--text-2);
  font-variant-numeric: tabular-nums; padding: 0 4px;
}

/* ── Reattempt switch — the exams/test.html toggle, same box, same knob, same
      two colours and same 0.3s slide. Built as a real <button role="switch">
      rather than a nested <div onclick>, so it is focusable and announceable;
      the geometry below is test.html's 42×24 track / 20×20 knob / 2px→20px
      travel verbatim. ────────────────────────────────────────────────────── */
.reattempt-toggle {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 9px;
  margin: 0 auto;                    /* centred between PREV and NEXT */
  padding: 5px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-2);
  cursor: pointer;
}
.reattempt-label {
  font-size: 11.5px; font-weight: 800; color: var(--text-2);
  white-space: nowrap; letter-spacing: .01em;
}
.reattempt-track {
  position: relative; flex: 0 0 auto;
  width: 42px; height: 24px; border-radius: 12px;
  background: #ccc; transition: background .3s;
}
.reattempt-knob {
  position: absolute; top: 2px; left: 2px;
  width: 20px; height: 20px; border-radius: 50%;
  background: #fff; transition: left .3s;
  box-shadow: 0 1px 3px rgba(0,0,0,.3);
}
.reattempt-toggle[aria-checked="true"] .reattempt-track { background: #0b5ed7; }
.reattempt-toggle[aria-checked="true"] .reattempt-knob  { left: 20px; }
.reattempt-toggle[aria-checked="true"] .reattempt-label { color: var(--primary); }

/* The palette column is 320px + 16px grid gap: keep the bar clear of it. */
@media (min-width: 992px) {
  body.palette-on .focus-nav { right: 332px; }
  .focus-nav-btn { max-width: 220px; padding: 14px 26px; }
}
@media (min-width: 1500px) {
  body.palette-on .focus-nav { right: 352px; }   /* 340px column + gap */
}
@media (max-width: 620px) {
  .focus-nav { gap: 8px; padding: 8px 10px calc(8px + env(safe-area-inset-bottom, 0px)); }
  .focus-nav-btn { max-width: none; flex: 1 1 0; padding: 12px 10px; }
  .reattempt-label { display: none; }            /* the switch alone is enough */
  .reattempt-toggle { margin: 0; padding: 5px 8px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   PALETTE
   Mobile  : a slide-over sheet from the right, opened by the FAB.
   ≥1024px : a real, sticky second column of the grid — no overlay, no FAB.
   Same markup, same grid, same colours; only its positioning changes.
   ══════════════════════════════════════════════════════════════════════════ */
.qpal-col { display: none; min-width: 0; }

.palette-wrap {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 1200;
  width: min(88vw, 336px);
  display: flex; flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-pop);
  transform: translateX(105%);
  transition: transform .26s cubic-bezier(.32, .72, 0, 1);
  padding-top: env(safe-area-inset-top, 0px);
}
body.palette-open .palette-wrap { transform: none; }

.palette-backdrop {
  position: fixed; inset: 0; z-index: 1150;
  background: rgba(10, 15, 30, .45);
  display: none;
  opacity: 0; transition: opacity .22s;
}
body.palette-open .palette-backdrop { opacity: 1; }

.palette-fab {
  position: fixed; right: 16px; bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  z-index: 1150;   /* above the deck (1200) is not needed; above the focus bar (1100) is */
  width: 52px; height: 52px; border-radius: 50%;
  border: 0; cursor: pointer;
  background: var(--grad-primary); color: #fff;
  font-size: 18px;
  display: grid; place-items: center;
  box-shadow: 0 6px 20px rgba(48, 80, 232, .42);
  transition: transform .14s;
}
.palette-fab:active { transform: scale(.92); }
/* Two cases where the FAB must never appear:
   · at >=992px the palette is already a permanent fixed column, so a toggle
     that opens it is a button with nothing to do;
   · while any .sv-modal is open, because it floated on top of the Attempt test
     and PDF sheets. body.modal-open is kept in step by watchModalsForFab(). */
body.modal-open .palette-fab { display: none !important; }

.pal-head {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 14px 9px;
  border-bottom: 1px solid var(--border);
  flex: 0 0 auto;
}
.pal-title { font-size: 14px; font-weight: 800; color: var(--text); letter-spacing: -.1px; }
.pal-close { margin-left: auto; }
.pal-user {
  padding: 8px 14px 0;
  font-size: 11px; font-weight: 700; color: var(--text-3);
  text-transform: uppercase; letter-spacing: .5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  flex: 0 0 auto;
}
.pal-user:empty { display: none; }

.palette-grid {
  flex: 1 1 auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(42px, 1fr));
  gap: 7px;
  padding: 12px 14px 14px;
  align-content: start;
}
.qbtn {
  aspect-ratio: 1 / 1;
  min-height: 40px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-2);
  border-radius: 11px;
  font: 700 13px/1 'Inter', sans-serif;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  display: grid; place-items: center;
  transition: transform .1s, background .15s, color .15s, border-color .15s;
}
.qbtn:hover { border-color: var(--primary); color: var(--primary); }
.qbtn:active { transform: scale(.92); }
.qbtn.seen { background: var(--emerald-soft); border-color: var(--emerald); color: var(--emerald-strong); }
.qbtn.current {
  background: var(--grad-primary); border-color: transparent; color: #fff;
  box-shadow: 0 2px 8px rgba(48, 80, 232, .4);
}

.pal-legend {
  flex: 0 0 auto;
  display: flex; gap: 14px; justify-content: center;
  padding: 9px 14px calc(11px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--border);
  font-size: 10.5px; font-weight: 600; color: var(--text-3);
}
.pal-legend span { display: inline-flex; align-items: center; gap: 5px; }
.lg-dot { width: 11px; height: 11px; border-radius: 4px; display: inline-block; }
.lg-seen { background: var(--emerald-soft); border: 1px solid var(--emerald); }
.lg-now  { background: var(--grad-primary); }

/* ══ v29: a STABLE palette ═════════════════════════════════════════════════
   It was position:sticky inside the content grid, which meant it travelled
   with the page for the first 12px of every scroll and its height was tied to
   the content column beside it. It is now position:fixed — genuinely out of
   the body scroll, pinned to the viewport, with .palette-grid as its own
   overflow-y:auto region. The body scrolls; the palette does not move at all.

   The grid still reserves the column (so content never slides under it), and
   .screen-scroll gets padding-right for the same reason. The fixed bar rules
   above already stop the focus bar at the palette's left edge. ══════════ */
@media (min-width: 992px) {
  /* The track is NOT reserved: .qpal-col's only child is the fixed palette, so
     reserving 320px here would leave an empty column beside content that the
     padding-right below has already pushed clear. */
  .qview { grid-template-columns: minmax(0, 1fr); }
  .qpal-col { display: block; }

  .palette-wrap {
    position: fixed;
    top: calc(12px + env(safe-area-inset-top, 0px));
    right: 12px;
    bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    width: 320px; height: auto; max-height: none;
    transform: none;
    border: 1px solid var(--border);
    border-radius: var(--r-card);
    box-shadow: var(--shadow-card);
    background: var(--surface);
    z-index: 900;
  }
  /* Always open: no sheet state, no backdrop, no slide-in on desktop. */
  body.palette-open .palette-wrap { transform: none; }
  .palette-backdrop { display: none !important; }
  /* No close button — there is nothing to close. */
  .pal-close { display: none !important; }
  /* The column is always on screen here, so the toggle that opens it is not. */
  .palette-fab { display: none !important; }
  .palette-grid { grid-template-columns: repeat(auto-fill, minmax(38px, 1fr)); }
  /* Keep the scrolling content clear of the fixed column. */
  body.palette-on .screen-scroll { padding-right: 344px; }
}
@media (min-width: 1500px) {
  .palette-wrap { width: 340px; }
  body.palette-on .screen-scroll { padding-right: 364px; }
}

/* Long bilingual text, TeX, tables and images must stay inside the card.
   The page owns the vertical scroll; no card creates a sideways/inner trap. */
.qmain, .q-cell, .mmh-card, .q-focus-stage { min-width:0; max-width:100%; }
.mmh-card .qtext-inner, .mmh-card .opt-text, .mmh-card .explanation,
.mmh-card .comprehension-box { overflow-wrap:anywhere; word-break:normal; }
.mmh-card img { max-width:100%; height:auto; }
.mmh-card table { width:100%; max-width:100%; table-layout:fixed; border-collapse:collapse; }
.mmh-card td, .mmh-card th { max-width:0; overflow-wrap:anywhere; }
.q-focus-stage .mmh-card { width:100%; }

/* ── view-mode modal ───────────────────────────────────────────────────── */
.vm-modal {
  position: fixed; inset: 0; z-index: 1400;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  background: rgba(10, 15, 30, .5);
  backdrop-filter: blur(3px);
}
.vm-card {
  width: min(520px, 100%);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  box-shadow: var(--shadow-pop);
  padding: 18px;
  opacity: 0; transform: translateY(12px) scale(.98);
  transition: opacity .2s, transform .2s;
}
.vm-modal.vm-in .vm-card { opacity: 1; transform: none; }
.vm-head { display: flex; align-items: center; gap: 12px; }
.vm-head h3 { margin: 0; font-size: 16.5px; font-weight: 800; letter-spacing: -.2px; }
.vm-head .icon-circle-btn { margin-left: auto; }
.vm-count { margin: 6px 0 15px; font-size: 12.5px; font-weight: 600; color: var(--text-3); }
.vm-choices { display: grid; grid-template-columns: 1fr; gap: 10px; }
@media (min-width: 460px) { .vm-choices { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.vm-choice {
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  padding: 15px 14px;
  border: 1.5px solid var(--border);
  border-radius: 14px;
  background: var(--surface-2);
  cursor: pointer; font-family: inherit; text-align: left;
  transition: transform .12s, border-color .16s, background .16s;
}
.vm-choice i { font-size: 18px; color: var(--primary); }
.vm-choice:hover { border-color: var(--primary); background: var(--primary-soft); transform: translateY(-2px); }
.vm-choice:active { transform: scale(.98); }
.vm-choice-name { font-size: 14px; font-weight: 800; color: var(--text); }
.vm-choice-sub { font-size: 11.5px; font-weight: 500; color: var(--text-2); line-height: 1.45; }

/* ── small screens ─────────────────────────────────────────────────────── */
@media (max-width: 620px) {
  .sec-title { font-size: 17px; }
  .folder-grid { gap: 10px; }
  .folder-card { padding: 12px 11px; gap: 10px; }
  .folder-ico { width: 42px; height: 42px; font-size: 17px; border-radius: 13px; }
  .folder-name { font-size: 13.5px; }
  .brand-sub { display: none; }
  .crumb-bar { padding: 0 14px 8px; }
}
@media (max-width: 400px) {
  /* v29: tiles are one-per-row on a phone now, so every count fits and the
     rule that dropped the third one to keep a two-up layout honest is gone. */
  .lang-select { padding: 7px 20px 7px 8px; font-size: 11px; }
}

/* ── print: the on-screen chrome must never reach the paper ────────────── */
@media print {
  .screen-header, .palette-wrap, .palette-fab, .palette-backdrop,
  .loader-box, .fatal-box, .mmh-toast, .vm-modal, .focus-nav, .crumb-bar { display: none !important; }
  .exam-page-container { position: static; display: block; overflow: visible; }
  .screen-scroll { overflow: visible; }
}

/* ══════════════════════════════════════════════════════════════════════════
   STAGE 2 — contextual action bar · three-dot menus · multi-select ·
             delete / move / merge modals
   ══════════════════════════════════════════════════════════════════════════ */

/* ── header density ───────────────────────────────────────────────────────
   Under 900px the appbar keeps only the back button, title, PDF and auth.
   The language and theme controls are physically MOVED into the breadcrumb
   row (one element, never a duplicate), so nothing is lost — it just moves
   down a row where there is room for it. */
.crumb-row {
  display: flex; align-items: center; gap: 10px;
  min-height: 0;
}
.crumb-bar { flex: 1 1 auto; min-width: 0; }
.crumb-actions {
  display: none; align-items: center; gap: 8px; flex: 0 0 auto;
}
body.header-narrow .crumb-actions { display: flex; }
body.header-narrow .saved-progress-row .crumb-actions { display:flex; }
body.header-narrow .crumb-actions .lang-select { height: 32px; font-size: 12px; padding: 0 8px; }
body.header-narrow .crumb-actions .theme-btn { width: 32px; height: 32px; }
body.header-narrow .appbar { padding: 8px 12px; }
body.header-narrow .brand-mark { width: 30px; height: 30px; }
body.header-narrow .brand-title { font-size: 14.5px; }
body.header-narrow .brand-sub { display: none; }

/* ══════════════════════════════════════════════════════════════════════════
   v29 — HEADER CONTRACT
   ≥621px : back · logo + title · PDF · language(globe) · theme.  Nothing else.
   ≤620px : back · title only · ONE hamburger. No logo, no other icons. The
            hamburger lists all three actions with icon + text; tapping
            "Change language" opens the language card.
   The auth/profile chip (#authHeaderArea) is removed from the markup entirely,
   and the language <select> is replaced by a globe icon + modal.
   ══════════════════════════════════════════════════════════════════════════ */
.lang-btn { color: var(--text-2); }
.lang-btn:hover { color: var(--primary); background: var(--primary-soft); border-color: var(--primary); }
.lang-btn i { font-size: 15px; }
.lang-btn.is-bilingual { color: var(--primary); border-color: var(--primary); background: var(--primary-soft); }

/* the old inline A/अ pill is retired; keep the class inert in case anything
   still references it, so it can never reappear in the appbar */
.appbar-actions .lang-select { display: none !important; }

/* ── hamburger + its dropdown (login.html's pattern, re-skinned to the saved
      page's token set) ─────────────────────────────────────────────────── */
.menu-wrap { position: relative; flex: 0 0 auto; }
.hamburger-btn { color: var(--text-2); }
.hamburger-btn:hover { color: var(--primary); background: var(--primary-soft); }
.hamburger-btn svg { width: 18px; height: 18px; }
.hamburger-btn[aria-expanded="true"] { color: var(--primary); background: var(--primary-soft); border-color: var(--primary); }

.hamburger-dropdown {
  position: absolute; top: 44px; right: 0;
  min-width: 214px; padding: 6px;
  display: none; flex-direction: column; gap: 2px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 13px;
  box-shadow: 0 18px 44px rgba(15,23,42,.20), 0 3px 10px rgba(15,23,42,.10);
  z-index: 1400;
  animation: popIn .13s ease-out;
}
.hamburger-dropdown.open { display: flex; }
.hamburger-dropdown button {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px 12px; border: 0; border-radius: 9px;
  background: transparent; color: var(--ink);
  font: 600 13.2px/1.2 'Inter', system-ui, sans-serif;
  cursor: pointer; text-align: left;
}
.hamburger-dropdown button i { width: 16px; text-align: center; font-size: 13px; color: var(--ink-3); }
.hamburger-dropdown button:hover { background: var(--primary-soft); color: var(--primary); }
.hamburger-dropdown button:hover i { color: var(--primary); }
.hamburger-dropdown button:disabled { opacity: .4; cursor: default; }
.hamburger-dropdown button:disabled:hover { background: transparent; color: var(--ink); }
.hamburger-dropdown button[aria-pressed="true"] i { color: var(--primary); }
[data-theme="dark"] .hamburger-dropdown { background: #141d33; border-color: #2a3859; box-shadow: 0 18px 44px rgba(0,0,0,.55); }
[data-theme="dark"] .hamburger-dropdown button { color: #e6ecfa; }
[data-theme="dark"] .hamburger-dropdown button:hover { background: #1c2743; }

/* ── ≤620px: title only + hamburger. The title ellipsises rather than pushing
      the hamburger off-screen, and the logo drops out entirely. ─────────── */
@media (max-width: 620px) {
  .screen-header .appbar { padding: 7px 10px 8px; gap: 8px; }
  .screen-header .brand { gap: 0; min-width: 0; flex: 1 1 auto; }
  .screen-header .brand-mark { display: none !important; }   /* no logo */
  .screen-header .brand-text { min-width: 0; }
  .screen-header .brand-title {
    font-size: 14.5px; white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis;   /* long titles clip, never wrap */
    max-width: 100%;
  }
  .screen-header .brand-sub { display: none; }
  /* every other appbar control hides; only the hamburger stays */
  .screen-header .appbar-actions { gap: 0; margin-left: 0; flex: 0 0 auto; }
  .screen-header .appbar-actions > .icon-btn,
  .screen-header .appbar-actions > .lang-select,
  .screen-header .appbar-actions > .theme-btn { display: none !important; }
  .screen-header .appbar-actions .menu-wrap { display: block; }
  .screen-header .appbar-actions .hamburger-btn { width: 34px; height: 34px; }
}
/* ≥621px: the hamburger is not needed — all three actions are on the bar */
@media (min-width: 621px) {
  .screen-header .appbar-actions .menu-wrap { display: none !important; }
}

/* ── contextual action bar ──────────────────────────────────────────────── */
.ctx-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 12px;
  border-top: 1px solid var(--border);
  background: linear-gradient(180deg, #eef3fd, #e5edfb);
  animation: ctxIn .18s ease-out;
}
.ctx-bar[hidden] { display: none !important; }
@keyframes ctxIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
[data-theme="dark"] .ctx-bar { background: linear-gradient(180deg,#17203a,#131b30); border-top-color:#223052; }

.ctx-close {
  width: 30px; height: 30px; border-radius: 9px; flex: 0 0 auto;
  border: 1px solid rgba(15,23,42,.14); background: #fff; color: var(--ink-2);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px;
}
.ctx-close:hover { color: var(--ink); border-color: rgba(15,23,42,.28); }
[data-theme="dark"] .ctx-close { background:#1b2540; border-color:#2a3859; color:#c3cde6; }

.ctx-count { font-size: 13px; color: var(--ink-2); white-space: nowrap; }
.ctx-count b { color: var(--brand); font-weight: 800; font-size: 14.5px; margin-right: 4px; }
.ctx-link {
  border: 0; background: transparent; color: var(--brand);
  font-size: 12.5px; font-weight: 700; cursor: pointer; padding: 4px 2px;
  white-space: nowrap; text-decoration: underline; text-underline-offset: 2px;
}
.ctx-link:disabled { opacity: .4; cursor: default; }
.ctx-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; }

.ctx-act {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid transparent; border-radius: 10px;
  padding: 7px 12px; font-size: 12.5px; font-weight: 750; cursor: pointer;
  font-family: inherit; white-space: nowrap; transition: filter .12s, transform .06s;
}
.ctx-act:active { transform: scale(.97); }
.ctx-act:disabled { opacity: .38; cursor: default; transform: none; }
.ctx-act i { font-size: 12.5px; }
.ctx-move  { background: #e8efff; color: #1d4ed8; border-color: #c5d7fb; }
.ctx-move:hover:not(:disabled)  { background: #dbe7ff; }
.ctx-merge { background: #ece9fe; color: #6d28d9; border-color: #d6ccfb; }
.ctx-merge:hover:not(:disabled) { background: #e2dcfd; }
.ctx-del   { background: #fdecec; color: #b42318; border-color: #f6c9c5; }
.ctx-del:hover:not(:disabled)   { background: #fbdede; }
[data-theme="dark"] .ctx-move  { background:#16233f; color:#8ab4ff; border-color:#27406e; }
[data-theme="dark"] .ctx-merge { background:#221c3d; color:#c0a8fb; border-color:#3a2c68; }
[data-theme="dark"] .ctx-del   { background:#33191c; color:#ff9a90; border-color:#5c272b; }

/* ── three-dot button ───────────────────────────────────────────────────── */
.dot-btn {
  /* v29: on a folder tile this is a real flex child at the right edge,
     vertically centred — not a corner overlay. Question cards already put it
     in the meta row (.mmh-card-head-extra .dot-btn below). */
  position: static; flex: 0 0 auto; align-self: center; margin-left: 2px;
  width: 30px; height: 30px; border-radius: 9px;
  border: 1px solid var(--border); background: rgba(255,255,255,.94);
  color: var(--ink-3); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px; transition: background .12s, color .12s, border-color .12s;
}
.dot-btn:hover { color: var(--brand); border-color: #c5d7fb; background: #fff; }
[data-theme="dark"] .dot-btn { background: rgba(23,32,58,.94); border-color: #2a3859; color: #8fa0c6; }
[data-theme="dark"] .dot-btn:hover { color: #8ab4ff; border-color: #3a5488; }
/* inside a question card the three-dot sits in the meta row, not floating */
.mmh-card-head-extra .dot-btn {
  position: static; width: 26px; height: 26px; border-radius: 7px; font-size: 12px;
}

/* ── popup menu ─────────────────────────────────────────────────────────── */
.menu-layer { position: fixed; inset: 0; z-index: 400; pointer-events: none; }
.menu-layer[hidden] { display: none !important; }
.pop-menu {
  position: absolute; pointer-events: auto;
  min-width: 186px; padding: 6px;
  background: #fff; border: 1px solid var(--border); border-radius: 13px;
  box-shadow: 0 18px 44px rgba(15,23,42,.20), 0 3px 10px rgba(15,23,42,.10);
  animation: popIn .13s ease-out;
}
@keyframes popIn { from { opacity: 0; transform: scale(.96) translateY(-4px); } to { opacity: 1; transform: none; } }
[data-theme="dark"] .pop-menu { background: #141d33; border-color: #2a3859; box-shadow: 0 18px 44px rgba(0,0,0,.55); }
.pop-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 11px; border: 0; border-radius: 9px; background: transparent;
  color: var(--ink); font-size: 13.2px; font-weight: 600; font-family: inherit;
  cursor: pointer; text-align: left;
}
.pop-item i { width: 16px; text-align: center; color: var(--ink-3); font-size: 12.5px; }
.pop-item:hover { background: #f1f5fd; }
.pop-item:hover i { color: var(--brand); }
.pop-danger { color: #b42318; }
.pop-danger i { color: #d9534a; }
.pop-danger:hover { background: #fdecec; }
[data-theme="dark"] .pop-item { color: #e6ecfa; }
[data-theme="dark"] .pop-item:hover { background: #1c2743; }
[data-theme="dark"] .pop-danger { color: #ff9a90; }
[data-theme="dark"] .pop-danger:hover { background: #33191c; }
.pop-sep { height: 1px; margin: 5px 8px; background: var(--border); }

/* ── selection ──────────────────────────────────────────────────────────── */
.sel-box {
  position: absolute; top: 10px; left: 10px; z-index: 3;
  width: 22px; height: 22px; border-radius: 7px;
  border: 2px solid rgba(15,23,42,.24); background: rgba(255,255,255,.92);
  display: none; align-items: center; justify-content: center;
  color: transparent; font-size: 11px; transition: all .12s;
}
.sel-box i { transform: scale(.5); transition: transform .12s; }
body.select-mode .sel-box { display: inline-flex; }
.is-selected > .sel-box, .is-selected .sel-box {
  background: var(--brand); border-color: var(--brand); color: #fff;
}
.is-selected .sel-box i { transform: scale(1); }
[data-theme="dark"] .sel-box { border-color: rgba(255,255,255,.3); background: rgba(20,29,51,.9); }

body.select-mode .folder-card { cursor: pointer; }
/* In selection mode the three-dot is suppressed, so nothing needs reserving. */
body.select-mode .folder-card .dot-btn { display: none; }
.folder-card.is-selected {
  border-color: var(--brand);
  box-shadow: 0 0 0 2px rgba(37,99,235,.20), 0 8px 20px rgba(37,99,235,.12);
  background: linear-gradient(180deg,#f5f9ff,#fff);
}
/* In selection mode the checkbox takes the folder icon's place, exactly like a
   phone file manager: the tile keeps its shape and nothing is overlaid. */
body.select-mode .folder-card > .folder-ico { display: none; }
.folder-card > .sel-box { position: static; order: -1; flex: 0 0 auto; width: 26px; height: 26px; border-radius: 8px; }
/* The marking readout is not needed while choosing, and dropping it keeps the
   card head from crowding on a 360px screen. */
.card-sel-box { position: static; flex: 0 0 auto; }
[data-theme="dark"] .folder-card.is-selected { background: linear-gradient(180deg,#182341,#131c33); }

.q-cell.is-selected .mmh-card, .mmh-card.is-selected {
  border-color: var(--brand);
  box-shadow: 0 0 0 2px rgba(37,99,235,.18), var(--card-shadow);
}
body.select-mode .mmh-card-marking { display: none; }
body.select-mode .mmh-card { cursor: pointer; }
/* in selection mode the palette mirrors the selection rather than "viewed" */
.palette-grid .qbtn.sel {
  background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 700;
}

/* ── modals (shared shell for confirm + transfer) ───────────────────────── */
.sv-modal {
  position: fixed; inset: 0; z-index: 350;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(15,23,42,.45);
  padding: 0;
}
.sv-modal.sv-in .sv-card { transform: none; opacity: 1; }
.sv-card {
  width: 100%; max-width: 468px;
  background: #fff; border-radius: 18px 18px 0 0;
  box-shadow: 0 -12px 44px rgba(15,23,42,.24);
  max-height: 88vh; display: flex; flex-direction: column;
  transform: translateY(14px); opacity: .6;
  transition: transform .2s cubic-bezier(.2,.9,.25,1), opacity .2s;
}
.sv-card-sm { max-width: 400px; }
.sv-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 15px 18px 12px;
}
.sv-head h3 { margin: 0; font-size: 16.5px; font-weight: 800; color: var(--ink); letter-spacing: -.01em; }
.sv-body { padding: 0 18px 6px; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.sv-foot {
  display: flex; gap: 10px; padding: 12px 18px calc(14px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--border); background: #fafbfe;
  border-radius: 0 0 18px 18px;
}
.sv-msg { margin: 0 0 12px; font-size: 13.6px; line-height: 1.62; color: var(--ink-2); }
.sv-msg b { color: var(--ink); font-weight: 750; }
.sv-warn {
  display: flex; align-items: center; gap: 9px;
  padding: 10px 12px; border-radius: 11px;
  background: #fff4f3; border: 1px solid #f6c9c5; color: #96302a;
  font-size: 12.6px; font-weight: 700;
}
.sv-warn i { font-size: 13px; }
.sv-note { margin: 12px 0 4px; font-size: 12.2px; line-height: 1.55; color: var(--ink-3); }

.sv-btn {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 44px; padding: 0 16px; border-radius: 12px;
  font-size: 14px; font-weight: 750; font-family: inherit; cursor: pointer;
  border: 1px solid transparent; transition: background .12s, filter .12s, transform .06s;
}
.sv-btn:active { transform: scale(.985); }
.sv-btn:disabled { cursor: default; }
.sv-btn-ghost { background: #fff; border-color: var(--border); color: var(--ink-2); }
.sv-btn-ghost:hover:not(:disabled) { background: #f5f7fb; color: var(--ink); }
.sv-btn-go { background: linear-gradient(135deg,#2563eb,#1d4ed8); color: #fff; box-shadow: 0 6px 16px rgba(37,99,235,.28); }
.sv-btn-go:hover:not(:disabled) { filter: brightness(1.06); }
.sv-btn-go:disabled { background: #d7dce6; color: #8b93a5; box-shadow: none; }
.sv-btn-danger { background: linear-gradient(135deg,#e0483c,#c62f26); color: #fff; box-shadow: 0 6px 16px rgba(198,47,38,.26); }
.sv-btn-danger:hover:not(:disabled) { filter: brightness(1.06); }
.sv-btn-danger:disabled { background: #e8d3d1; color: #a08482; box-shadow: none; }

/* The busy state: label goes transparent and a CSS ring takes its place, so
   the button never changes width mid-write and never needs an icon font. */
.sv-btn.is-busy { position: relative; color: transparent !important; pointer-events: none; }
.sv-btn.is-busy .sv-go-label { opacity: 0; }
.sv-btn.is-busy::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 18px; height: 18px; margin: -9px 0 0 -9px;
  border-radius: 50%;
  border: 2.5px solid rgba(255,255,255,.35);
  border-top-color: #fff;
  animation: svSpin .7s linear infinite;
}
@keyframes svSpin { to { transform: rotate(360deg); } }
.exit-locked { opacity: .45; cursor: not-allowed !important; }

[data-theme="dark"] .sv-modal { background: rgba(4,8,18,.62); }
[data-theme="dark"] .sv-card { background: #131c33; box-shadow: 0 -12px 44px rgba(0,0,0,.6); }
[data-theme="dark"] .sv-head h3 { color: #e6ecfa; }
[data-theme="dark"] .sv-msg { color: #9dabd0; }
[data-theme="dark"] .sv-msg b { color: #e6ecfa; }
[data-theme="dark"] .sv-foot { background: #101829; border-top-color: #223052; }
[data-theme="dark"] .sv-btn-ghost { background: #1b2540; border-color: #2a3859; color: #c3cde6; }
[data-theme="dark"] .sv-warn { background: #2d1719; border-color: #5c272b; color: #ffb3ab; }
[data-theme="dark"] .sv-note { color: #7b8ab0; }
[data-theme="dark"] .sv-btn-go:disabled { background: #232e4a; color: #5d6b8c; }
[data-theme="dark"] .sv-btn-danger:disabled { background: #3a2224; color: #7d5a58; }

/* ── "currently in" readout ─────────────────────────────────────────────── */
.sv-current { margin-bottom: 14px; }
.sv-current-label {
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: 7px;
}
.sv-current-boxes { display: flex; gap: 10px; }
.sv-cur-box {
  flex: 1; min-width: 0; padding: 10px 12px;
  border: 1px dashed var(--border); border-radius: 12px; background: #fafbfe;
}
.sv-cur-box span {
  display: block; font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 3px;
}
.sv-cur-box b {
  display: block; font-size: 13.6px; font-weight: 750; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
[data-theme="dark"] .sv-cur-box { background: #101829; border-color: #2a3859; }
[data-theme="dark"] .sv-cur-box b { color: #e6ecfa; }

/* ── target pickers ─────────────────────────────────────────────────────── */
.sv-targets { display: flex; flex-direction: column; gap: 14px; }
.pk-label {
  display: block; font-size: 11.5px; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-2); margin-bottom: 7px;
}
.pk-hint { font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--ink-3); font-size: 11px; }
.pk-row { display: flex; gap: 8px; }
.pk-select {
  flex: 0 0 auto; padding: 0 14px; min-height: 42px; border-radius: 11px;
  border: 1px solid #c5d7fb; background: #e8efff; color: #1d4ed8;
  font-size: 12.8px; font-weight: 750; font-family: inherit; cursor: pointer;
}
.pk-select:hover { background: #dbe7ff; }
.pk-input {
  flex: 1; min-width: 0; padding: 0 12px; min-height: 42px; border-radius: 11px;
  border: 1px solid var(--border); background: #fff; color: var(--ink);
  font-size: 13.8px; font-family: inherit;
}
.pk-input:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px rgba(37,99,235,.14); }
.pk-list {
  margin-top: 7px; max-height: 176px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: 12px; background: #fff;
  padding: 4px; -webkit-overflow-scrolling: touch;
}
.pk-list[hidden] { display: none !important; }
.pk-opt {
  display: block; width: 100%; text-align: left;
  padding: 9px 11px; border: 0; border-radius: 9px; background: transparent;
  color: var(--ink); font-size: 13.2px; font-family: inherit; cursor: pointer;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pk-opt:hover { background: #f1f5fd; color: var(--brand); }
.pk-err {
  margin-top: 7px; padding: 8px 11px; border-radius: 10px;
  background: #fff4f3; border: 1px solid #f6c9c5; color: #96302a;
  font-size: 12.2px; font-weight: 650; line-height: 1.7;
}
.pk-err[hidden] { display: none !important; }
.pk-pill {
  display: inline-block; min-width: 20px; padding: 1px 6px; margin: 0 2px;
  border-radius: 6px; background: #fbd9d5; color: #7d231d;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 700; text-align: center;
}
[data-theme="dark"] .pk-select { background: #16233f; border-color: #27406e; color: #8ab4ff; }
[data-theme="dark"] .pk-input { background: #0f1729; border-color: #2a3859; color: #e6ecfa; }
[data-theme="dark"] .pk-list { background: #0f1729; border-color: #2a3859; }
[data-theme="dark"] .pk-opt { color: #dbe4f8; }
[data-theme="dark"] .pk-opt:hover { background: #1c2743; color: #8ab4ff; }
[data-theme="dark"] .pk-err { background: #2d1719; border-color: #5c272b; color: #ffb3ab; }
[data-theme="dark"] .pk-pill { background: #4d2225; color: #ffd0cb; }

/* ── responsive ─────────────────────────────────────────────────────────── */
@media (min-width: 900px) {
  .sv-modal { align-items: center; padding: 24px; }
  .sv-card { border-radius: 18px; }
  .sv-foot { border-radius: 0 0 18px 18px; }
}
@media (max-width: 899px) {
  /* icon-only actions below 900px — the spec's "only the icon will be there" */
  .ctx-act span { display: none; }
  .ctx-act { padding: 8px 10px; }
  .ctx-bar { gap: 7px; padding: 6px 10px; }
  .ctx-count { font-size: 12px; }
  .ctx-link { font-size: 11.5px; }
  .sv-current-boxes { flex-direction: column; gap: 8px; }
  .pk-row { flex-direction: column; }
  .pk-select { min-height: 38px; }
}
@media (max-width: 420px) {
  .ctx-count #ctxCountWord { display: none; }
  .ctx-count::after { content: "selected"; font-size: 12px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   STAGE 3 — contextual "Save as PDF"
   The modal reuses the Stage 2 .sv-modal / .sv-card / .sv-btn shell, so the
   spinner, the locked exits and the sheet-to-dialog responsive behaviour all
   carry over unchanged. Only the PDF-specific contents are new.
   ══════════════════════════════════════════════════════════════════════════ */

/* the header button, so it reads as a document action next to the theme icon */
.appbar .pdf-btn { color: #b42318; }
.appbar .pdf-btn:hover { background: #fdecec; border-color: #f2c7c3; }
.appbar .pdf-btn:disabled { opacity: .35; cursor: default; }
.appbar .pdf-btn[hidden] { display: none; }
[data-theme="dark"] .appbar .pdf-btn { color: #ff9a90; }
[data-theme="dark"] .appbar .pdf-btn:hover { background: #33191c; border-color: #5c272b; }

/* ── "you are in" ───────────────────────────────────────────────────────── */
.pdf-context {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px; margin-bottom: 13px;
  border-radius: 11px; background: #f1f5fd; border: 1px solid #dfe8fa;
}
.pdf-context-label {
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-3);
}
.pdf-context-value { font-size: 13.4px; font-weight: 750; color: var(--brand); }
[data-theme="dark"] .pdf-context { background: #141d33; border-color: #24314f; }
[data-theme="dark"] .pdf-context-value { color: #8ab4ff; }

/* ── scope chooser ──────────────────────────────────────────────────────── */
.pdf-scopes { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.pdf-scope {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 13px; border-radius: 12px; cursor: pointer;
  border: 1.5px solid var(--border); background: var(--surface);
  transition: border-color .13s, background .13s, box-shadow .13s;
}
.pdf-scope:hover { border-color: var(--border-strong); }
/* .is-checked is set by script and mirrors :has() for WebViews that lack it. */
.pdf-scope:has(input:checked), .pdf-scope.is-checked {
  border-color: var(--brand); background: #f5f9ff;
  box-shadow: 0 0 0 3px rgba(37,99,235,.11);
}
.pdf-scope input { width: 17px; height: 17px; flex: 0 0 auto; accent-color: var(--brand); margin: 0; }
.pdf-scope-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.pdf-scope-name {
  font-size: 13.4px; font-weight: 750; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pdf-scope-name i { color: var(--brand); margin-right: 6px; font-size: 12px; }
.pdf-scope-hint { font-size: 11.4px; color: var(--ink-3); line-height: 1.4; }
.pdf-scope-count {
  flex: 0 0 auto; min-width: 30px; padding: 3px 8px; border-radius: 999px;
  background: #e8efff; color: #1d4ed8;
  font-size: 12px; font-weight: 800; text-align: center;
  font-variant-numeric: tabular-nums;
}
[data-theme="dark"] .pdf-scope { background: #131c33; border-color: #2a3859; }
[data-theme="dark"] .pdf-scope:has(input:checked),
[data-theme="dark"] .pdf-scope.is-checked { background: #182341; border-color: #3a5488; }
[data-theme="dark"] .pdf-scope-name { color: #e6ecfa; }
[data-theme="dark"] .pdf-scope-count { background: #16233f; color: #8ab4ff; }

/* ── options ────────────────────────────────────────────────────────────── */
.pdf-opts {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 11px 13px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--surface-2);
}
.pdf-opt { display: inline-flex; align-items: center; gap: 8px; font-size: 12.8px; font-weight: 650; color: var(--ink-2); }
.pdf-opt > span:first-child {
  font-size: 10.5px; font-weight: 800; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3);
}
.pdf-select {
  padding: 7px 10px; border-radius: 9px; border: 1px solid var(--border);
  background: var(--surface); color: var(--ink);
  font-size: 12.8px; font-weight: 650; font-family: inherit; cursor: pointer;
}
.pdf-select:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px rgba(37,99,235,.14); }
.pdf-check { cursor: pointer; margin-left: auto; }
.pdf-check input { width: 16px; height: 16px; accent-color: var(--brand); margin: 0; cursor: pointer; }
.pdf-check span { font-size: 12.8px; font-weight: 650; color: var(--ink-2); }
[data-theme="dark"] .pdf-opts { background: #101829; border-color: #2a3859; }
[data-theme="dark"] .pdf-select { background: #0f1729; border-color: #2a3859; color: #e6ecfa; }

/* ── the "this is big" warning ──────────────────────────────────────────── */
.pdf-bigwarn {
  display: flex; align-items: flex-start; gap: 9px;
  margin-top: 12px; padding: 10px 12px; border-radius: 11px;
  background: #fff8ec; border: 1px solid #f5d9a8; color: #8a5a12;
  font-size: 12.3px; font-weight: 650; line-height: 1.55;
}
.pdf-bigwarn[hidden] { display: none !important; }
.pdf-bigwarn i { margin-top: 2px; font-size: 12.5px; }
.pdf-bigwarn b { font-weight: 800; }
[data-theme="dark"] .pdf-bigwarn { background: #2a2113; border-color: #5a4520; color: #f0c987; }

.pdf-howto { margin-top: 10px; }
.pdf-howto b { color: var(--ink-2); font-weight: 750; }

@media (max-width: 899px) {
  .pdf-check { margin-left: 0; }
  .pdf-opts { flex-direction: column; align-items: stretch; gap: 10px; }
  .pdf-opt { justify-content: space-between; }
  .pdf-select { flex: 1 1 auto; }
}

/* ══════════════════════════════════════════════════════════════════════════
   STAGE 4 — ATTEMPT TEST
   ══════════════════════════════════════════════════════════════════════════ */

/* ── a token fix that predates this stage ────────────────────────────────────
   This file speaks in "ink" (--ink, --ink-2, --ink-3) while design.css defines
   "text" (--text, --text-2, --text-3). The ink tokens were never defined
   anywhere, so all 27 var(--ink*) declarations below and in Stages 1-2 were
   invalid at computed-value time and silently fell back to the inherited
   colour: every muted note, message and ghost-button label rendered at full
   strength instead of its intended secondary tone.

   They are aliased on BODY as well as :root on purpose. body.dark-mode
   redefines --text*, but a custom property declared on :root resolves var()
   against the HTML element's own values — which are always the light ones.
   Declaring on body makes the alias resolve against body's theme, so dark mode
   gets dark ink. */
:root, body {
  --ink:   var(--text);
  --ink-2: var(--text-2);
  --ink-3: var(--text-3);
}

/* v29: the .attempt-dock footer is gone — "Attempt mode" is now the second
   button of the floating .ex-dock ported from the home page, so the whole
   footer rule set (dock, info, count, label, button, its ≤620px/≤420px
   responsive variants and its dark-theme overrides) was dead weight and has
   been removed rather than left to drift out of step with the markup. */

/* v29: the FAB is pinned bottom-right, and both bottom bars are full-width, so
   it is lifted clear of whichever one is showing — the floating deck in normal
   mode, the taller fixed focus bar in focus mode. Selection hides both, so the
   FAB drops back to the bottom edge. (The legacy .has-attempt-dock hook is
   gone with the .attempt-dock footer it belonged to.) */
body.saved-deck-visible .palette-fab {
  bottom: calc(88px + env(safe-area-inset-bottom, 0px));
}
body.saved-focus .palette-fab {
  bottom: calc(76px + env(safe-area-inset-bottom, 0px));
}
body.select-mode .palette-fab {
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
}

/* ── the settings modal ────────────────────────────────────────────────────── */
.at-fields {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 11px 12px; margin: 14px 0 2px;
}
.at-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.at-field > span {
  font-size: 11px; font-weight: 750; letter-spacing: .03em;
  text-transform: uppercase; color: var(--ink-3);
}
.at-field-wide { grid-column: 1 / -1; }
.at-input {
  width: 100%; min-width: 0; box-sizing: border-box;
  padding: 9px 11px; border-radius: var(--r-btn);
  border: 1.5px solid var(--border-strong);
  background: var(--surface); color: var(--ink);
  font-size: 14.5px; font-weight: 650; font-family: inherit;
  transition: border-color .14s, box-shadow .14s;
}
.at-input:focus {
  outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}
.at-summary {
  margin: 13px 0 2px; padding: 9px 12px;
  border-radius: var(--r-btn);
  background: var(--primary-soft); color: var(--primary);
  font-size: 13px; font-weight: 750; text-align: center;
  font-variant-numeric: tabular-nums;
}

/* Three buttons in the foot: Cancel, then the two order choices. The order is a
   fork rather than a primary/secondary pair, so Shuffle reads as an equal
   alternative — outlined, not greyed — and Topic-wise keeps the filled
   treatment the rest of the app uses for "go". */
.at-foot { flex-wrap: wrap; }
.at-foot .sv-btn { flex: 1 1 auto; }

/* ── the order chooser ───────────────────────────────────────────────────────
   Topic-wise / Shuffle used to be two footer buttons that differed only in this
   one setting, so choosing an order and starting a build were the same click.
   They are now a segmented radiogroup inside the form and the footer holds a
   single Generate test action. Styled to match .at-input so it reads as another
   field, not as a button pair. */
.at-order {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px;
}
.at-order-opt {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 12px; min-width: 0;
  border: 1.5px solid var(--border-strong); border-radius: var(--r-btn);
  background: var(--surface); color: var(--ink-2);
  font: 650 13.5px/1 'Inter', sans-serif; font-family: inherit;
  cursor: pointer; white-space: nowrap;
  transition: border-color .14s, background .14s, color .14s;
}
.at-order-opt i { font-size: 12.5px; }
.at-order-opt:hover { border-color: var(--primary); color: var(--primary); }
.at-order-opt.is-on {
  border-color: var(--primary); background: var(--primary-soft); color: var(--primary);
  box-shadow: inset 0 0 0 1px var(--primary);
}
.at-order-opt:disabled { opacity: .55; cursor: not-allowed; }
body.dark-mode .at-order-opt { background: var(--surface); color: var(--text-2); }
body.dark-mode .at-order-opt.is-on { background: rgba(91,116,255,.15); color: #93b4ff; }

/* ── responsive ────────────────────────────────────────────────────────────── */
@media (max-width: 620px) {
  .at-foot { flex-direction: column; }
  .at-foot .sv-btn { width: 100%; }
}
@media (max-width: 420px) {
  .at-fields { grid-template-columns: 1fr; }
}

@media (max-width:640px){
  .mmh-card-num::before{ content:"QS:"; }
  .mmh-card-num{ min-width:34px; padding-left:6px; padding-right:6px; gap:1px; }
  .mmh-direct-btn{ width:28px; min-width:28px; height:28px; padding:0; gap:0; }
  .mmh-direct-label{ display:none; }
  .mmh-card-head-extra{ gap:4px; }
  .mmh-direct-actions{ gap:3px; }
}

/* ══ v28 follow-up: compact one-line header + body progress + app deck ══ */
/* ══ v29: the crumb row is body content, NOT a second header ══════════════
   It used to carry background:var(--surface) + border-bottom, which painted a
   white band straight under the appbar and read exactly like a sub-header.
   Both are gone: no surface of its own, no rule of its own, so it inherits the
   page background and sits quietly in the body. Padding-top is increased so it
   drops a little lower, away from the header's edge. ═════════════════════ */
.saved-progress-row{
  display:flex;align-items:center;gap:10px;min-height:34px;
  background:transparent;border-bottom:0;
  padding:14px 16px 0;position:relative;z-index:5;
}
.saved-progress-row .crumb-bar{padding:0;min-height:26px;}
.saved-progress-row .crumb-actions{display:none;}
/* Nothing left to show on a phone — the title already names the folder. */
@media(max-width:620px){ .saved-progress-row{display:none;} }

/* v29: this whole ≤620px block is retired. Every rule in it targeted a header
   control that no longer exists on a phone — the A/अ language <select>, the
   theme and PDF icon buttons, and the #authHeaderArea login/avatar chip (all
   three collapsed into the single hamburger, and the auth chip removed from the
   markup outright). It also set .brand-title{font-size:14px;white-space:nowrap}
   at the same specificity as the new contract below but LATER in the file, so
   leaving it in place would have silently won the cascade and stripped the new
   text-overflow:ellipsis. The phone header now lives entirely in the
   "v29 — HEADER CONTRACT" block above. */

/* ══ v29: the mode deck — the HOME PAGE dock, verbatim ════════════════════
   .ex-dock / .ex-dock-item are copied straight out of css/home.css (the same
   floating pill bar the home and exams pages render through app-core.js's
   renderBottomNav()). Fixed + left:50% + width:min(100vw - 20px, 620px) is
   what makes the two modes sit together, centred, on a big screen instead of
   stretching edge to edge as the old .saved-bottom-nav did.

   Only intentional deltas from home.css:
     • these are <button>s, not <a>s, so they need border:0 / font / cursor;
     • the icon is a Font Awesome <i> rather than an inline <svg>, so it is
       sized by font-size instead of width/height;
     • no raised centre FAB — there are only two peer modes here, neither of
       them is "home", so .ex-dock-center is deliberately not used.
   Everything else — geometry, radii, padding, shadow, active dot, :active
   scale, the <380px tighten — is the home dock unchanged. ═══════════════ */
.saved-dock{
    position:fixed;
    left:50%; transform:translateX(-50%);
    bottom:calc(12px + env(safe-area-inset-bottom));
    z-index:1200;
    display:flex; align-items:stretch; justify-content:space-between;
    width:min(calc(100vw - 20px), 620px);
    background:var(--surface);
    border:1px solid var(--border);
    border-radius:26px;
    padding:8px 10px;
    box-shadow:0 18px 40px rgba(15,23,42,.16);
}
body.dark-mode .saved-dock{ box-shadow:0 18px 44px rgba(0,0,0,.5); }
.saved-dock[hidden]{ display:none !important; }
.saved-dock .ex-dock-item{
    position:relative;
    flex:1; min-width:0;
    display:flex; flex-direction:column; align-items:center; justify-content:flex-end;
    gap:3px;
    padding:9px 2px 11px;
    border-radius:16px;
    color:var(--text-3); text-decoration:none;
    font-size:10px; font-weight:700; letter-spacing:.2px;
    transition:color .15s ease;
    /* button reset — the home dock's items are anchors */
    border:0; background:transparent; cursor:pointer; font-family:inherit;
}
.saved-dock .ex-dock-item i{ font-size:21px; line-height:1; }
.saved-dock .ex-dock-item:active{ transform:scale(.94); }
.saved-dock .ex-dock-item.active{ color:var(--primary); }
.saved-dock .ex-dock-item.active::after{
    content:'';
    position:absolute; bottom:3px; left:50%; transform:translateX(-50%);
    width:4px; height:4px; border-radius:50%;
    background:var(--primary);
}
@media (max-width:379.98px){
    .saved-dock{ padding:7px 6px; border-radius:22px; }
}

/* The deck floats, so the scrolling content needs clearance or the last card
   hides behind it. Focus mode swaps the deck for the fixed focus bar, which is
   taller, so it gets more. */
body.saved-deck-visible .screen-inner{ padding-bottom:104px; }
body.saved-focus .screen-inner{ padding-bottom:112px; }
/* The deck is gone in focus mode and during multi-select — exactly as before,
   but the selector now targets the ported class. */
body.saved-focus .saved-dock,body.select-mode .saved-dock{ display:none !important; }

/* v29: .focus-nav is ALWAYS the fixed bar now (see the block above), so the
   old body.saved-focus overrides that re-declared it are gone. Leaving them
   here would fight the new padding/gap at equal specificity. */
body.saved-focus .focus-nav-btn{ min-width:0; }

/* Explicit blue selection state: the previous var(--brand) token was not
   defined on every saved-page theme, making the check appear invisible. */
.sel-box{border-color:var(--primary)!important;background:var(--surface)!important;color:transparent;}
.is-selected>.sel-box,.is-selected .sel-box{background:var(--primary)!important;border-color:var(--primary)!important;color:#fff!important;}
.folder-card.is-selected,.q-cell.is-selected .mmh-card,.mmh-card.is-selected{border-color:var(--primary)!important;box-shadow:0 0 0 3px rgba(61,90,254,.24),var(--shadow-card)!important;}

/* Initial saved-library skeleton: visible in the body while the first tree
   read runs, with no page-wide blur or hidden content. */
.saved-skeleton{padding:4px 0 20px;animation:skeletonIn .2s ease both;}
.skeleton-heading{display:flex;align-items:center;gap:10px;margin:2px 0 18px;}
.skeleton-heading span{width:180px;height:22px;border-radius:8px;background:linear-gradient(90deg,var(--surface-2),var(--border),var(--surface-2));background-size:200% 100%;animation:skeletonMove 1.25s linear infinite;}
.skeleton-heading i{width:86px;height:13px;border-radius:8px;background:var(--surface-2);}
.skeleton-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;}
.skeleton-folder{height:76px;border-radius:16px;border:1px solid var(--border);background:var(--surface);padding:14px;display:flex;align-items:center;gap:12px;box-shadow:var(--shadow-card);}
.skeleton-folder>b{width:44px;height:44px;border-radius:13px;background:linear-gradient(90deg,var(--surface-2),var(--border),var(--surface-2));background-size:200% 100%;animation:skeletonMove 1.25s linear infinite;}
.skeleton-folder span{display:grid;gap:8px;flex:1}.skeleton-folder i{display:block;height:10px;border-radius:7px;background:var(--surface-2)}.skeleton-folder i:first-child{width:78%}.skeleton-folder i:last-child{width:52%}
@keyframes skeletonMove{to{background-position:-200% 0}}@keyframes skeletonIn{from{opacity:0}to{opacity:1}}
@media(min-width:640px){.skeleton-grid{grid-template-columns:repeat(3,minmax(0,1fr));}}@media(min-width:1000px){.skeleton-grid{grid-template-columns:repeat(4,minmax(0,1fr));}}

/* Body spinner, not a full-screen blur. */
.loader-box{position:relative;inset:auto;min-height:150px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:20px;background:transparent;backdrop-filter:none;pointer-events:none;z-index:1;}

/* ══════════════════════════════════════════════════════════════════════════
   v29 — QUESTION SKELETONS
   Opening a folder used to raise the full-screen spinner with a live
   "Loading questions… 37 / 240" counter under it. It now paints card-shaped
   skeletons straight into the body — the same shimmer the folder screen already
   used — and the spinner only appears for the genuinely modal work (preparing a
   PDF, building a test), where it shows text and NO count.
   ══════════════════════════════════════════════════════════════════════════ */
.q-skeleton { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
.q-skeleton-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.q-skeleton-head {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 13px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.q-skeleton-head b {
  width: 27px; height: 27px; border-radius: 9px; flex: 0 0 auto;
  background: linear-gradient(90deg, var(--surface-2), var(--border), var(--surface-2));
  background-size: 200% 100%; animation: skeletonMove 1.25s linear infinite;
}
.q-skeleton-head i {
  height: 12px; border-radius: 7px; background: var(--surface-2); display: block;
}
.q-skeleton-head i:first-of-type { width: 96px; }
.q-skeleton-head i:last-of-type { width: 54px; margin-left: auto; }
.q-skeleton-body { padding: 14px 13px 18px; display: grid; gap: 9px; }
.q-skeleton-body i {
  display: block; height: 11px; border-radius: 7px; background: var(--surface-2);
}
.q-skeleton-body i:nth-child(1) { width: 96%; }
.q-skeleton-body i:nth-child(2) { width: 88%; }
.q-skeleton-body i:nth-child(3) { width: 62%; }
.q-skeleton-opts { margin-top: 4px; display: grid; gap: 7px; }
.q-skeleton-opt {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px;
  border: 1px solid var(--border); border-radius: 10px;
}
.q-skeleton-opt b {
  width: 18px; height: 18px; border-radius: 50%; flex: 0 0 auto;
  background: var(--surface-2);
}
.q-skeleton-opt span { height: 10px; border-radius: 6px; background: var(--surface-2); display: block; }
.q-skeleton-opt:nth-child(1) span { width: 64%; }
.q-skeleton-opt:nth-child(2) span { width: 48%; }
.q-skeleton-opt:nth-child(3) span { width: 71%; }
.q-skeleton-opt:nth-child(4) span { width: 39%; }
/* Focus mode shows one card, so one skeleton is enough. */
body.saved-focus .q-skeleton-card:not(:first-child) { display: none; }

/* ══════════════════════════════════════════════════════════════════════════
   v29 — LANGUAGE CARD
   Replaces the appbar's "A / अ / A-अ" <select>. Reuses the .sv-modal shell so
   the sheet-on-phone / dialog-on-desktop behaviour and the escape handling all
   carry over; only the three choice rows are new.
   ══════════════════════════════════════════════════════════════════════════ */
.lang-choices { display: flex; flex-direction: column; gap: 8px; padding-bottom: 10px; }
.lang-choice {
  display: flex; align-items: center; gap: 12px;
  width: 100%; padding: 12px 13px;
  border: 1.5px solid var(--border); border-radius: 12px;
  background: var(--surface); cursor: pointer;
  font-family: inherit; text-align: left;
  transition: border-color .13s, background .13s, box-shadow .13s;
}
.lang-choice:hover { border-color: var(--border-strong); background: var(--surface-2); }
.lang-choice:active { transform: scale(.99); }
.lang-choice-glyph {
  flex: 0 0 auto;
  min-width: 42px; height: 34px; padding: 0 8px;
  display: grid; place-items: center;
  border-radius: 9px;
  background: var(--surface-2); border: 1px solid var(--border);
  font: 800 13px/1 'Inter', 'Noto Sans Devanagari', system-ui, sans-serif;
  color: var(--text-2);
}
.lang-choice-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.lang-choice-name { font-size: 13.6px; font-weight: 750; color: var(--ink); }
.lang-choice-sub { font-size: 11.4px; font-weight: 500; color: var(--ink-3); line-height: 1.4; }
.lang-choice-tick { flex: 0 0 auto; font-size: 13px; color: var(--primary); opacity: 0; }
.lang-choice.is-on {
  border-color: var(--primary); background: var(--primary-soft);
  box-shadow: 0 0 0 3px rgba(61,90,254,.11);
}
.lang-choice.is-on .lang-choice-glyph { background: var(--primary); border-color: var(--primary); color: #fff; }
.lang-choice.is-on .lang-choice-tick { opacity: 1; }
[data-theme="dark"] .lang-choice { background: #131c33; border-color: #2a3859; }
[data-theme="dark"] .lang-choice-glyph { background: #101829; border-color: #2a3859; color: #c3cde6; }
[data-theme="dark"] .lang-choice.is-on { background: #182341; border-color: #5b74ff; }
