/* ===== Hippo — the focused quiz view =====================================
   Loaded after styles.css. EVERY rule in this file is scoped under
   body[data-ui="v2"], which only quiz.js sets, and quiz.js only sets it when
   localStorage.hippo_ui === "v2". Remove the <script src="quiz.js"> tag and this
   whole stylesheet becomes inert — that is the rollback boundary, and it only
   works if nothing here is written at plain `.class` scope. Do not add a rule
   here without that prefix.

   The view is CSS over a STABLE DOM. Nothing is removed, nothing is moved: the
   navigator that becomes the left rail is the same #qnav that lives in #quiz-bar
   in list mode, repositioned. Relocating a node with a module-scope listener in
   app.js is risk R1, the one that blanks the app for everyone.

   Colours come from the tokens at styles.css:4-25. No new palette. ========= */

/* ---- The entry control, visible in list mode too ---- */
body[data-ui="v2"] .qb-link.focus-in { border-color: var(--purple); color: var(--purple); }
body[data-ui="v2"] .qb-link.focus-in[hidden] { display: none !important; }

/* ---- What the quiz view hides. All widths. ----
   display:none is the whole rule here, so there is no [hidden] trap to pair. */
body[data-ui="v2"][data-view="quiz"] .pane-left,
body[data-ui="v2"][data-view="quiz"] .pane-lib,
body[data-ui="v2"][data-view="quiz"] .quiz-head,
body[data-ui="v2"][data-view="quiz"] .generator,
body[data-ui="v2"][data-view="quiz"] #ask-bar,
body[data-ui="v2"][data-view="quiz"] #btn-restart,
body[data-ui="v2"][data-view="quiz"] #save-switch,
body[data-ui="v2"][data-view="quiz"] #btn-nav,
body[data-ui="v2"][data-view="quiz"] .qb-sep,
/* These three scroll to nodes that this view hides, so they were dead buttons sitting
   in the rail — and #go-ask un-hid #ask-bar on the way to doing nothing, leaving it open
   for when the student came back to the studio. */
body[data-ui="v2"][data-view="quiz"] #go-material,
body[data-ui="v2"][data-view="quiz"] #go-generate,
body[data-ui="v2"][data-view="quiz"] #go-ask,
/* The anon bar sits ABOVE the sticky topbar in the document, so while it is showing the
   topbar is not at y=0 and the rail — pinned at top: var(--topbar-h), z-index 6 against
   the topbar's 10 — hides its own "← Volver" behind it at scroll 0. An anonymous visitor
   gets a real transcribed sample, so this view is reachable for them. The banner is
   waiting when they come out. */
body[data-ui="v2"][data-view="quiz"] .anon-bar,
body[data-ui="v2"][data-view="quiz"] .qb-link.focus-in { display: none; }

body[data-ui="v2"][data-view="quiz"] .split {
  grid-template-columns: 1fr; padding: 0; gap: 0; max-width: none;
}
/* The bottom padding is the ONLY clearance under the fixed action bar — .split's own
   padding is 0 here. Sized off --actions-h rather than a guessed number, because on a
   notched iPhone the safe-area inset makes the bar ~100px and "Calificar examen", which
   sits in normal flow at the end of .pane-right, ended up permanently behind it. */
body[data-ui="v2"][data-view="quiz"] .pane-right {
  border: 0; background: transparent; box-shadow: none;
  padding: 22px 22px calc(var(--actions-h) + 28px) calc(var(--rail-w) + 34px);
}

/* ---- The rail. All widths: it is fixed here and becomes a horizontal strip in
   the <=820px block at the bottom of this file. The node is #quiz-bar itself,
   which in list mode is the sticky bar — same element, different geometry. ---- */
body[data-ui="v2"] {
  --rail-w: 236px;
  /* 10 + 48 (.qa-btn min-height) + 10, plus the home-indicator inset. index.html carries
     viewport-fit=cover, so that inset is real on an iPhone and worth ~34px. */
  --actions-h: calc(68px + env(safe-area-inset-bottom, 0px));
}
body[data-ui="v2"][data-view="quiz"] #quiz-bar {
  display: flex; flex-direction: column; gap: 10px;
  position: fixed; left: 0; top: var(--topbar-h); bottom: 0; width: var(--rail-w);
  z-index: 6; margin: 0; border-radius: 0; border-width: 0 1px 0 0;
  padding: 14px 12px; overflow-y: auto; box-shadow: none;
}
/* ⚠ REQUIRED, same trap as .anon-bar and .paywall. styles.css has
   `.quiz-bar[hidden] { display: none }` at (0,2,0); the rule above is (1,2,1) and
   beats it, so without this line `el.hidden = true` on #quiz-bar silently does
   nothing and an empty rail sits over the page. */
