/* Language color-coding, used systematically wherever sme/fi/en text is
   shown. All three hues come from the Sámi flag's own four-color palette
   (red/green/yellow/blue) rather than each language's separate national
   flag, so sme/fi/en read as one consistent, Sámi-rooted system:
   green = Sámi, blue = Finnish, red = English. ("sme" — Sámi's real ISO
   639-3 code — not "se", which reads as Swedish; see docs/decisions.md.) */
:root {
  --lang-sme: #007a3d;
  --lang-fi: #0038a8;
  --lang-en: #d81e05;
  /* The Sámi flag's fourth color, previously unused (see
     docs/decisions.md's Licensing section) — not a language color like
     the three above, so not a --lang-* variable; used for the dashboard's
     section-heading underline (.section-heading below). */
  --sami-flag-yellow: #fcd116;
}

body {
  font-family: system-ui, sans-serif;
  max-width: 40rem;
  margin: 2rem auto;
  padding: 0 1rem;
  color: #222;
}

.lang-sme {
  color: var(--lang-sme);
}

.lang-fi {
  color: var(--lang-fi);
}

.lang-en {
  color: var(--lang-en);
}

header h1 a {
  color: inherit;
  text-decoration: none;
}

.flashes {
  list-style: none;
  padding: 0.5rem 1rem;
  margin: 1rem 0;
  background: #f0f4ff;
  border-left: 4px solid #4a6cf7;
}

/* Fixed-layout game screen (templates/play.html, templates/learn.html) —
   see docs/decisions.md's "Fixed game-screen layout" section. Each of
   these reserves the same footprint whether or not this round's word
   actually fills it, so the page doesn't jump between words. */

.game-mode-line {
  text-align: center;
  font-size: 1.1rem;
  margin: 0.8rem 0 0;
}

.back-line {
  text-align: left;
  margin: 0.2rem 0 1rem;
}

/* The "->"/"<-" arrows in mode labels (game.py's label_html, e.g. "Sámi
   -> Finnish") and back links — plain inline text by default, easy to
   miss next to bold-colored language names either side of it. Bigger and
   bold, not tied to any language color (the arrow itself isn't a
   language), so it reads as a clear signpost rather than blending in. */
.nav-arrow {
  font-weight: bold;
  font-size: 1.3em;
  color: #444;
}

/* Dashboard's "Vocabulary"/"Phrases" section headings — a yellow
   underline under the whole trilingual heading, not per-word, using the
   Sámi flag's fourth color (see --sami-flag-yellow above) now that the
   flag icons/arrows brought red/green/blue into the mode labels too —
   directly requested, "maybe have a yellow underline... for the entire
   trilingual header." Deliberately subtle (a border, not a background
   fill) per "not sure how prominent it would be." */
.section-heading {
  display: inline-block;
  border-bottom: 3px solid var(--sami-flag-yellow);
  padding-bottom: 0.15rem;
}

/* The "new user" pop-up (templates/index.html) — a native <dialog>, so
   most of its behavior (backdrop, centering, focus trap, Escape-to-close)
   is free from the browser; this is just enough styling that it doesn't
   look like unstyled browser chrome next to the rest of the site. */
dialog#new-user-dialog {
  border: none;
  border-radius: 8px;
  padding: 1.5rem;
  max-width: 22rem;
  width: 90%;
}

dialog#new-user-dialog::backdrop {
  background: rgba(0, 0, 0, 0.4);
}

dialog#new-user-dialog label {
  display: block;
  margin: 0.75rem 0;
}

dialog#new-user-dialog input {
  display: block;
  margin-top: 0.25rem;
  width: 100%;
  box-sizing: border-box;
}

dialog#new-user-dialog .dialog-buttons {
  display: flex;
  gap: 0.5rem;
  margin-top: 1rem;
}

/* The index page's own name+password login form (templates/index.html)
   — replaces the old clickable account-picker list. Same field/label
   shape as the new-user dialog just above, for visual consistency,
   just not boxed inside a <dialog>. */
.user-login-form {
  max-width: 22rem;
}

