:root {
  color-scheme: light;

  /* ---- Design tokens ------------------------------------------------------------------- */
  --color-primary: #5B6EE8;
  --color-primary-hover: #4A5DD9;
  --color-primary-active: #3E50C4;
  --color-primary-soft: #EEF0FF;
  --color-bg: #F5F6FB;
  --color-surface: #FFFFFF;
  --color-text: #1B1D29;
  --color-text-muted: #656A7D;
  --color-text-faint: #9599AB;
  --color-border: #E6E8F2;
  --color-border-strong: #D4D7E6;
  --color-danger: #E5484D;
  --color-danger-soft: #FDECEC;
  --color-success: #21A366;
  --color-flag: #C9820A;
  --color-flag-soft: #FBF0DD;
  --color-success-soft: #E7F8EF;

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-pill: 999px;

  --shadow-xs: 0 1px 2px rgba(23, 26, 55, 0.05);
  --shadow-sm: 0 2px 6px rgba(23, 26, 55, 0.07);
  --shadow-md: 0 8px 24px rgba(23, 26, 55, 0.10);
  --shadow-lg: 0 16px 40px rgba(23, 26, 55, 0.18);

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;

  --transition-fast: 0.12s ease;
  --transition-base: 0.18s ease;
}

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--color-bg);
  color: var(--color-text);
  margin: 0;
  padding: 24px 20px 48px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

#app {
  max-width: 640px;
  margin: 0 auto;
  transition: max-width var(--transition-base);
}

#app.wide {
  max-width: 960px;
}

#lang-switcher-wrap {
  position: fixed;
  top: 16px;
  right: 16px;
  z-index: 100;
}

#lang-switcher {
  width: auto;
  /* Extra right padding so the browser's own native dropdown arrow (its position isn't
     controlled by padding, just the fixed inset it always renders at) gets real breathing room
     from the edge - a full pill radius crowded it visually, so this uses the same moderate
     radius as other controls instead. */
  padding: 7px 34px 7px 14px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border-strong);
  font-size: 13px;
  font-weight: 500;
  background: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
  box-shadow: var(--shadow-xs);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

#lang-switcher:hover {
  border-color: var(--color-border-strong);
  box-shadow: var(--shadow-sm);
}

/* ---- Typography ------------------------------------------------------------------------- */

h1 {
  font-size: 23px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 var(--space-3);
}

h2 {
  font-size: 19px;
  font-weight: 700;
  margin: 0 0 var(--space-2);
}

h3 {
  font-size: 16px;
  font-weight: 700;
  margin: 0 0 var(--space-3);
  letter-spacing: -0.005em;
}

p {
  margin: 0 0 var(--space-2);
}

.muted {
  color: var(--color-text-muted);
  font-size: 14px;
}

.ok {
  color: var(--color-success);
  font-weight: 600;
}

.bad {
  color: var(--color-danger);
  font-weight: 600;
}

.error {
  color: var(--color-danger);
  font-size: 14px;
}

/* ---- Surfaces ----------------------------------------------------------------------------- */

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 22px;
  margin: var(--space-4) 0;
  box-shadow: var(--shadow-sm);
}

.card h3 {
  padding-bottom: var(--space-3);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
}

/* a <details class="card"> whose own h3 is the <summary> (e.g. the group statistics' collapsible
   member list) - same header look as .card h3 above, plus a small disclosure triangle. State is
   never remembered (no id, nothing reads [open] back) - it's just always open again on re-render. */
.card > summary {
  cursor: pointer;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.005em;
  padding-bottom: var(--space-3);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
  list-style: none;
}
.card > summary::-webkit-details-marker { display: none; }
.card > summary::before { content: '▸'; display: inline-block; width: 1em; color: var(--color-text-muted); }
.card[open] > summary::before { content: '▾'; }

.auth-card {
  max-width: 360px;
  margin: 72px auto 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 32px 28px;
  box-shadow: var(--shadow-md);
  text-align: center;
}

.auth-card h1 {
  font-size: 24px;
}

.auth-card label {
  display: block;
  text-align: left;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
  margin: var(--space-3) 0 var(--space-1);
}

/* ---- Form controls ------------------------------------------------------------------------ */

label {
  color: var(--color-text);
}

input[type=text],
input[type=email],
input[type=password],
input[type=number],
input[type=search],
textarea,
select {
  width: 100%;
  box-sizing: border-box;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: 15px;
  font-family: inherit;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

/* Safari/Chrome give type=search its own native chrome (full pill shape, baked-in cancel button)
   that ignores the border/radius above unless this is turned off */
input[type=search] {
  -webkit-appearance: none;
  appearance: none;
}

input[type=text]:hover,
input[type=email]:hover,
input[type=password]:hover,
input[type=number]:hover,
input[type=search]:hover,
textarea:hover,
select:hover {
  border-color: var(--color-text-faint);
}

input[type=text]:focus,
input[type=email]:focus,
input[type=password]:focus,
input[type=number]:focus,
input[type=search]:focus,
textarea:focus,
select:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-soft);
}

/* the browser's own autofill highlight (a yellow fill/border Chrome and Firefox draw themselves, outside
   our own border/box-shadow styling above) - overridden to our normal surface colour so it doesn't clash;
   the 9999s transition is the standard trick to stop Chrome's own colour from flashing in first */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:autofill {
  border-color: var(--color-border-strong);
  -webkit-text-fill-color: var(--color-text);
  -webkit-box-shadow: 0 0 0 1000px var(--color-surface) inset;
  box-shadow: 0 0 0 1000px var(--color-surface) inset;
  transition: background-color 9999s ease-in-out 0s;
}

input:-webkit-autofill:focus {
  border-color: var(--color-primary);
  -webkit-box-shadow: 0 0 0 1000px var(--color-surface) inset, 0 0 0 3px var(--color-primary-soft);
  box-shadow: 0 0 0 1000px var(--color-surface) inset, 0 0 0 3px var(--color-primary-soft);
}

textarea {
  min-height: 70px;
  resize: vertical;
}

select {
  cursor: pointer;
}

::placeholder {
  color: var(--color-text-faint);
}

:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* ---- Buttons ------------------------------------------------------------------------------ */