body[data-ui="v2"][data-view="quiz"] #quiz-bar[hidden] { display: none !important; }

/* Order, not DOM position — see the header. .qb-row carries the pager and must sit
   under the head; the navigator fills the rest; the legend and the paywall chip sit
   at the foot. */
body[data-ui="v2"][data-view="quiz"] .rail-head { order: 1; }
body[data-ui="v2"][data-view="quiz"] .qb-row    { order: 2; }
body[data-ui="v2"][data-view="quiz"] .qnav      { order: 3; }
body[data-ui="v2"][data-view="quiz"] .rail-legend { order: 4; }
body[data-ui="v2"][data-view="quiz"] .rail-locked { order: 5; }

/* Wraps, deliberately. The row carries the pager, the PDF button and the timer, and the
   rail is 236px wide — nowrap here pushed them off the edge instead of onto a second
   line. Wrapping costs vertical space the rail has and horizontal space it does not. */
body[data-ui="v2"][data-view="quiz"] .qb-row { flex-wrap: wrap; gap: 6px; }
body[data-ui="v2"][data-view="quiz"] .pager { flex: 1 1 auto; justify-content: space-between; }
body[data-ui="v2"][data-view="quiz"] .pg-lab { flex: 1 1 auto; }

/* The navigator gets the room it never had in the sticky bar. All widths: the
   168px scroll box inside a sticky bar inside the page scroll is the gesture trap
   Phase 1 removed on phones, and the rail must not reintroduce it. */
body[data-ui="v2"][data-view="quiz"] .qnav {
  max-height: none; overflow: visible; margin: 0; padding: 0; border-top: 0;
  grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
}
body[data-ui="v2"][data-view="quiz"] .qnav[hidden] { display: none !important; }
body[data-ui="v2"][data-view="quiz"] .qn.here {
  background: var(--ink); border-color: var(--ink); color: #fff; outline: 0;
}

/* ---- New rail furniture ---- */
body[data-ui="v2"] .rail-head { display: flex; flex-direction: column; gap: 8px; }
body[data-ui="v2"] .rail-head[hidden] { display: none !important; }
body[data-ui="v2"] .rail-back {
  align-self: flex-start; border: 1px solid var(--line); background: var(--bg);
  color: var(--muted); font: inherit; font-size: 12.5px; font-weight: 600;
  border-radius: 999px; padding: 0 13px; min-height: 44px; cursor: pointer;
}
body[data-ui="v2"] .rail-back:hover { border-color: var(--purple); color: var(--purple); }
body[data-ui="v2"] .rail-title {
  font-size: 13.5px; font-weight: 700; line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
body[data-ui="v2"] .rail-count { font-size: 12px; color: var(--muted); }
body[data-ui="v2"] .rail-bar { height: 6px; border-radius: 999px; background: var(--panel); overflow: hidden; }
body[data-ui="v2"] .rail-fill { height: 100%; background: var(--ok); width: 0; transition: width .25s; }

/* The navigator has colour-coded every cell since it shipped and has never said
   what the colours mean. */
body[data-ui="v2"] .rail-legend {
  display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: 11.5px; color: var(--muted);
  border-top: 1px solid var(--line); padding-top: 10px;
}
body[data-ui="v2"] .rail-legend[hidden] { display: none !important; }
body[data-ui="v2"] .rail-legend span { display: inline-flex; align-items: center; gap: 5px; }
body[data-ui="v2"] .rail-legend i {
  width: 11px; height: 11px; border-radius: 3px; border: 1px solid var(--line); background: #fff;
}
body[data-ui="v2"] .rail-legend .lg-ok { background: var(--ok-bg); border-color: var(--ok); }
body[data-ui="v2"] .rail-legend .lg-bad { background: var(--bad-bg); border-color: var(--bad); }
body[data-ui="v2"] .rail-legend .lg-ans { background: var(--panel); border-color: var(--teal); }

/* The conversion gate, as one chip instead of a wall of blur.
   At one question per screen the blurred placeholder cards would land under the
   LAST question as a full screen of nothing — and they are placeholders: the
   server never transcribed them, so there is no content behind the blur. */
body[data-ui="v2"] .rail-locked {
  display: block; width: 100%; text-align: left; cursor: pointer;
  border: 1px dashed var(--purple); border-radius: 12px; background: var(--panel);
  color: var(--ink); font: inherit; font-size: 12.5px; padding: 11px 12px; line-height: 1.4;
}
body[data-ui="v2"] .rail-locked[hidden] { display: none !important; }
body[data-ui="v2"] .rail-locked b { display: block; font-size: 13px; margin-bottom: 3px; }

/* ---- One question, given the whole screen ---- */
/* scroll-margin-top: renderQuizPage scrolls #quiz into view on every page turn in this
   view, and .topbar is sticky at top:0 — without this the question lands underneath it. */
body[data-ui="v2"][data-view="quiz"] #quiz {
  max-width: 720px; margin: 0 auto; scroll-margin-top: calc(var(--topbar-h) + 10px);
}
body[data-ui="v2"][data-view="quiz"] .q-card { padding: 26px; }
body[data-ui="v2"][data-view="quiz"] .q-text { font-size: 18px; line-height: 1.5; }
body[data-ui="v2"][data-view="quiz"] .opt { font-size: 16px; padding: 14px 14px; min-height: 52px; }
body[data-ui="v2"][data-view="quiz"] #btn-grade-all { display: block; margin: 18px auto 0; }
/* ⚠ REQUIRED. app.js hides this button in every instant-grading mode with
   `.hidden = true`, and the display:block above beats the [hidden] attribute's UA
   display:none — without this line "Calificar examen" appears in a mode that grades
   as you go. Same trap as .anon-bar and .paywall. */