.user-login-form label {
  display: block;
  margin: 0.75rem 0;
}

.user-login-form input {
  display: block;
  margin-top: 0.25rem;
  width: 100%;
  box-sizing: border-box;
}

.user-login-form button {
  margin-top: 0.5rem;
}

/* Small flag/icon image in a mode label's icon zone (see game.py's
   _mode_label() and its _SAMI_FLAG/_FINLAND_FLAG/etc. constants) — sized
   to sit inline with text rather than towering over it. See
   docs/resources.md's "Flags and icons" section for sourcing/license. */
.lang-flag {
  height: 1em;
  width: auto;
  vertical-align: -0.15em;
}

/* Structured mode-label layout — all symbols first (.mode-icons), all
   text after (.mode-text) — see game.py's _mode_label() and
   docs/decisions.md. Directly requested: "the text should only follow
   *all* of the symbols... the textual description should start at the
   same horizontal position for each game." `.mode-icons` is a fixed
   total width (not sized to its content), so .mode-text always starts at
   the same x offset down the whole mode list, regardless of which icons
   a given mode uses or how long its own text turns out to be. Every mode
   label has exactly four icon-zone elements (source language, arrow,
   target language, mode-type icon — see _mode_label), so 5.5em
   comfortably fits all four with room to spare rather than being tuned
   to exactly fit today's set. */
.mode-label {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  column-gap: 0.6em;
  row-gap: 0.15em;
}

.mode-icons {
  display: inline-flex;
  align-items: center;
  column-gap: 0.15em;
  width: 5.5em;
  flex-shrink: 0;
}

.mode-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.3em;
  flex-shrink: 0;
}

.mode-text {
  display: inline-block;
}

/* The last segment of .mode-text — a Sámi word for what kind of exercise
   this is ("válljen"/choice, "riektačállin"/spelling — see
   game._MC_WORD/_SPELLING_WORD) — only ever a dictionary-verified word,
   never guessed at. Smaller and muted so it reads as a descriptor, not
   another language name competing with the sme/fi ones before it. */
.mode-desc {
  font-size: 0.85em;
  font-style: italic;
  color: #666;
}

/* Reserves ~3 lines regardless of whether there's feedback to show yet
   (e.g. the very first question in a mode) — border/background only
   appear once a verdict is known. */
.feedback-slot {
  min-height: 4.4rem;
  margin: 0 0 1rem;
  padding: 0.5rem 1rem;
  border-left: 4px solid transparent;
  border-radius: 2px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.feedback-slot p {
  margin: 0.15rem 0;
}

.feedback-slot.flash-correct {
  background: #e6f6ea;
  border-left-color: #1a7a3d;
  color: #14532d;
}

.feedback-slot.flash-incorrect {
  background: #fdeceb;
  border-left-color: #c62828;
  color: #7a1c1c;
}

/* Reserves room for a two-line word (the longest current entries, e.g.
   "mánáidmánná"/"guovssahasat", are ~11-12 characters) so a short word one
   round and a long one the next don't change the page's height. */
.prompt-word-slot {
  min-height: 5.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}

/* "Contest this" flag buttons (see templates/_macros.html's
   contest_previous_button/contest_current_button macros) — icon-only, no
   text, positioned in the two corners requested: the previous round's
   flag sits right below the colored feedback box, right-aligned, in the
   white space above the word; the current question's sits right above
   the answer UI, left-aligned. Both slots are always reserved so the
   layout doesn't shift depending on whether there's anything to contest
   yet — same rule as every other slot on this screen. */
.contest-previous-slot {
  min-height: 2.4rem;
  text-align: right;
  margin: 0 0 0.2rem;
}

.contest-current-slot {
  min-height: 2.4rem;
  text-align: left;
  margin: 0.2rem 0 0;
}

.contest-flag-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  height: 2.2rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: none;
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
}

.contest-flag-btn:hover,
.contest-flag-btn:focus {
  background: rgba(0, 0, 0, 0.06);
}

.contest-flag-btn:disabled {
  cursor: default;
  opacity: 0.8;
  background: none;
}