button {
  padding: 10px 18px;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--color-primary);
  color: #fff;
  font-size: 15px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  margin-top: 10px;
  transition: background-color var(--transition-fast), box-shadow var(--transition-fast), transform var(--transition-fast);
}

button:hover:not(:disabled) {
  background: var(--color-primary-hover);
}

button:active:not(:disabled) {
  background: var(--color-primary-active);
  transform: translateY(1px);
}

button:disabled {
  opacity: 0.5;
  cursor: default;
}

button.secondary {
  background: transparent;
  color: var(--color-primary);
  border: 1px solid var(--color-border-strong);
}

button.secondary:hover:not(:disabled) {
  background: var(--color-primary-soft);
  border-color: var(--color-primary);
}

button.secondary:active:not(:disabled) {
  background: var(--color-primary-soft);
}

/* ---- Topbar + menus ------------------------------------------------------------------------ */

.topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
  flex-wrap: wrap;
}

/* Direct-child combinator, deliberately not ".topbar button" - the icon-btn circles further down
   the tree (.topbar-menus > .menu-wrap > button.icon-btn) are also <button> elements, and the old
   broader selector's extra type-selector specificity was beating .icon-btn's own padding:0,
   squeezing the 38x38 circle down to a sliver and badly distorting the avatar initial inside it. */
.topbar > button {
  margin: 0 0 0 10px;
  padding: 7px 14px;
  font-size: 13px;
}

.topbar-menus {
  display: flex;
  gap: 10px;
}

.menu-wrap {
  position: relative;
}

.icon-btn {
  margin: 0;
  padding: 0;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-text);
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-xs);
  transition: box-shadow var(--transition-fast), border-color var(--transition-fast);
}

.icon-btn:hover:not(:disabled) {
  background: var(--color-surface);
  border-color: var(--color-border-strong);
  box-shadow: var(--shadow-sm);
}

.avatar-circle {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: var(--color-primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 700;
}

.menu-dropdown {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  min-width: 200px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: 6px;
  z-index: 50;
  animation: menu-pop 0.14s ease;
}

@keyframes menu-pop {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}

.menu-user-name {
  margin: 6px 10px 8px;
  font-size: 13px;
  color: var(--color-text-muted);
  font-weight: 700;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--color-border);
}

.menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  color: var(--color-text);
  font-weight: 500;
  margin: 0;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  transition: background-color var(--transition-fast);
}

/* :not(:disabled) isn't about disabled menu items (there are none) - it's there purely to make
   this selector's specificity (class + 2 pseudo-classes) beat the generic
   "button:hover:not(:disabled)" rule above (type + 2 pseudo-classes ties on count, then wins on
   the tie-break of having a type selector) - without it, plain ".menu-item:hover" silently lost
   to the generic rule and every menu item showed the jarring solid-primary button hover instead
   of this subtle tint, even on a plain mouse-over with no click at all. Same reasoning for the
   :active override below (jarring solid fill on click) and the focus-visible one (the default
   *outward* 2px outline had room to spill past the dropdown's own 6px padding and visibly
   overlap its rounded edge). */
.menu-item:hover:not(:disabled) {
  background: var(--color-bg);
}

.menu-item:active:not(:disabled) {
  background: var(--color-primary-soft);
}

.menu-item:focus-visible {
  outline-offset: -2px;
}

/* ---- Small inline controls ------------------------------------------------------------------ */

.checkbox-inline {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  font-size: 14px;
  cursor: pointer;
}

.checkbox-inline input[type=checkbox] {
  width: auto;
  margin: 0;
  accent-color: var(--color-primary);
}

.checkbox-inline.checkbox-disabled {
  opacity: 0.5;
  cursor: default;
}

.attempt-actions {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-4);
}

/* ---- Dashboard quiz cards -------------------------------------------------------------------- */

.quiz-card-link {
  display: block;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  transition: transform var(--transition-base), box-shadow var(--transition-base), border-color var(--transition-base);
}

.quiz-card-link:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
  border-color: var(--color-border-strong);
}

.quiz-card button {
  width: 100%;
}

/* ---- Attempt flow ----------------------------------------------------------------------------- */

.progress-bar {
  height: 7px;
  background: var(--color-border);
  border-radius: var(--radius-pill);
  overflow: hidden;
  margin-bottom: var(--space-2);
}

.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--color-primary), #7C8BFF);
  border-radius: var(--radius-pill);
  transition: width var(--transition-base);
}

.prompt-text {
  font-size: 18px;
  font-weight: 700;
  line-height: 1.4;
  white-space: pre-line; /* a prompt may list things line by line */
}

.prompt-image {
  max-width: 100%;
  border-radius: var(--radius-md);
  margin: var(--space-3) 0;
}

/* admin question editor: the question's current image (above) and the "pick one" gallery after a
   multi-file upload (below) - see js/admin-question-editor.js */
#q-image-current { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.prompt-image-preview { max-width: 220px; max-height: 160px; border-radius: var(--radius-md); display: block; }
.prompt-image-thumb { max-width: 90px; max-height: 70px; border-radius: var(--radius-sm); display: block; }
#q-image-gallery .order-row { align-items: center; }

.option-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 12px 14px;
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-md);
  margin: var(--space-2) 0;
  cursor: pointer;
  transition: border-color var(--transition-fast), background-color var(--transition-fast);
}

.option-row:hover {
  border-color: var(--color-border-strong);
  background: var(--color-bg);
}

.option-row:has(input:checked) {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
}

.option-row input {
  accent-color: var(--color-primary);
  width: auto;
}

.order-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  margin: var(--space-2) 0;
  background: var(--color-surface);
  transition: background-color var(--transition-fast), box-shadow var(--transition-fast);
}

.order-row .order-text {
  flex: 1;
}

.drag-handle {
  color: var(--color-text-faint);
  cursor: grab;
  font-size: 16px;
}

.order-row.sortable-ghost {
  opacity: 0.4;
  background: var(--color-primary-soft);
  border-style: dashed;
  border-color: var(--color-primary);
}

.order-row.sortable-chosen:not(.sortable-ghost) {
  background: var(--color-bg);
  box-shadow: var(--shadow-sm);
}

.order-row.sortable-drag {
  box-shadow: var(--shadow-md);
}

.order-row button {
  margin: 0;
  padding: 5px 12px;
  font-size: 13px;
}

