:root {
  /* High Contrast Dark Ed-Tech Palette (Refined) */
  --bg-base: #0f172a; 
  --bg-surface: #1e293b;
  --bg-elevated: #334155;
  --bg-modal: rgba(15, 23, 42, 0.85);
  
  --text-main: #ffffff;
  --text-muted: #cbd5e1;
  --text-input: #ffffff;
  
  /* Primary Action (Softer Pastel Blue) */
  --accent: #4086f6;
  --accent-shadow: #245cb0; 
  --accent-glow: rgba(110, 162, 245, 0.4);
  
  /* Destructive */
  --danger: #ef4444;
  --danger-shadow: #b91c1c;
  
  /* Info (Teal) */
  --info-teal: #0cbc67;
  --info-shadow: #0d9443;
  
  /* User Settings (Softer Pastel Orange) */
  --next-orange: #ff7f2a;
  --next-shadow: #d46b29;

  /* Inactive Tabs (Greyed-out Blue / Slate) */
  --muted-blue: #64748b;
  --muted-blue-shadow: #475569;

  /* Active Tabs (Lighter Blue Green) */
  --active-teal: #06b6d4;
  --active-teal-shadow: #0891b2;

  /* ---- Spacing ---- */
  --page-top-gap: 30px; /* Gap from top of viewport to page content — tweak here */

  /* ---- Global font size offset ---- */
  /* Add to (or subtract from) every font-size in the app in one place.
     0px  = default sizes.
    -2px  = all text 2 px smaller.
    +2px  = all text 2 px larger.
     Any font-size written as calc((Xpx + var(--font-adjust)) * var(--font-scale)) will respond. */
  --font-adjust: 0px;

  /* ---- Accessibility viewing size ----
     One user-chosen "viewing size" drives these. Standard = today's sizing.
     Large / Extra Large grow text and touch targets toward the Apple &
     Google accessibility maximums. The mode is set by data-text-size on
     <html> (see shared/accessibility.js). Tune the three blocks below only.
       --font-scale     multiplies every scale-aware font-size
       --control-scale  multiplies button heights / min touch targets
       --touch-min      minimum tap target (WCAG 44 / Android 48dp and up) */
  --font-scale: 1;
  --control-scale: 1;
  --touch-min: 44px;

  --radius-sm: 12px;
  --radius-md: 20px;
  --radius-lg: 28px;
  
  --font-main: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --shadow-soft: 0 8px 24px rgba(0, 0, 0, 0.4);
}

/* --- Accessibility viewing-size modes (set on <html>) --- */
html[data-text-size="large"] {
  --font-scale: 1.30;
  --control-scale: 1.18;
  --touch-min: 52px;
}
html[data-text-size="xl"] {
  --font-scale: 1.70;
  --control-scale: 1.40;
  --touch-min: 60px;
}

/* Lock out the OS's own text auto-sizing (iOS Dynamic Type / Android font
   scale) so OUR chosen viewing size is the single source of truth. */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* --- Light Mode Variables --- */
body.light-theme {
  --bg-base: #f1f5f9; 
  --bg-surface: #ffffff;
  --bg-elevated: #e2e8f0;
  --bg-modal: rgba(241, 245, 249, 0.9);
  
  --text-main: #0f172a;
  --text-muted: #475569;
  --text-input: #0f172a;

  --shadow-soft: 0 4px 12px rgba(0, 0, 0, 0.08);
}

/* --- Global Resets --- */
* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: var(--font-main);
  background: var(--bg-base);
  color: var(--text-main);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
  transition: background-color 0.3s, color 0.3s;
}

.hidden { display: none !important; }

/* --- Layout Container --- */
.app {
  max-width: 620px;
  margin: 0 auto;
  padding: var(--page-top-gap) 12px 32px;
  display: flex;
  flex-direction: column;
  gap: 16px; 
  min-height: 100vh;
}

/* On wider viewports (desktop/tablet), give the app a "raised page" look —
   a visible border edge with a soft shadow down either side, and a bit of
   breathing room from the very edge of the app's content. Below 681px the
   app fills the viewport as before, with no border/shadow. */