.audio-slot {
  min-height: 2.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 0.4rem;
}

/* Fixed-size box for the word's photo/visual (image mode's prompt, or
   sami mode's optional thumbnail) — a bigger source image is capped to
   this box, a smaller one is just centered in it, so the box itself never
   changes size whether or not this round's word even has one. */
.picture-slot {
  width: 12rem;
  height: 12rem;
  margin: 0.8rem auto 0;
}

.picture-slot .photo-credit {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.picture-slot img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
}

.user-list, .mode-list, .stat-list, .module-list, .batch-session-list {
  list-style: none;
  padding: 0;
}

.user-list li, .mode-list li, .stat-list li, .module-list li, .batch-session-list li {
  margin: 0.4rem 0;
}

.module-list label {
  cursor: pointer;
}

/* A saved run's row (templates/batch_list.html/phrase_batch_list.html) —
   the run link itself plus a small, visually subordinate "Remove" button
   next to it (a real <form>/<button>, kept out of the <a> since a button
   inside a link is invalid HTML). Each row gets its own bordered box and
   extra vertical gap between rows — reported directly: with no visual
   boundary, "Remove" sitting between two runs made it unclear which one
   it would actually remove, especially once it wrapped onto its own line
   on a narrow screen. The border keeps the button visually anchored to
   its own run's box no matter how the row wraps. */
.batch-session-list li.batch-session-row {
  margin: 0.7rem 0;
}

.batch-session-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.6rem 0.8rem;
  border: 1px solid #ddd;
  border-radius: 6px;
}

.batch-session-delete {
  margin: 0 0 0 auto;
}

/* A <button> styled to read as a plain, quiet text link rather than a
   boxed button — used for the "Remove" action so it doesn't visually
   compete with the run link itself. */
.link-button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: #b00020;
  cursor: pointer;
  text-decoration: underline;
}

/* Same idea as .link-button (a <button> that reads as plain text, not a
   boxed control) but neutral-colored rather than red — used for actions
   that are rare/optional, not destructive (e.g. "Skip round" on the
   batch summary screen), so it doesn't read as a warning the way the
   run list's red "Remove" link correctly does. */
.quiet-button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: #666;
  cursor: pointer;
  text-decoration: underline;
}

/* The batch summary screen's own "Skip round" / "Start" pair (see
   templates/batch_play.html's batch_summary block) — directly reported:
   "I'm always about to press the skip lesson button," with the two
   sitting right next to each other at equal weight. Skip gets its own
   row, right-aligned and quiet; Start gets the row below, centered and
   made deliberately more prominent — different row, different
   alignment, different size, not just different color, so the far more
   common action (Start) is hard to miss and the rarer one (Skip) is
   hard to hit by accident. */
.batch-summary-start-row {
  display: flex;
  justify-content: center;
  margin: 0.8rem 0 0.3rem;
}

.batch-summary-skip-row {
  display: flex;
  justify-content: flex-end;
  margin: 0.3rem 0 1rem;
}

.batch-summary-start-btn {
  font-size: 1.25rem;
  font-weight: bold;
  padding: 0.9rem 2.2rem;
  min-height: 3.2rem;
  cursor: pointer;
}

/* The phrase batch game's step 5 (listen and write) — same "the two
   sat at equal weight, easy to hit the wrong one" report, same fix:
   "Check" gets its own centered, prominent row (identical sizing to
   .batch-summary-start-btn above); "I can't listen right now" gets its
   own row below, spaced apart and styled quiet (.quiet-button) rather
   than as a second real button competing for attention. */
.listen-write-check-row {
  display: flex;
  justify-content: center;
  margin: 0.8rem 0 0.3rem;
}

.listen-write-check-btn {
  font-size: 1.25rem;
  font-weight: bold;
  padding: 0.9rem 2.2rem;
  min-height: 3.2rem;
  cursor: pointer;
}

.listen-write-cant-listen-row {
  display: flex;
  justify-content: center;
  margin: 1rem 0 0.3rem;
}

