:root {
  --bg: #0b1120;
  --bg-alt: #0f172a;
  --panel: #161f36;
  --panel-border: #263352;
  --text: #e8edf7;
  /* Was a dimmer gray (#8b96ad, then #b4bfd6) — labels, the deck-position
     counter, the signed-in email, and empty-state text like "No attempts
     yet" all read this color, and both earlier attempts still read as
     visibly duller than --text next to it (e.g. the cert title sitting
     right above the email). Aliased directly to --text: same brightness,
     no more gray, full stop. */
  --muted: var(--text);
  /* Default accent (shown pre-login, before any cert/provider is known)
     — the same sky-blue/indigo pair the site always used. */
  --accent: #38bdf8;
  --accent-2: #6366f1;
  --accent-rgb: 56, 189, 248;
  --good: #22c55e;
  --good-dim: #16a34a;
  --bad: #f43f5e;
  --bad-dim: #e11d48;
  --radius: 14px;
}

/* Once a cert is selected, app.js stamps the provider onto <body> and the
   accent pair swaps to that provider's brand color — the gradients,
   progress bar, sign-in button, and answer text all key off --accent/
   --accent-2/--accent-rgb, so this one override re-themes everything. */
body[data-provider="aws"] {
  --accent: #ff9900;
  --accent-2: #ff6600;
  --accent-rgb: 255, 153, 0;
}

body[data-provider="azure"] {
  --accent: #50e6ff;
  --accent-2: #0078d4;
  --accent-rgb: 0, 120, 212;
}

body[data-provider="oci"] {
  --accent: #f2694b;
  --accent-2: #c74634;
  --accent-rgb: 199, 70, 52;
}

/* Explicit toggle, not the OS's prefers-color-scheme — dark stays the
   default for every visitor regardless of their system setting, and only
   flips when someone clicks the sun/moon button (app.js persists the
   choice and stamps it here as early as possible to avoid a flash). Same
   relative depth relationship as the dark palette, just inverted: the
   page canvas (--bg) reads slightly deeper than the cards (--panel)
   sitting on it, so cards still visually "lift" off the page. */
:root[data-theme="light"] {
  --bg: #e8ecf3;
  --bg-alt: #f4f7fb;
  --panel: #ffffff;
  --panel-border: #d7deea;
  --text: #16202f;
  /* Aliased to --text — see the dark theme's --muted comment above. */
  --muted: var(--text);
  --good: #16a34a;
  --good-dim: #15803d;
  --bad: #dc2626;
  --bad-dim: #b91c1c;
  /* Default (pre-selection) accent, darkened for legible text on a white
     card — the dark-mode pair was tuned to glow on a near-black panel
     and reads as washed-out on white at the same lightness. */
  --accent: #0284c7;
  --accent-2: #4338ca;
  --accent-rgb: 2, 132, 199;
}

/* Same reasoning per provider — especially Azure's pale cyan, which is
   nearly invisible as text on white despite working well on dark panels.
   AWS's true brand orange (#FF9900) only reaches ~2.1:1 against white —
   well under any WCAG text threshold — so some darkening is required no
   matter what; this value trades some of the extra darkening the original
   #c2660a had (~4.0:1, itself already short of the 4.5:1 small-text
   threshold, just less so) for a shade closer to the real brand color,
   landing around 3.4:1 — at/above the 3:1 floor used for UI components
   and large text. */
:root[data-theme="light"] body[data-provider="aws"] {
  --accent: #dd6b10;
  --accent-2: #b3430a;
  --accent-rgb: 221, 107, 16;
}

:root[data-theme="light"] body[data-provider="azure"] {
  --accent: #0078d4;
  --accent-2: #004e8c;
  --accent-rgb: 0, 120, 212;
}

:root[data-theme="light"] body[data-provider="oci"] {
  --accent: #c1432b;
  --accent-2: #8f1f1f;
  --accent-rgb: 193, 67, 43;
}

* { box-sizing: border-box; }

/* Fixed behind everything (z-index puts it below body's own normal-flow
   content, but still above body's background-color/gradient — see the
   note in index.html). The animation itself — particles drifting and
   linking up when close — is entirely bg-particles.js; this is just the
   canvas's own sizing/stacking, plus a same-size fallback for the
   instant before that script's first resize() runs. */
.bg-texture {
  position: fixed;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
}

#theme-toggle {
  position: fixed;
  top: 1rem;
  right: 1rem;
  z-index: 20;
  width: 2.25rem;
  height: 2.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 999px;
  color: var(--muted);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.4s ease;
}