.gap-fill-text {
  font-size: 17px;
  line-height: 2.5;
}

.blank-input {
  display: inline-block;
  width: 140px;
  margin: 0 4px;
}

.blank-select {
  display: inline-block;
  width: auto;
  margin: 0 4px;
}

.matching-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 10px 0;
  border-bottom: 1px solid var(--color-border);
}

.matching-row:last-child {
  border-bottom: none;
}

.highlight-text {
  font-size: 17px;
  line-height: 2.3;
}

.token {
  cursor: pointer;
  padding: 3px 5px;
  border-radius: var(--radius-sm);
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.token:hover {
  background: var(--color-bg);
}

.token.selected {
  background: var(--color-primary);
  color: #fff;
}

/* VIDEO_ESSAY transcript word-marking - two independent layers that can coexist on the same word:
   .important (the group leader's pick for this lesson, admin editor and learner view alike) is a
   background fill; .flagged (a learner's own "I don't know this" click) is an outline on top of
   whatever fill is already there - so a word that is both reads as a filled token with a ring
   around it, rather than needing a third hardcoded colour for "both". */
.token.important {
  background: var(--color-primary-soft);
}

.token.flagged {
  outline: 2px solid var(--color-flag);
  outline-offset: -1px;
}

/* Opt-in (quiz-settings panel) dictionary-meaning popup for a transcript word that turns out to be
   in the shared dictionary - hover (desktop) or long-press (touch) triggered, see
   renderVideoEssay()'s wireWordHints(). Reads
   as a small glossary card, not a generic dark SaaS tooltip: same surface/border/radius language as
   the rest of the app, a primary-coloured headword like a dictionary entry. position: absolute
   against the document (not the token) since the token can be anywhere inside a scrolled page. */
.word-hint-tooltip {
  position: absolute;
  z-index: 500;
  max-width: 260px;
  padding: 10px 12px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  font-size: 14px;
  line-height: 1.4;
  pointer-events: none;
  animation: word-hint-in 0.12s ease-out;
}

@keyframes word-hint-in {
  from { opacity: 0; transform: translateY(2px) scale(0.98); }
  to { opacity: 1; transform: none; }
}

/* A DRAFT word (nobody has reviewed it yet - lib/word_bookmark.php, words_ai_fill etc. all create
   these) still gets shown, unlike ARCHIVED, but with the same danger-soft tint used elsewhere for
   "not yet correct/vetted" (e.g. a wrong-answer highlight) so it reads as unverified at a glance,
   not just via the .badge label next to the lemma (colour alone is not enough on its own). */
.word-hint-tooltip.word-hint-draft {
  background: var(--color-danger-soft);
  border-color: var(--color-danger);
}

.word-hint-draft-label {
  margin: 0 0 4px;
}

/* A homograph pair (e.g. German "das Unternehmen" the noun vs. "unternehmen" the verb) shows as
   several .word-hint-entry blocks in one tooltip, not one box each - a divider between them is
   what actually tells the learner "these are two different meanings", not just more text. */
.word-hint-entry + .word-hint-entry {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--color-border);
}

.word-hint-lemma {
  font-weight: 700;
  color: var(--color-primary);
}

.word-hint-article {
  font-weight: 400;
  font-style: italic;
  color: var(--color-text-muted);
}

.word-hint-meaning {
  margin-top: 2px;
}

.word-hint-example {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--color-border);
  color: var(--color-text-muted);
  font-style: italic;
}

.video-transcript-box {
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  transition: border-color var(--transition-fast);
}

.video-transcript-box:focus-within {
  border-color: var(--color-primary);
}

.video-transcript-box textarea {
  display: block;
  border: none;
  border-radius: 0;
}

.video-transcript-box textarea[hidden] {
  display: none;
}

.video-transcript-box textarea:hover,
.video-transcript-box textarea:focus {
  border: none;
  box-shadow: none;
}

.video-transcript-box .highlight-text {
  padding: 10px 12px;
  margin: 0;
}

/* The transcript's clickable view renders through the same markdown-lite HTML as the WYSIWYG editor
   (mountMarkdownWysiwyg's .v2-md-surface, or the app's base body text in v1) - .highlight-text's own
   font-size/line-height (17px/2.3, tuned elsewhere for comfortable word tap targets in short lists like
   TEXT_HIGHLIGHT) is a different scale than ordinary body text, so the same markdown read differently
   sized and more loosely spaced here than in the editor right above it. Fall back to the ordinary body
   text size/line-height for the transcript specifically, so paragraph breaks, headings etc. look the
   same before and after switching out of edit mode - word padding below is still enough of a tap target. */
#video-transcript-tokens,
#transcript-tokens {
  font-size: inherit;
  line-height: 1.5;
}

/* .token's own horizontal padding (5px each side, tuned for short word-bank lists elsewhere) stacks
   with the ordinary space character already between words - the user wants the transcript to read
   exactly like the WYSIWYG editor above it, so drop the horizontal padding entirely here (vertical
   padding alone is still plenty of a click target on a word's own glyphs). */
#video-transcript-tokens .token,
#transcript-tokens .token {
  padding: 1px 0;
}

.video-transcript-box .link-btn {
  background: none;
  border: 0;
  padding: 0 0 8px;
  margin: 0;
  display: block;
  width: auto;
  font: inherit;
  font-size: 13px;
  color: var(--color-primary);
  cursor: pointer;
}

.video-transcript-box .link-btn:hover {
  text-decoration: underline;
}

.video-essay .video-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--color-text);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: var(--space-3);
}

.video-essay .video-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.video-essay #transcript-body {
  margin-bottom: var(--space-4);
}

#feedback {
  min-height: 24px;
  margin: var(--space-3) 0;
  animation: fade-in var(--transition-base);
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.result-card {
  text-align: center;
  margin-top: 48px;
  padding: 40px 24px;
}

.result-card h1 {
  font-size: 28px;
}

/* ---- Admin shell ------------------------------------------------------------------------------ */

.admin-tabs {
  display: flex;
  gap: 4px;
  margin-bottom: var(--space-5);
  padding: 4px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  overflow-x: auto;
}