/* Separates the dashboard's content sections (Game, Phrases) from the
   account-level links below them (Settings, admin pages, switch user) —
   see templates/dashboard.html. Plain and quiet on purpose, just enough
   to stop the links after the last h3 from reading as part of it. */
.dashboard-section-break {
  border: none;
  border-top: 1px solid #ddd;
  margin: 1.5rem 0;
}

/* The one module left enabled when everything else is off — see
   templates/settings.html's script. Can't be unchecked right now (both
   this and app.py's update_modules enforce "at least one stays on"), so it
   looks visibly different rather than just silently refusing the click. */
.module-list li.is-locked {
  background: #f0f4ff;
  border-radius: 4px;
  padding: 0.2rem 0.4rem;
  margin: 0.4rem -0.4rem;
}

.module-list li.is-locked label {
  cursor: default;
}

.module-list li.is-locked::after {
  content: "🔒";
  margin-left: 0.4rem;
  font-size: 0.85em;
}

.hardest-list {
  padding-left: 1.4rem;
}

.copyright-list {
  list-style: none;
  padding: 0;
  margin: 0.3rem 0 1.2rem;
  font-size: 0.9rem;
}

.copyright-list li {
  margin: 0.15rem 0;
}

.hardest-list li {
  margin: 0.3rem 0;
}

.prompt {
  text-align: center;
  margin: 2rem 0;
}

.prompt-word {
  font-size: 2.2rem;
  font-weight: 600;
}

/* Per-photo attribution badge (see templates/_macros.html and
   docs/decisions.md's "Photo attribution" section) — revealed on hover or
   keyboard focus for a mouse/desktop visitor, and toggled by tap via
   static/photo_credit.js's `.is-open` class for a touch visitor, since
   touch devices have no real hover state. Both read the exact same
   markup/rules, so there's one behavior to get right, not two. */
.photo-credit {
  position: relative;
  display: inline-block;
  /* Room below the image for the badge to sit in, outside the photo
     itself rather than overlapping its bottom-right corner. */
  margin-bottom: 1.7rem;
}

.photo-credit-badge {
  position: absolute;
  bottom: -1.6rem;
  right: 0;
  width: 1.5rem;
  height: 1.5rem;
  line-height: 1.5rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: 1rem;
  cursor: pointer;
}

/* Small "this photo depicts an action" badge for verb-module words (see
   templates/_macros.html and docs/decisions.md's "Verb badge" section) —
   sits bottom-left in the same reserved margin the credit badge (above)
   uses bottom-right, so the two never overlap even when both are present. */
.verb-badge {
  position: absolute;
  bottom: -1.6rem;
  left: 0;
  width: 1.5rem;
  height: 1.5rem;
  line-height: 1.5rem;
  border-radius: 50%;
  background: rgba(0, 122, 61, 0.75); /* Sámi flag green, matches --lang-sme */
  color: #fff;
  font-size: 0.9rem;
  font-weight: 700;
  text-align: center;
  cursor: default;
}

.photo-credit-info {
  display: none;
  position: absolute;
  bottom: 100%;
  right: 0;
  margin-bottom: 0.3rem;
  padding: 0.4rem 0.6rem;
  width: max-content;
  max-width: 80vw;
  background: #222;
  color: #fff;
  font-size: 0.8rem;
  border-radius: 4px;
  z-index: 5;
  text-align: left;
}

.photo-credit-info a {
  color: #9ecbff;
}

.photo-credit.has-credit:hover .photo-credit-info,
.photo-credit.has-credit:focus-within .photo-credit-info,
.photo-credit.has-credit.is-open .photo-credit-info {
  display: block;
}

.choices {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 0.6rem;
}

.choices button {
  width: 100%;
  min-height: 3.2rem;
  padding: 0.8rem;
  font-size: 1.1rem;
  cursor: pointer;
  border: 2px solid transparent;
  transition: background-color 0.15s ease, border-color 0.15s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
}

.choices button:disabled {
  cursor: default;
}

/* Step 1's "batch summary" screen (sectioned modules only, e.g.
   numbers_time — see batch_game._build_batch_summary) — every word this
   batch is about to introduce, listed together on one screen. */