body[data-ui="v2"][data-view="quiz"] #btn-grade-all[hidden] { display: none !important; }

/* ---- The action bar. The rail is orientation and progress; THIS is the control the
   student's thumb uses on every question, so it is pinned to the bottom of the screen
   at every width. On a phone the rail sits above the question, which is exactly where
   a "next" button must not be. ---- */
body[data-ui="v2"] .quiz-actions {
  display: flex; align-items: center; gap: 10px;
  position: fixed; right: 0; bottom: 0; left: var(--rail-w); z-index: 7;
  padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px));
  background: var(--card); border-top: 1px solid var(--line);
}
body[data-ui="v2"] .quiz-actions[hidden] { display: none !important; }
/* The toast is fixed at bottom:20px with z-index 50, so it landed squarely on top of
   "Siguiente" — including toastAction's clickable button. Lift it clear. All widths. */
body[data-ui="v2"][data-view="quiz"] .toast { bottom: calc(var(--actions-h) + 14px); }
body[data-ui="v2"] .qa-btn {
  flex: 0 0 auto; min-height: 48px; padding: 0 18px; border-radius: 12px;
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  font: inherit; font-size: 14.5px; font-weight: 600; cursor: pointer;
}
body[data-ui="v2"] .qa-btn:hover:not(:disabled) { border-color: var(--purple); color: var(--purple); }
body[data-ui="v2"] .qa-btn:disabled { opacity: .35; cursor: default; }
body[data-ui="v2"] .qa-next { margin-left: auto; }
/* Answered in an instant-feedback mode: draw the eye to "Siguiente" instead of moving
   the screen out from under someone who is still reading why they were wrong. */