@media (min-width: 620px) {
  .app {
    padding-left: 30px;
    padding-right: 30px;
    background: var(--bg-surface);
    border-left: 1px solid var(--bg-elevated);
    border-right: 1px solid var(--bg-elevated);
    box-shadow: -12px 0 24px rgba(0, 0, 0, 0.25), 12px 0 24px rgba(0, 0, 0, 0.25);
  }
  body.light-theme .app {
    box-shadow: -12px 0 24px rgba(0, 0, 0, 0.08), 12px 0 24px rgba(0, 0, 0, 0.08);
  }

  /* Background image behind the raised page, in the gutters either side of
     .app. Rendered on a ::before pseudo-element (rather than directly as
     body's own background) purely so its opacity can be adjusted without
     fading the page's actual content — body's own "opacity" would affect
     everything inside it too. position: fixed pins it to the viewport so
     it never scrolls with the page and sits behind everything (z-index:
     -1); sized to the full window width with its own height following
     from that (aspect ratio preserved). Below 620px .app fills the
     viewport edge-to-edge, so there's no gutter for it to show in and
     it's left off entirely. */
  body::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image: url('../images/background.png');
    background-repeat: no-repeat;
    background-position: top center;
    background-size: 100% auto;
    opacity: 0.8; /* <- change this (0 = invisible, 1 = fully opaque) to adjust the background image's opacity */
  }
}

/* --- Headers & Hero --- */
.hero { text-align: center; }
.app-titleWrap { display: flex; justify-content: center; align-items: center; min-height: 60px; }
.app-titleImg { max-width: 100%; height: auto; object-fit: contain; }
.fallback-title { font-size: max(11pt, calc((26px + var(--font-adjust)) * var(--font-scale))); font-weight: 900; color: var(--text-main); letter-spacing: -0.5px; }

/* Title Image Toggling */
.img-light { display: none; }
body.light-theme .img-dark { display: none; }
body.light-theme .img-light { display: block; }

/* The outlined panel for the greeting */
.welcome-panel {
  background: var(--bg-surface);
  border: 0px solid var(--bg-elevated);
  border-radius: var(--radius-md);
  padding: 16px 20px;
  box-shadow: var(--shadow-soft);
  margin-top: 8px;
  margin-bottom: -4px;
  transition: background-color 0.3s, border-color 0.3s;
}

.welcome-heading {
  text-align: center;
  font-size: max(11pt, calc((20px + var(--font-adjust)) * var(--font-scale)));
  font-weight: 900;
  color: var(--text-main);
  margin: 0; 
  line-height: 1.3;
}

/* --- Core Ed-Tech Buttons --- */
.btn {
  font-family: var(--font-main);
  min-height: calc(52px * var(--control-scale));
  height: auto;
  padding-top: 6px;
  padding-bottom: 6px;
  border-radius: var(--radius-sm);
  border: none;
  font-size: max(11pt, calc((16px + var(--font-adjust)) * var(--font-scale)));
  font-weight: 800;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.1s, box-shadow 0.1s, background-color 0.3s, color 0.3s, border-color 0.3s;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  padding-left: 16px;
  padding-right: 16px;
  background: var(--bg-elevated);
  color: var(--text-main);
  box-shadow: 0 4px 0 rgba(0,0,0,0.2);
}