.batch-summary-list {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 0.5rem;
  margin: 0 0 1rem;
}

.batch-summary-list li {
  padding: 0.6rem 0.8rem;
  border: 1px solid #ddd;
  border-radius: 6px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.batch-summary-list audio {
  height: 1.8rem;
}

/* Small per-choice thumbnail (see game.py's pick_question "visual" on each
   choice, for `meaning`/`audio_finnish` — the modes that lost their big
   target-image slot because it made the answer too easy to read straight
   off the photo; see docs/decisions.md's "Images in every mode" section).
   Plain <img>, no credit badge — nesting the badge's own <button> inside
   the choice's <button> would be invalid HTML (see _macros.html's
   choice_image macro). */
.choice-thumb-img {
  width: 2.2rem;
  height: 2.2rem;
  object-fit: contain;
  flex-shrink: 0;
}

/* `sme_image` mode: every choice IS a picture, laid out as a 2x2 grid of
   square tiles rather than a vertical list of text rows — see
   docs/decisions.md. */
.choices.choices-images {
  grid-template-columns: 1fr 1fr;
}

.choice-image-btn {
  aspect-ratio: 1 / 1;
  min-height: 0;
}

.choice-image-img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Post-answer flash: the correct choice always turns green; the one you
   clicked also turns red if it wasn't the correct one. Both can apply to
   different buttons in the same round, or the same one when you got it
   right. !important (on the button and any nested language span, e.g. a
   choice-supporting gloss) overrides the lang-sme/lang-fi/lang-en text
   color so the flash reads clearly regardless of language. */
.choices button.choice-correct,
.choices button.choice-correct *,
.choices button.choice-wrong,
.choices button.choice-wrong * {
  color: #fff !important;
  opacity: 1;
}

.choices button.choice-correct {
  background-color: #1a7a3d;
  border-color: #1a7a3d;
}

.choices button.choice-wrong {
  background-color: #c62828;
  border-color: #c62828;
}

.choice-supporting {
  font-size: 0.85em;
  opacity: 0.85;
}

.supporting-langs {
  margin-top: 0.4rem;
  font-size: 1.1rem;
}

.supporting-langs span:not(:last-child)::after {
  content: " · ";
  color: #999;
}

.spell-form {
  text-align: center;
}

/* Letter-hint scaffold for the batch-learning game's steps 6-7 (see
   batch_game._letter_hint and templates/batch_play.html) — a masked
   preview like "b _ a _ a" shown above the same spell-input the
   unhinted step already uses. Monospace so blanks/letters line up
   evenly regardless of which are revealed. */
.spell-hint {
  font-family: monospace;
  font-size: 1.4rem;
  letter-spacing: 0.1rem;
  text-align: center;
  margin-top: 0.4rem;
  color: #555;
}

.spell-input {
  display: block;
  margin: 0.6rem auto 1rem;
  width: 100%;
  max-width: 16rem;
  padding: 0.6rem;
  font-size: 1.3rem;
  text-align: center;
}

.flashcard {
  padding-bottom: 0.5rem;
}

/* Phrase batch game's word-order widget (steps 3-4 — see
   phrase_batch_game.py, templates/phrase_batch_play.html,
   static/phrase_dnd.js). Two zones (an "answer" row tapped words move
   into, and a "bank" row of not-yet-placed tiles below it) rather than a
   single reorderable list, so it's always visually obvious which words
   are placed vs. still available — the same distinction a physical set of
   word cards on a table would make. Tap-to-place, not real drag-and-drop
   — see phrase_dnd.js's own module comment for why (real dragging "was
   working really badly," directly reported). */
.dnd-answer,
.dnd-bank {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  min-height: 3rem;
  padding: 0.6rem;
  border-radius: 0.4rem;
}

.dnd-answer {
  border: 2px dashed #999;
  margin-bottom: 0.8rem;
}

.dnd-bank {
  background-color: rgba(0, 0, 0, 0.04);
}

.dnd-tile {
  display: inline-flex;
  align-items: center;
  padding: 0.5rem 0.9rem;
  font-size: 1.1rem;
  border: 2px solid #999;
  border-radius: 0.4rem;
  background-color: #fff;
  cursor: pointer;
  user-select: none;
}

.dnd-tile.dnd-locked {
  cursor: default;
  background-color: rgba(0, 0, 0, 0.06);
  border-style: solid;
  opacity: 0.85;
}

.dnd-ready {
  display: block;
  margin: 0 auto;
}

/* Verbs-present-tense grammar lesson (templates/verb_present_play.html) —
   the 9-form singular/dual/plural x 1st/2nd/3rd person grid. A plain
   3-column CSS grid (same technique as .choices-images above), not an
   HTML <table>: every cell is equally a "cell" whether it's given text
   or a blank input, so there's no real header/data-row distinction an
   actual table would buy. */
.verb-grid {
  display: grid;
  grid-template-columns: auto 1fr 1fr 1fr;
  gap: 0.4rem 0.6rem;
  align-items: center;
  margin: 1rem 0;
}

.verb-grid .verb-row-label {
  font-size: 0.85em;
  text-align: right;
  padding-right: 0.4rem;
}

.verb-grid .verb-col-label {
  font-size: 0.8em;
  text-align: center;
  line-height: 1.2;
}

.verb-cell {
  text-align: center;
  padding: 0.5rem 0.3rem;
  border-radius: 4px;
  min-height: 2.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.verb-cell.verb-cell-given {
  background: #f2f2f2;
}

.verb-cell input {
  width: 100%;
  padding: 0.5rem;
  font-size: 1.05rem;
  text-align: center;
}

.verb-cell.verb-cell-correct {
  background: #e6f6ea;
  color: #14532d;
}

.verb-cell.verb-cell-wrong {
  background: #fdeceb;
  color: #7a1c1c;
}

.verb-cell-wrong .verb-cell-your-answer {
  display: block;
  font-size: 0.8em;
  text-decoration: line-through;
  opacity: 0.75;
}

.verb-conneg-row {
  margin-top: 0.8rem;
  padding-top: 0.6rem;
  border-top: 1px solid #ddd;
  text-align: center;
}

/* "Easy" difficulty's pre-screen "read all" button (see
   templates/verb_present_play.html) — highlights whichever word is
   currently being spoken, cycling through the prompt word, each of the
   9 present-tense cells, then the negative row. */
.verb-reading {
  outline: 3px solid #1a7a3d;
  outline-offset: 1px;
  background: #e6f6ea;
  border-radius: 4px;
}

/* strong_weak_grade's "easy" difficulty onboarding (see
   templates/grammar_play.html's `teach` block) — a plain table of
   nominative → genitive-accusative example pairs, styled to read as
   reference material rather than another quiz. */
.teach-examples {
  width: 100%;
  margin: 0.8rem 0;
  border-collapse: collapse;
}
.teach-examples td {
  padding: 0.3rem 0.5rem;
  border-bottom: 1px solid #eee;
}
.teach-examples td:nth-child(2) {
  text-align: center;
  opacity: 0.6;
  padding: 0.3rem 0.2rem;
}

/* "medium" difficulty's (and "easy," once onboarding is done) word-
   length hint — see grammar._build_question's own comment for what it
   means and when it's shown. Small and unobtrusive; it's a hint, not
   part of the question itself. */
.length-hint {
  font-size: 0.85em;
  opacity: 0.75;
  margin: 0.4rem 0;
}

/* `spell` mode's "easy" difficulty letter-hint (game.letter_hint,
   reused from the batch game's own steps 6-7) — monospace and letter-
   spaced so the underscores/letters line up clearly and are easy to
   scan, unlike the plain word-length hint above. */
.spell-hint {
  font-family: monospace;
  font-size: 1.1em;
  letter-spacing: 0.15em;
  margin: 0.4rem 0;
}

/* Admin-only pages (templates/contests.html, templates/rate_images.html) —
   see docs/decisions.md. Plain bordered cards; these aren't seen by every
   user, so they don't need the same polish as the main game screens. */
.contest-list {
  list-style: none;
  padding: 0;
}

.contest-item {
  border: 1px solid #ddd;
  border-radius: 4px;
  padding: 0.6rem 0.8rem;
  margin: 0.6rem 0;
}

.contest-item p {
  margin: 0.3rem 0;
}

.rate-images-item {
  text-align: center;
  margin: 1rem 0;
}

.rate-images-item img {
  max-width: 12rem;
  max-height: 12rem;
}

.face-buttons {
  display: flex;
  justify-content: center;
  gap: 0.6rem;
  margin: 0.6rem 0;
}

.face-buttons button {
  font-size: 1.8rem;
  background: none;
  border: 2px solid transparent;
  border-radius: 8px;
  padding: 0.2rem 0.5rem;
  cursor: pointer;
}

.face-buttons button.is-current-rating {
  border-color: #4a6cf7;
}

.face-buttons form {
  display: inline;
}

.rate-images-credit {
  font-size: 0.8rem;
  color: #666;
}

footer {
  margin-top: 1.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid #ddd;
  font-size: 0.8rem;
  color: #666;
  text-align: center;
}

footer a {
  color: inherit;
}

/* Mobile: ~20% more compact than desktop, as requested — most margins,
   paddings, min-heights, and font-sizes below are the desktop value * 0.8.
   Two deliberate exceptions, both accessibility floors rather than a
   literal 20% cut: answer-choice buttons keep a ~44px (2.75rem) minimum
   touch target (Apple/Google's usual guideline), and footer/copyright text
   stops shrinking once it'd drop below ~0.7rem, since a straight 20% cut
   there starts to hurt legibility rather than just density. The photo
   credit "i" badge is left alone entirely for the same touch-target
   reason — it's already small. Breakpoint matches `body`'s own desktop
   `max-width: 40rem` (640px), so this only kicks in once the container
   would be full-width anyway, not on an arbitrarily narrowed desktop
   window. See docs/decisions.md's "Mobile compactness" section. */
@media (max-width: 640px) {
  body {
    margin: 1.6rem auto;
    padding: 0 0.8rem;
  }

  header h1 {
    font-size: 1.6rem;
  }

  .flashes {
    padding: 0.4rem 0.8rem;
    margin: 0.8rem 0;
  }

  .game-mode-line {
    font-size: 0.88rem;
    margin: 0.64rem 0 0;
  }

  .back-line {
    margin: 0.16rem 0 0.8rem;
  }

  .feedback-slot {
    min-height: 3.5rem;
    margin: 0 0 0.8rem;
    padding: 0.4rem 0.8rem;
  }

  .prompt {
    margin: 1.6rem 0;
  }

  .prompt-word-slot {
    min-height: 4.3rem;
  }

  .prompt-word {
    font-size: 1.76rem;
  }

  .audio-slot {
    min-height: 2.1rem;
    margin-top: 0.32rem;
  }

  .picture-slot {
    width: 9.6rem;
    height: 9.6rem;
  }

  .supporting-langs {
    font-size: 0.88rem;
    margin-top: 0.32rem;
  }

  .choices {
    gap: 0.48rem;
  }

  .choices button {
    min-height: 2.75rem; /* touch-target floor, not a literal 0.8x — see comment above */
    padding: 0.64rem;
    font-size: 0.88rem;
  }

  .spell-input {
    margin: 0.48rem auto 0.8rem;
    padding: 0.48rem;
    font-size: 1.04rem;
  }

  .flashcard {
    padding-bottom: 0.4rem;
  }

  .user-list li, .mode-list li, .stat-list li, .module-list li {
    margin: 0.32rem 0;
  }

  .hardest-list {
    padding-left: 1.12rem;
  }

  .hardest-list li {
    margin: 0.24rem 0;
  }

  .copyright-list {
    font-size: 0.75rem; /* legibility floor, not a literal 0.8x (0.72rem) */
    margin: 0.24rem 0 1rem;
  }

  footer {
    margin-top: 1rem;
    padding-top: 0.4rem;
    font-size: 0.7rem; /* legibility floor, not a literal 0.8x (0.64rem) */
  }
}