#theme-toggle:hover { border-color: var(--accent); color: var(--text); }
#theme-toggle svg { width: 1.1rem; height: 1.1rem; }

/* Sun while dark (click to let light in), moon while light (click to go
   dark) — the icon shown is the theme a click will switch you to. */
.icon-moon { display: none; }
:root[data-theme="light"] .icon-sun { display: none; }
:root[data-theme="light"] .icon-moon { display: block; }

body {
  margin: 0;
  /* The card's glow (::before, below) bleeds a bit past its own edges on
     narrow viewports — this keeps that from ever creating a horizontal
     scrollbar instead of shrinking the glow itself. */
  overflow-x: hidden;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  background:
    radial-gradient(1200px 600px at 50% -10%, rgba(var(--accent-rgb), 0.12), transparent),
    radial-gradient(700px 500px at 105% 15%, rgba(var(--accent-rgb), 0.08), transparent),
    radial-gradient(600px 450px at -5% 75%, rgba(var(--accent-rgb), 0.06), transparent),
    var(--bg);
  color: var(--text);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  -webkit-font-smoothing: antialiased;
  transition: background 0.4s ease;
}

header {
  width: 100%;
  max-width: 680px;
  padding: 1.5rem 1.25rem 1rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.4rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.7rem;
}

.brand-mark { flex-shrink: 0; }

/* The logo mark's gradient (shared by the header icon and the sign-in
   gate's larger icon via the same #mark-g def) — re-themed per provider
   just like the brand text and progress bar. */
.mark-stop-1 { stop-color: var(--accent); transition: stop-color 0.4s ease; }
.mark-stop-2 { stop-color: var(--accent-2); transition: stop-color 0.4s ease; }

.brand-name {
  font-family: "Manrope", sans-serif;
  font-weight: 800;
  font-size: 0.95rem;
  letter-spacing: -0.01em;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  transition: background 0.4s ease;
}

h1 {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text);
  margin: 0.1rem 0 0;
}

#header-right {
  display: flex;
  align-items: center;
  gap: 1rem;
  /* Lines up with the cert title above it (past the icon), rather than
     the header's own left edge — the icon's width plus its gap to
     .brand-text, matching the .brand rule below exactly. */
  margin-left: calc(30px + 0.7rem);
}

#stats {
  color: var(--muted);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  /* Sits in #deck-toolbar, alongside the deck position and reset button
     — pushed to the row's far right so the position/reset action stay
     grouped on the left, aligned with the filters above them. */
  margin-left: auto;
}

#auth-status { font-size: 0.85rem; color: var(--muted); }

.auth-link {
  color: var(--accent);
  cursor: pointer;
  background: none;
  border: none;
  font-size: 0.85rem;
  font-weight: 500;
  padding: 0;
  font-family: inherit;
}

.auth-link:hover { text-decoration: underline; }

.reset-progress-wrap { position: relative; }

.btn-reset {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  padding: 0.4rem 0.7rem;
  font-family: inherit;
  font-size: 0.8rem;
  font-weight: 500;
  cursor: pointer;
  transition: border-color 0.15s ease;
}

.btn-reset:hover { border-color: var(--accent); }

.reset-menu {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  min-width: 160px;
  background: linear-gradient(180deg, var(--panel), var(--bg-alt));
  border: 1px solid var(--panel-border);
  border-radius: 10px;
  box-shadow: 0 16px 40px -20px rgba(0, 0, 0, 0.7);
  padding: 0.3rem;
  gap: 0.1rem;
}

.reset-menu button {
  background: none;
  border: none;
  color: var(--text);
  font-family: inherit;
  font-size: 0.85rem;
  text-align: left;
  padding: 0.5rem 0.6rem;
  border-radius: 6px;
  cursor: pointer;
}

.reset-menu button:hover { background: var(--panel-border); }

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  background: rgba(0, 0, 0, 0.55);
}