.tab-btn {
  background: transparent;
  color: var(--color-text-muted);
  border: none;
  padding: 8px 18px;
  font-size: 14px;
  font-weight: 600;
  margin-top: 0;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.tab-btn:hover:not(.active) {
  background: var(--color-bg);
  color: var(--color-text);
}

.tab-btn.active {
  background: var(--color-primary);
  color: #fff;
}

.tab-btn:active:not(:disabled) {
  background: var(--color-primary-soft);
}

.tab-btn.active:active:not(:disabled) {
  background: var(--color-primary-active);
}

.tab-btn:focus-visible {
  outline-offset: -2px;
}

.table-scroll {
  overflow-x: auto;
  margin: 0 -2px;
}

/* the word list's pager (shown-count + "load more") used to sit flush against the table with no
   breathing room, as just another .filter-row - pushed down and centered so it reads as its own
   footer, not another filter control */
.wl-pager {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-5);
}

.wl-pager .muted {
  margin: 0;
}

/* a small inline "working" indicator for the word list's bulk actions (approve-all/AI-fill/import -
   these can take a while, especially the chunked AI calls, and a merely-disabled button was easy to
   read as "did nothing" rather than "working") */
.spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-right: 8px;
  vertical-align: -2px;
  border: 2px solid var(--color-border);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: wl-spin 0.7s linear infinite;
}

@keyframes wl-spin {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 2.5s; }
}

table {
  width: 100%;
  border-collapse: collapse;
}

th, td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--color-border);
  font-size: 14px;
  white-space: nowrap;
}

/* The group edit page's "Tagok" table: shorter rows (owner's own request, 2026-10-17, tightened
   further same day) - most rows there carry little content (a name, an e-mail, a role), so the
   default row height looked too tall/airy for it. Scoped to this one table, not every table. */
.compact-rows th, .compact-rows td { padding: 6px 12px; }

/* The word list's AI-filled "Jelentés"/"Példamondat" columns can hold a full sentence, not the short
   label/name most other tables' cells have - the shared th/td nowrap above let one long row push the
   whole table (and the page around it) far past the viewport instead of wrapping. table-layout: fixed
   gives every column a share of a fixed total width instead of sizing to its longest cell, so wrapped
   text actually constrains the row height instead of being fought by an ever-growing column. */
.data-table { table-layout: fixed; }
.data-table td { white-space: normal; overflow-wrap: break-word; }
.data-table .dt-meaning { width: 32%; }
.data-table .dt-narrow { width: 8%; }

th {
  color: var(--color-text-muted);
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

tr:hover td {
  background: var(--color-bg);
  transition: background-color var(--transition-fast);
}

.order-row input[type=text],
.order-row input[type=number] {
  width: auto;
  flex: 1;
}

.order-row label {
  white-space: nowrap;
  font-size: 13px;
  color: var(--color-text-muted);
}

.access-columns {
  display: flex;
  gap: var(--space-5);
  flex-wrap: wrap;
  margin: var(--space-3) 0;
}

.access-columns > div {
  flex: 1;
  min-width: 220px;
}

.checkbox-list {
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3);
  margin-top: var(--space-2);
  background: var(--color-bg);
}

.checkbox-list label {
  display: block;
  font-size: 14px;
  padding: 5px 0;
}

.checkbox-list input[type=checkbox] {
  width: auto;
  margin-right: var(--space-2);
  accent-color: var(--color-primary);
}

.kind-tree-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
  margin: var(--space-3) 0 var(--space-1);
}

.category-picker {
  margin: 0 0 var(--space-2);
}

.category-sub-select {
  margin-top: var(--space-2);
}

.category-sub-enter-active,
.category-sub-leave-active {
  transition: opacity var(--transition-base), transform var(--transition-base);
}

.category-sub-enter-from,
.category-sub-leave-to {
  opacity: 0;
  transform: translateY(-4px);
}

/* ---- Toast -------------------------------------------------------------------------------------- */

#toast {
  position: fixed;
  left: 50%;
  bottom: max(28px, env(safe-area-inset-bottom, 0px));
  transform: translate(-50%, 12px);
  background: var(--color-text);
  color: #fff;
  padding: 13px 22px;
  border-radius: var(--radius-md);
  font-size: 14px;
  font-weight: 500;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-base), transform var(--transition-base);
  z-index: 1000;
  max-width: min(90vw, 420px);
}

#toast.visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

#toast.toast-error {
  background: var(--color-danger);
}

#toast.toast-warning {
  background: var(--color-flag);
}

/* ---- Small-viewport polish ------------------------------------------------------------------------ */

@media (max-width: 480px) {
  body {
    padding: 16px 12px 40px;
  }

  .card {
    padding: 16px;
  }

  .auth-card {
    margin-top: 40px;
    padding: 24px 20px;
  }

  #lang-switcher-wrap {
    top: 10px;
    right: 10px;
  }

  .result-card {
    padding: 24px 12px;
  }
}

/* ---- Categories, filter row, assignments, import ------------------------------------------ */

.badge {
  display: inline-block;
  padding: 2px 10px;
  border-radius: var(--radius-pill);
  background: var(--color-primary-soft);
  color: var(--color-primary-active);
  font-size: 12px;
  font-weight: 600;
  margin-right: var(--space-2);
}

.badge-todo { background: var(--color-primary-soft); color: var(--color-primary-active); }
.badge-done { background: var(--color-success-soft); color: var(--color-success); }
.badge-overdue { background: var(--color-danger-soft); color: var(--color-danger); }
.badge-upcoming { background: var(--color-bg); color: var(--color-text-muted); }

.filter-row {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-bottom: var(--space-3);
}
/* a `hidden` .filter-row (web/js/dictionary.js's own language-picker row, shown only once a
   learner's bookmarks span more than one language) would otherwise still render: the `[hidden]`
   user-agent default (display: none) and this class's own `display: flex` have the same (0,1,0)
   specificity, and an author rule always wins that tie over the UA stylesheet - found 2026-10-30,
   owner-reported ("the filters/margins look wrong"), confirmed live: the element's `hidden`
   attribute was true, yet it still rendered, flex-laid-out and empty. */
.filter-row[hidden] {
  display: none;
}

.filter-row input[type="text"] {
  flex: 1 1 200px;
  margin-bottom: 0;
}

.filter-row select {
  flex: 0 1 260px;
  width: auto;
}

