/* Tokens (edit here to rebrand) + shared component styles; each activity adds only its own CSS. */

@import url('assets/shared/vendor/lexend/lexend.css');
@import url('assets/shared/vendor/fontawesome-6.5.1/css/all.min.css'); /* Font Awesome Free */

:root {
  /* ======================= TOKENS (rebrand here) ======================== */
  /* Color primitives */
  --color-blue-100: #E2EEFF; --color-blue-200: #9DC6FF; --color-blue-300: #4592FF; --color-blue-400: #00409B; --color-blue-500: #00204D;
  --color-yellow-100: #FFF5D9; --color-yellow-200: #FFECB9; --color-yellow-300: #FFD768; --color-yellow-400: #B08200; --color-yellow-500: #4C3800;
  --color-green-100: #D8F0E0; --color-green-200: #8FD5A6; --color-green-300: #41AA64; --color-green-400: #22723C; --color-green-500: #044F1D;
  --color-neutral-000: #FFFFFF; --color-neutral-50: #E5E7EB; --color-neutral-100: #A3ACB7; --color-neutral-200: #6C747F; --color-neutral-300: #485260; --color-neutral-400: #283445; --color-neutral-500: #011633;
  --color-red-100: #FEC4C1; --color-red-200: #E8706A; --color-red-300: #B3261E;
  /* Grade palettes (Main used now; accents reserved) */
  --grade-lower-main: #F2EDB1; --grade-lower-accent-1: #A4C5FF; --grade-lower-accent-2: #F96B94; --grade-lower-accent-3: #A0BA5D;
  --grade-upper-main: #BDDBFF; --grade-upper-accent-1: #4592FF; --grade-upper-accent-2: #8D8AFF; --grade-upper-accent-3: #FFB889;
  --grade-mh-main:    #F5F2ED; --grade-mh-accent-1: #00409B; --grade-mh-accent-2: #A675CB; --grade-mh-accent-3: #E1EEFF;
  /* Semantic status */
  --color-correct: var(--color-green-300); --color-incorrect: var(--color-red-300); --color-selected: var(--color-yellow-300);
  /* Typography (Lexend) */
  --font-family: "Lexend", system-ui, -apple-system, sans-serif;
  --weight-regular: 400; --weight-medium: 500; --weight-semibold: 600; --weight-bold: 700;
  --text-xs: 0.75rem; --text-s: 0.875rem; --text-m: 1rem; --text-l: 1.125rem; --text-xl: 1.5rem; --text-2xl: 2rem; --text-3xl: 2.25rem;
  /* Spacing (px; DS scale) */
  --spacing-0: 0px; --spacing-1: 4px; --spacing-2: 8px; --spacing-3: 12px; --spacing-4: 16px; --spacing-5: 20px; --spacing-6: 24px; --spacing-7: 28px;
  --spacing-8: 32px; --spacing-9: 36px; --spacing-10: 40px; --spacing-11: 44px; --spacing-12: 48px; --spacing-14: 56px; --spacing-16: 64px; --spacing-20: 72px;
  --spacing-24: 80px; --spacing-28: 112px; --spacing-32: 128px; --spacing-36: 144px; --spacing-40: 160px; --spacing-44: 176px; --spacing-48: 192px; --spacing-52: 208px;
  --spacing-56: 224px; --spacing-60: 240px; --spacing-64: 256px; --spacing-72: 288px; --spacing-80: 320px; --spacing-96: 384px;
  /* Radius */
  --radius-sm: 2px; --radius-default: 4px; --radius-md: 6px; --radius-lg: 8px; --radius-xl: 12px; --radius-2xl: 16px; --radius-3xl: 24px; --radius-full: 9999px;
  /* Borders */
  --border-width: 1px; --border-color-default: var(--color-neutral-100); --border-color-hover: var(--color-neutral-200);
  /* Shadows (Figma) */
  --shadow-500: 0 10px 32px -4px #18274B1A, 0 6px 14px -6px #18274B1F;
  --shadow-chip: 0 12px 42px -4px #18274B1F, 0 8px 18px -6px #18274B1F;
  /* Icons */
  --icon-color: var(--color-neutral-500); --icon-color-inverse: #FFFFFF; --icon-size: 1.25rem;

  /* =================== SEMANTIC ALIASES (design refs these) ============= */
  --bg:           var(--color-blue-100);   /* page background (was #E8F1FB) */
  --bg-hover:     #CFE1F7;                  /* literal — no token between Blue 100/200 */
  --surface:      var(--color-neutral-000);/* white */
  --navy:         var(--color-blue-500);   /* was #1A3561 → closest Blue 500 */
  --navy-mid:     var(--color-blue-300);   /* was #2F5FCC → closest Blue 300 */
  --text:         var(--color-neutral-500);/* was #1A3561 → Neutral 500 */
  --muted:        var(--color-neutral-200);/* was #6B7A99 → Neutral 200 */
  --card-border:  rgba(26,53,97,0.09);      /* literal — navy tint */
  --slot-bg:      rgba(26,53,97,0.04);      /* literal — navy tint */
  --slot-border:  rgba(26,53,97,0.22);      /* literal — navy tint */
  --correct:      var(--color-correct);
  --incorrect:    var(--color-incorrect);
  --selected:     var(--color-selected);
  /* --topbar-bg / --topbar-title are set by the grade classes (lower/upper/mh),
     which every activity carries on <body>. There is no ungraded "base" state. */
  --btn-yellow:       var(--color-yellow-200);
  --btn-yellow-hover: var(--color-yellow-300);
  --btn-blue:         var(--color-blue-400);
  --btn-blue-hover:   var(--color-blue-500);
  --radius:       var(--radius-2xl);        /* was 14px → 16px (closest) */
  --gap:          var(--spacing-3);         /* 12px */
  --font:         var(--font-family);

  /* sizing (mobile-first; desktop bumps below) */
  --nub-size: 26px; --nub-center: 50%;
  --content-max-width: 860px;
  --content-pad:       var(--spacing-5);    /* 20px */
  --fs-title:           var(--text-xl);     /* 1.5rem */
  --fs-instructions:    var(--text-s);
  --fs-card:            var(--text-s);
  --fs-section-label:   var(--text-xs);
  --fs-btn:             var(--text-s);
  --card-min-h: 60px; --card-pad-y: 14px; --card-pad-x: var(--spacing-4);
  --rack-width: 300px; --btn-pad-y: 10px; --btn-pad-x: 22px;
}