body.light-theme .btn { box-shadow: 0 4px 0 #cbd5e1; }
.btn-large { min-height: calc(64px * var(--control-scale)); height: auto; font-size: max(11pt, calc((18px + var(--font-adjust)) * var(--font-scale))); border-radius: var(--radius-md); }
.btn:active:not(:disabled) { transform: translateY(4px); box-shadow: 0 0px 0 transparent !important; }
.btn-block { width: 100%; }

/* Explicit 2px solid border mapping to the shadow colors */
.primary { 
  background: var(--accent); 
  color: #fff; 
  border: 2px solid var(--accent-shadow); 
  box-shadow: 0 4px 0 var(--accent-shadow); 
}
body.light-theme .primary { box-shadow: 0 4px 0 var(--accent-shadow); }

.danger-btn { 
  background: var(--danger); 
  color: #fff; 
  border: 2px solid var(--danger-shadow); 
  box-shadow: 0 4px 0 var(--danger-shadow); 
}
body.light-theme .danger-btn { box-shadow: 0 4px 0 var(--danger-shadow); }

/* --- Top Actions Layout --- */
.top-actions-row {
  display: flex;
  flex-wrap: wrap;
  /* row-gap (the space between the Progress button and the Settings/Info
     row once they wrap onto a second line) is matched to the 10px gap
     below this row, down to the nav-row category tabs (16px .app gap -
     8px margin-bottom below + 2px nav-row padding-top = 10px). column-gap
     (horizontal space in the single-line state) is unrelated and stays 4px. */
  row-gap: 10px;
  column-gap: 4px;
  min-width: 0;
  margin-bottom: -8px;
}

/* Progress & Results takes the main row and grows to fill it; ellipsis keeps
   it on one line until the viewing size makes it wrap (see large/xl rules). */
.progress-btn {
  flex: 1 1 auto;
  min-width: 0;
  justify-content: center;
  font-size: max(11pt, calc((16px + var(--font-adjust)) * var(--font-scale)));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Settings + Info are grouped so they wrap together onto a second line as a
   unit when there isn't room beside Progress. */
.icon-actions {
  display: flex;
  flex: 0 0 auto;
  gap: 4px;
  min-width: 0;
}
.icon-btn {
  flex: 0 1 auto;
  min-width: var(--touch-min);
  width: auto;
  padding: 0 14px;
  gap: 6px;
  font-size: max(11pt, calc((20px + var(--font-adjust)) * var(--font-scale)));
}
/* Each icon button holds an emoji icon and a text label. Inline (compact)
   it shows just the icon. */
.icon-btn .ib-icon  { display: inline; }
.icon-btn .ib-label {
  display: none;
  /* Lets the label shrink below its own content width (instead of forcing
     the flex item wider) and clips rather than visibly overflowing past the
     button if it still doesn't fit — see label-overflow fallback below. */
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: clip;
}

/* Wide screens (>550px): show text label next to icon, match progress-btn font size.
   Standard size gets the same +2pt boost that .progress-btn has (see bottom of file). */
@media (min-width: 500px) {
  .icon-btn .ib-label { display: inline; }
  .icon-btn { font-size: max(11pt, calc((16px + var(--font-adjust)) * var(--font-scale))); }
  html[data-text-size="standard"] .icon-btn {
    font-size: calc(max(11pt, calc((16px + var(--font-adjust)) * var(--font-scale))) + 2pt);
  }
}

/* Extra Large: nudge the Settings / Info labels down by 1pt. */
html[data-text-size="xl"] .icon-btn {
  font-size: max(11pt, calc((20px + var(--font-adjust)) * var(--font-scale) - 1pt));
}

/* Wrapped state: the icon group fills its line and the two buttons share it
   equally, swapping the emoji icon for the full text label ("Settings" /
   "Information"). If script.js finds a button's word is still too wide for
   it (very narrow screens / large text sizes) it adds .label-overflow,
   which falls back to the emoji instead of letting the text spill past the
   button's edge. */
.top-actions-row.icons-wrapped .icon-actions {
  flex: 1 1 100%;
  width: 100%;
}
.top-actions-row.icons-wrapped .icon-btn { flex: 1 1 0; }
.top-actions-row.icons-wrapped .icon-btn .ib-icon  { display: none; }
.top-actions-row.icons-wrapped .icon-btn .ib-label { display: inline-block; }

.top-actions-row.icons-wrapped .icon-btn.label-overflow .ib-icon  { display: inline; }
.top-actions-row.icons-wrapped .icon-btn.label-overflow .ib-label { display: none; }

/* Filter & Sort Bar */
.filter-bar {
  display: flex;
  gap: 8px;
  justify-content: center; 
  margin-bottom: 0px;
}

/* Half height mini-buttons */
.mini-btn {
  min-height: calc(32px * var(--control-scale));
  height: auto;
  font-size: max(11pt, calc((11pt + var(--font-adjust)) * var(--font-scale)));
  border-radius: var(--radius-sm);
  padding: 0 12px;
}

/* Difficulty quick-filter bar */
.diff-quick-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  margin-top: 10px;
  margin-bottom: 0;
}

/* Selected states — each tier's vivid colour + shadow from DIFFICULTY_BANDS */
.diff-quick-btn.active[data-diff="beginner"] {
  background: #22c55e;
  border-color: #38935a;
  box-shadow: 0 4px 0 #15803d;
  color: #fff;
}
.diff-quick-btn.active[data-diff="intermediate"] {
  background: #3b82f6;
  border-color: #3f69de;
  box-shadow: 0 4px 0 #1d4ed8;
  color: #fff;
}
.diff-quick-btn.active[data-diff="advanced"] {
  background: #f97316;
  border-color: #cb5e30;
  box-shadow: 0 4px 0 #c2410c;
  color: #fff;
}
.diff-quick-btn.active[data-diff="extra-advanced"] {
  background: #dc2626;
  border-color: #a83d3d;
  box-shadow: 0 4px 0 #991b1b;
  color: #fff;
}
/* "All" selected: same glass-grey base, just reinforced opacity */
.diff-quick-btn.active[data-diff="all"] {
  background: rgba(203, 213, 225, 0.35);
  border-color: rgba(203, 213, 225, 0.65);
  box-shadow: 0 4px 0 rgba(203, 213, 225, 0.65);
}
body.light-theme .diff-quick-btn.active[data-diff="all"] {
  background: rgba(100, 116, 139, 0.3);
  border-color: rgba(100, 116, 139, 0.6);
  box-shadow: 0 4px 0 rgba(100, 116, 139, 0.6);
}

.btn-orange {
  background: var(--next-orange);
  color: #fff;
  border: 2px solid var(--next-shadow);
  box-shadow: 0 4px 0 var(--next-shadow);
}
body.light-theme .btn-orange { box-shadow: 0 4px 0 var(--next-shadow); }

.btn-teal {
  background: var(--info-teal);
  color: #fff;
  border: 2px solid var(--info-shadow);
  box-shadow: 0 4px 0 var(--info-shadow);
}
body.light-theme .btn-teal { box-shadow: 0 4px 0 var(--info-shadow); }

/* Semi-transparent Grey Buttons */
.btn-glass-grey {
  background: rgba(203, 213, 225, 0.15); 
  color: var(--text-main);
  border: 2px solid rgba(203, 213, 225, 0.3);
  box-shadow: 0 4px 0 rgba(203, 213, 225, 0.3);
}
body.light-theme .btn-glass-grey {
  background: rgba(148, 163, 184, 0.25); 
  border-color: rgba(148, 163, 184, 0.5);
  box-shadow: 0 4px 0 rgba(148, 163, 184, 0.5);
}

/* --- Navigation Tabs --- */
.nav-row {
  display: grid;
  /* Column count is chosen by script.js (layoutNavRow): it starts by trying
     every button on one row and steps down a column at a time until every
     label fits on a single line. Equal-width (1fr) columns make the row
     span the full available width, same as the progress/settings/info
     buttons above it. Driven purely by whether the text fits, at ANY
     viewing size. This is just the starting point before the script
     measures and may refine it. */
  grid-template-columns: repeat(4, 1fr);
  gap: 4px;
  row-gap: 14px;
  padding-top: 2px;
}

.nav-btn {
  min-height: calc(42px * var(--control-scale));
  height: auto;
  min-width: calc(48px * var(--control-scale));
  font-size: max(11pt, calc((16px + var(--font-adjust)) * var(--font-scale)));
  padding: 0 6px;
  margin-bottom: -6px;
  /* Keep each label on one line so layoutNavRow can detect when it no longer
     fits and step the grid down to fewer columns. */
  white-space: nowrap;
  overflow: hidden;
}

.tab-btn {
  background: var(--muted-blue);
  color: #fff;
  border: 2px solid var(--muted-blue-shadow);
  box-shadow: 0 4px 0 var(--muted-blue-shadow);
}

.tab-btn.active {
  background: var(--active-teal); 
  border-color: var(--active-teal-shadow); 
  box-shadow: 0 4px 0 var(--active-teal-shadow); 
}
body.light-theme .tab-btn.active {
  box-shadow: 0 4px 0 var(--active-teal-shadow);
}

/* --- Content Areas & Tiles --- */
.content-container { min-height: 200px; }
.content-section { animation: fadeIn 0.3s ease-in-out; }

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(5px); }
  to { opacity: 1; transform: translateY(0); }
}