.assignment-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  margin-top: var(--space-2);
  color: inherit;
  text-decoration: none;
}

.assignment-item:hover {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
}

.assignment-item.status-overdue { border-left: 4px solid var(--color-danger); }
.assignment-item.status-todo { border-left: 4px solid var(--color-primary); }
.assignment-item.status-done { border-left: 4px solid var(--color-success); }

/* a locked (overdue) row is a <div>, not a link - it doesn't navigate, so it also shouldn't look like it does */
.assignment-item.assignment-locked { cursor: not-allowed; opacity: 0.7; }
.assignment-item.assignment-locked:hover { border-color: var(--color-border); background: none; }

.assignment-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

@media (max-width: 560px) {
  .two-col { grid-template-columns: 1fr; }
}

.button-row {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-3);
}

.import-json {
  width: 100%;
  font-family: ui-monospace, Consolas, monospace;
  font-size: 13px;
}

.error-list {
  color: var(--color-danger);
  font-size: 14px;
  padding-left: var(--space-5);
}

.inline-form {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.inline-form input[type="text"] { flex: 1 1 180px; }
.inline-form select { flex: 0 1 220px; width: auto; }

/* One category per row, as a small stack: the quiz count (minimal, 8px) above the name, then the
   name, parent/"type" picker and Save/Delete all together on one line, then (language categories
   only) the language picker below that. */
.category-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
}

.category-row-count { font-size: 8px; line-height: 1.2; margin: 0; }

.category-row-main {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.category-row-sub {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.category-row-main .cat-name { flex: 1 1 160px; min-width: 0; }
.category-row-main .cat-parent { flex: 0 1 200px; width: auto; }
/* button's own base rule (see "Buttons" above) sets margin-top:10px for normal block stacking under
   a field - inside this single-line row that only pushes Mentés/Törlés visibly lower than the
   name/parent inputs next to them despite align-items:center, since centering still measures each
   item's own margin box. */
.category-row-main button { margin-top: 0; }

.folder-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
}

.folder-row .folder-name { flex: 1 1 160px; min-width: 0; }
.folder-row .folder-parent { flex: 0 1 200px; width: auto; }

/* ---- Gamification -------------------------------------------------------------------------- */

.gamification-card .gami-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.level-pill {
  background: var(--color-primary);
  color: #fff;
  border-radius: var(--radius-pill);
  padding: 4px 12px;
  font-weight: 700;
  font-size: 14px;
}

.xp-bar {
  flex: 1 1 120px;
  height: 10px;
  background: var(--color-primary-soft);
  border-radius: var(--radius-pill);
  overflow: hidden;
}

.xp-bar > span {
  display: block;
  height: 100%;
  background: var(--color-primary);
  border-radius: var(--radius-pill);
  transition: width var(--transition-base);
}

.gami-streak { margin: var(--space-2) 0; }

.badge-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-2) 0;
}

.gami-badge {
  border-radius: var(--radius-pill);
  padding: 3px 10px;
  font-size: 13px;
  font-weight: 600;
  border: 1px solid var(--color-border);
}

.gami-badge.earned { background: var(--color-success-soft); color: var(--color-success); border-color: transparent; }
.gami-badge.locked { color: var(--color-text-faint); filter: grayscale(1); opacity: 0.7; }

.leaderboard summary { cursor: pointer; color: var(--color-text-muted); font-size: 14px; margin-top: var(--space-2); }
.leaderboard-list { list-style: none; padding: 0; margin: var(--space-2) 0; }
.leaderboard-list li { display: flex; gap: var(--space-2); padding: 4px 0; border-bottom: 1px solid var(--color-border); }
.leaderboard-list li.me { font-weight: 700; color: var(--color-primary-active); }

.markdown-view { margin-top: var(--space-3); padding: var(--space-3) var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-bg); max-height: 60vh; overflow: auto; }
.markdown-view h3, .markdown-view h4, .markdown-view h5 { margin: var(--space-4) 0 var(--space-2); }
.markdown-view pre { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-sm); padding: var(--space-3); overflow-x: auto; font-size: 12px; }
.markdown-view code { font-family: ui-monospace, Consolas, monospace; font-size: 12px; }
.markdown-view table { font-size: 13px; }
.category-language-note { margin: var(--space-1) 0 0; }


/* ---- Breadcrumb, result chips, favorites, answer marking -------------------------------------- */

.breadcrumb { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; font-size: 12px; color: var(--color-text-muted); margin-bottom: var(--space-2); }
.breadcrumb .crumb.current { color: var(--color-primary-active); font-weight: 600; }
.breadcrumb .crumb-sep { color: var(--color-text-faint); }
.crumb-level { margin-left: var(--space-2); padding: 1px 8px; border-radius: var(--radius-pill); background: var(--color-primary-soft); color: var(--color-primary-active); font-weight: 700; }

.result-chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: var(--space-2) 0 0; }
.pct-chip { padding: 2px 10px; border-radius: var(--radius-pill); font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }
.pct-chip.good { background: var(--color-success-soft); color: var(--color-success); }
.pct-chip.mid { background: var(--color-primary-soft); color: var(--color-primary-active); }
.pct-chip.low { background: var(--color-danger-soft); color: var(--color-danger); }