/* Responsive type — mirrors typography.js (Tailwind sm=640px, lg=1024px) */
@media (max-width: 1023.98px) { :root { --text-l: 1rem; --text-2xl: 1.75rem; --text-3xl: 2rem; } }
@media (max-width: 639.98px)  { :root { --text-xl: 1.25rem; --text-2xl: 1.5rem; --text-3xl: 1.75rem; } }

/* Desktop size-up (all bumps in one place) */
@media (min-width: 721px) {
  :root {
    --content-max-width: 1120px;
    --fs-title: 1.785rem; /* 2.1rem * 0.85 — trimmed from Figma's original 2.1rem, header ran too tall */
    --fs-instructions: 1.1rem; --fs-card: 1.1rem;
    --fs-section-label: 0.82rem; --fs-btn: 1rem;
    --card-min-h: 82px; --card-pad-y: 18px; --card-pad-x: 24px;
    --rack-width: 380px; --btn-pad-y: 13px; --btn-pad-x: 28px; --gap: 16px;
  }
}

/* Base */
* { box-sizing: border-box; margin: 0; padding: 0; }
/* Also on html: an off-screen fixed element can still widen the document's scrollable width. */
html { overflow-x: hidden; }
body {
  font-family: var(--font);
  color: var(--text);
  background-color: var(--bg);
  background-image: radial-gradient(circle, rgba(26,53,97,0.09) 1.5px, transparent 1.5px);
  background-size: 28px 28px;
  min-height: 100vh;
  /* No page-level horizontal scroll; off-edge fixed decorations (e.g. Flashcards' side art) widen scrollWidth. */
  overflow-x: hidden;
}
/* Fixed-pixel tile size (not cover) so the pattern keeps its size at every width. */
body.grade-mh {
  background-image: url("assets/shared/pattern tile_blue line.png");
  background-size: 80px 80px;
  background-repeat: repeat;
}
/* On mobile, Middle & High drops the tiled pattern for a flat page-color
   background (#E2EEFF). Applies to every interactive activity. */
@media (max-width: 720px) {
  body.grade-mh { background-image: none; background-color: var(--bg); }
}
main { padding: 0; }

/* Grade switch changes only these: top bar background, title color and illustration. */
body.grade-lower { --topbar-bg: var(--color-yellow-100); --topbar-title: var(--text); }              /* #FFF5D9 / #011633 */
body.grade-upper { --topbar-bg: var(--color-blue-200);   --topbar-title: var(--text); }              /* #9DC6FF / #011633 */
body.grade-mh    { --topbar-bg: var(--color-blue-400);   --topbar-title: var(--color-neutral-000); } /* #00409B / white  */

/* url() lives in a rule so it resolves relative to global.css for every activity; hidden under 480px. */
body.grade-lower .top-bar { background-image: url("assets/shared/topbar-LE.svg"); }
body.grade-upper .top-bar { background-image: url("assets/shared/topbar-UE.svg"); }
body.grade-mh    .top-bar { background-image: url("assets/shared/topbar-MH.svg"); }

/* State / loader */
.state { text-align: center; padding: 100px 20px; color: var(--muted); font-size: 0.95rem; }
.state.error { color: var(--incorrect); }
.loader { width: 44px; height: 44px; border: 3px solid rgba(26,53,97,0.15); border-top-color: var(--navy-mid); border-radius: 50%; animation: spin 0.8s linear infinite; margin: 0 auto 16px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Top bar */
.top-bar {
  background-color: var(--topbar-bg);
  background-repeat: no-repeat;                 /* grade illustration set per grade below */
  background-position: left top;
  background-size: auto 100%;                   /* fills bar height, bleeds to edges */
  padding: 14px var(--content-pad);             /* was 18px — header ran too tall at every width */
  border-radius: 0 0 30px 30px;                 /* rounded bottom corners (Figma) */
  overflow: hidden;                             /* clip illustration at corners */
}
.top-bar-inner { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 16px; min-height: 46px; }   /* was 56px */
.top-bar-text { grid-column: 2; text-align: center; }
/* Right-hand action buttons (sound settings + Review Instructions). */
.top-bar-actions { grid-column: 3; justify-self: end; display: flex; align-items: center; gap: 8px; }
.top-bar-action { }
.activity-title { font-size: var(--fs-title); font-weight: var(--weight-bold); color: var(--topbar-title); margin-bottom: 6px; line-height: 1.2; }

/* Instructions pill; Lower Elementary uses the default surface, so only Upper and MH override. */
.activity-instructions {
  width: fit-content;
  max-width: 100%;
  margin: 0 auto var(--spacing-6);
  padding: var(--spacing-5);
  background: var(--surface);
  color: var(--color-neutral-300);
  font-size: var(--text-l);
  font-weight: var(--weight-semibold);
  text-align: center;
  line-height: 1.3;
  border-radius: 20px;
}
body.grade-upper .activity-instructions { background: var(--color-yellow-100); }
/* Darker text on the MH instructions background (Blue/200) for contrast. */
body.grade-mh    .activity-instructions { background: var(--color-blue-200); color: var(--color-neutral-500); }
/* Read-aloud button at the end of the instruction sentence */
.instr-tts {
  border: none;
  background: transparent;
  cursor: pointer;
  color: inherit;
  font-size: var(--text-s);
  line-height: 1;
  padding: 4px;
  margin-left: 8px;
  border-radius: 6px;
  opacity: 1;
  vertical-align: middle;
  transition: opacity 0.15s cubic-bezier(0.22, 1, 0.36, 1), background 0.15s cubic-bezier(0.22, 1, 0.36, 1);
}
.instr-tts:hover { opacity: 1; background: rgba(26,53,97,0.08); }
.instr-tts:focus-visible { opacity: 1; outline: 2px solid var(--navy-mid); outline-offset: 2px; }

/* Shared read-aloud icon button; each activity adds its own positioning. */
.tts {
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--color-neutral-300);
  font-size: var(--text-s);
  opacity: 1;
  line-height: 1;
  padding: 5px;
  border-radius: 6px;
  transition: opacity 0.15s cubic-bezier(0.22, 1, 0.36, 1), background 0.15s cubic-bezier(0.22, 1, 0.36, 1);
}
.tts:hover { background: rgba(26,53,97,0.06); }
.tts:focus-visible { outline: 2px solid var(--navy-mid); outline-offset: 2px; }

