/* Drishya - the Sanskrit sentence you can watch */

:root {
  --bg: #0a0a14;
  --panel: #15152a;
  --panel-2: #1c1c36;
  --line: #2a2a4a;
  --text: #eceaf6;
  --muted: #9a9ac0;
  --accent: #5858FD;
  --saffron: #f2851c;
  --teal: #2ec4b6;
  --green: #2ec46b;
  --red: #e23b3b;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html, body {
  margin: 0;
  min-height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* The device's own Devanagari face, for the reasons set out in akshara: every
   platform ships one that shapes correctly, and a webfont for this script is a
   real download on a phone connection. */
[lang="sa"] {
  font-family: "Nirmala UI", "Noto Sans Devanagari", "Noto Serif Devanagari",
               "Devanagari Sangam MN", "Kohinoor Devanagari", "Mangal", serif;
  font-feature-settings: "kern" 1, "liga" 1;
}

.wrap { max-width: 900px; margin: 0 auto; padding: 18px 16px 40px; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px max(12px, env(safe-area-inset-right)) 10px max(12px, env(safe-area-inset-left));
  background: rgba(10, 10, 20, 0.92);
  border-bottom: 1px solid var(--line);
  backdrop-filter: blur(6px);
}
.brand { margin: 0; font-weight: 700; letter-spacing: 0.5px; }
.back { color: var(--muted); text-decoration: none; font-size: 13.5px; }
.back::before { content: "< "; }
.back:hover { color: var(--text); }
.hud-btn {
  padding: 8px 14px;
  min-height: 40px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}
.hud-btn:hover { color: var(--text); border-color: var(--accent); }
.hud-btn[aria-pressed="true"] { color: #ff8c8c; border-color: rgba(255, 140, 140, 0.35); }

.intro-card {
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background:
    radial-gradient(120% 130% at 8% 0%, rgba(46, 196, 182, 0.16), rgba(0, 0, 0, 0) 60%),
    radial-gradient(120% 130% at 95% 100%, rgba(88, 88, 253, 0.18), rgba(0, 0, 0, 0) 58%),
    var(--panel);
}
.kicker {
  margin: 0 0 6px;
  font-size: 11px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--teal);
}
h1 { margin: 0 0 10px; font-size: 30px; letter-spacing: -0.7px; }
.lede { margin: 0 0 16px; color: var(--muted); font-size: 15px; line-height: 1.65; max-width: 60ch; }

.overall { margin: 0 0 16px; }
.bar { height: 8px; border-radius: 999px; background: rgba(255, 255, 255, 0.09); overflow: hidden; }
.bar span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--teal), var(--accent));
  transition: width .35s ease;
}
.overall-text { margin: 8px 0 0; color: var(--muted); font-size: 13px; }

.beta {
  margin: 18px 0 10px;
  padding: 12px 14px;
  border: 1px solid rgba(242, 133, 28, 0.4);
  border-radius: 12px;
  background: rgba(242, 133, 28, 0.08);
  color: #f6d5b4;
  font-size: 13px;
  line-height: 1.6;
}
.beta a { color: #ffd7ae; }
.cross { margin: 0 0 6px; color: var(--muted); font-size: 13.5px; }
.cross a { color: var(--teal); }

.section-title {
  margin: 26px 0 12px;
  font-size: 12px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--muted);
}

/* Sets */
.themes { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.theme {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  flex-wrap: wrap;
}
.theme.is-complete { border-color: rgba(46, 196, 107, 0.45); }
.theme-copy { flex: 1 1 240px; min-width: 0; }
.theme-copy h3 { margin: 0 0 3px; font-size: 16px; }
.theme-copy p { margin: 0 0 8px; color: var(--muted); font-size: 13px; line-height: 1.5; }
.theme-count { margin: 6px 0 0 !important; font-size: 12px !important; }
.theme-actions { display: flex; gap: 8px; flex: 0 0 auto; }

.btn {
  padding: 10px 16px;
  min-height: 44px;
  border-radius: 10px;
  border: 1px solid transparent;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
}
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: #4646e0; }
.btn-ghost { background: transparent; border-color: var(--line); color: var(--text); }
.btn-ghost:hover { border-color: var(--accent); }

/* Word list */
.view-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 16px; }
.view-head h2 { margin: 0; font-size: 20px; }
.view-note { margin: 2px 0 0; color: var(--muted); font-size: 13.5px; }