.tile-grid {
  display: grid;
  /* Fully fluid: column count follows the available width AND the chosen
     viewing size (bigger text -> wider minimum -> fewer columns), so the
     grid adapts across every device size and text-size setting with no
     per-width breakpoints. minmax(0, ...) prevents content overflow. */
  grid-template-columns: repeat(auto-fill, minmax(min(100%, calc(140px * var(--font-scale))), 1fr));
  column-gap: 6px;
  /* Each row's height is simply the height of its tallest tile — the
     default behaviour for CSS grid rows (grid-auto-rows: auto) — and
     align-items: stretch (also the default, set explicitly here for
     clarity) makes every other tile in that row grow to match it. This
     gives clean, even row lines at the cost of a little extra vertical
     space compared to a masonry-style packed layout. */
  row-gap: 12px;
  align-items: stretch;
}

.tile-btn {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;   /* content begins at the top */
  text-align: center;
  /* Content-sized button tiles: a tappable minimum, then they grow to fit
     their text. No fixed aspect-ratio. The minimum grows with viewing size. */
  min-height: calc(72px * var(--font-scale));
  height: auto;
  /* Vertical spacing between tiles now comes from .tile-grid's row-gap;
     list view (below) lays its rows out with its own flex gap instead. */
  position: relative;
  overflow: hidden;
  background: var(--bg-surface); color: var(--text-main); text-decoration: none;
  border: 2px solid var(--tile-diff-color, var(--bg-elevated));
  border-radius: 10px;
  /* Fixed per viewing mode — no vw / width-based scaling, so tile text never
     changes size as the screen resizes; only the chosen viewing size does. */
  font-size: calc(16px * var(--font-scale));
  font-weight: 700;
  line-height: 1.2;
  box-shadow: 0 6px 0 var(--tile-diff-shadow, var(--bg-elevated));
  transition: transform 0.1s, box-shadow 0.1s, background-color 0.2s, border-color 0.2s;
  cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent;
}