/* Hiding from view until TTS service is implemented. Markup/handlers are kept (JS still looks these up); delete this rule to bring the buttons back. */
.tts, .instr-tts, .fc-tts, button[aria-label*="aloud"] { display: none !important; }

/* Filled circle number badge — shared across activities with numbered
   items (Q&A, Fill in the Blanks): Blue/200 circle, medium-weight number. */
.num-badge {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--color-blue-200); color: var(--text); font-weight: var(--weight-medium); font-size: 0.9em;
}

/* Icon-only settings button beside Review Instructions; opens the sound toggle modal. */
.settings-btn {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 40px; height: 40px; border-radius: 50%; border: none; cursor: pointer;
  transition: background-color 0.15s cubic-bezier(0.22, 1, 0.36, 1), transform 0.1s cubic-bezier(0.22, 1, 0.36, 1);
}
.settings-btn:active { transform: scale(0.94); }
.settings-btn:focus-visible { outline: 2px solid var(--navy-mid); outline-offset: 2px; }

/* Grade button treatments (Figma): LE/UE dark-blue button, MH light-blue button */
body.grade-lower .top-bar-action, body.grade-lower .settings-btn,
body.grade-upper .top-bar-action, body.grade-upper .settings-btn {
  background: var(--btn-blue); color: var(--color-neutral-000); border: none;
}
body.grade-lower .top-bar-action:hover, body.grade-lower .settings-btn:hover,
body.grade-upper .top-bar-action:hover, body.grade-upper .settings-btn:hover { background: var(--btn-blue-hover); }
body.grade-mh .top-bar-action, body.grade-mh .settings-btn {
  background: var(--color-blue-200); color: var(--navy); border: none;
}
body.grade-mh .top-bar-action:hover, body.grade-mh .settings-btn:hover { background: var(--color-blue-100); }

/* Settings modal toggle row (Sound on/off). */
.settings-body { text-align: left; margin: 20px 0; background: var(--color-yellow-100); border-radius: 16px; padding: 16px 18px; }
.settings-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.settings-row + .settings-row { margin-top: 12px; }
.settings-label { font-weight: var(--weight-semibold); color: var(--navy); font-size: 0.95rem; }
.switch { position: relative; flex-shrink: 0; width: 48px; height: 28px; border-radius: 999px; border: none; background: var(--color-neutral-100); cursor: pointer; transition: background .2s; padding: 0; }
.switch[aria-checked="true"] { background: var(--btn-blue); }
.switch-thumb { position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.25); transition: transform .2s cubic-bezier(0.22, 1, 0.36, 1); }
.switch[aria-checked="true"] .switch-thumb { transform: translateX(20px); }
.switch:focus-visible { outline: 2px solid var(--navy-mid); outline-offset: 2px; }

/* Toolbar row (Submit / Restart) */
.toolbar-row { display: flex; justify-content: center; gap: 10px; margin: 24px 0 28px; flex-wrap: wrap; }

/* Content shell + section labels */
.app-shell { max-width: var(--content-max-width); margin: 0 auto; padding: 24px var(--content-pad) 80px; }
.section-label { font-size: var(--fs-section-label); font-weight: var(--weight-semibold); text-transform: uppercase; letter-spacing: 1.5px; color: var(--muted); margin-bottom: 10px; }

/* Buttons */
.btn { border: none; border-radius: 999px; padding: var(--btn-pad-y) var(--btn-pad-x); font-weight: var(--weight-semibold); font-size: var(--fs-btn); cursor: pointer; font-family: inherit; transition: transform 0.1s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.15s cubic-bezier(0.22, 1, 0.36, 1), background-color 0.15s cubic-bezier(0.22, 1, 0.36, 1); white-space: nowrap; }
.btn:active { transform: scale(0.97); }
.btn-primary { background: var(--btn-blue); color: white; }
.btn-primary:hover { background: var(--btn-blue-hover); }
.btn-primary:active { background: var(--btn-blue-hover); }
.btn-ghost { background: var(--btn-yellow); color: var(--navy); border: 1.5px solid var(--color-yellow-400); }
.btn-ghost:hover { background: var(--btn-yellow-hover); border-color: var(--color-yellow-400); }
/* Blue secondary: a quieter action next to a primary (e.g. ending a round early). Blue 200 fill, Blue 400 border. */
.btn-secondary { background: var(--color-blue-200); color: var(--navy); border: 1.5px solid var(--btn-blue); }
.btn-secondary:hover { background: var(--color-blue-100); }
/* pointer-events:none makes disabled buttons inert even where :hover/:active still fire. */
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.4; cursor: not-allowed; pointer-events: none; }