.quiz-card-wrap { position: relative; margin-bottom: var(--space-3); }
.quiz-card-wrap .quiz-card { margin-bottom: 0; }
.fav-btn { position: absolute; top: 8px; right: 8px; width: 36px !important; height: 36px; padding: 0; border-radius: var(--radius-pill); font-size: 20px; line-height: 1; background: transparent; color: var(--color-text-faint); border: 0; box-shadow: none; }
.fav-btn.on { color: #d99a00; }
.fav-btn:hover:not(:disabled) { background: var(--color-primary-soft); }
.fav-toggle[aria-pressed="true"] { background: var(--color-primary); color: #fff; }

.option-row.answer-correct,
.option-row.answer-correct:has(input) { border: 2px solid var(--color-success); background: var(--color-success-soft); }
.option-row.answer-wrong,
.option-row.answer-wrong:has(input) { border: 2px solid var(--color-danger); background: var(--color-danger-soft); }
input.answer-correct { border-color: var(--color-success); background: var(--color-success-soft); }
input.answer-wrong, select.answer-wrong { border-color: var(--color-danger); background: var(--color-danger-soft); }
select.answer-correct { border-color: var(--color-success); background: var(--color-success-soft); }
.answer-key { color: var(--color-success); font-weight: 600; font-size: 14px; }

.ai-feedback { margin-top: 10px; padding: 10px 12px; border-radius: var(--radius-sm); background: var(--color-primary-soft); }
.ai-feedback-label { display: block; margin-bottom: 4px; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-primary); }
.ai-feedback p { margin: 0; white-space: pre-wrap; }

.quiz-card.archived { opacity: 0.7; border-style: dashed; }

.pct-chip.pending { background: var(--color-bg); color: var(--color-text-muted); border: 1px dashed var(--color-border-strong); }

.grading-answer { margin: 8px 0; padding: 8px 12px; border-left: 3px solid var(--color-border-strong); background: var(--color-bg); white-space: pre-wrap; }
.grading-form { display: grid; gap: 8px; margin-top: 8px; max-width: 480px; }

.user-picker { display: grid; gap: 8px; }
.up-selected { display: flex; flex-wrap: wrap; gap: 6px; }
.up-chip { display: inline-flex; align-items: center; gap: 4px; padding: 2px 4px 2px 10px; border-radius: 999px; background: var(--color-primary-soft); color: var(--color-primary-active); }
.up-chip .up-remove { border: 0; background: transparent; color: inherit; cursor: pointer; font-size: 16px; line-height: 1; padding: 2px 6px; }
.up-controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.up-controls .up-q { flex: 1; min-width: 160px; }
.up-results { max-height: 220px; overflow: auto; }
.up-result { display: flex; align-items: center; gap: 8px; padding: 4px 0; }

.review-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.review-line { cursor: default; }
.assignment-row { display: flex; align-items: center; gap: 8px; }
.assignment-row .assignment-item { flex: 1; }
.review-link { white-space: nowrap; }
.token.answer-correct { background: var(--color-success-soft); outline: 2px solid var(--color-success); }
.token.answer-wrong { background: var(--color-danger-soft); outline: 2px solid var(--color-danger); }
.token.answer-missed { outline: 2px dashed var(--color-success); }
.order-row.answer-correct, .matching-row select.answer-correct { border: 2px solid var(--color-success); background: var(--color-success-soft); }
.order-row.answer-wrong, .matching-row select.answer-wrong { border: 2px solid var(--color-danger); background: var(--color-danger-soft); }
.blank-mark { border-bottom: 2px solid var(--color-border-strong); padding: 0 12px; }

.blank-drop { display: inline-block; min-width: 72px; min-height: 1.6em; padding: 0 8px; margin: 0 2px; border-bottom: 2px dashed var(--color-border-strong); background: var(--color-bg); border-radius: 4px; text-align: center; cursor: pointer; vertical-align: baseline; }
.blank-drop.filled { border-bottom-style: solid; background: var(--color-primary-soft); }
.blank-drop.answer-correct { border-bottom-color: var(--color-success); background: var(--color-success-soft); }
.blank-drop.answer-wrong { border-bottom-color: var(--color-danger); background: var(--color-danger-soft); }
.word-bank { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; padding: 12px; min-height: 48px; border: 1px dashed var(--color-border-strong); border-radius: 8px; }
.word-chip { padding: 6px 12px; border: 1px solid var(--color-border-strong); border-radius: 999px; background: var(--color-surface, #fff); cursor: grab; user-select: none; }
.word-chip.armed { outline: 2px solid var(--color-primary); }

/* ---- Responsive layout ------------------------------------------------------------------------------
   Breakpoints (mobile first is not used here: the base styles above are the tablet/desktop look):
     >= 1100px  wide desktop  - the admin shell gets more room
     <= 900px   tablet        - columns collapse, filter controls take the full width
     <= 600px   phone         - one column, larger tap targets, 16px inputs (no iOS zoom), full-width primary buttons
     <= 380px   small phone   - tighter gutters
   Rule of thumb everywhere: no horizontal page scroll; only tables / code may scroll inside their own container.
   ------------------------------------------------------------------------------------------------------ */

@media (min-width: 1100px) {
  #app.wide { max-width: 1180px; }
}

@media (max-width: 900px) {
  #app.wide { max-width: 100%; }
  .access-columns > div { flex: 1 1 100%; min-width: 0; }
  .filter-row select { flex: 1 1 100%; }
  .up-controls .up-q { flex: 1 1 100%; }
  .grading-form { max-width: none; }
  .table-scroll table { min-width: 560px; }
  .card { overflow-wrap: anywhere; }
}

@media (max-width: 600px) {
  body { padding: 16px 14px 40px; font-size: 15px; }
  h1 { font-size: 20px; }
  h2 { font-size: 18px; }

  /* topbar: title on its own line, controls wrap below */
  .topbar { align-items: flex-start; }
  .topbar > h1 { flex: 1 1 100%; }
  .topbar > button { margin-left: 0; }
  .topbar-menus { margin-left: auto; }

  /* the language switcher of the login page must not sit on top of the card */
  #lang-switcher-wrap { position: absolute; top: 8px; right: 12px; }
  .auth-card { margin-top: 56px; }

  /* tap targets and no zoom-on-focus */
  input, select, textarea { font-size: 16px; }
  button, .tab-btn, .word-chip, .blank-drop, .option-row, .token, .up-remove { min-height: 44px; }
  .tab-btn { padding: 8px 14px; }
  .option-row { padding: 12px; }
  .token { padding: 6px 8px; display: inline-block; }
  .word-chip { display: inline-flex; align-items: center; }
  .up-chip { min-height: 36px; }
  .up-remove { min-width: 36px; }

  /* forms: primary actions span the row */
  form > button[type="submit"], .button-row > button, .grading-form > button { width: 100%; }
  .button-row { flex-direction: column; }

  /* lists of cards / rows stack */
  .assignment-item { flex-wrap: wrap; }
  .assignment-row { flex-wrap: wrap; }
  .assignment-row .assignment-item { flex: 1 1 100%; }
  .review-head { flex-wrap: wrap; }
  .category-row { margin-left: 0 !important; }
  .category-row-main, .category-row-sub { flex-wrap: wrap; }
  .category-row input, .category-row select { flex: 1 1 100%; }
  .folder-row { flex-wrap: wrap; margin-left: 0 !important; }
  .folder-row input, .folder-row select { flex: 1 1 100%; }
  .matching-row { flex-direction: column; align-items: stretch; gap: 6px; }
  .matching-row select { width: 100%; }
  .up-controls select, .up-controls label { flex: 1 1 100%; }
  .filter-row > * { flex: 1 1 100%; }

  /* tables keep their columns and scroll inside .table-scroll; a bit denser */
  table { font-size: 12px; }
  th, td { padding: 6px 8px; }
  .dropdown, .menu-dropdown { max-width: calc(100vw - 28px); }
}

@media (max-width: 380px) {
  body { padding: 12px 10px 32px; }
  .card { padding: 12px; }
  .tab-btn { padding: 8px 10px; font-size: 13px; }
}

/* ---- Red time bars (whole quiz + current question), shrinking towards the right ---- */
.timebar { display: flex; justify-content: flex-end; height: 8px; margin: 6px 0; border-radius: 4px; background: var(--color-danger-soft); overflow: hidden; }
.timebar-fill { width: 100%; height: 100%; background: var(--color-danger); border-radius: 4px; transition: width 0.25s linear; }
.question-timebar { height: 6px; opacity: 0.85; }
.attempt-limit { margin: 6px 0; }
.count-picker { display: block; margin: 8px 0; }
.count-picker input { width: 90px; display: inline-block; }

/* ---- Statistics ---- */
.stat-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 10px; margin: 12px 0; }
.stat-tile { padding: 12px; border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-surface); }
.stat-value { font-size: 22px; font-weight: 700; }
.stat-label { font-size: 12px; color: var(--color-text-muted); }
.stat-chart { display: flex; align-items: flex-end; gap: 3px; height: 90px; padding-top: 6px; }
.stat-bar-wrap { flex: 1; height: 100%; display: flex; align-items: flex-end; }
.stat-bar { width: 100%; background: var(--color-primary); border-radius: 3px 3px 0 0; min-height: 0; }
.mistake-row { padding: 6px 0; border-bottom: 1px solid var(--color-border); }

.word-search-results { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 10px; }
.word-history { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.word-relations { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 4px; margin: 6px 0; }
.word-relations li { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 4px 8px; background: #F7F8FC; border-radius: var(--radius-sm); }
.word-relations .wl-relation-remove, .word-relations .wl-synonym-remove { font-size: 1.1em; line-height: 1; color: var(--color-text-muted); }

.collapse-toggle { background: none; border: 0; padding: 0; font: inherit; color: inherit; cursor: pointer; text-align: left; }
.practice-card input[type="text"] { width: 100%; box-sizing: border-box; font-size: 16px; }
.practice-choice { display: block; width: 100%; text-align: left; margin: 6px 0; }
.practice-explanation { white-space: pre-line; }
.todo-count { display: inline-block; min-width: 1.4em; padding: 0 6px; border-radius: 999px; background: var(--color-primary-soft); color: var(--color-primary-active); font-size: 0.8em; text-align: center; }

.practice-prompt { margin: 0 0 4px; font-weight: 600; color: var(--color-text-muted); }

.flag-btn { min-width: 2.6em; font-size: 1.2em; line-height: 1; }
.flag-btn.flagged { color: var(--color-danger); border-color: var(--color-danger); }

/* collapsed cards are one small line */
.assignments-card.collapsed, .gamification-card.collapsed { padding: 4px 10px; margin-bottom: 6px; }
.assignments-card.collapsed h3 { margin: 0; font-size: 0.95em; }
.gamification-card { position: relative; }
.gamification-card .gami-head { padding-right: 22px; }
.gamification-card .gami-toggle {
  position: absolute; top: 10px; right: 3px; margin: 0; padding: 2px 5px;
  background: none; border: 0; box-shadow: none; border-radius: 4px;
  font-size: 0.85em; line-height: 1; color: var(--color-text-muted); cursor: pointer;
}
.gamification-card .gami-toggle:hover { background: var(--color-bg); color: var(--color-text); }

/* confirmation modal (confirmDialog) */
.modal-overlay { position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; padding: 16px; background: rgba(15, 23, 42, 0.55); }
.modal-box { width: min(440px, 100%); background: var(--color-surface, #fff); color: var(--color-text); border-radius: 12px; padding: 20px 22px; box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35); }
.modal-box h3 { margin: 0 0 8px; }
.modal-box p { margin: 0 0 18px; line-height: 1.45; }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; }
.modal-actions button { min-width: 96px; }
.modal-actions button:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }

/* .v2-topic-modal (word-list and help-topic editors, admin-words.js/help-editor.js) - despite the
   name this markup is used in BOTH looks, not just the new one. Capped at the viewport height with
   a scrolling body and a fixed action row (style-v2.css re-states the same sizing under its own
   html.v2 selector, purely for specificity - this is what makes it work at all in the old look,
   where a modal with enough content, like a word's full edit history, otherwise grew past the
   bottom of the screen with its Save button left unreachable). */
.v2-topic-modal { max-height: 85vh; display: flex; flex-direction: column; }
.v2-topic-modal-body { overflow-y: auto; }
.v2-topic-modal .modal-actions { flex: none; margin-top: 18px; }
button.danger { background: var(--color-danger); border-color: var(--color-danger); color: #fff; }

button.practice-choice.answer-correct, button.practice-choice.answer-correct:disabled { background: var(--color-success-soft); border: 2px solid var(--color-success); color: var(--color-text); opacity: 1; }
button.practice-choice.answer-wrong, button.practice-choice.answer-wrong:disabled { background: var(--color-danger-soft); border: 2px solid var(--color-danger); color: var(--color-text); opacity: 1; }
.practice-card input[type="text"].answer-correct:disabled, .practice-card input[type="text"].answer-wrong:disabled { opacity: 1; }

.level-badge { display: inline-block; vertical-align: middle; margin-left: 6px; padding: 1px 8px; border-radius: 999px; font-size: 0.5em; font-weight: 600; background: var(--color-primary-soft); color: var(--color-primary-active); }

/* help / description */
.quiz-help { margin: 8px 0 12px; }
.quiz-help summary { cursor: pointer; font-weight: 600; }
.help-content { margin-top: 8px; }
.help-content blockquote { margin: 8px 0; padding: 4px 12px; border-left: 3px solid var(--color-border); color: var(--color-text-muted); }
.help-content ol, .help-content ul { padding-left: 1.4em; }
.help-actions { display: flex; gap: 8px; flex-wrap: wrap; margin: 8px 0; }
.help-panel { margin: 8px 0; }
.hint-text { margin: 0; }
.help-topic-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; padding: 4px 0; }

/* quiz help: an icon button on the quiz page and a floating one during the quiz */
.quiz-help-btn { display: inline-flex; align-items: center; gap: 8px; margin: 6px 0 10px; }
.help-icon { flex: none; vertical-align: middle; }
.help-fab {
  position: fixed; right: 16px; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); z-index: 900;
  width: 52px; height: 52px; padding: 0; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  background: var(--color-primary); color: #fff; border: 0; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.28); cursor: pointer;
}
.help-fab:hover { filter: brightness(1.08); }
.help-fab:focus-visible { outline: 3px solid var(--color-primary-soft); outline-offset: 3px; }
.help-modal { max-height: 85vh; display: flex; flex-direction: column; width: min(640px, 100%); }
.help-modal-head h3 { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; }
.help-modal-body { overflow-y: auto; margin-bottom: 14px; }

/* In-quiz settings (answer-reveal mode + auto-submit) - a quiet .icon-btn, deliberately not the
   solid .help-fab treatment, and bottom-LEFT rather than bottom-right, so it doesn't compete with
   the quiz-help fab when a quiz has both. The panel reuses .menu-dropdown for its chrome (border,
   shadow, radius, padding, pop-in animation) and only overrides its positioning, since it opens
   upward from a fixed corner button instead of downward from a relatively-positioned one. */
.quiz-settings-fab {
  position: fixed;
  left: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  z-index: 900;
  width: 44px;
  height: 44px;
}
.quiz-settings-panel {
  position: fixed;
  top: auto;
  right: auto;
  left: 16px;
  bottom: calc(16px + 44px + 10px + env(safe-area-inset-bottom, 0px));
  width: min(280px, calc(100vw - 32px));
}
.quiz-settings-group { margin: 10px 2px; }
.quiz-settings-group:first-child { margin-top: 2px; }
.quiz-settings-group-label { margin: 0 0 4px; font-size: 13px; font-weight: 700; }
.quiz-settings-hint { margin: 2px 0 0 26px; font-size: 12px; }
.quiz-settings-suboption { margin-left: 22px; margin-top: 10px; }

/* statistics: clickable runs, clickable group members, and the read-only review window */
tr.run-row { cursor: pointer; }
tr.run-row:hover td, tr.run-row:focus-visible td { background: var(--color-primary-soft); }
tr.run-row:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }
tr.stats-member-row { cursor: pointer; }
tr.stats-member-row:hover td, tr.stats-member-row:focus-visible td { background: var(--color-primary-soft); }
tr.stats-member-row:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }
.member-name-link { color: var(--color-primary); text-decoration: underline; }
tr.stats-member-row:hover .member-name-link { text-decoration-thickness: 2px; }
.review-modal { width: min(760px, 100%); max-height: 88vh; display: flex; flex-direction: column; }
.review-modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 8px; }
.review-modal-head h3 { margin: 0; }
.review-modal-body { overflow-y: auto; }