/* Plain tiles (quizzes / videos / tools / etc.) have no bands — center the
   label with breathing room. */
.tile-btn:not(.game-tile) {
  justify-content: center;
  padding: 14px 4px;
  overflow-wrap: break-word;
  word-break: break-word;
  hyphens: auto;
}

/* Resources tab: a single stacked column regardless of viewing size, rather
   than the auto-fill masonry layout used elsewhere — only one resource tile
   exists today and more will simply stack below it. */
.resources-tile-grid {
  grid-template-columns: 1fr;
}

/* Resource tile: an image-only tile (the artwork already contains its own
   title text) sized to match the source image's aspect ratio rather than
   the usual text-driven min-height. Specificity note: ".tile-btn.resource-tile"
   (not just ".resource-tile") is required here so this padding override
   actually beats ".tile-btn:not(.game-tile)" above, which is more specific
   (two class-equivalent selectors) than a lone ".resource-tile" would be. */
.tile-btn.resource-tile {
  padding: 0;
  aspect-ratio: 4 / 3;
}

.resource-tile-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Game tiles: difficulty is also shown by the gradient background colour
   (set by script.js) in addition to the top band below. */
.game-tile {
  padding: 0;
  background: linear-gradient(135deg, var(--tile-grad-from, var(--bg-surface)) 0%, var(--tile-grad-to, var(--bg-elevated)) 100%);
}

/* Difficulty banner pinned to the very top of the tile (text label sits
   below it — see .tile-label order). Sizing (font-size, padding, line-height)
   intentionally mirrors .tile-achievement below so both bands share the same
   height. Background uses its own vivid colour (--tile-diff-band-color),
   independent of the border/shadow colour (--tile-diff-color). */
.tile-diff-band {
  order: 0;
  flex: 0 0 auto;
  width: 100%;
  padding: 5px 6px;
  overflow: hidden;
  font-size: calc(12px * var(--font-scale));
  font-weight: 900;
  letter-spacing: 0.4px;
  text-align: center;
  white-space: normal;
  line-height: 1.15;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
  background: var(--tile-diff-band-color, var(--bg-elevated));
}

/* Label sits below the difficulty banner. */
.tile-label {
  order: 1;
  flex: 1 1 auto;
  width: 100%;
  display: flex;
  align-items: flex-start;       /* text begins near the top */
  justify-content: center;
  padding: 12px 4px 8px;
  overflow: hidden;
  overflow-wrap: break-word;
  word-break: break-word;
  hyphens: auto;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}

/* Achievement band pinned to the bottom; wraps instead of truncating. */
.tile-achievement {
  order: 2;
  margin-top: auto;
  position: relative;
  flex: 0 0 auto;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5px 6px;
  overflow: hidden;
  pointer-events: none;
  font-size: calc(12px * var(--font-scale));
  font-weight: 900;
  color: #fff;
  letter-spacing: 0.4px;
  text-shadow: 0 1px 3px rgba(0,0,0,0.35);
  white-space: normal;
  text-align: center;
  line-height: 1.15;
}

/* Locked tiles' "Click To Unlock" band reuses .tile-achievement (see
   applyLockVisuals in script.js) but should stay static, not shine. */
.tile-achievement:not(.tile-achievement--unplayed)::after {
  content: '';
  position: absolute;
  top: -50%;
  left: -60%;
  width: 35%;
  height: 200%;
  background: linear-gradient(
    to right,
    transparent 0%,
    rgba(255,255,255,0.6) 50%,
    transparent 100%
  );
  transform: skewX(-15deg);
  animation: achievementShimmer 4s linear infinite;
  pointer-events: none;
}
.tile-btn.tile-locked .tile-achievement::after {
  content: none;
  animation: none;
}

@keyframes achievementShimmer {
  from { left: -60%; }
  to   { left: 130%; }
}

/* Bands used to be hidden entirely below 300px because the text would
   wrap at that width. Instead they now stay visible at every width -
   script.js measures each band and, if its text would overflow/wrap,
   trims characters off the end and appends ".." so it always stays on
   one line (see fitBandTextToAvoidOverflow in script.js). */

.tile-btn:active { transform: translateY(6px); box-shadow: 0 0px 0 var(--tile-diff-shadow, var(--bg-elevated)); background: var(--bg-elevated); }
.tile-btn:hover { border-color: var(--accent); }