/* Idle wiggle for the Roll/Spin buttons before first use. */
@keyframes wiggleBounce {
  0%, 55%, 100% { transform: scale(1) rotate(0deg); }
  16% { transform: scale(1.08) rotate(-2deg); }
  33% { transform: scale(0.98) rotate(2deg); }
  44% { transform: scale(1.02) rotate(-1deg); }
}
.play-bounce { animation: wiggleBounce 2s cubic-bezier(0.34, 1.56, 0.64, 1) infinite; }

/* Modal / overlay */
/* safe center + overflow-y:auto on the overlay keeps a too-tall modal scrollable from anywhere on screen. */
.overlay { position: fixed; inset: 0; background: rgba(26,53,97,0.38); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); display: flex; align-items: safe center; justify-content: center; overflow-y: auto; padding: 20px; z-index: 20; }
.overlay[hidden] { display: none; }
.modal { position: relative; background: white; color: var(--navy); border-radius: 28px; max-width: 520px; width: 100%; padding: 40px 36px; text-align: center; box-shadow: 0 28px 72px rgba(26,53,97,0.22); animation: modal-in 0.24s cubic-bezier(0.34, 1.56, 0.64, 1) both; }
.modal-close { position: absolute; top: 16px; right: 16px; width: 34px; height: 34px; border: none; border-radius: 50%; background: var(--bg); color: var(--navy); cursor: pointer; font-size: 15px; line-height: 1; display: flex; align-items: center; justify-content: center; transition: background 0.15s cubic-bezier(0.22, 1, 0.36, 1); }
.modal-close:hover { background: var(--bg-hover); }
@keyframes modal-in { from { transform: scale(0.88) translateY(16px); opacity: 0; } to { transform: scale(1) translateY(0); opacity: 1; } }
/* Close is quicker and calmer than open; closeModal() waits for animationend. */
@keyframes modal-out { from { transform: scale(1); opacity: 1; } to { transform: scale(0.96); opacity: 0; } }
.modal--closing { animation: modal-out 0.15s cubic-bezier(0.22, 1, 0.36, 1) both; }
.modal h1 { font-size: var(--fs-title); font-weight: var(--weight-bold); margin-bottom: 10px; line-height: 1.2; }
.modal p { font-size: var(--text-s); color: var(--muted); line-height: 1.7; margin-bottom: 28px; font-weight: var(--weight-regular); }
.modal .cta-row { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.cta-row--single-line { flex-wrap: nowrap; gap: 8px; overflow-x: auto; padding-bottom: 2px; }
.cta-row--single-line .btn { padding: 10px 16px; font-size: 0.8rem; flex-shrink: 0; }
/* Hero media in content modals: 16:9, 30px radius. */
.modal-media { display: block; width: 100%; aspect-ratio: 4096 / 2304; object-fit: cover; border-radius: 30px; }
.modal-image-placeholder { width: 100%; aspect-ratio: 4096 / 2304; background: var(--bg); border: 2px dashed var(--slot-border); border-radius: 30px; display: flex; align-items: center; justify-content: center; color: var(--muted); font-size: 34px; }
.completed-art {
  width: 360px; max-width: 100%; height: 200px; margin: 0 auto;
  background-repeat: no-repeat; background-position: center; background-size: contain;
}
body.grade-lower .completed-art { background-image: url("assets/shared/completed-LE.png"); }
body.grade-upper .completed-art { background-image: url("assets/shared/completed-UE.png"); }
body.grade-mh    .completed-art { background-image: url("assets/shared/completed-MH.png"); }

/* Big modal layout for opening/review/completed/exit-warning; :has() keeps small text modals on the base style. */
.modal:has(:is(.completed-art, .modal-media, .modal-image-placeholder, .exit-warning-art)) { max-width: 560px; border-radius: 60px; padding: 40px; box-shadow: 0 28px 36px rgba(26,53,97,0.22); }
.modal:has(:is(.completed-art, .modal-media, .modal-image-placeholder, .exit-warning-art)) h1 { font-size: 1.875rem; margin: 32px 0 0; }   /* 30px, navy (inherited) */
.modal:has(:is(.completed-art, .modal-media, .modal-image-placeholder, .exit-warning-art)) p  { color: var(--color-neutral-400); font-size: var(--text-m); line-height: 1.7; margin: 14px 0 0; }
.modal:has(:is(.completed-art, .modal-media, .modal-image-placeholder, .exit-warning-art)) .cta-row { gap: 8px; margin-top: 24px; }
.modal:has(:is(.completed-art, .modal-media, .modal-image-placeholder, .exit-warning-art)) .cta-row .btn { padding: 14px 20px; font-size: var(--text-m); }
/* Opening / review show a single fixed-width primary CTA (180px, Figma) */
.modal:has(:is(.modal-media, .modal-image-placeholder)) .cta-row .btn { min-width: 180px; }
/* Shared error-state icon, grade-swapped like .completed-art. */
.warning-art {
  width: 200px; height: 200px; max-width: 100%; margin: 0 auto;
  background-repeat: no-repeat; background-position: center; background-size: contain;
}
body.grade-lower .warning-art { background-image: url("assets/shared/warning_LE.png"); }
/* UE art sits off-center in its canvas; nudge right to look centered. */
body.grade-upper .warning-art { background-image: url("assets/shared/warning_UE.png"); background-position: 60% center; }
body.grade-mh    .warning-art { background-image: url("assets/shared/warning_MH.png"); }

/* "Are you sure?" art for progress-loss confirmations; shares the big-modal spacing. */
.exit-warning-art {
  width: 200px; height: 200px; max-width: 100%; margin: 0 auto;
  background-repeat: no-repeat; background-position: center; background-size: contain;
}
body.grade-lower .exit-warning-art { background-image: url("assets/shared/exit-warning_LE.svg"); }
body.grade-upper .exit-warning-art { background-image: url("assets/shared/exit-warning_UE.svg"); }
body.grade-mh    .exit-warning-art { background-image: url("assets/shared/exit-warning_MH.svg"); }

/* Shared error/fallback card for a bad id or failed fetch. */
.error-card {
  display: inline-flex; flex-direction: column; align-items: center; gap: 14px;
  max-width: 460px; margin: 0 auto;
  background: var(--surface); border-radius: 60px; box-shadow: var(--shadow-500);
  padding: 28px 32px 48px; color: var(--color-neutral-400); text-align: center;
}
.error-card p { margin: 0; font-size: var(--fs-card); line-height: 1.5; }
.error-card-code { font-size: 0.85em; opacity: 0.8; }
.error-card .error-card-retry { margin-top: var(--spacing-2); }
/* Tooltip: data-tip="Label" on a control shows the label on hover and keyboard focus.
   data-tip-pos="top" puts it above; data-tip-align="end" lines it up with the right edge. */
[data-tip] { position: relative; }
[data-tip]::after { content: attr(data-tip); position: absolute; z-index: 30; top: calc(100% + 8px); left: 50%; transform: translate(-50%, -4px); background: var(--navy); color: var(--color-neutral-000); font-family: var(--font-family); font-size: var(--text-s); font-weight: var(--weight-semibold); line-height: 1.2; white-space: nowrap; padding: 6px 10px; border-radius: var(--radius-lg); box-shadow: var(--shadow-500); pointer-events: none; opacity: 0; transition: opacity .15s ease, transform .15s ease; }
[data-tip][data-tip-pos="top"]::after { top: auto; bottom: calc(100% + 8px); transform: translate(-50%, 4px); }
[data-tip][data-tip-align="end"]::after { left: auto; right: 0; transform: translateY(-4px); }
[data-tip][data-tip-pos="top"][data-tip-align="end"]::after { transform: translateY(4px); }
@media (hover: hover) { [data-tip]:hover::after { opacity: 1; transform: translate(-50%, 0); } [data-tip][data-tip-align="end"]:hover::after { transform: none; } }
[data-tip]:focus-visible::after { opacity: 1; transform: translate(-50%, 0); }
[data-tip][data-tip-align="end"]:focus-visible::after { transform: none; }
/* data-tip-pos="left": beside the control, for spots that clip below (the top bar). */
[data-tip][data-tip-pos="left"]::after { top: 50%; left: auto; right: calc(100% + 8px); transform: translate(4px, -50%); }
@media (hover: hover) { [data-tip][data-tip-pos="left"]:hover::after { transform: translate(0, -50%); } }
[data-tip][data-tip-pos="left"]:focus-visible::after { transform: translate(0, -50%); }
/* Plain tiled background for errors; the html prefix beats activities' own body.grade-X rules. */
html body:has(.error-card) { background: var(--color-yellow-100) url("assets/shared/pattern tile_yellow grid.png") repeat; }

/* Toast */
.toast { position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%); background: var(--incorrect); color: white; padding: 10px 20px; border-radius: 999px; font-weight: var(--weight-semibold); font-size: var(--text-s); z-index: 30; box-shadow: 0 4px 16px rgba(224,64,42,0.3); }
.toast[hidden] { display: none; }