#essay-input { min-height: 14em; }

/* the overview tab exists for the new look only */
.v2-tabs, .v2-radios, .v2-new, #new-quiz-toggle, .v2-list-head, .v2-crumbs, .v2-edit-head, #tab-home, #v2-top, .v2-role, .v2-nav-group, .v2-side-foot,
.v2-chips, .v2-add-btn, .v2-page-sub, .v2-page-actions, .qc-toggle { display: none; }
/* new-look-only markers (a required-field asterisk, a hover hint dot): invisible text, not a hidden block, so they
   must be display:none individually rather than joining the block list above. */
.v2-required, .v2-hint-dot { display: none; }

/* a checkbox label that carries its own explanation: without this the <small> ran straight into the
   label text in the original look ("Azonnali visszajelzésA felhasználó minden kérdés után...") */
.v2-check-text small { display: block; color: var(--color-text-muted); font-size: 13px; }

/* a white/outlined badge variant (the new look's "individual user" chip, next to the green .badge used for a group) */
.badge-plain { background: var(--color-surface); border: 1px solid var(--color-border-strong); color: var(--color-text-muted); }

/* "My groups": clickable group name for the group's owner, opening the group's admin page - functional, both looks */
.group-name-link { color: inherit; text-decoration: none; }
.group-name-link:hover { text-decoration: underline; }
/* same class on a <button> (a plain member's name, opening the roster modal instead of navigating): strip the
   browser's default button chrome so it reads exactly like the owner's <a> version */