.words { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.word {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}
.word.is-learnt { border-color: rgba(46, 196, 107, 0.45); }
.word-sa { font-size: 24px; line-height: 1.35; }
.word-tr { color: var(--muted); font-size: 13.5px; }
.word-en { font-size: 15px; }
.word-g {
  justify-self: end;
  min-width: 24px;
  text-align: center;
  padding: 2px 7px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
}
.gender-key { margin: 14px 0 0; color: var(--muted); font-size: 12.5px; }
.gender-key .word-g { display: inline-block; margin: 0 2px; }

/* The board */
.round-head { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.round-theme { margin: 0; flex: 1 1 auto; font-weight: 700; }
.round-stat { margin: 0; color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }

.board {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.cell {
  min-height: 76px;
  padding: 12px 10px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  color: var(--text);
  font: inherit;
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease, opacity .2s ease;
  overflow-wrap: anywhere;
}
.cell.is-sa span { font-size: 27px; line-height: 1.35; }
.cell.is-en span { font-size: 17px; }
.cell:hover:not(:disabled) { border-color: var(--accent); }
.cell.is-picked { border-color: var(--teal); background: rgba(46, 196, 182, 0.14); }
.cell.is-wrong { border-color: var(--red); background: rgba(226, 59, 59, 0.16); }
/* Cleared pairs stay on the board rather than vanishing: the grid is a list of
   what has been learnt by the end, and an empty square teaches nothing. */
.cell.is-done {
  opacity: 0.4;
  border-color: rgba(46, 196, 107, 0.5);
  background: rgba(46, 196, 107, 0.1);
  cursor: default;
}

.feedback { margin: 16px 0 0; min-height: 44px; text-align: center; font-size: 15px; line-height: 1.55; }
.feedback.is-right { color: #8ff0b5; }
.feedback.is-wrong { color: #ffc7c7; }

/* Result */
.done-card {
  padding: 24px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--panel);
  text-align: center;
}
.done-card h2 { margin: 0 0 6px; font-size: 22px; }
.done-time {
  margin: 0 0 8px;
  font-size: 44px;
  font-weight: 800;
  letter-spacing: -1px;
  font-variant-numeric: tabular-nums;
}
.done-list { margin: 18px 0 0; padding: 0; list-style: none; display: grid; gap: 6px; text-align: left; }
.done-list li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 10px;
  align-items: baseline;
  padding: 8px 12px;
  border-radius: 10px;
  background: var(--panel-2);
}
.done-list span[lang="sa"] { font-size: 22px; }
.done-list em { font-style: normal; color: var(--muted); font-size: 13px; }
.done-actions { display: flex; gap: 10px; justify-content: center; margin-top: 22px; flex-wrap: wrap; }

.foot {
  padding: 22px 16px max(22px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  text-align: center;
  color: var(--muted);
  font-size: 13px;
}
.foot a { color: var(--muted); }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

@media (min-width: 700px) {
  .board { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 520px) {
  h1 { font-size: 24px; }
  .theme-actions { width: 100%; }
  .theme-actions .btn { flex: 1 1 auto; }
  .word { grid-template-columns: minmax(0, 1fr) auto; row-gap: 4px; }
  .word-tr { grid-column: 1; }
  .word-en { grid-column: 1; font-size: 14px; }
  .word-g { grid-row: 1; grid-column: 2; }
  .done-list li { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

/* ===================================================================
   Touch targets, 12/09/2026.

   A hit test across all seven games found the same defect on every one
   of them: the chrome and the option controls were sized for a mouse.
   The way back to the games list - the single most used control on a
   game page - was 17 to 38px tall depending on the game, the option
   buttons were 34 to 36px, and links inside a sentence were 17px. The
   mark is 44px, and a phone is the main way these are played.

   Gated on a coarse pointer so a desktop keeps its compact chrome
   exactly as it was: this is a phone fix, not a redesign.
   =================================================================== */
@media (pointer: coarse) {

  /* The way out. It is the control a lost player reaches for, so it is
     the last one that should be hard to hit. */
  .back, .link-back, .hud-back {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 10px 0 6px;
    margin-left: -6px;
    border-radius: 10px;
  }
  .back:active, .link-back:active { background: rgba(255, 255, 255, 0.06); }

  /* Option rows: level, difficulty, traffic, which mark you play. */
  .segmented button { min-height: 44px; }

  /* Everything already shaped like a button, brought up to the mark. */
  .hud-btn, .ghost-btn, .icon-btn, .btn, .tbtn { min-height: 44px; }
  .icon-btn { min-width: 44px; }

  /* A link inside a sentence cannot be 44px without wrecking the line, so
     the line is opened up instead and the link padded into it. 17px to
     33px is the difference between a miss and a hit. */
  .foot p a, .beta a, .cross a, .intro a, .note a, .tip a {
    display: inline-block;
    padding: 8px 0;
  }
  .foot p, .beta, .cross { line-height: 2.05; }

  /* A disclosure triangle is a control too. */
  summary { min-height: 44px; }
}

/* ------------------------------------------- the course, in the footer
   Every Sanskrit page carries all three games and says which one the reader
   is on. It used to be one sentence with three links threaded through it:
   the order was invisible and each link was a 17px tap target. */
.foot-line { margin: 0 0 12px; }
.foot-steps {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
}
.foot-steps a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 44px;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--text);
  text-decoration: none;
  font-size: 13.5px;
}
.foot-steps a:hover { border-color: var(--teal, #2ec4b6); }
.foot-steps a:focus-visible { outline: 2px solid var(--teal, #2ec4b6); outline-offset: 2px; }
.foot-steps em { font-style: normal; color: var(--muted); }
.step-n {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--line);
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
}
/* The page you are already on is a label, not a link you want to take. */
.foot-steps a.is-here {
  border-color: var(--teal, #2ec4b6);
  background: rgba(46, 196, 182, 0.1);
}
.foot-steps a.is-here .step-n { background: var(--teal, #2ec4b6); color: #08131a; }

/* `.daily-share summary` sets its own 34px, which outranks the 44px in the
   touch block above on specificity. A rule that loses silently is the trap
   this project keeps meeting; this is the explicit override. */
@media (pointer: coarse) {
  .daily-share summary { min-height: 44px; }
}

/* The same bar the hub and milaojobs.tsblack.in carry: who owns the site, and
   who built it. Sits under the course row so every page ends the same way. */
.foot-bar {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: var(--muted);
}
.foot-bar p { margin: 0; }
.foot-bar a { color: var(--teal, #2ec4b6); text-decoration: none; }
.foot-bar a:hover { text-decoration: underline; }
.foot-bar a:focus-visible { outline: 2px solid var(--teal, #2ec4b6); outline-offset: 2px; }

@media (min-width: 700px) {
  .foot-bar { flex-direction: row; justify-content: center; gap: 6px 18px; }
}

/* Those two are links inside a sentence, so they get the same treatment as the
   rest of the prose links: a line opened up and the link padded into it. */
@media (pointer: coarse) {
  .foot-bar { line-height: 2.05; }
  .foot-bar a { display: inline-block; padding: 8px 0; }
}


/* Controls are controls, not text: a thumb held on one must not raise a
   selection or an iOS copy callout. Every game here carries the same list, and
   tools/verify.js fails if one of them loses a line of it. Prose is left out on
   purpose - One Over's share card is a textarea a player copies from - and so
   is any text input, which has to stay selectable to be usable. */
button, kbd, canvas, summary, label,
.tbtn, .tbtn-stack, .touch, .touch-left, .touch-right, .touch-row, .touch-pad,
.zone, .stick, .bomb-btn, .board, .tiles, .swatches,
.hud, .hud-btn, .hud-btns, .hud-stats, .chips, .topbar, .topbar-actions,
.segmented, .more-sheet,
a.hud-back, a.icon-back, a.link-back, a.btn,
[role="button"], [role="radio"], [role="gridcell"], [role="checkbox"], [role="switch"] {
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

/* While a run is on, the page is the game. */
body.is-playing .foot { display: none !important; }

/* In fullscreen the game is the only thing on the screen. The two prefixes
   cannot share a rule: one selector a browser does not know invalidates the
   whole list, so they are written out separately. */
:fullscreen .foot { display: none !important; }
:-webkit-full-screen .foot { display: none !important; }

/* One more button in the bar, so the bar is allowed to wrap rather than push
   its last control off a narrow screen. */
.topbar { flex-wrap: wrap; }
.topbar-actions { flex-wrap: wrap; }

/* ===================================================================
   The way out is one icon button, the same in every game - 14/09/2026.

   It used to be a text link reading "All games" in six games, "Home"
   in Race Dash, each at its own size and with a "< " glued on in CSS.
   A chevron into a line reads as back at any size, costs no width on a
   narrow HUD, and is the same shape on all eight pages.

   It stays a link, not a button, so middle click and open in a new tab
   behave. The label is still in the markup for a screen reader and as
   the tooltip, so nothing is lost by dropping the visible words.
   =================================================================== */
.icon-back {
  display: inline-grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  margin: 0;
  flex: 0 0 auto;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 11px;
  background: rgba(255, 255, 255, 0.04);
  color: inherit;
  opacity: 0.82;
  text-decoration: none;
}
.icon-back:hover { opacity: 1; background: rgba(255, 255, 255, 0.10); }
.icon-back:active { background: rgba(255, 255, 255, 0.16); }
.icon-back svg { display: block; }
/* The old text link glued its arrow on with a pseudo element. */
.icon-back::before, .icon-back::after { content: none !important; }

/* Its own copy of the screen reader label, so the icon carries a name in
   every game whatever that game calls its hidden text class. */
.icon-back .visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

@media (pointer: coarse) {
  .icon-back { width: 44px; height: 44px; padding: 0; margin: 0; }
}

/* ===================================================================
   Drishya - the stage, the acts, the word chips and the cast

   Every act is a CSS animation rather than a frame loop, for the reason
   set out at the top of game.js. They all run for 2.6s, which is what
   game.js waits before calling a scene finished; change one and change
   ACT_MS with it, or the caption arrives while the elephant is still
   walking.

   Positions come in as custom properties written onto the elements by
   drawScene: --walk is a step in that element's own coordinates,
   --mx/--my is the actor's mouth and --hx/--hy the top of its head, both
   relative to where the object stands.
   =================================================================== */

.section-title { margin: 26px 0 12px; font-size: 17px; }
.hint { margin: 10px 0 0; color: var(--muted); font-size: 12.5px; line-height: 1.55; }

/* Two ways in, side by side: neither is a step after the other. */
.modes { display: grid; gap: 12px; margin: 16px 0 0; }
.mode {
  width: 100%;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 14px;
  padding: 16px;
  min-height: 76px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.mode:hover { border-color: var(--accent); }
.mode-badge {
  display: inline-grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 12px;
  background: var(--panel-2);
  color: var(--teal);
  font-weight: 800;
  font-size: 18px;
}
.mode-make .mode-badge { color: var(--saffron); }
.mode-text { display: grid; gap: 3px; }
.mode-text b { font-size: 16px; }
.mode-text em { font-style: normal; color: var(--muted); font-size: 13px; line-height: 1.5; }
.mode-bests {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin: 12px 0 0;
  color: var(--muted);
  font-size: 12.5px;
}

.stars { display: inline-flex; gap: 3px; }
.star svg { width: 18px; height: 18px; display: block; fill: #33334f; }
.star.is-on svg { fill: #ffd166; }

/* The cast: every word this game can say, with the picture it is drawn as. */
/* The cast folds away: worth having on the page, not worth putting between a
   child and the Play button. */
.cast-fold {
  margin: 26px 0 0;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
}
.cast-fold > summary {
  min-height: 48px;
  display: flex;
  align-items: center;
  padding: 0 16px;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.cast-fold > summary::-webkit-details-marker { display: none; }
.cast-fold > summary::after {
  content: "+";
  margin-left: auto;
  color: var(--muted);
  font-size: 20px;
  line-height: 1;
}
.cast-fold[open] > summary::after { content: "-"; }
.cast-fold > .hint { padding: 0 16px; }
.cast-fold > .cast-list { padding: 12px 16px 16px; }

.cast-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 8px;
}
.cast {
  display: grid;
  justify-items: center;
  gap: 1px;
  padding: 10px 6px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  text-align: center;
}
.cast-art { width: 56px; height: 56px; }
.cast-art svg { width: 100%; height: 100%; display: block; }
.cast-sa { font-size: 19px; line-height: 1.4; }
.cast-tr { color: var(--muted); font-size: 11.5px; }
.cast-en { color: var(--teal); font-size: 12px; }

/* A round */
.round-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.bar { flex: 1 1 120px; height: 8px; border-radius: 999px; background: var(--panel-2); overflow: hidden; }
.bar span { display: block; height: 100%; background: var(--teal); transition: width .2s ease; }
.round-count, .round-stat { margin: 0; color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }

/* The stage is capped rather than filling the column. At full width on a
   desktop a 320 x 180 scene is nearly 500px tall, which pushes all four
   sentences below the fold - and a game that makes you scroll away from the
   thing you just watched to answer about it is unplayable. On a phone the
   width is the cap already. */
.stage {
  max-width: 560px;
  margin: 0 auto;
  position: relative;
  border: 1px solid var(--line);
  border-radius: 16px;
  overflow: hidden;
  background: var(--panel-2);
}
.stage .scene { display: block; width: 100%; height: auto; }
.stage-row { max-width: 560px; margin-left: auto; margin-right: auto; display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 10px 0 4px; flex-wrap: wrap; }
.caption { margin: 0; color: var(--muted); font-size: 13px; }
.ask { margin: 0 0 12px; font-size: 19px; font-weight: 700; line-height: 1.45; }

/* The acts. Nothing here moves until game.js adds the class, and every one
   of them ends where it started, so a stage is never left mid gesture. */
.gaze path, .spark circle { opacity: 0; }

@keyframes dr-lean {
  0%, 12% { transform: none; }
  32%, 72% { transform: translateX(calc(var(--walk) * 0.34)) rotate(9deg); }
  92%, 100% { transform: none; }
}
@keyframes dr-drain {
  0%, 28% { transform: none; }
  78%, 100% { transform: translateY(14px); }
}
.is-act-drink .actor { animation: dr-lean 2.6s ease-in-out both; transform-origin: 0 0; }
.is-act-drink .obj .level { animation: dr-drain 2.6s ease-in-out both; }

@keyframes dr-to-mouth {
  0%, 14% { transform: none; }
  54%, 66% { transform: translate(var(--mx), var(--my)); }
  84%, 100% { transform: translate(var(--mx), var(--my)) scale(0.1); opacity: 0; }
}
@keyframes dr-chew {
  0%, 60% { transform: none; }
  70%, 90% { transform: translateY(-2px) scaleY(0.96); }
  100% { transform: none; }
}
.is-act-eat .obj { animation: dr-to-mouth 2.6s ease-in-out both; }
.is-act-eat .actor { animation: dr-chew 2.6s ease-in-out both; transform-origin: 0 0; }

@keyframes dr-look {
  0%, 16% { opacity: 0; stroke-dashoffset: 60; }
  40%, 88% { opacity: 1; stroke-dashoffset: 0; }
  100% { opacity: 0; stroke-dashoffset: 0; }
}
@keyframes dr-noticed {
  0%, 40% { transform: none; }
  56% { transform: scale(1.14); }
  72% { transform: none; }
  88% { transform: scale(1.08); }
  100% { transform: none; }
}
.is-act-see .gaze path { animation: dr-look 2.6s ease-in-out both; }
.is-act-see .obj { animation: dr-noticed 2.6s ease-in-out both; }

@keyframes dr-hold-up {
  0%, 12% { transform: none; }
  46%, 100% { transform: translate(calc(var(--mx) + 6px), calc(var(--my) + 14px)) rotate(-8deg); }
}
@keyframes dr-nod {
  0%, 40% { transform: none; }
  55% { transform: rotate(5deg); }
  70% { transform: none; }
  85% { transform: rotate(5deg); }
  100% { transform: none; }
}
.is-act-read .obj { animation: dr-hold-up 2.6s ease-in-out both; }
.is-act-read .actor { animation: dr-nod 2.6s ease-in-out both; transform-origin: 0 -40px; }

/* Carry: the object rises onto the head, then the two travel together. They
   are separate elements, so they only stay together because both animations
   run for the same time with the same easing over the same travel. */
@keyframes dr-lift {
  0%, 14% { transform: none; }
  34% { transform: translate(var(--hx), var(--hy)); }
  62% { transform: translate(calc(var(--hx) + var(--walk)), var(--hy)); }
  86% { transform: translate(var(--hx), var(--hy)); }
  100% { transform: none; }
}
@keyframes dr-stroll {
  0%, 14% { transform: none; }
  34% { transform: none; }
  62% { transform: translateX(var(--walk)); }
  86%, 100% { transform: none; }
}
.is-act-carry .obj { animation: dr-lift 2.6s ease-in-out both; }
.is-act-carry .actor { animation: dr-stroll 2.6s ease-in-out both; transform-origin: 0 0; }

@keyframes dr-dash {
  0% { transform: none; }
  16% { transform: translateX(calc(var(--walk) * 0.2)) translateY(-3px); }
  50% { transform: translateX(calc(var(--walk) * 1.25)); }
  66% { transform: translateX(calc(var(--walk) * 1.25)) translateY(-3px); }
  100% { transform: none; }
}
.is-act-run .actor { animation: dr-dash 2.6s cubic-bezier(.4, .1, .5, 1) both; transform-origin: 0 0; }

@keyframes dr-sway {
  0%, 100% { transform: none; }
  15% { transform: translateY(-5px) rotate(-8deg); }
  35% { transform: rotate(6deg); }
  55% { transform: translateY(-5px) rotate(-6deg); }
  75% { transform: rotate(8deg); }
  90% { transform: translateY(-3px); }
}
.is-act-dance .actor { animation: dr-sway 2.6s ease-in-out both; transform-origin: 0 0; }

@keyframes dr-chuckle {
  0%, 100% { transform: none; }
  12%, 36%, 60% { transform: translateY(-4px) rotate(-3deg); }
  24%, 48%, 72% { transform: translateY(0) rotate(3deg); }
}
@keyframes dr-pop {
  0%, 10% { opacity: 0; }
  40% { opacity: 1; }
  100% { opacity: 0; }
}
.is-act-laugh .actor { animation: dr-chuckle 2.6s ease-in-out both; transform-origin: 0 0; }
.is-act-laugh .spark circle {
  fill: #ffd166;
  animation: dr-pop 1.5s ease-out infinite;
}
.is-act-laugh .spark circle:nth-child(1) { transform: translate(126px, 100px); }
.is-act-laugh .spark circle:nth-child(2) { transform: translate(136px, 90px); animation-delay: .35s; }
.is-act-laugh .spark circle:nth-child(3) { transform: translate(118px, 84px); animation-delay: .7s; }

/* The four sentences */
.options { display: grid; gap: 10px; margin-top: 14px; }
.opt {
  display: grid;
  gap: 2px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease;
}
.opt:hover:not(:disabled) { border-color: var(--accent); }
.opt.is-right { border-color: var(--green); background: rgba(46, 196, 107, 0.16); }
.opt.is-wrong { border-color: var(--red); background: rgba(226, 59, 59, 0.16); }
.opt.is-hint { outline: 2px dashed var(--saffron); outline-offset: -4px; }
.sent-sa { font-size: 25px; line-height: 1.45; }
.sent-tr { color: var(--muted); font-size: 13px; }
.sent-en { color: var(--teal); font-size: 12.5px; }

/* Make mode: one row of word chips per slot */
.builder { display: grid; gap: 14px; margin-top: 14px; }
.slot h3 {
  margin: 0 0 8px;
  font-size: 11px;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--muted);
}
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  display: grid;
  justify-items: center;
  gap: 1px;
  min-height: 56px;
  padding: 7px 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
.chip span { font-size: 21px; line-height: 1.35; }
.chip em { font-style: normal; color: var(--muted); font-size: 11.5px; }
.chip:hover { border-color: var(--accent); }
/* The "nothing at all" chip is an answer, not an absence, so it looks like
   every other chip rather than like a cleared field. */
.chip-none span { color: var(--muted); font-size: 24px; line-height: 1.1; }
.chip.is-picked { border-color: var(--teal); background: rgba(46, 196, 182, 0.16); }
.chip.is-hint { outline: 2px dashed var(--saffron); outline-offset: -4px; }

.show-row { display: flex; justify-content: flex-end; margin-top: 14px; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

.feedback em { font-style: normal; color: var(--muted); }
.feedback span[lang="sa"] { font-size: 19px; }
.done-score { margin: 0 0 6px; font-size: 44px; font-weight: 800; letter-spacing: -1px; font-variant-numeric: tabular-nums; }

/* The two guides, one per input. The gate has to be !important: the blocks
   below carry their own display, which outranks a plain attribute selector
   and loses silently, showing both guides at once. */
.how { margin: 26px 0 0; padding: 16px 18px; border: 1px solid var(--line); border-radius: 14px; background: var(--panel); }
.how h3 { margin: 0 0 10px; font-size: 12px; letter-spacing: .6px; text-transform: uppercase; color: var(--muted); }
.how ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.how li { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; color: var(--muted); font-size: 14px; line-height: 1.5; }
.how kbd {
  display: inline-block;
  min-width: 24px;
  padding: 2px 7px;
  border: 1px solid #3a3a60;
  border-bottom-width: 2px;
  border-radius: 6px;
  background: var(--panel-2);
  color: var(--text);
  font: inherit;
  font-size: 12px;
  text-align: center;
}
@media (pointer: coarse) { .how[data-input="key"] { display: none !important; } }
@media (pointer: fine) { .how[data-input="touch"] { display: none !important; } }

@media (min-width: 700px) {
  .modes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .options { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 520px) {
  .ask { font-size: 16.5px; }
  .sent-sa { font-size: 21px; }
  .chip span { font-size: 19px; }
  .cast-list { grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); }
}

/* The scene is the substance and the flourish around it is not. A reader who
   has asked for less motion still gets the act - without it there is nothing
   to read - but the laughing sparks, which repeat forever, are dropped. */
@media (prefers-reduced-motion: reduce) {
  .is-act-laugh .spark circle { animation: none; opacity: 0; }
}

/* THEME START - generated by tools/gen-theme.js, do not edit here */
/* Light theme. Every game was drawn dark first, and every one of them names
   its colours through the same handful of variables, so the light theme is
   mostly those variables redefined. What follows the variables are the few
   surfaces that carry a colour of their own. A game's own light fixes sit
   below the END marker, in that game's stylesheet. */
:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f4f4f8;
  --panel: #ffffff;
  --panel-2: #eceef6;
  --line: #d6d8e6;
  --text: #1c1c2b;
  --muted: #585a74;
  --accent: #4a4ae8;
  --amber: #b86a00;
  --teal: #0b8a80;
  --saffron: #c25f00;
  --green: #17864a;
  --red: #c42b2b;
  --rose: #c9365a;
}
:root[data-theme="light"] body { background: var(--bg); color: var(--text); }
:root[data-theme="light"] .topbar,
:root[data-theme="light"] .hud { background: rgba(255, 255, 255, 0.94); }
:root[data-theme="light"] .hud-btn[aria-pressed="true"] { color: #b3261e; border-color: rgba(179, 38, 30, 0.35); }
:root[data-theme="light"] .overlay { background: rgba(28, 28, 43, 0.45); }
:root[data-theme="light"] .modal,
:root[data-theme="light"] .panel,
:root[data-theme="light"] .intro-card,
:root[data-theme="light"] .done-card { background: var(--panel); box-shadow: 0 18px 50px rgba(28, 28, 60, 0.14); }
:root[data-theme="light"] .btn-primary { color: #fff; }
:root[data-theme="light"] kbd { background: var(--panel-2); color: var(--text); border-color: var(--line); }
:root[data-theme="light"] .beta { background: #fff4e5; border-color: #f0c48a; color: #5c3a0b; }
:root[data-theme="light"] .beta a { color: #8a4b00; }
:root[data-theme="light"] .feedback.is-right { color: #146b3a; }
:root[data-theme="light"] .feedback.is-wrong { color: #a4231f; }
:root[data-theme="light"] .foot-bar a,
:root[data-theme="light"] .cross a { color: #0b7a71; }
:root[data-theme="light"] .foot-steps a.is-here .step-n { color: #fff; }

/* The toggle itself: a sun in the dark, a moon in the light, so it always
   shows what pressing it will do - the icon alone says that, so the label
   is announced to a screen reader (title/aria-label, set in the script
   below) rather than spelled out next to it on every single page. */
.theme-toggle { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.theme-toggle svg { width: 16px; height: 16px; flex: 0 0 auto; }
.theme-toggle .ico-moon { display: none; }
:root[data-theme="light"] .theme-toggle .ico-sun { display: none; }
:root[data-theme="light"] .theme-toggle .ico-moon { display: inline; }
.theme-toggle .theme-label {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* The Play button. Every game's way into play is the same button: the widest,
   tallest thing on its start screen, with a play triangle, so nobody has to
   work out which of the options starts the game. It lives in this block
   because this block already goes into every game. */
.btn-play:not([hidden]) {
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
  gap: 10px;
  flex: 1 1 auto;
  min-height: 54px !important;
  font-size: 17px !important;
  font-weight: 700;
  letter-spacing: 0.2px;
  box-shadow: 0 8px 22px rgba(74, 74, 232, 0.35);
}
/* On a Sanskrit start screen it is the whole width of the card. */
.intro-card .btn-play:not([hidden]) { display: flex !important; width: 100%; margin-top: 6px; }
.btn-play::before {
  content: "";
  width: 14px;
  height: 16px;
  flex: 0 0 auto;
  background: currentColor;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}
.btn-play:focus-visible { outline: 3px solid #ffd166; outline-offset: 3px; }
@media (prefers-reduced-motion: no-preference) {
  .btn-play { animation: btn-play-glow 2.4s ease-in-out infinite; }
  .btn-play:hover, .btn-play:focus-visible { animation: none; }
}
@keyframes btn-play-glow {
  0%, 100% { box-shadow: 0 8px 22px rgba(74, 74, 232, 0.35); }
  50% { box-shadow: 0 8px 30px rgba(74, 74, 232, 0.6); }
}
/* THEME END */

.modes-or { margin: 16px 0 8px; color: var(--muted); font-size: 13px; }

/* COMPACT PANELS (13/10/2026): start, pause and result panels use less room. Paddings and
   type only; buttons and their 12px spacing are left to the rules above. */
.overlay .modal-head, .overlay .panel-head, .overlay .m-head { padding-top: 10px; padding-bottom: 6px; }
.overlay .modal-head h1, .overlay .panel-head h1 { font-size: 20px; line-height: 1.15; }
.overlay .modal-head h2, .overlay .panel-head h2, .overlay .m-head h2 { font-size: 16px; }
.overlay .modal-body, .overlay .panel-body, .overlay .m-body { padding-top: 4px; padding-bottom: 10px; }
.overlay .modal-body p, .overlay .panel-body p, .overlay .m-body p { margin-bottom: 8px; font-size: 13.5px; line-height: 1.45; }
.overlay .modal-body h2, .overlay .panel-body h2, .overlay .modal-body h3, .overlay .panel-body h3 { margin-top: 10px; margin-bottom: 6px; }
.overlay .modal-foot, .overlay .panel-foot, .overlay .m-foot { padding-top: 8px; padding-bottom: 8px; }

/* A double tap must never zoom the page: manipulation allows scrolling and
   pinching but not the double tap zoom. On html it covers every element. */
html { touch-action: manipulation; }