/* Shared animations */
@keyframes shake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } }
.shake { animation: shake 0.35s; }

/* Shared responsive (chrome only) */
@media (min-width: 721px) {
  .app-shell { padding-top: 32px; padding-bottom: 40px; }
}
@media (max-width: 720px) {
  .modal { padding: 32px 24px; }
  /* Drop the illustration at the MD breakpoint (selectors repeated to match the
     per-grade specificity so they win). The bar stays horizontal until 480px. */
  body.grade-lower .top-bar,
  body.grade-upper .top-bar,
  body.grade-mh .top-bar { background-image: none; }
}
/* Mobile top bar (Figma): at 480px switch to the stacked, centered layout —
   title above the button (illustration already removed at the MD breakpoint). */
@media (max-width: 480px) {
  .top-bar { padding: 14px 20px; }   /* was 18px, matching the trim above */
  .top-bar-inner { grid-template-columns: 1fr; gap: 12px; }
  .top-bar-text   { grid-column: 1; }
  .top-bar-actions { grid-column: 1; justify-self: center; }
  .activity-title { font-size: 1.5rem; }   /* 24px per Figma mobile */
}
/* 481-830px: drop the illustration and left-align the title; <=480px keeps its stacked layout. */
@media (min-width: 481px) and (max-width: 830px) {
  body.grade-lower .top-bar,
  body.grade-upper .top-bar,
  body.grade-mh    .top-bar { background-image: none; }
  /* Two-item flex row (title left, button right); text-align alone would leave the title centered-ish. */
  .top-bar-inner { display: flex; justify-content: space-between; align-items: center; }
  .top-bar-text { text-align: left; }
}
/* Let "Review Instructions" wrap once the header is tight; scoped so other .btn stay nowrap. */
@media (max-width: 600px) {
  .top-bar-action { white-space: normal; }
}