button.group-name-link { display: inline; background: none; border: none; padding: 0; margin: 0; font: inherit; cursor: pointer; }

/* "My groups": the roster modal opened from a plain member's group name (openGroupMembersModal) */
.group-members-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.group-member-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.group-member-row .grow { flex: 1 1 auto; min-width: 0; }

/* The learner's own "Szótáram" and a group's shared word bank (dictionary.js) - a word's row inside
   .group-members-list above. .dict-word-head keeps the headword and its (quiet, .badge-plain) topic
   tag on one line without the tag ever pushing onto its own line unless it has to wrap. */
.dict-word-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.dict-word-head .badge-plain { font-size: 11px; padding: 1px 9px; }
.dict-audio-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0; margin: 0; border: 0; border-radius: 50%;
  background: none; color: var(--color-primary); font-size: 14px; line-height: 1; cursor: pointer;
}
.dict-audio-btn:hover { background: var(--color-primary-soft); }
.dict-related-toggle {
  background: none; border: 0; padding: 4px 0 0; margin: 0; display: block; width: auto;
  font: inherit; font-size: 13px; color: var(--color-primary); cursor: pointer;
}
.dict-related-toggle:hover { text-decoration: underline; }
.dict-related-panel { margin-top: 6px; }
.dict-related-panel p { margin: 0 0 4px; }
.dict-related-panel .badge-plain { margin: 0 4px 4px 0; font-size: 12px; }