/* Wrapper for collapsible category groups (e.g. Beginner, Intermediate...) */
.games-groups {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.category-group .tile-grid {
  margin-top: 10px;
}

.category-group.collapsed .tile-grid,
.category-group.collapsed .game-list {
  display: none;
}

/* --- Content Locking --- */

/* Locked tiles: fully desaturated instead of dark-tinted, so the title
   text stays easy to read while the tile is still clearly unavailable.
   filter renders the tile (and everything inside it) as one image before
   desaturating, so the background gradient, border, box-shadow AND the
   difficulty band's background (now reading "Locked" — see script.js)
   all lose their colour together without needing separate overrides. */
.tile-btn.tile-locked {
  filter: saturate(0);
}

/* NON-GAME tiles (quizzes, resources, etc.): lock bar via ::before so it
   never adds to the tile's layout height or disturbs the grid.
   Absolute-positioned on top of the tile (.tile-btn is already
   position: relative). */
.tile-btn.tile-locked:not(.game-tile)::before {
  content: '🔒 CLICK TO UNLOCK';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  font-weight: 900;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.95);
  background: rgba(0, 0, 0, 0.72);
  border-radius: inherit;           /* respects tile's rounded top corners */
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  pointer-events: none;
}

/* Legacy .tile-lock-bar — kept for safety but no longer inserted by JS */
.tile-lock-bar {
  order: -1;
  height: 20px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  font-weight: 900;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.95);
  background: rgba(0, 0, 0, 0.72);
  position: relative;
  z-index: 4;
  pointer-events: none;
}

/* Locked list items: grey out text/description */
.list-item.list-item-locked .list-item-title,
.list-item.list-item-locked .list-item-desc { opacity: 0.45; }

/* Unlock bar (sits below the difficulty buttons) */
.unlock-bar {
  display: flex;
  justify-content: center;
  margin-top: 10px;
}

/* Error text inside the unlock modal */
.unlock-error {
  margin-top: 10px;
  font-size: max(11pt, calc((13px + var(--font-adjust)) * var(--font-scale)));
  font-weight: 700;
  color: var(--danger);
}

/* Section view bar (View: Tiles / View: List toggle for non-game sections) */
.section-view-bar { margin-top: 2px; margin-bottom: 12px; }

/* Non-game sections in list view — CSS-driven, no JS re-render needed */
.content-section.section-list-view .tile-grid {
  display: flex;
  flex-direction: column;
  gap: 0;
}
.content-section.section-list-view .tile-btn:not(.resource-tile) {
  min-height: unset;
  height: auto;
  padding: 10px 4px;
  border-radius: 0;
  border: none;
  border-bottom: 1px solid var(--bg-elevated);
  box-shadow: none;
  background: transparent;
  justify-content: flex-start;
  text-align: left;
  margin-bottom: 0;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.content-section.section-list-view .tile-btn:nth-child(even):not(.resource-tile) {
  background: rgba(0, 0, 0, 0.12);
}
body.light-theme .content-section.section-list-view .tile-btn:nth-child(even):not(.resource-tile) {
  background: rgba(0, 0, 0, 0.06);
}
.content-section.section-list-view .tile-btn:last-child { border-bottom: none; }

/* --- List View (games section) --- */
.game-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-top: 10px;
}

.list-item {
  display: flex;
  flex-direction: column;
  padding: 10px 4px;
  border: none;
  border-bottom: 1px solid var(--bg-elevated);
  background: transparent;
  text-decoration: none;
  color: var(--text-main);
  cursor: pointer;
  transition: opacity 0.1s;
  -webkit-tap-highlight-color: transparent;
}

.list-item:nth-child(even) { background: rgba(0, 0, 0, 0.12); }
body.light-theme .list-item:nth-child(even) { background: rgba(0, 0, 0, 0.06); }
.list-item:last-child { border-bottom: none; }
.list-item:hover      { opacity: 0.75; }
.list-item:active     { opacity: 0.5; }