/* Shared buttons (first built for the Social Skills Quiz Show). Hover styles only apply on devices that can hover. */
/* Text link button, for small secondary actions such as "Reset avatars". */
.link-btn { display: inline-flex; align-items: center; gap: var(--spacing-2); border: none; background: none; font-family: inherit; font-size: var(--text-s); font-weight: var(--weight-semibold); color: var(--btn-blue); padding: var(--spacing-2); border-radius: var(--radius-lg); cursor: pointer; }
@media (hover: hover) { .link-btn:hover { text-decoration: underline; text-underline-offset: 3px; } }
.link-btn[hidden] { display: none; }
.link-btn:focus-visible { outline: 2px solid var(--focus-ring, var(--color-blue-500)); outline-offset: 2px; }
/* Small tool chip next to a question, such as Skip or Hint; pair with .btn .btn-ghost. */
.q-tool { min-width: 0; min-height: 44px; padding: var(--spacing-2) var(--spacing-4); font-size: var(--text-s); }
.q-tool i { margin-right: var(--spacing-2); }
/* Moderator marking buttons (Correct / Incorrect); the icon slides in on hover or focus. Pair with .btn. */
.mark-btn { display: inline-flex; align-items: center; justify-content: center; }
.mark-btn i { display: inline-block; width: 0; text-align: center; opacity: 0; margin-right: 0; overflow: hidden; transition: width .18s cubic-bezier(0.22, 1, 0.36, 1), opacity .18s ease, margin .18s cubic-bezier(0.22, 1, 0.36, 1); }
/* 1.25em: some icons (the star) are wider than 1em and were clipped. */
.mark-btn:focus-visible i { width: 1.25em; opacity: 1; margin-right: var(--spacing-2); }
@media (hover: hover) { .mark-btn:hover i { width: 1.25em; opacity: 1; margin-right: var(--spacing-2); } }
.mark-correct { background: var(--color-green-100); color: var(--color-green-500); border: 2px solid var(--color-green-400); }
@media (hover: hover) { .mark-correct:hover { background: var(--color-green-200); color: var(--color-neutral-500); } }
/* Fill is Red 100 mixed half with white: Red 300 text on Red 100 was 4.3:1; on this tint it is 5.3:1 (WCAG AA). */
.mark-incorrect { background: color-mix(in srgb, var(--color-red-100) 50%, var(--color-neutral-000)); color: var(--color-red-300); border: 2px solid var(--color-red-300); }
@media (hover: hover) { .mark-incorrect:hover { background: var(--color-red-200); color: var(--color-neutral-500); } }
/* Reveal box: the cover ("Reveal answer") slides up to show a hidden answer; a tab on the box's top edge hides it again. */
.reveal-area { position: relative; margin-top: var(--spacing-10); }
.reveal-box { position: relative; overflow: hidden; border-radius: var(--radius-2xl); }
.reveal-cover { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--spacing-2); border: none; border-radius: inherit; background: var(--color-blue-100); color: var(--navy); font-family: inherit; font-size: var(--text-l); font-weight: var(--weight-bold); cursor: pointer; transition: transform .35s cubic-bezier(0.22, 1, 0.36, 1), background-color .15s ease; }
@media (hover: hover) { .reveal-cover:hover { background: var(--color-blue-200); } .reveal-cover:hover i { transform: translateY(-3px); } }
.reveal-cover i { transition: transform .2s ease; }
.reveal-cover:focus-visible { outline: 3px solid var(--focus-ring, var(--color-blue-500)); outline-offset: -3px; }
.reveal-box.is-open .reveal-cover { transform: translateY(-100%); }
.reveal-tab { position: absolute; bottom: 100%; left: 50%; z-index: 1; transform: translateX(-50%); display: inline-flex; align-items: center; gap: var(--spacing-2); border: none; border-radius: var(--radius-lg) var(--radius-lg) 0 0; font-family: inherit; font-size: var(--text-s); font-weight: var(--weight-semibold); white-space: nowrap; padding: var(--spacing-2) var(--spacing-5); cursor: pointer; transition: background-color .15s ease; }
/* Invisible extension so the small tab is still a 44px target. */
.reveal-tab::before { content: ""; position: absolute; inset: -12px -6px 0; }
.reveal-tab i { font-size: 0.85em; }
.reveal-tab--hide { background: var(--btn-blue); color: var(--color-neutral-000); animation: revealTabUp .3s .15s cubic-bezier(0.22, 1, 0.36, 1) both; }
/* The Hide tab slides up out of the box's top edge as the answer is revealed. */
@keyframes revealTabUp { from { transform: translate(-50%, 100%); clip-path: inset(0 0 100% 0); } to { transform: translate(-50%, 0); clip-path: inset(0); } }
@media (hover: hover) { .reveal-tab--hide:hover { background: var(--btn-blue-hover); } }
.reveal-tab[hidden] { display: none; }
.reveal-tab:focus-visible { outline: 3px solid var(--focus-ring, var(--color-blue-500)); outline-offset: 2px; }
/* Arrow button for scrolling a row of content (rounded rectangle, Blue 200). */
.board-arrow { display: flex; align-items: center; justify-content: center; width: 56px; height: 44px; border: none; border-radius: var(--radius-xl); background: var(--color-blue-200); color: var(--navy); font-size: var(--text-l); cursor: pointer; transition: opacity .2s ease, background-color .15s ease; }
@media (hover: hover) { .board-arrow:hover { background: var(--color-blue-100); } }
.board-arrow:disabled { opacity: .35; cursor: default; }
.board-arrow:focus-visible { outline: 3px solid var(--focus-ring, var(--color-blue-500)); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .reveal-cover, .reveal-tab, .mark-btn i { transition: none; } .reveal-tab--hide { animation: none; } }