body[data-ui="v2"] .qa-next.ready {
  background: var(--ink); border-color: var(--ink); color: #fff;
}
body[data-ui="v2"] .qa-next.ready:hover { background: #2b2b2b; color: #fff; }
body[data-ui="v2"] .qa-count {
  flex: 1 1 auto; text-align: center; font-size: 13px; font-weight: 600; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body[data-ui="v2"] .rail-keys {
  font-size: 11px; color: var(--muted); line-height: 1.5;
  border-top: 1px solid var(--line); padding-top: 9px;
}
body[data-ui="v2"] .rail-keys[hidden] { display: none !important; }
body[data-ui="v2"] .rail-keys kbd {
  font: inherit; font-size: 10.5px; border: 1px solid var(--line); border-bottom-width: 2px;
  border-radius: 4px; padding: 1px 5px; background: #fff; color: var(--ink);
}
body[data-ui="v2"][data-view="quiz"] .rail-keys { order: 6; }

/* ---- Timed mode. Lives in .qb-row, so it is present in BOTH the list view and the
   focus rail — the chip is styled here rather than in a sixth stylesheet, but note it
   is scoped to [data-ui] only and NOT to [data-view]: it must work in both. ---- */
body[data-ui="v2"] .qb-time {
  border: 1px solid var(--line); background: var(--bg); color: var(--muted);
  font-family: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer;
  border-radius: 999px; padding: 6px 10px; min-height: 44px; max-width: 150px;
}
body[data-ui="v2"] .qb-time:hover { border-color: var(--purple); color: var(--purple); }
body[data-ui="v2"] .qb-clock {
  display: inline-flex; align-items: center; font-variant-numeric: tabular-nums;
  font-size: 13px; font-weight: 700; border-radius: 999px; padding: 6px 11px;
  min-height: 44px; border: 1px solid var(--line); background: var(--card); color: var(--ink);
  white-space: nowrap;
}
/* display:inline-flex beats the UA [hidden] rule, and the clock is hidden whenever no
   timer is running — without this it would show a frozen 0:00 forever. */
body[data-ui="v2"] .qb-clock[hidden] { display: none !important; }
/* No --warn token exists and this is not the place to invent one; --orange is the
   brand's amber and reads correctly against the card. */
body[data-ui="v2"] .qb-clock.warn { border-color: var(--orange); color: #a03d13; }
body[data-ui="v2"] .qb-clock.bad {
  border-color: var(--bad); background: var(--bad-bg); color: #98290c;
}


/* ===== RESPONSIVE — every width-based breakpoint lives here, and only here =====
   Same rule as styles.css and for the same reason: a base rule written LATER in a
   file beats an earlier @media that targets it, so keeping the breakpoints in one
   block at the bottom, widest first, is what makes them actually apply. One block
   per breakpoint. A rule that must hold at ALL widths belongs above this line. */

@media (max-width: 1180px) {
  body[data-ui="v2"] { --rail-w: 200px; }
}

@media (max-width: 820px) {
  /* No fixed side rail on a phone: 200px of a 390px screen is half the question. The
     rail unpins to a sticky strip above the question, which is what #quiz-bar already
     is in list mode.

     ⚠ AND IT MUST NOT SCROLL VERTICALLY. An earlier version capped it at 62vh with the
     base rule's `overflow-y: auto` still in force — which rebuilds exactly the construct
     Phase 1 deleted from .qnav: a vertical scroll box inside a sticky bar inside the page
     scroll, the strongest candidate for the "something in the middle was slow/blocking"
     from the 2026-09-04 call. So: no height cap, no vertical overflow, and the navigator
     becomes ONE horizontally-scrolling row instead of six stacked ones. A horizontal
     scroller does not compete for the vertical gesture, and it keeps the strip short
     enough that the question is still on screen. */
  body[data-ui="v2"][data-view="quiz"] #quiz-bar {
    position: sticky; top: var(--topbar-h); left: auto; bottom: auto; width: auto;
    border-width: 1px; border-radius: 12px; padding: 10px; margin-bottom: 12px;
    max-height: none; overflow: visible;
  }
  body[data-ui="v2"][data-view="quiz"] .qnav {
    display: flex; flex-wrap: nowrap; gap: 6px;
    overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch;
    padding-bottom: 2px;
  }
  /* The [hidden] partner for that display:flex lives at base scope (it is
     `…[data-view="quiz"] .qnav[hidden]`, higher specificity AND !important), so it wins
     here too — but it is stated in the base block, not this one, on purpose. */
  body[data-ui="v2"][data-view="quiz"] .qn { flex: 0 0 44px; }
  body[data-ui="v2"][data-view="quiz"] .rail-head { flex-direction: row; align-items: center; gap: 8px; }
  body[data-ui="v2"][data-view="quiz"] .rail-back { min-height: 40px; padding: 0 11px; }
  body[data-ui="v2"][data-view="quiz"] .rail-bar { display: none; }  /* the count says it */
  body[data-ui="v2"][data-view="quiz"] .pane-right {
    padding: 12px 12px calc(var(--actions-h) + 22px);
  }
  body[data-ui="v2"][data-view="quiz"] .q-card { padding: 16px; }
  body[data-ui="v2"][data-view="quiz"] .q-text { font-size: 16.5px; }
  /* No fixed rail to sit beside, so the action bar spans the screen. */
  body[data-ui="v2"] .quiz-actions { left: 0; padding: 9px 12px calc(9px + env(safe-area-inset-bottom, 0px)); }
  body[data-ui="v2"] { --actions-h: calc(66px + env(safe-area-inset-bottom, 0px)); }
  /* A physical keyboard is not the input method here. */
  body[data-ui="v2"] .rail-keys { display: none; }
}

@media (max-width: 430px) {
  body[data-ui="v2"][data-view="quiz"] #quiz-bar { padding: 8px; }
  body[data-ui="v2"][data-view="quiz"] .pane-right {
    padding: 10px 10px calc(var(--actions-h) + 18px);
  }
  body[data-ui="v2"][data-view="quiz"] .q-card { padding: 14px; }
  body[data-ui="v2"][data-view="quiz"] .opt { font-size: 15.5px; }
  body[data-ui="v2"] .rail-legend { gap: 3px 10px; font-size: 11px; }
  body[data-ui="v2"] .qa-btn { padding: 0 13px; font-size: 14px; }
  body[data-ui="v2"] .qa-count { font-size: 12px; }
  body[data-ui="v2"][data-view="quiz"] .rail-title { font-size: 12.5px; }
}