.list-item-row1 {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* Title: same size & weight as tile text */
.list-item-title {
  font-size: max(11pt, calc((16px + var(--font-adjust)) * var(--font-scale)));
  font-weight: 700;
  color: var(--text-main);
  line-height: 1.2;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Attainment pill: white text on tier-coloured background */
.list-item-pill {
  flex-shrink: 0;
  font-size: max(11pt, calc((12px + var(--font-adjust)) * var(--font-scale)));
  font-weight: 800;
  color: #fff;
  padding: 2px 9px;
  border-radius: 999px;
  white-space: nowrap;
  text-shadow: 0 1px 2px rgba(0,0,0,0.3);
  letter-spacing: 0.3px;
}

.list-item-pill--unplayed {
  color: #111 !important;
  text-shadow: none !important;
}

/* Description: slightly smaller and lighter than title; never below 11pt/16px */
.list-item-desc {
  font-size: max(11pt, calc((14px + var(--font-adjust)) * var(--font-scale)));
  font-weight: 500;
  color: var(--text-muted);
  margin-top: 5px;
  line-height: 1.35;
}

/* Category Heading - click/tap to collapse or expand its games */
.category-title {
  font-size: max(11pt, calc((16px + var(--font-adjust)) * var(--font-scale)));
  font-weight: 700;
  color: var(--text-main);
  margin-top: 12px;
  margin-bottom: 0px;
  border-bottom: 2px solid var(--bg-elevated);
  padding-bottom: 6px;
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  user-select: none;
}

.category-title:hover { color: var(--text-main); }

.category-arrow {
  font-size: max(11pt, calc((14px + var(--font-adjust)) * var(--font-scale)));
  line-height: 1;
}

/* --- Settings & Form Inputs --- */
.settings-group { margin-bottom: 20px; }
.settings-label { display: block; font-size: max(11pt, calc((15px + var(--font-adjust)) * var(--font-scale))); font-weight: 800; color: var(--text-muted); margin-bottom: 12px; border-bottom: 1px solid var(--bg-elevated); padding-bottom: 4px; }

/* Custom Form Rows */
.checkbox-row, .radio-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
  font-size: max(11pt, calc((16px + var(--font-adjust)) * var(--font-scale)));
  color: var(--text-main);
  font-weight: 600;
}
.checkbox-row input, .radio-row input {
  width: calc(20px * var(--control-scale));
  height: calc(20px * var(--control-scale));
  accent-color: var(--accent);
  cursor: pointer;
}
.checkbox-row label, .radio-row label { cursor: pointer; user-select: none; }

.text-input {
  width: 100%; background: var(--bg-base); border: 2px solid var(--bg-elevated);
  color: var(--text-input); font-size: max(11pt, calc((16px + var(--font-adjust)) * var(--font-scale))); font-family: var(--font-main);
  font-weight: 600; padding: 16px; border-radius: var(--radius-sm);
  outline: none; transition: border-color 0.2s;
}
.text-input:focus { border-color: var(--accent); }

/* --- Modals --- */
.modal {
  position: fixed; inset: 0; background: var(--bg-modal);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center;
  z-index: 100; padding: 12px; opacity: 1; transition: opacity 0.2s;
}

.modalCard {
  width: 100%; max-width: 500px; background: var(--bg-surface);
  border-radius: var(--radius-lg); padding: 24px 20px;
  box-shadow: 0 -10px 40px rgba(0,0,0,0.5); border: 2px solid var(--bg-elevated);
  max-height: 90vh; overflow-y: hidden;
  display: flex; flex-direction: column;
  animation: slideUp 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.modalCard-sm {
  max-width: 360px;
  padding: 20px 16px;
}
.modalCard-sm .modalTitle {
  font-size: max(11pt, calc((20px + var(--font-adjust)) * var(--font-scale)));
  margin-bottom: 12px;
}

body.light-theme .modalCard { box-shadow: 0 -10px 40px rgba(0,0,0,0.15); }
body.light-theme .modalBody {
  background:
    linear-gradient(var(--bg-base), var(--bg-base) 50%, transparent)     top    / 100% 28px local  no-repeat,
    linear-gradient(transparent, var(--bg-base) 50%, var(--bg-base))      bottom / 100% 28px local  no-repeat,
    radial-gradient(farthest-side at 50% 0%,   rgba(0,0,0,0.08), transparent) top    / 100% 10px scroll no-repeat,
    radial-gradient(farthest-side at 50% 100%, rgba(0,0,0,0.08), transparent) bottom / 100% 10px scroll no-repeat,
    var(--bg-base);
}

@keyframes slideUp { from { transform: translateY(100px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

.modalTitle { font-size: max(11pt, calc((22px + var(--font-adjust)) * var(--font-scale))); font-weight: 900; text-align: center; margin-bottom: 16px; color: var(--text-main); }
.modalBody {
  font-size: max(11pt, calc((15px + var(--font-adjust)) * var(--font-scale))); color: var(--text-muted); text-align: center; margin-bottom: 12px; font-weight: 500;
  flex: 1 1 auto; overflow-y: auto; min-height: 0;

  /* Distinct scrollable zone */
  border-radius: var(--radius-sm);
  border: 1px solid var(--bg-elevated);
  padding: 12px 14px;

  /* Scroll-shadow effect: gradients with local attachment act as covers that
     hide the fixed-attachment shadow gradients when the user is already at
     that edge — so shadows only appear when there is more content to scroll. */
  background:
    linear-gradient(var(--bg-base), var(--bg-base) 50%, transparent)     top    / 100% 28px local  no-repeat,
    linear-gradient(transparent, var(--bg-base) 50%, var(--bg-base))      bottom / 100% 28px local  no-repeat,
    radial-gradient(farthest-side at 50% 0%,   rgba(0,0,0,0.18), transparent) top    / 100% 10px scroll no-repeat,
    radial-gradient(farthest-side at 50% 100%, rgba(0,0,0,0.18), transparent) bottom / 100% 10px scroll no-repeat,
    var(--bg-base);
}
.modalBody p { margin-bottom: 12px; }
.text-left { text-align: left; }
.modalActions { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; flex-shrink: 0; }
.side-by-side-actions { flex-direction: row !important; gap: 8px !important; margin-top: 8px; }
.side-by-side-actions .btn { flex: 1; margin: 0 !important; }

/* Global intro modal contract — all games get side-by-side Back Home / Advance automatically */
#introModal .modalActions { flex-direction: row; gap: 8px; margin-top: 8px; }
#introModal .modalActions .btn { flex: 1; width: auto; margin: 0; }

@keyframes ringPulse { 0% { outline: 0px solid var(--ringColor); } 50% { outline: 8px solid var(--ringColor); } 100% { outline: 0px solid rgba(0,0,0,0); } }
.pulse { --ringColor: var(--accent-glow); animation: ringPulse 1.5s ease-in-out infinite; }

/* --- Footer --- */
.app-footer {
  text-align: center; margin-top: auto; padding-top: 32px;
  font-size: max(11pt, calc((13px + var(--font-adjust)) * var(--font-scale))); font-weight: 700; color: var(--text-muted); 
  opacity: 0.5;
}
/* =====================================================================
   ACCESSIBILITY VIEWING SIZE — layout adjustments & size-picker UI
   ===================================================================== */

/* At larger viewing sizes the Progress & Results label needs room to wrap
   onto two lines instead of being clipped, and the top row should stack. */
html[data-text-size="large"] .progress-btn,
html[data-text-size="xl"] .progress-btn {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  text-align: center;
  line-height: 1.15;
  min-height: calc(52px * var(--control-scale));
}
html[data-text-size="xl"] .top-actions-row .progress-btn {
  flex: 1 1 100%;
  min-width: 100%;
}

/* Standard viewing size only: Progress & Results label set 2pt larger than
   the base size (large/xl already get their own treatment above). */
html[data-text-size="standard"] .progress-btn {
  font-size: calc(max(11pt, calc((16px + var(--font-adjust)) * var(--font-scale))) + 2pt);
}

/* Safety: never let a control bleed off the side of the screen. */
.btn { max-width: 100%; }

/* ---- Size-picker option buttons (first-launch modal) ---- */
.size-options { gap: 14px; }
.size-option {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 0;
  height: auto;
  padding: 14px 12px;
  text-align: center;
}
.size-option .size-option-name {
  font-weight: 900;
  font-size: 16px;
  letter-spacing: 0.3px;
}
.size-option .size-option-sample {
  font-weight: 700;
  opacity: 0.95;
  line-height: 1.1;
}
/* Fixed-size previews so users actually SEE the difference between modes,
   independent of whatever size is currently active. */
.size-option[data-size="standard"] .size-option-sample { font-size: 15px; }
.size-option[data-size="large"]    .size-option-sample { font-size: 21px; }
.size-option[data-size="xl"]       .size-option-sample { font-size: 28px; }
.size-option.selected {
  background: var(--accent);
  color: #fff;
  border: 2px solid var(--accent-shadow);
  box-shadow: 0 4px 0 var(--accent-shadow);
}

/* ---- Segmented Viewing Size control (Settings modal) ---- */
.size-segment {
  display: flex;
  gap: 8px;
}
.size-segment .seg-btn {
  flex: 1 1 0;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
  padding: 10px 6px;
}
.size-segment .seg-btn .seg-sample {
  font-weight: 800;
  line-height: 1;
}
.size-segment .seg-btn[data-size="standard"] .seg-sample { font-size: 14px; }
.size-segment .seg-btn[data-size="large"]    .seg-sample { font-size: 18px; }
.size-segment .seg-btn[data-size="xl"]       .seg-sample { font-size: 23px; }
.size-segment .seg-btn .seg-label {
  font-size: 12px;
  font-weight: 800;
  opacity: 0.9;
}
.size-segment .seg-btn.selected {
  background: var(--accent);
  color: #fff;
  border: 2px solid var(--accent-shadow);
  box-shadow: 0 4px 0 var(--accent-shadow);
}