/* Reduced motion (decorative motion only). .modal keeps a near-zero duration, not none,
   so animationend still fires for closeModal(). */
@media (prefers-reduced-motion: reduce) {
  .modal, .modal--closing { animation-duration: 0.01s; }
  .play-bounce { animation: none; }
}


/* ==========================================================================
   Game UI components (from SSQS, 2026-11-04): shared building blocks for new games.
   Buttons extras, the game card, choice cards, answer options and the hover ring.
   ========================================================================== */

/* Buttons: minimum width, keyboard focus ring, and the arrow / check that slide in on hover or focus
   (add <i class="hover-arrow"> or <svg class="hover-check"> inside a .btn). */
.btn { min-width: 140px; }
.btn:focus-visible { outline: 3px solid var(--focus-ring, var(--color-blue-500)); outline-offset: 3px; }
/* Hover check (every "Got it"): slides in like Next's arrow, then the stroke draws itself. */
.btn:has(.hover-check) { display: inline-flex; align-items: center; justify-content: center; }
.hover-check { display: inline-block; flex-shrink: 0; width: 0; height: 18px; margin-left: 0; opacity: 0; overflow: visible; fill: none; stroke: currentColor; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 20; stroke-dashoffset: 20; transition: width .18s cubic-bezier(0.22, 1, 0.36, 1), opacity .18s cubic-bezier(0.22, 1, 0.36, 1), margin .18s cubic-bezier(0.22, 1, 0.36, 1), stroke-dashoffset .35s .1s cubic-bezier(0.22, 1, 0.36, 1); }
.btn:focus-visible .hover-check { width: 18px; opacity: 1; margin-left: var(--spacing-2); stroke-dashoffset: 0; }
@media (hover: hover) { .btn:hover .hover-check { width: 18px; opacity: 1; margin-left: var(--spacing-2); stroke-dashoffset: 0; } }
.btn:has(.hover-arrow), .btn:has(.hover-arrow-left) { display: inline-flex; align-items: center; justify-content: center; }
.hover-arrow, .hover-arrow-left { display: inline-block; width: 0; opacity: 0; overflow: hidden; transition: width .24s cubic-bezier(0.25, 0.8, 0.4, 1), opacity .24s ease, margin .24s cubic-bezier(0.25, 0.8, 0.4, 1); }
.btn:focus-visible .hover-arrow { width: 1em; opacity: 1; margin-left: var(--spacing-2); }
@media (hover: hover) { .btn:hover .hover-arrow { width: 1em; opacity: 1; margin-left: var(--spacing-2); } }
.btn:focus-visible .hover-arrow-left { width: 1em; opacity: 1; margin-right: var(--spacing-2); }
@media (hover: hover) { .btn:hover .hover-arrow-left { width: 1em; opacity: 1; margin-right: var(--spacing-2); } }
/* Touch screens: hover colors would stick after a tap. */
@media (hover: none) { .btn-primary:hover { background: var(--btn-blue); } .btn-ghost:hover { background: var(--btn-yellow); } }
@media (prefers-reduced-motion: reduce) { .hover-check, .hover-arrow, .hover-arrow-left { transition: none; } }

/* Game card: the white rounded panel that holds a setup screen (number of players, avatars, game mode...). */
.game-card { --card-px: var(--spacing-9); background: var(--surface); border-radius: 40px; box-shadow: var(--shadow-500); padding: var(--spacing-9) var(--card-px) var(--spacing-12); max-width: 860px; margin: 0 auto; text-align: center; }
@media (max-width: 720px) { .game-card { --card-px: var(--spacing-5); padding: var(--spacing-6) var(--card-px) var(--spacing-9); border-radius: 32px; } }

/* Choice cards: a <label class="choice-card"> around a hidden radio/checkbox. Hover ring (Blue 200, 2px + 1px outside),
   slight grow on hover, press-in on click, Blue 300 selected ring with a check badge (.choice-check), disabled state. */
.choice-grid { display: grid; gap: var(--spacing-4); }
.choice-card { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--spacing-2); background: var(--surface); border: 2px solid var(--slot-border); border-radius: var(--radius-3xl); padding: var(--spacing-5) var(--spacing-4); cursor: pointer; color: var(--navy); transition: border-color .15s cubic-bezier(0.22, 1, 0.36, 1), background-color .15s cubic-bezier(0.22, 1, 0.36, 1), transform .2s cubic-bezier(0.34, 1.56, 0.64, 1); }
.choice-card input { position: absolute; opacity: 0; width: 1px; height: 1px; }
/* Hover: the same ring as the avatar cards, a 2px Blue 200 border plus 1px just outside it (not on selected or disabled cards). */
.choice-card::after { content: ""; position: absolute; inset: -2px; pointer-events: none; opacity: 0; transition: opacity .2s ease; border: 2px solid var(--color-blue-200); border-radius: inherit; box-shadow: 0 0 0 1px var(--color-blue-200); }
@media (hover: hover) { .choice-card:not(:has(input:checked)):not(:has(input:disabled)):hover { border-color: transparent; background-color: var(--surface); } }
@media (hover: hover) { .choice-card:not(:has(input:checked)):not(:has(input:disabled)):hover::after { opacity: 1; } }
/* Hover grows the whole card (transform, so nothing around it moves). */
@media (hover: hover) { .choice-card:not(:has(input:disabled)):hover { transform: scale(1.03); } }
/* Selected: one solid 4px ring (a 3px border plus the 1px ring), drawn as the 2px border plus 2px just outside it, so the
   card's content doesn't shift (an inset shadow left a visible gap at the corners). */