.modal-card {
  position: relative;
  width: 100%;
  max-width: 400px;
  max-height: calc(100vh - 2.5rem);
  overflow-y: auto;
  background: linear-gradient(180deg, var(--panel), var(--bg-alt));
  border: 1px solid var(--panel-border);
  border-radius: var(--radius);
  padding: 1.75rem;
  box-shadow: 0 20px 60px -20px rgba(0, 0, 0, 0.6);
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

.modal-card h2 {
  font-family: "Manrope", sans-serif;
  font-size: 1.15rem;
  margin: 0 1.5rem 0 0;
}

.modal-card p { margin: 0; line-height: 1.5; font-size: 0.9rem; color: var(--muted); }

/* The on/off status line is the modal's headline fact, not supporting
   detail — full-contrast text instead of the muted tone every other
   paragraph here uses. */
.modal-card p.security-status { color: var(--text); }

/* Enable/Turn off/Back are the modal's one action, not part of a form
   row (unlike the verify step's input+button pair) — center them under
   the text instead of leaving them stuck at the left edge. */
#security-body > .btn-reset {
  display: block;
  margin: 0 auto;
}

.modal-close {
  position: absolute;
  top: 0.9rem;
  right: 0.9rem;
  background: none;
  border: none;
  color: var(--muted);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  padding: 0.2rem;
}

.modal-close:hover { color: var(--text); }

.security-loading { color: var(--muted); font-size: 0.9rem; }

.security-error { color: var(--bad); font-size: 0.85rem; }

/* The QR itself stays fixed black-on-white (see mfa.js) so it scans
   reliably in either theme — this is just its mount/padding, not a
   recolor of the code. */
.mfa-qr {
  align-self: center;
  width: 200px;
  padding: 0.75rem;
  background: white;
  border-radius: 10px;
}

.mfa-qr svg { display: block; width: 100%; height: 100%; }

.mfa-secret {
  align-self: center;
  font-family: "SFMono-Regular", Consolas, monospace;
  font-size: 0.9rem;
  letter-spacing: 0.05em;
  background: var(--bg-alt);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  padding: 0.5rem 0.8rem;
  word-break: break-all;
  text-align: center;
}

.modal-card label { font-size: 0.85rem; color: var(--muted); }

.mfa-verify-row { display: flex; gap: 0.6rem; }

.mfa-verify-row input {
  flex: 1;
  min-width: 0;
  background: var(--bg-alt);
  color: var(--text);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  padding: 0.5rem 0.7rem;
  font-family: inherit;
  font-size: 1rem;
  letter-spacing: 0.1em;
}

.mfa-verify-row input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.mfa-verify-row button { flex-shrink: 0; }