.choice-card:has(input:checked) { border-color: var(--color-blue-300); background-color: var(--color-blue-100); box-shadow: 0 0 0 2px var(--color-blue-300); }
/* Check badge pops in, then its tick draws itself. */
.choice-check { position: absolute; top: var(--spacing-2); right: var(--spacing-2); width: 26px; height: 26px; border-radius: 50%; background: var(--btn-blue); display: flex; align-items: center; justify-content: center; opacity: 0; transform: scale(0.4); transition: opacity .15s ease, transform .25s cubic-bezier(0.34, 1.56, 0.64, 1); }
.choice-check svg { width: 14px; height: 14px; fill: none; stroke: var(--color-neutral-000); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 18; stroke-dashoffset: 18; transition: stroke-dashoffset .24s .1s cubic-bezier(0.22, 1, 0.36, 1); }
.choice-card:has(input:checked) .choice-check { opacity: 1; transform: none; }
.choice-card:has(input:checked) .choice-check svg { stroke-dashoffset: 0; }
.choice-card:has(input:disabled) { cursor: not-allowed; opacity: 0.45; }
@media (hover: hover) { .choice-card:has(input:disabled):hover { border-color: var(--slot-border); } }
/* Click: every choice card presses in, then springs back on release (transform transition). */
.choice-card:not(:has(input:disabled)):active { transform: scale(0.95); }
.choice-card:has(input:focus-visible) { outline: 3px solid var(--focus-ring, var(--color-blue-500)); outline-offset: 3px; }

/* Answer options: .q-options list of <label class="q-option"> (letter, text, status). Same hover ring; selected,
   then correct / wrong once the list is .locked. */
.q-options { display: flex; flex-direction: column; gap: var(--spacing-3); border: none; }
.q-option { display: flex; align-items: center; gap: var(--spacing-4); background: var(--surface); border: 2px solid var(--slot-border); border-radius: var(--radius-2xl); padding: var(--spacing-4) var(--spacing-5); cursor: pointer; transition: border-color .15s cubic-bezier(0.22, 1, 0.36, 1), background-color .15s cubic-bezier(0.22, 1, 0.36, 1); }
.q-option input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.q-option { position: relative; }
/* Hover: the avatar cards' ring, a 2px Blue 200 border plus 1px outside it (not once an answer is chosen or locked). */
.q-option::after { content: ""; position: absolute; inset: -2px; pointer-events: none; opacity: 0; transition: opacity .2s ease; border: 2px solid var(--color-blue-200); border-radius: inherit; box-shadow: 0 0 0 1px var(--color-blue-200); }
@media (hover: hover) { .q-options:not(.locked) .q-option:not(:has(input:checked)):hover { border-color: transparent; background: var(--color-blue-100); } }
@media (hover: hover) { .q-options:not(.locked) .q-option:not(:has(input:checked)):hover::after { opacity: 1; } }
@media (hover: hover) { .q-options:not(.locked) .q-option:not(:has(input:checked)):hover .q-letter { background: var(--surface); } }
.q-option:has(input:focus-visible) { outline: 3px solid var(--focus-ring, var(--color-blue-500)); outline-offset: 3px; }
.q-letter { flex-shrink: 0; width: 44px; height: 44px; border-radius: 50%; background: var(--bg); color: var(--navy); font-weight: var(--weight-bold); font-size: var(--text-l); display: flex; align-items: center; justify-content: center; }
.q-option-text { flex: 1; color: var(--text); font-size: var(--text-xl); line-height: 1.35; }
.q-option-status { flex-shrink: 0; display: none; align-items: center; gap: var(--spacing-2); font-weight: var(--weight-bold); font-size: var(--text-s); white-space: nowrap; }
.q-option:has(input:checked) { border-color: var(--btn-blue); background: var(--color-blue-100); }
.q-option:has(input:checked) .q-letter { background: var(--btn-blue); color: var(--color-neutral-000); }
.q-options.locked .q-option { cursor: default; }
@media (hover: hover) { .q-options.locked .q-option:hover { border-color: var(--slot-border); } }
/* Scoped under .locked so the reveal beats the :checked "selected" style. */
.q-options.locked .q-option.is-correct { border-color: var(--correct); background: var(--color-green-100); }
.q-options.locked .q-option.is-correct .q-letter { background: var(--color-green-400); color: var(--color-neutral-000); }
.q-options.locked .q-option.is-correct .q-option-status { display: inline-flex; color: var(--color-green-400); }
/* Same tint as the Incorrect button, so "Chosen answer" in Red 300 passes 4.5:1. */
.q-options.locked .q-option.is-wrong { border-color: var(--incorrect); background: color-mix(in srgb, var(--color-red-100) 50%, var(--color-neutral-000)); }
.q-options.locked .q-option.is-wrong .q-letter { background: var(--incorrect); color: var(--color-neutral-000); }
.q-options.locked .q-option.is-wrong .q-option-status { display: inline-flex; color: var(--incorrect); }
.q-option-text { min-width: 0; overflow-wrap: anywhere; }
@media (prefers-reduced-motion: reduce) { .choice-card, .q-option, .choice-check, .choice-check svg { transition-duration: 0.01s; transition-delay: 0s; } }