main {
  width: 100%;
  max-width: 680px;
  padding: 0.5rem 1.25rem 2rem;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

.gate {
  width: 100%;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1.25rem 6rem;
}

.gate-card {
  background: linear-gradient(180deg, var(--panel), var(--bg-alt));
  border: 1px solid var(--panel-border);
  border-radius: 20px;
  padding: 3rem 2.5rem;
  max-width: 380px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  text-align: center;
  box-shadow: 0 20px 60px -20px rgba(0, 0, 0, 0.6);
}

.gate-card h2 {
  font-family: "Manrope", sans-serif;
  font-size: 1.3rem;
  margin: 0.3rem 0 0;
}

.gate-card p {
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.5;
  margin: 0 0 0.5rem;
}

.gate-chips {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  justify-content: center;
}

/* Literal per-provider hex, not the live --accent variable — this page
   shows before any cert is picked, so there's no single active provider
   to key off; these three chips are meant to stay visible side by side
   regardless of theme or which cert gets chosen next. */
.gate-chip {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 0.3rem 0.65rem;
  border-radius: 999px;
  border: 1px solid;
}

.gate-chip--aws { color: #ff9900; border-color: rgba(255, 153, 0, 0.35); background: rgba(255, 153, 0, 0.08); }
.gate-chip--azure { color: #50e6ff; border-color: rgba(80, 230, 255, 0.35); background: rgba(80, 230, 255, 0.08); }
.gate-chip--oci { color: #f2694b; border-color: rgba(242, 105, 75, 0.35); background: rgba(242, 105, 75, 0.08); }

/* Same darkened-for-white-backgrounds treatment as the live per-provider
   theme overrides above (Azure's pale cyan especially needs it). */
:root[data-theme="light"] .gate-chip--aws { color: #c2660a; border-color: rgba(194, 102, 10, 0.35); background: rgba(194, 102, 10, 0.08); }
:root[data-theme="light"] .gate-chip--azure { color: #0078d4; border-color: rgba(0, 120, 212, 0.35); background: rgba(0, 120, 212, 0.08); }
:root[data-theme="light"] .gate-chip--oci { color: #c1432b; border-color: rgba(193, 67, 43, 0.35); background: rgba(193, 67, 43, 0.08); }

.gate-substat {
  font-size: 0.78rem;
  margin: -0.4rem 0 0.3rem;
  font-variant-numeric: tabular-nums;
}

/* Study vs. Test Mode — a plain two-way segmented control, always visible
   (not tucked inside #study-view) so switching back from an active exam
   or the results screen is always one click away. */
.mode-toggle {
  display: inline-flex;
  align-self: flex-start;
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 999px;
  padding: 0.2rem;
  gap: 0.2rem;
}

.mode-toggle-btn {
  background: none;
  border: none;
  color: var(--muted);
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}

.mode-toggle-btn:hover:not(.active) { color: var(--text); }

.mode-toggle-btn.active {
  color: white;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
}

.mode-toggle-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Pulled up against the toggle above it (same "closer than the layout's
   own gap" trick as .choice-select-hint/.gate-substat) so it reads as the
   toggle's own caption, not a separate paragraph floating in the flow. */
.mode-toggle-note {
  margin: -0.6rem 0 0;
  font-size: 0.78rem;
  color: var(--muted);
  line-height: 1.4;
}

#study-view {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

#controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1rem;
  color: var(--muted);
  font-size: 0.85rem;
}

.control-group {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/* A shared fixed-width label slot — sized to "Certification", the widest
   of the three — so the select/button immediately after it lines up at
   the same x on every row, regardless of that row's own label length.
   The labels/count stay put on the left; only what comes after them
   shifts to a common column. */
.control-group label,
#deck-position {
  min-width: 6.5rem;
}

select {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  padding: 0.4rem 0.6rem;
  font-family: inherit;
  font-size: 0.85rem;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%238b96ad'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.6rem center;
  padding-right: 1.6rem;
}

select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Its own row, always — a long domain name in the row above must never
   push this (or the reset button beside it) around; it sits between the
   filters and the progress bar no matter how the filters wrap. */
#deck-toolbar {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--muted);
  font-size: 0.85rem;
}

#deck-position {
  font-variant-numeric: tabular-nums;
}

.progress-track {
  height: 4px;
  background: var(--panel-border);
  border-radius: 999px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: width 0.25s ease, background 0.4s ease;
}

.card {
  position: relative;
  min-height: 260px;
  cursor: pointer;
  outline: none;
  perspective: 1400px;
  -webkit-perspective: 1400px;
  /* app.js sets --tilt-x/--tilt-y on pointer move (desktop, fine-pointer
     only) for a subtle tilt-toward-cursor; they default to 0 everywhere
     else, so this is a no-op until JS opts a device in. Its own fast
     transition is independent of .card-inner's slower flip transition
     below — nested transforms, so both apply at once without fighting
     over one shared duration. */
  transform: perspective(1000px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg));
  transition: transform 0.15s ease-out;
}

/* The tilt fit a card you flip over; it doesn't fit one you're trying to
   read and click precise option rows inside — off entirely in choice
   mode (app.js also stops updating --tilt-x/--tilt-y for these cards,
   so this isn't fighting a value that keeps getting reapplied). */
.card.mode-choice {
  transform: none;
}

/* A soft provider-colored glow behind the card — reinforces the brand
   color more than the 1px border alone, and gives the card some lift
   off the page. Sits behind .card-inner purely by DOM order (it's a
   ::before, so it paints first) — no z-index needed.

   inset is a percentage of the card's own size, which was tuned against
   a short flashcard — a multiple-choice card with several option rows
   is much taller, so the same percentage bleeds a lot more glow along
   its height. Rather than re-tune one glow size to fit two very
   different card shapes, it's just off in choice mode — the option
   rows carry plenty of their own visual interest already. */
.card:not(.mode-choice)::before {
  content: "";
  position: absolute;
  inset: -16% -8%;
  background: radial-gradient(closest-side, rgba(var(--accent-rgb), 0.22), transparent 70%);
  filter: blur(32px);
  transition: background 0.4s ease;
  pointer-events: none;
}

/* Sits outside .card-inner (the piece that actually rotates), so it stays
   put — same corner, no flip animation — regardless of which face is
   showing, and survives on top of both. */
#btn-flag {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  z-index: 5;
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease;
}

#btn-flag svg {
  width: 1.15rem;
  height: 1.15rem;
  fill: none;
  transition: fill 0.15s ease;
}

#btn-flag:hover { color: var(--accent); }

/* Amber regardless of provider theme, so "flagged" reads consistently
   rather than blending into whichever accent color happens to be active. */
#btn-flag.flagged { color: #f5a623; }
#btn-flag.flagged svg { fill: currentColor; }

.card-inner {
  position: relative;
  width: 100%;
  display: grid;
  grid-template-areas: "face";
  transition: transform 0.55s cubic-bezier(0.4, 0.15, 0.15, 1);
  transform-style: preserve-3d;
  -webkit-transform-style: preserve-3d;
}

.card.flipped .card-inner {
  /* The slight scale rides the same transition as the rotation — a small
     lift while it turns, not a separate effect to keep in sync. */
  transform: rotateY(180deg) scale(1.02);
  -webkit-transform: rotateY(180deg) scale(1.02);
}

/* Both faces share the same grid area (instead of being absolutely
   positioned) so the card's height auto-grows to fit whichever face has
   more content — a long answer is never clipped or scrolled, the card
   is simply taller. backface-visibility still only reliably hides a
   face in Safari when the rotating element has no overflow/border-
   radius/box-shadow combo on itself — those stay on this static shell. */
.card-face {
  grid-area: face;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  background: linear-gradient(180deg, var(--panel), var(--bg-alt));
  border-radius: var(--radius);
  border: 1px solid var(--panel-border);
  box-shadow: 0 16px 40px -24px rgba(0, 0, 0, 0.7);
  transition: border-color 0.15s ease, box-shadow 0.55s ease;
}

/* Deeper shadow plus a whisper of the provider accent as rim light on
   the answer side — reads as the card lifting further as it turns,
   riding the same duration as the rotation instead of a separate cue. */
.card.flipped .card-face {
  box-shadow: 0 28px 60px -20px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(var(--accent-rgb), 0.1);
}

.card-face-content {
  padding: 2.25rem 1.75rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.1rem;
}

.card:hover .card-face { border-color: #33456f; }
.card:focus .card-face { border-color: var(--accent); }

.card-back {
  transform: rotateY(180deg);
  -webkit-transform: rotateY(180deg);
}

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

.card-domain {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--accent);
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  transition: color 0.4s ease;
}

/* currentColor, inherited from .card-domain's own `color` — this is
   plain CSS inheritance, not an SVG paint server referenced via url(),
   so (unlike the logo gradient) it repaints correctly on its own when
   --accent changes and needs no refreshMarkGradient()-style workaround. */
.domain-icon {
  width: 0.85rem;
  height: 0.85rem;
  flex-shrink: 0;
}

.card-question {
  font-size: 1.2rem;
  font-weight: 500;
  line-height: 1.55;
}

.card-answer {
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1.55;
}

.card-explanation {
  font-size: 0.88rem;
  color: var(--muted);
  line-height: 1.6;
}

.card-source-link {
  align-self: flex-start;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
}

.card-source-link:hover { text-decoration: underline; }

/* Multiple-choice/multiple-response — a plain option list rather than a
   flip. .card-choice is a sibling of .card-inner inside #card and shares
   its sizing/background/shadow via the .card-face rule both belong to;
   only what's specific to the options list lives here. */
.choice-select-hint {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: -0.6rem;
}

.choice-options {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.choice-option {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--panel-border);
  border-radius: 10px;
  background: var(--bg-alt);
  cursor: pointer;
  font-size: 0.92rem;
  line-height: 1.45;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.choice-option:hover { border-color: var(--accent); }

.choice-option-marker {
  flex-shrink: 0;
  width: 1.1rem;
  height: 1.1rem;
  margin-top: 0.15rem;
  border: 2px solid var(--muted);
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

.choice-option-marker.marker-radio { border-radius: 999px; }
.choice-option-marker.marker-checkbox { border-radius: 4px; }

.choice-option.selected {
  border-color: var(--accent);
  background: linear-gradient(180deg, rgba(var(--accent-rgb), 0.1), var(--bg-alt));
}

.choice-option.selected .choice-option-marker {
  border-color: var(--accent);
  background: var(--accent);
}

/* Set after Submit — options stop responding to clicks, and the answer
   key is revealed: every correct option turns green (even one the user
   didn't pick, so a missed multiple-response option is still visible),
   and anything wrongly picked turns red. */
.choice-option.correct-answer {
  border-color: var(--good);
  background: linear-gradient(180deg, rgba(34, 197, 94, 0.12), var(--bg-alt));
  cursor: default;
}

.choice-option.correct-answer .choice-option-marker {
  border-color: var(--good);
  background: var(--good);
}

.choice-option.wrong-answer {
  border-color: var(--bad);
  background: linear-gradient(180deg, rgba(244, 63, 94, 0.12), var(--bg-alt));
  cursor: default;
}

.choice-option.wrong-answer .choice-option-marker {
  border-color: var(--bad);
  background: var(--bad);
}

/* Matching cards (Study Mode's #card-matching and Test Mode's
   #test-question-matching) — a prompt list, each paired with a <select>
   of every response, instead of the radio/checkbox rows choice cards use.
   A dropdown per prompt rather than drag-and-drop: same information,
   far less code, and works cleanly on mobile with no drag library. */
.matching-rows {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.matching-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--panel-border);
  border-radius: 10px;
  background: var(--bg-alt);
  font-size: 0.92rem;
  line-height: 1.45;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.matching-row-prompt { flex: 1; }

.matching-row select {
  flex-shrink: 0;
  max-width: 55%;
}

/* Set after Submit — same green/red reveal language as
   .choice-option.correct-answer/.wrong-answer. .review is the
   non-interactive variant used on Test Mode's results screen, where the
   select is replaced by plain text (there's nothing left to change). */
.matching-row.correct {
  border-color: var(--good);
  background: linear-gradient(180deg, rgba(34, 197, 94, 0.12), var(--bg-alt));
}

.matching-row.incorrect {
  border-color: var(--bad);
  background: linear-gradient(180deg, rgba(244, 63, 94, 0.12), var(--bg-alt));
}

.matching-row-response {
  flex-shrink: 0;
  max-width: 55%;
  text-align: right;
  font-weight: 600;
}

.matching-row.correct .matching-row-response { color: var(--good); }
.matching-row.incorrect .matching-row-response { color: var(--bad); }

.choice-actions { display: flex; }

.btn-choice-submit {
  flex: 1;
  padding: 0.85rem;
  border-radius: 10px;
  font-size: 0.95rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  border: none;
  color: white;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  transition: filter 0.15s ease, opacity 0.15s ease, transform 0.1s ease;
}

.btn-choice-submit:active:not(:disabled) { transform: scale(0.98); }
.btn-choice-submit:hover:not(:disabled) { filter: brightness(1.08); }

.btn-choice-submit:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Post-answer state: the same button, now just advancing to the next
   question. Deliberately outline rather than filled so "commit" (Submit
   answer) and "move on" (Next question) don't look identical — the same
   distinction Test Mode draws between "Submit exam" and its nav buttons. */
.btn-choice-submit.is-advance {
  background: transparent;
  color: var(--accent);
  border: 2px solid var(--accent);
}
.btn-choice-submit.is-advance:hover:not(:disabled) {
  background: rgba(var(--accent-rgb), 0.09);
  filter: none;
}

.hint {
  font-size: 0.72rem;
  color: var(--muted);
  text-align: center;
  margin-top: auto;
  letter-spacing: 0.01em;
}

.hidden { display: none !important; }

.grading {
  display: flex;
  gap: 0.75rem;
}

.btn {
  flex: 1;
  padding: 0.8rem;
  border-radius: 10px;
  font-size: 0.95rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  transition: transform 0.1s ease, filter 0.15s ease, border-color 0.15s ease,
    background-color 0.15s ease;
}

.btn:active { transform: scale(0.98); }

/* Grading buttons follow the same dark-panel-plus-colored-accent language
   as the rest of the UI (card faces, selects) instead of a bright solid
   fill — the semantic color lives in the border/text/glow, not a block
   of saturated color. */
.btn-correct,
.btn-incorrect {
  background: linear-gradient(180deg, var(--panel), var(--bg-alt));
  border: 1px solid var(--panel-border);
}

.btn-correct { color: var(--good); }
.btn-incorrect { color: var(--bad); }

.btn-correct:hover {
  border-color: var(--good);
  background: linear-gradient(180deg, rgba(34, 197, 94, 0.12), var(--bg-alt));
  box-shadow: 0 8px 20px -12px rgba(34, 197, 94, 0.5);
}

.btn-incorrect:hover {
  border-color: var(--bad);
  background: linear-gradient(180deg, rgba(244, 63, 94, 0.12), var(--bg-alt));
  box-shadow: 0 8px 20px -12px rgba(244, 63, 94, 0.5);
}

.btn-signin {
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  border: none;
  color: white;
  padding: 0.85rem 2.5rem;
  box-shadow: 0 8px 24px -8px rgba(var(--accent-rgb), 0.5);
}

.btn-signin:hover { filter: brightness(1.08); }

/* --- Test Mode ------------------------------------------------------- */

#test-setup-form {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

#test-setup-form > label:not(.test-setup-timed-row) {
  font-size: 0.85rem;
  color: var(--muted);
}

.test-setup-timed-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  color: var(--text);
  cursor: pointer;
}

.test-setup-timed-row input {
  width: 1.1rem;
  height: 1.1rem;
  accent-color: var(--accent);
}

.modal-card p.test-setup-note {
  font-size: 0.8rem;
  color: var(--muted);
  margin: -0.3rem 0 0.3rem;
}

#test-active {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

.test-timer-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 10px;
  padding: 0.6rem 0.9rem;
}

.test-timer-display {
  font-variant-numeric: tabular-nums;
  font-size: 1.1rem;
  font-weight: 700;
  font-family: "SFMono-Regular", Consolas, monospace;
  color: var(--text);
}

/* Under 5 minutes remaining — a clear, color-only urgency cue, no motion. */
.test-timer-display.low-time { color: var(--bad); }

.test-palette {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.test-palette-btn {
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 8px;
  border: 1px solid var(--panel-border);
  background: var(--bg-alt);
  color: var(--muted);
  font-family: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}

.test-palette-btn:hover { border-color: var(--accent); }

.test-palette-btn.current {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px rgba(var(--accent-rgb), 0.3);
}

/* Solid cert-brand fill — the same accent-gradient + white-text treatment
   used for .mode-toggle-btn.active elsewhere, so "answered" reads as an
   unmistakable filled square and stays legible against every cert's
   accent pair (each already tuned for white text). */
.test-palette-btn.answered {
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  border-color: var(--accent);
  color: white;
}

/* Hard diagonal half-split (not repeating stripes) — a repeating pattern
   at this button size dilutes its own color via anti-aliasing on each
   diagonal edge plus the eye's optical mixing of fine repeated patterns,
   so it reads washed out next to .answered's unbroken solid fill. Two
   large, uninterrupted halves have neither problem — each half stays
   full-saturation. The filled half runs the SAME accent -> accent-2
   gradient .answered uses (not a flat --accent, and not amber) — a flat
   single tone reads lighter than .answered's gradient even when the
   starting color is identical, since .answered's blend trends toward the
   meaningfully darker accent-2. Amber is kept only on the border, as a
   secondary "this is flagged" cue independent of fill color; bottom half
   reveals the real --bg-alt panel color.
   Deliberately a single selector, not also `.answered.flagged` — flagged
   is one visual state regardless of answered status, so it wins outright
   (declared after .answered) rather than blending into a third look. */
.test-palette-btn.flagged {
  background-image: linear-gradient(
    135deg,
    var(--accent) 0%,
    var(--accent-2) 50%,
    transparent 50%,
    transparent 100%
  );
  background-color: var(--bg-alt);
  border-color: #f5a623;
  color: var(--text);
}

#test-question-card { position: relative; }

/* Same look/position as Study Mode's #btn-flag — a different id because
   this one operates on the exam-session-local flag set (app.js's
   examSession.flagged), not the persistent per-card progress flag. */
.test-flag-btn {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  z-index: 5;
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease;
}

.test-flag-btn svg {
  width: 1.15rem;
  height: 1.15rem;
  fill: none;
  transition: fill 0.15s ease;
}

.test-flag-btn:hover { color: var(--accent); }
.test-flag-btn.flagged { color: #f5a623; }
.test-flag-btn.flagged svg { fill: currentColor; }

.test-pause-overlay {
  position: absolute;
  inset: 0;
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  background: var(--bg-alt);
  border-radius: var(--radius);
}

.test-pause-overlay p {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text);
}

/* Review-only rendering of .choice-options (see #test-review-list below)
   — every option is already resolved (correct-answer/wrong-answer), so
   neither the pointer cursor nor the hover border make sense here. */
.choice-option.review { cursor: default; }
.choice-option.review:hover { border-color: var(--panel-border); }

.test-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
}

.test-nav-position {
  color: var(--muted);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

/* Question-to-question navigation — commits nothing (answers stay
   editable until Submit exam). Outline treatment reads as "navigate";
   the filled gradient is reserved for #btn-test-submit, the one commit.
   Same visual family as Study Mode's post-answer "Next question →". */
.test-nav-btn {
  background: transparent;
  color: var(--accent);
  border: 2px solid var(--accent);
  border-radius: 8px;
  padding: 0.55rem 1.15rem;
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.15s ease, opacity 0.15s ease;
}
.test-nav-btn:hover:not(:disabled) { background: rgba(var(--accent-rgb), 0.09); }
.test-nav-btn:active:not(:disabled) { transform: scale(0.98); }
.test-nav-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  border-color: var(--panel-border);
  color: var(--muted);
}

.test-submit-btn { width: 100%; }

#test-results {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

.test-score-summary {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  background: linear-gradient(180deg, var(--panel), var(--bg-alt));
  border: 1px solid var(--panel-border);
  border-radius: var(--radius);
  padding: 1.75rem;
  text-align: center;
}

.test-score-pct {
  font-family: "Manrope", sans-serif;
  font-size: 2.6rem;
  font-weight: 800;
  line-height: 1;
}

.test-score-pct.pass { color: var(--good); }
.test-score-pct.fail { color: var(--bad); }

.test-score-detail { color: var(--muted); font-size: 0.9rem; }

.test-score-pass-label {
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.test-score-pass-label.pass { color: var(--good); }
.test-score-pass-label.fail { color: var(--bad); }

.test-domain-breakdown {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.test-domain-row {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.test-domain-row-label {
  display: flex;
  justify-content: space-between;
  font-size: 0.85rem;
  color: var(--text);
}

.test-domain-row-label span:last-child {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.test-domain-bar-track {
  height: 6px;
  background: var(--panel-border);
  border-radius: 999px;
  overflow: hidden;
}

.test-domain-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
}

.test-results-actions { display: flex; gap: 0.75rem; }
.test-results-actions button { flex: 1; }

.test-section-heading {
  font-family: "Manrope", sans-serif;
  font-size: 1rem;
  margin: 0.4rem 0 0;
}

.test-review-list,
.test-history-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.test-review-item {
  background: linear-gradient(180deg, var(--panel), var(--bg-alt));
  border: 1px solid var(--panel-border);
  border-radius: var(--radius);
  padding: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.test-review-item .card-domain { margin-bottom: -0.3rem; }

.test-history-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 10px;
  padding: 0.7rem 0.9rem;
  cursor: pointer;
  transition: border-color 0.15s ease;
}

.test-history-row:hover { border-color: var(--accent); }

.test-history-row-main {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.test-history-row-cert { font-size: 0.85rem; font-weight: 600; }
.test-history-row-meta { font-size: 0.75rem; color: var(--muted); }

.test-history-row-score {
  font-size: 1.1rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.test-history-row-score.pass { color: var(--good); }
.test-history-row-score.fail { color: var(--bad); }

.test-history-empty { color: var(--muted); font-size: 0.85rem; }

/* Studying on a phone during a commute is a primary use case, not a
   fallback — this isn't just patching overflow, it's making the whole
   flow comfortable one-handed: a compact header that never wraps mid-
   word, full-width dropdowns so long cert names are actually readable,
   and more of the screen's height left for the card itself. */
@media (max-width: 600px) {
  header {
    padding: 1.1rem 1.25rem 0.75rem;
  }

  #header-right {
    gap: 0.3rem 1rem;
  }

  .control-group {
    flex-direction: column;
    align-items: stretch;
    width: 100%;
    gap: 0.25rem;
  }

  .control-group select { width: 100%; }

  /* The fixed alignment slot only matters when a label sits beside its
     select on one line, as on desktop — here labels stack above their
     selects instead, so let the toolbar wrap and reclaim that space. */
  .control-group label { min-width: 0; }

  #deck-toolbar { flex-wrap: wrap; row-gap: 0.4rem; }

  #deck-position { min-width: 0; }

  #stats { margin-left: 0; width: 100%; }

  .card-face-content {
    padding: 1.6rem 1.25rem;
    gap: 0.9rem;
  }

  .card-question { font-size: 1.1rem; }
  .card-answer { font-size: 1.05rem; }

  .btn { min-height: 48px; }

  .test-palette-btn { width: 2.4rem; height: 2.4rem; }

  .test-score-pct { font-size: 2.1rem; }

  .test-results-actions { flex-direction: column; }

  .test-history-row { flex-wrap: wrap; }

  .matching-row {
    flex-direction: column;
    align-items: stretch;
  }

  .matching-row select,
  .matching-row-response {
    max-width: 100%;
    text-align: left;
  }
}
