@font-face {
  font-family: "Rubik";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("fonts/rubik-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Rubik";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("fonts/rubik-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Rubik";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("fonts/rubik-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

:root {
  /* Base sits above the halation threshold (~#121212): a near-black ground
     makes light text glow for astigmatic eyes and forces every accent to
     either vanish or vibrate. Text is held near 12.5:1 rather than the 16:1
     a near-white on near-black gives — still far past AAA, without the buzz. */
  --bg: #18161c;
  --bg-glow: #232029;
  --panel: #201d26;
  --panel-2: #2a2632;
  --border: #35303d;
  --tile: #2c2834;
  --tile-edge: #393341;
  --text: #d6d8de;
  --muted: #969aa6;
  --accent: #3f9c82;
  --accent-2: #2d7562;
  --on-accent: #04231c;
  --danger: #f0635a;
  /* near miss: wrong, but not the same wrong as naming another object */
  --warn: #e0a94a;
  --input-border: #363040;
  /* Success title, board ring and calendar bar; dark keeps the E2c gold. */
  --success-text: #e8c15e;
  --success-ring: 0 0 0 3px #e8c15e;
  --success-bar: #e8c15e;
  /* Outline that keeps a flag's white field apart from the page (Indonesia,
     Poland, Japan…): light on the dark ground, dark on the light one. */
  --flag-ring: rgba(255, 255, 255, .18);
}

html[data-theme="light"] {
  --bg: #eef1f6;
  --bg-glow: #ffffff;
  --panel: #ffffff;
  --panel-2: #e6eaf1;
  --border: #d8dee8;
  --tile: #2c2834;          /* covering tiles stay dark so reveals read clearly */
  --tile-edge: #393341;
  --text: #1a1f29;
  --muted: #5c6675;
  --accent: #2d7562;
  --accent-2: #24604f;
  --on-accent: #ffffff;
  --danger: #d6453c;
  --warn: #a9711a;
  --input-border: #c9d1dd;
  --success-text: var(--accent);
  --success-ring: 0 0 0 3px var(--accent);
  --success-bar: var(--accent);
  /* player report 2026-10-10: the white half of the Indonesian flag vanished
     into the light page — the dark-theme white ring was invisible here */
  --flag-ring: rgba(26, 31, 41, .32);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }

body {
  background: radial-gradient(1200px 800px at 50% -200px, var(--bg-glow) 0%, var(--bg) 60%);
  background-color: var(--bg);
  color: var(--text);
  font-family: "Rubik", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
  overscroll-behavior: none;
}

button, input, textarea, select { font-family: inherit; }

#app {
  min-height: 100dvh;
  max-width: 460px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  padding: calc(var(--safe-area-inset-top, env(safe-area-inset-top, 0px)) + 10px) 16px
           calc(var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)) + 16px);
  /* phones in landscape / cut-outs: never under a side system bar */
  padding-left: max(16px, var(--safe-area-inset-left, env(safe-area-inset-left, 0px)));
  padding-right: max(16px, var(--safe-area-inset-right, env(safe-area-inset-right, 0px)));
}

.screen.hidden { display: none; }

/* Edge-to-edge phones (Android app): a solid strip under the status bar, so
   scrolled content never shows through the clock and icons. Zero-height on
   the web and wherever there is no top inset. */
body::before {
  content: ''; position: fixed; top: 0; left: 0; right: 0; z-index: 9;
  height: var(--safe-area-inset-top, env(safe-area-inset-top, 0px));
  background: var(--bg); pointer-events: none;
}
.icon-btn {
  background: none; border: none; color: var(--muted);
  font-size: 20px; width: 38px; height: 38px; border-radius: 10px;
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
}
.icon-btn:active { background: var(--panel-2); }

/* ================= HOME ================= */
/* Lower specificity than .screen.hidden: routing still owns visibility. */
[data-screen="home"] { display: flex; flex-direction: column; flex: 1 0 auto; }
.home-top { display: flex; justify-content: space-between; align-items: center; }
.home-tools { display: flex; align-items: center; gap: 4px; }
.home-tools svg { display: block; }
.logo-img { height: 30px; width: auto; display: block; }
/* The wordmark is fixed #F7F7F2 (dark-surface brand spec); flip it for the
   light theme rather than shipping a second asset. */
html[data-theme="light"] .logo-img { filter: invert(1); }

.home-hero { text-align: center; padding: 26px 0 10px; }
.home-tiles {
  display: grid; grid-template-columns: repeat(3, 26px); grid-auto-rows: 26px;
  gap: 4px; justify-content: center; margin-bottom: 18px;
}
.home-tiles i { background: var(--tile); border-radius: 5px; box-shadow: inset 0 0 0 1px var(--tile-edge); }
.home-tiles i.peek { background: var(--accent); box-shadow: none; }
.home-hero h1 { font-size: 30px; line-height: 1.15; font-weight: 800; letter-spacing: -0.01em; text-wrap: balance; }
.home-sub { margin-top: 10px; color: var(--muted); font-size: 14px; white-space: pre-line; line-height: 1.45; }

.home-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.btn-primary, .btn-secondary {
  height: 58px; border: none; border-radius: 16px;
  font-size: 17px; font-weight: 800; cursor: pointer; letter-spacing: .01em;
}
.btn-primary { background: var(--accent); color: var(--on-accent); }
.btn-primary:disabled { opacity: .55; }
.btn-secondary { background: var(--panel); color: var(--text); border: 1px solid var(--border); font-weight: 700; }
.btn-primary:active, .btn-secondary:active { transform: scale(.97); }
/* Endless as a full-weight twin of the Daily CTA (playtest 2026-09-13): the
   old gray panel read as tertiary. Inverted text/background — the second
   strongest surface there is, in both themes. */
.btn-secondary.btn-play { background: var(--text); color: var(--bg); border: none; }

/* Home hierarchy; shared buttons on the other screens keep their sizes. */
.home-actions .btn-primary, .home-actions .btn-secondary {
  height: 54px; border-radius: 16px; font-size: 16px; font-weight: 800;
}
.home-actions .btn-primary { height: 60px; }

/* Two-line buttons: label + small status line (Daily countdown, Resume). */
.btn-2line { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; line-height: 1.05; }
.btn-sub { font-size: 12px; font-weight: 600; opacity: .85; }

/* Interrupted-session row: resume button + a quiet discard. */
.resume-row { display: flex; gap: 8px; align-items: stretch; }
.resume-row .btn-secondary { flex: 1; }
.resume-row .icon-btn { width: 46px; flex: none; }

/* Lifetime record, promoted out of Stats (playtest 2026-09-13). */
.streak-chip { text-align: center; color: var(--success-text); font-size: 14px; line-height: 20px; font-weight: 700; padding: 2px 0 6px; }

/* There is no generic .hidden in this stylesheet — every component owns one. */
.resume-row.hidden, .streak-chip.hidden, .btn-sub.hidden { display: none; }

/* W4–W6 (owner 2026-10-31): level + weekly goal card in the empty lower half,
   under the actions — the hero, the streak and the buttons keep the approved
   E4a places and spacing. Only transform/opacity animate (ui/home.js, fx.js). */
.home-progress {
  display: flex; flex-direction: column; gap: 7px; margin: 12px 0 0; padding: 9px 12px 10px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 16px;
}
.hp-level { position: relative; display: flex; align-items: center; gap: 10px; }
.hp-badge {
  flex: none; width: 36px; height: 36px; border-radius: 10px; display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--on-accent); font-size: 17px; font-weight: 800; font-variant-numeric: tabular-nums;
}
.hp-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.hp-title { display: flex; align-items: baseline; gap: 6px; line-height: 18px; white-space: nowrap; overflow: hidden; }
.hp-title b { font-size: 15px; font-weight: 800; color: var(--text); }
/* "+N" rides on the badge's corner, out of the row's width, so it can never
   push the level text into the week (Codex, ≤ 660 px) */
.hp-gain {
  position: absolute; left: 24px; top: -7px; z-index: 1;
  font-size: 11.5px; font-weight: 800; line-height: 16px; padding: 0 6px; border-radius: 999px;
  background: var(--accent); color: var(--on-accent); box-shadow: 0 0 0 2px var(--panel);
}
.hp-gain.hidden { display: none; }
.hp-bar { display: block; height: 6px; border-radius: 3px; background: var(--panel-2); overflow: hidden; }
.hp-bar b { display: block; height: 100%; background: var(--accent); transform-origin: 0 50%; }
.hp-next { font-size: 12px; line-height: 15px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hp-week { display: flex; flex-direction: column; gap: 4px; }
.hp-week-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; line-height: 16px; }
.hp-week-label { font-size: 12.5px; font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.hp-days { display: flex; gap: 5px; flex: none; font-size: 10.5px; font-weight: 700; color: var(--muted); text-transform: uppercase; }
.hp-days .today { color: var(--accent); }
.hp-segs { display: grid; grid-template-columns: repeat(20, minmax(0, 1fr)); gap: 2px; }
.hp-segs i { height: 6px; border-radius: 2px; background: var(--panel-2); transform-origin: 50% 100%; }
.hp-segs i.on { background: var(--accent); }
.home-progress.week-done .hp-week-label { color: var(--success-text); }
.home-progress.week-done .hp-segs i.on { background: var(--success-bar); }
/* W6: an unplayed Daily keeps a quiet dot before its status line */
#btn-daily.waiting .btn-sub::before {
  content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; margin-right: 6px; vertical-align: 1px;
}

.play-style { display: flex; align-items: center; gap: 10px; margin-top: 2px; }
.play-style-label { color: var(--muted); font-size: 12.5px; white-space: nowrap; }
.play-style .segmented { flex: 1; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; padding: 0; }
.play-style .segmented button { height: 36px; font-size: 13px; font-weight: 700; }

.home-links { display: flex; justify-content: center; gap: 6px; margin-top: auto; padding-top: 12px; }
.home-links button {
  background: none; border: none; color: var(--muted); font-size: 14px; line-height: 17px;
  padding: 10px 12px; cursor: pointer; border-radius: 10px;
}
.home-links button:active { color: var(--text); }

/* Short phones keep the mockup spacing unless Resume needs another row. */
@media (max-height: 700px) {
  .home-hero h1 { font-size: 26px; }
}
/* Short screens (a phone browser with its toolbar is ~660–740 px tall): the
   progress card folds into one row — level and bar on the left, the week and
   its steps on the right — so Home still fits without touching the hero. */
@media (max-height: 740px) {
  .home-progress { flex-direction: row; align-items: center; gap: 12px; margin-top: 8px; padding: 7px 10px; }
  .hp-level { flex: 0 0 38%; min-width: 0; gap: 8px; }
  .hp-badge { width: 28px; height: 28px; border-radius: 8px; font-size: 14px; }
  .hp-gain { left: 16px; top: -8px; }
  .hp-title { line-height: 16px; }
  .hp-title b { font-size: 13px; }
  .hp-next, .hp-days { display: none; }
  .hp-week { flex: 1; min-width: 0; gap: 5px; }
  .hp-week-label { font-size: 11.5px; line-height: 15px; }
  .hp-bar, .hp-segs i { height: 5px; }
}
/* The shortest (≤ 690 px — Firefox on Android also keeps ~24 px for the
   gesture bar): one line — badge, level and its bar, then the week
   in words; the week's steps rest until there is room (Codex/Muse, 640 px). */
@media (max-height: 690px) {
  .home-progress { margin-top: 3px; padding: 4px 10px; }
  .hp-badge { width: 20px; height: 20px; border-radius: 6px; font-size: 12px; }
  .hp-gain { left: 10px; top: -10px; font-size: 10.5px; line-height: 14px; padding: 0 5px; }
  .hp-main { flex-direction: row; align-items: center; gap: 6px; }
  .hp-title { line-height: 15px; flex: none; }
  .hp-title b { font-size: 12.5px; }
  .hp-bar { flex: 1; min-width: 16px; height: 4px; }
  .hp-segs { display: none; }
  .hp-week { gap: 0; }
  .hp-week-label { font-size: 11px; line-height: 14px; }
}
@media (max-height: 760px) {
  [data-screen="home"]:has(#resume-row:not(.hidden)) .home-hero { padding: 8px 0 6px; }
  [data-screen="home"]:has(#resume-row:not(.hidden)) .home-tiles { grid-template-columns: repeat(3, 22px); grid-auto-rows: 22px; margin-bottom: 12px; }
  [data-screen="home"]:has(#resume-row:not(.hidden)) .home-sub { margin-top: 8px; }
  [data-screen="home"]:has(#resume-row:not(.hidden)) .home-actions { gap: 8px; }
  [data-screen="home"]:has(#resume-row:not(.hidden)) #btn-resume { height: 48px; }
  [data-screen="home"]:has(#resume-row:not(.hidden)) .home-links { padding-top: 4px; }
}

/* ================= GENERIC SCREENS ================= */
.screen-top { display: flex; align-items: center; gap: 6px; padding-bottom: 12px; }
.screen-top h2 { font-size: 20px; flex: 1; }
.screen-top-spacer { width: 38px; }

.panel-list { display: flex; flex-direction: column; gap: 12px; }
.panel { background: var(--panel); border: 1px solid var(--border); border-radius: 16px; padding: 6px 16px; }
.panel.placeholder-note { padding: 16px; color: var(--muted); font-size: 14px; line-height: 1.5; }
.panel.placeholder-note b { color: var(--text); }
.section-label { font-size: 12px; text-transform: uppercase; letter-spacing: .12em; color: var(--muted); margin: 8px 2px 0; }
.muted-note { color: var(--muted); font-size: 13px; text-align: center; padding: 8px 12px; }

/* ================= DAILY CALENDAR ================= */
.cm-nav { display: flex; align-items: center; justify-content: space-between; margin: 4px 0 10px; }
.cm-nav b { font-size: 17px; font-weight: 800; color: var(--text); }
.cm-nav button { width: 40px; height: 36px; border-radius: 10px; border: 1px solid var(--border); background: var(--panel); color: var(--text); font-size: 18px; cursor: pointer; }
.cm-nav button:disabled { opacity: .35; cursor: default; }
.cm-sum { font-size: 13px; color: var(--muted); text-align: center; margin: -4px 0 10px; }
.cm-wd, .cm-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 5px; }
.cm-wd span { font-size: 11px; font-weight: 700; color: var(--muted); text-align: center; text-transform: lowercase; padding-bottom: 4px; }
.cm-day { position: relative; aspect-ratio: 1; border: 0; padding: 0; border-radius: 10px; overflow: hidden; background: var(--panel); }
button.cm-day { cursor: pointer; }
.cm-day img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* The ring and check sit ABOVE the photo; inset shadow on the cell would be covered. */
.cm-day.ok::before { content: ''; position: absolute; inset: 2px; border-radius: 8px; box-shadow: var(--success-ring); z-index: 1; pointer-events: none; }
.cm-day.miss img { filter: grayscale(1); opacity: .38; }
.cm-day.future { background: transparent; box-shadow: inset 0 0 0 1px var(--panel-2); }
.cm-day.today { background: transparent; box-shadow: inset 0 0 0 2px var(--accent); }
.cm-day.blank { background: transparent; }
.cm-day i { position: absolute; left: 5px; top: 3px; font-style: normal; font-size: 11px; font-weight: 800; color: var(--muted); z-index: 2; }
.cm-day.ok i, .cm-day.miss i { color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.8); }
.cm-day.today i { color: var(--accent); }
.cm-day.ok::after { content: '✓'; position: absolute; right: 4px; bottom: 2px; font-size: 12px; font-weight: 900; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.8); z-index: 2; pointer-events: none; }

/* ================= CATEGORIES ================= */
.cat-goal {
  display: grid; gap: 6px; width: 100%; margin-bottom: 10px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 16px;
  padding: 12px 14px; cursor: pointer; text-align: left; font-family: inherit; line-height: 1.2;
}
.cat-goal:active { transform: scale(.97); border-color: var(--accent); }
.cat-goal.hidden { display: none; }
.cat-goal b { font-size: 15px; font-weight: 800; color: var(--text); }
.cat-goal-bar { height: 8px; background: var(--panel-2); border-radius: 99px; overflow: hidden; }
.cat-goal-bar i { display: block; height: 100%; background: var(--success-bar); }
.cat-goal > span:last-child { font-size: 12.5px; color: var(--muted); }
.category-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.cat-cover {
  position: relative; min-width: 0; aspect-ratio: 1; border-radius: 14px; overflow: hidden;
  background: var(--tile); border: 0; padding: 0; cursor: pointer; font-family: inherit; text-align: left;
}
.cat-cover:active { transform: scale(.97); }
.cat-cover img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cat-tiles { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(4, 1fr); }
.cat-tiles i { background: var(--tile); box-shadow: inset 0 0 0 .5px var(--tile-edge); }
.cat-tiles i.off { opacity: 0; }
.cat-cap {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 26px 8px 8px;
  background: linear-gradient(rgba(0,0,0,0), rgba(0,0,0,.6) 38%, rgba(0,0,0,.82)); color: #fff;
  display: grid; gap: 4px; line-height: 1.15;
}
/* These names also exist in STATS; scope cover typography and bars here. */
.cat-cap .cat-name { width: auto; font-size: 14px; font-weight: 800; }
.cat-cap small { font-size: 11.5px; font-weight: 600; opacity: .88; }
.cat-cap .cat-name, .cat-cap small { text-shadow: 0 1px 2px rgba(0,0,0,.6); }
.cat-cap .cat-bar { height: 4px; border-radius: 99px; background: rgba(255,255,255,.22); overflow: hidden; }
.cat-cap .cat-bar i { display: block; height: 100%; background: var(--success-bar); }
.cat-stars { display: inline-block; color: var(--success-text); margin-left: 4px; font-size: inherit; white-space: nowrap; }
/* Captions are always dark; light-theme success (accent) is meant for light backgrounds.
   Use white stars like the caption text there; dark-theme stars keep --success-text. */
html[data-theme="light"] .cat-stars { color: #fff; }

/* ================= STATS ================= */
.stat-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1px; background: var(--border); border-radius: 16px; overflow: hidden; }
.stat-cell { background: var(--panel); padding: 14px 8px; text-align: center; }
.stat-cell b { display: block; font-size: 19px; font-variant-numeric: tabular-nums; }
.stat-cell span { font-size: 10.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }

.cat-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; }
.cat-name { width: 88px; font-size: 13px; font-weight: 600; }
.cat-bar { flex: 1; height: 6px; border-radius: 3px; background: var(--panel-2); overflow: hidden; }
.cat-bar i { display: block; height: 100%; background: var(--accent); }
.cat-val { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* ================= LEADERBOARD ================= */
.lb-tabs { display: flex; gap: 6px; margin-bottom: 10px; }
.lb-tabs button {
  flex: 1; height: 38px; border-radius: 10px; border: 1px solid var(--border);
  background: none; color: var(--muted); font-size: 13px; font-weight: 600; cursor: pointer;
}
.lb-tabs button.active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.lb-caption { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .08em; padding: 8px 0 2px; text-wrap: balance; }

.lb-row { display: flex; align-items: center; gap: 10px; padding: 10px 6px; border-bottom: 1px solid var(--border); border-radius: 6px; }
.lb-row:last-child { border-bottom: none; }
.lb-row.me { background: rgba(63, 156, 130, .1); border: 1px solid var(--accent); }
.lb-rank { width: 26px; color: var(--muted); font-weight: 700; font-size: 13px; }
.lb-player { flex: 1; min-width: 0; }
.lb-player > .lb-date { display: block; }
.lb-answer { display: flex; align-items: center; flex: 1; min-width: 0; font-weight: 600; font-size: 14px; }
.lb-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-answer .you-tag { flex: none; white-space: nowrap; font-style: normal; font-size: 10px; color: var(--accent); border: 1px solid var(--accent); border-radius: 6px; padding: 1px 5px; margin-left: 4px; }
.lb-date { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.lb-score { font-variant-numeric: tabular-nums; color: var(--accent); }
.lb-report { background: none; border: none; color: var(--muted); font-size: 13px; padding: 4px 6px; margin-left: -4px; cursor: pointer; white-space: nowrap; opacity: .55; }
.lb-divider { height: 1px; background: var(--border); margin: 6px 0; }
.retry-btn { width: 100%; height: 44px; margin-top: 10px; font-size: 14px; }

/* ================= PLAYER NAME ================= */
.player-name { color: var(--accent); font-size: 13px; font-weight: 600; }
.name-edit {
  background: none; border: 1px solid var(--border); color: var(--text);
  border-radius: 10px; padding: 8px 14px; font-size: 13px; cursor: pointer;
}
.name-editor { display: flex; flex-wrap: wrap; gap: 8px; padding: 4px 0 10px; }
.name-editor.hidden { display: none; }
.name-editor input {
  flex: 1; min-width: 0; height: 42px; border-radius: 10px;
  border: 1px solid var(--input-border); background: var(--bg);
  color: var(--text); font-size: 15px; padding: 0 12px; outline: none;
  -webkit-user-select: text; user-select: text;
}
.name-editor .btn-secondary { height: 42px; padding: 0 14px; font-size: 13px; }
.name-note { font-size: 12px; color: var(--muted); min-height: 16px; padding-bottom: 8px; }
.name-note.error { color: var(--danger); }

.name-rules { flex-basis: 100%; margin: 0 0 10px; font-size: 12px; line-height: 1.5; color: var(--muted); }
.name-rules a { color: var(--accent); text-decoration: underline; }
.player-card { overflow-y: auto; }
.player-card h2 { margin: 8px 0 16px; font-size: 20px; overflow-wrap: anywhere; }
.player-card button { width: 100%; min-height: 44px; height: auto; padding: 10px 14px; white-space: normal; }
.player-note { margin: 6px 0 18px; color: var(--muted); font-size: 13px; line-height: 1.5; }

/* First-launch welcome card (index.html #welcome-overlay) */
.welcome-card h2 { font-size: 24px; font-weight: 800; margin: 6px 0 8px; }
.welcome-card .welcome-intro { font-size: 14px; color: var(--muted); margin: 0 0 14px; line-height: 1.4; }
.welcome-card .name-editor { padding: 0 0 6px; }
.welcome-card .btn-primary { width: 100%; margin-top: 4px; }
.welcome-card .muted-note { padding: 12px 0 0; }

/* ================= SETTINGS ================= */
.app-version { font-size: 12px; padding: 0 12px 4px; -webkit-user-select: text; user-select: text; }
.setting-row { display: flex; justify-content: space-between; align-items: center; padding: 13px 0; font-size: 15px; }
.setting-row + .setting-row { border-top: 1px solid var(--border); }
.setting-row small.muted-note { display: block; padding: 2px 0 0; text-align: left; }
a.setting-row { color: inherit; text-decoration: none; }
#delete-server-note { margin: 0 0 6px; }
#delete-server-note.error { color: var(--danger); }
.deletion-code { font: 600 15px/1.6 ui-monospace, "SFMono-Regular", Consolas, monospace; letter-spacing: .08em; user-select: all; }
.deletion-code-row { border-top: 1px solid var(--border); }
#deletion-code-new.hidden { display: none; }

.credits-panel .setting-row { cursor: pointer; }
.credits-list { max-height: 42vh; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }
.credits-list.hidden { display: none; }
.credit-item { font-size: 12.5px; color: var(--muted); line-height: 1.45; border-top: 1px solid var(--border); padding-top: 9px; }
.credit-item:first-child { border-top: none; padding-top: 2px; }
.credit-item strong { color: var(--text); font-size: 13px; font-weight: 600; display: block; margin-bottom: 1px; }
.credit-item a { color: var(--accent); text-decoration: none; }
.credit-item a:hover { text-decoration: underline; }
.credit-tag { display: inline-block; font-size: 10.5px; padding: 1px 6px; border-radius: 8px; margin-left: 6px; vertical-align: 1px; background: var(--panel-2); color: var(--muted); }
.credit-tag.by { background: var(--accent); color: var(--on-accent); }

.toggle {
  width: 52px; height: 30px; flex-shrink: 0; margin-left: 12px; border-radius: 15px; border: none;
  background: var(--panel-2); position: relative; cursor: pointer; transition: background .15s;
}
.toggle i {
  position: absolute; top: 3px; left: 3px; width: 24px; height: 24px;
  border-radius: 50%; background: var(--muted); transition: transform .15s, background .15s;
}
.toggle.on { background: var(--accent); }
.toggle.on i { transform: translateX(22px); background: var(--on-accent); }

.segmented { display: flex; gap: 6px; padding: 0 0 14px; }
.segmented.wrap { flex-wrap: wrap; }
.segmented.wrap button { flex: 1 1 30%; min-width: 96px; }
.segmented button {
  flex: 1; height: 40px; border-radius: 10px; border: 1px solid var(--border);
  background: none; color: var(--muted); font-size: 13px; font-weight: 600; cursor: pointer;
}
.segmented button.active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.segmented button .beta-tag { font-size: 9px; font-weight: 700; letter-spacing: .06em; opacity: .7; vertical-align: super; margin-left: 1px; }

.danger-btn {
  width: 100%; height: 46px; margin: 10px 0; border-radius: 12px;
  border: 1px solid var(--danger); background: none; color: var(--danger);
  font-size: 14px; font-weight: 700; cursor: pointer;
}
.danger-btn:active { background: var(--danger); color: #fff; }

/* ================= GAME ================= */
/* Top bar „Kategoria na czele” (owner 2026-10-26; Claude + Codex + Muse):
   ← | the hint as the title, the level under it | 🔥 streak + shield.
   Still one fixed 42px row, so the photo keeps its size. */
.game-top { position: relative; display: flex; align-items: center; gap: 8px; height: 42px; flex: none; padding-bottom: 4px; }
.hud-ctx { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 1px; }
.hud-title { display: flex; align-items: center; gap: 6px; min-width: 0; line-height: 1.2; }
.hud-sub { display: flex; align-items: baseline; gap: 6px; min-width: 0; line-height: 1.2; }
.hud-sub:not(:has(> :not(.hidden))) { display: none; }
.game-mode { min-width: 0; font-size: 16px; font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A labelled category chip is the title; the mode name steps aside. */
/* Not on the Daily result: the chips are hidden there and the mode name
   carries the date (Codex review of a582ec2, P2). */
section[data-screen="game"]:not(.as-daily-result) .hud-title.has-cat-label .game-mode { display: none; }
.game-hud { display: flex; align-items: center; gap: 6px; flex: none; font-size: 14px; color: var(--muted); font-variant-numeric: tabular-nums; }
.game-hud b { color: var(--text); }
.game-hud .hud-stat.streak-fire { padding: 3px 10px; }
/* W3 (js/ui/fx.js): the flame breathes and the number rolls like an odometer;
   the outgoing figure is a throwaway copy, #hud-streak always holds the number. */
.hud-flame { display: inline-block; }
.streak-roll { position: relative; display: inline-block; }
.streak-roll b { display: inline-block; }
.streak-roll .roll-old { position: absolute; left: 0; top: 0; }
.bonus-tag { font-size: 11.5px; font-weight: 800; color: var(--accent); white-space: nowrap; }
.bonus-tag.hidden { display: none; }
/* Daily is one round: no streak, no shield, no session score. */
section[data-screen="game"].mode-daily .game-hud,
section[data-screen="game"].mode-daily .stake-session { display: none; }

/* Streak shield (js/ui/streak-shield.js): fixed slot, never moves the bar. */
.hud-shield {
  position: relative; display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 30px; height: 36px; padding: 0; margin: 0 -4px 0 -2px; border: none; background: none; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.hud-shield[hidden] { display: none; }
.hud-shield svg { width: 21px; height: 23px; overflow: visible; }
.hud-shield .sh-out { fill: none; stroke: var(--muted); stroke-width: 1.7; stroke-linejoin: round; }
.hud-shield .sh-fill { fill: var(--accent); opacity: .6; }
.hud-shield .sh-check { fill: none; stroke: var(--on-accent); stroke-width: 2.3; stroke-linecap: round; stroke-linejoin: round; display: none; }
.hud-shield .sh-num { font: 800 9px Rubik, system-ui, sans-serif; fill: var(--text); }
.hud-shield.on .sh-out { stroke: var(--accent); fill: var(--accent); }
.hud-shield.on .sh-fill { opacity: 1; }
.hud-shield.on .sh-check { display: inline; }
.hud-shield.on svg { filter: drop-shadow(0 0 4px color-mix(in srgb, var(--accent) 65%, transparent)); }
.hud-shield.pop svg { animation: shield-pop .6s ease-out; }
@keyframes shield-pop { 0% { transform: scale(1); } 40% { transform: scale(1.35); } 100% { transform: scale(1); } }
html.reduced-motion .hud-shield.pop svg { animation: none; }
@media (prefers-reduced-motion: reduce) { .hud-shield.pop svg { animation: none; } }
.shield-tip {
  position: absolute; right: 0; top: 42px; z-index: 6; width: min(260px, calc(100% - 16px));
  display: grid; gap: 3px; padding: 10px 12px; border-radius: 12px;
  background: var(--panel); border: 1px solid var(--border); box-shadow: 0 8px 24px rgba(0, 0, 0, .35);
  font-size: 13px; line-height: 1.35; color: var(--text);
}
.shield-tip b { color: var(--accent); }
/* The Daily sheet owns these details. Keep the fixed 42px top row so hiding
   them gives the title more width without moving the board. */
section[data-screen="game"].as-daily-result .game-hud,
section[data-screen="game"].as-daily-result #diff-chip,
section[data-screen="game"].as-daily-result #cat-chip { display: none; }
/* Current puzzle's category, top-right. Casual mercy: shown on calm/classic
   endless rounds; hardcore and the ranked daily keep it hidden (it is a
   solving hint) and category sessions already carry it in the mode label. */
/* Owner 2026-10-26: the grey chip went unnoticed — the labelled category is
   now the bar's title (16px, text colour); a flag-only chip (category
   sessions) sits next to the mode name. */
.cat-chip {
  min-width: 0; font-size: 16px; font-weight: 700; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cat-chip[data-label="0"] { flex-shrink: 0; }
/* The chip owns its .hidden, like every component in this stylesheet — and
   until now it did not, so the class startRound toggles landed on an element
   nothing hid. Hardcore and the ranked daily with its intro card announced the
   category they exist to withhold, and a category session showed a stale label
   in the very spot the origin flag takes over: startRound writes the category
   name before it knows whether this record has an origin, and only clears it
   on the branch that draws the flag. */
.cat-chip.hidden { display: none; }
/* Origin flag inside the chip (wariant A): a bundled image per country, not
   emoji — Windows has no flag glyphs and degrades them to letter codes that
   read as no flag at all. Sized to the chip's 11px text, one text-space gap
   from the label and between flags comes from the renderer. */
.origin-flag {
  width: 17px; height: 12.5px; object-fit: cover; border-radius: 2px;
  box-shadow: 0 0 0 1px var(--flag-ring);
  vertical-align: -2px;
}

.stage { display: flex; justify-content: center; flex: none; }
.board-wrap {
  --ring-room: 4px; /* 3px success ring + 1px clear of the section's clip */
  width: min(calc(100% - 2 * var(--ring-room)), max(0px, calc(var(--vvh, 100dvh) - var(--game-insets) - 90px - var(--lower-height))));
  display: flex; flex-direction: column; gap: 0;
}
/* One size formula in every phase. The photo never animates or changes
   layout when controls give way to the result. */

.board {
  position: relative; width: 100%; aspect-ratio: 1 / 1;
  border-radius: 16px; overflow: hidden; background: #000;
  box-shadow: 0 10px 40px rgba(0, 0, 0, .55), 0 0 0 1px rgba(255, 255, 255, .04);
}
/* No scale "pop" any more (E2c): with the rising sheet it made
   the solve feel jumpy — the success frame alone marks it. */
.board.correct { box-shadow: var(--success-ring), 0 10px 40px rgba(0, 0, 0, .55); }

#puzzle-image { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* No long-press image menu (Open / Download / Google Lens): mid-round it is a
   peek behind the tiles, and after a solve a held Go tap that lands on the
   photo opened it over the result (emulator, 2026-10-09). */
#puzzle-image { pointer-events: none; -webkit-user-drag: none; }
.board { -webkit-touch-callout: none; user-select: none; -webkit-user-select: none; }
.tiles { position: absolute; inset: 0; display: grid; }
.tile {
  background: var(--tile);
  box-shadow: inset 0 0 0 1px var(--tile-edge);
  /* Binary reveal: a covering tile is never translucent and never shrinks —
     no fade frames, no scale-down gaps for the photo to shine through. */
  transition: none;
}
.tile.revealed { opacity: 0; pointer-events: none; }

/* W1 (owner 2026-10-31): while js/ui/fx.js traces the success ring around the
   photo, the board's own ring waits; the trace hands over in the same task. */
.board.correct.ring-tracing { box-shadow: 0 10px 40px rgba(0, 0, 0, .55), 0 0 0 1px rgba(255, 255, 255, .04); }

/* Visual rewards (js/ui/fx.js): one fixed throwaway layer over the screen,
   never in hit-testing, never in layout. Only transform/opacity animate. */
/* Under every modal (.overlay is z-index 10): a summary or a sheet opened
   mid-celebration covers it. Particles get no will-change of their own. */
.fx-layer { position: fixed; inset: 0; z-index: 9; pointer-events: none; overflow: hidden; }
.fx-layer > * { position: absolute; pointer-events: none; }
.fx-layer > .fx-points { will-change: transform, opacity; }
.fx-ring { overflow: visible; }
.fx-ring rect { fill: none; stroke: var(--success-text); stroke-width: 3; }
.fx-points {
  font: 900 40px/1 Rubik, system-ui, sans-serif; color: #fff; white-space: nowrap; opacity: 0;
  text-shadow: 0 2px 0 rgba(0, 0, 0, .35), 0 0 18px rgba(0, 0, 0, .45);
}
.fx-points.big { font-size: 46px; }
.fx-spark { border-radius: 50%; }
.fx-smoke { border-radius: 50%; background: #9aa0aa; }
.fx-ringout { border: 3px solid; border-radius: 50%; background: none; }
.fx-confetti { width: 7px; height: 11px; border-radius: 2px; }
.fx-shield { display: inline-flex; align-items: center; justify-content: center; margin: 0; }
html.reduced-motion .fx-layer { display: none; }
@media (prefers-reduced-motion: reduce) { .fx-layer { display: none; } }

/* Announced bonus round: pill over the covered board, never in hit-testing. */
.bonus-badge {
  position: absolute; top: 10px; left: 10px;
  pointer-events: none; white-space: nowrap;
  transition: opacity .4s ease;
  background: var(--accent); color: var(--on-accent);
  font-size: 12px; font-weight: 800; letter-spacing: .04em;
  padding: 6px 12px; border-radius: 999px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .35);
}
.bonus-badge.hidden { display: none; }
/* A hint, not furniture: game.js adds .fade ~3 s into the reveal (it sat on the
   image for the whole round and hid what the player needed, report 2026-09-22). */
.bonus-badge.fade { opacity: 0; }

/* The stake row: bar + "still to win N". The bar is the stake as a share of
   the round's maximum, so it starts full and shrinks with every fallen tile. */
/* Top bar proposal 1: the bar runs the full width in the 6px that used to
   separate the photo from this row (same 24px as before: 2 + 3 + 1 + 18),
   and the round + session score sit left of the stake — "what I have" next
   to "what I can win". */
.stake { display: flex; flex-direction: column; gap: 1px; height: 24px; padding-top: 2px; line-height: 18px; flex: none; }
.progress { flex: none; width: 100%; height: 3px; border-radius: 2px; background: var(--panel-2); overflow: hidden; }
.stake-row { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; height: 18px; }
.stake-session { font-size: 12.5px; color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.stake-session b { color: var(--text); }
.stake-row .stake-num { margin-left: auto; }
.progress-fill { height: 100%; width: 100%; background: linear-gradient(90deg, var(--accent-2), var(--accent)); transition: width .12s linear; }
.stake-num { font-size: 12.5px; color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.stake-num b { color: var(--text); font-size: 15px; font-weight: 800; }
.stake-drop { color: var(--muted); font-weight: 800; margin-right: 6px; opacity: 0; transition: opacity .2s ease; }
.stake-drop.show { opacity: 1; }

/* A miss, said calmly on the photo: no caps, no red. The cost rides along
   (only when there was one to pay); a near miss is warm, not accusing. */
.miss-pill {
  /* Keep the hint near the tiles the player is watching. */
  position: absolute; left: 50%; top: 12px; transform: translateX(-50%);
  max-width: calc(100% - 24px); pointer-events: none; z-index: 2;
  background: rgba(14, 13, 18, .8); color: #f1f0f4;
  font-size: 14px; font-weight: 600; line-height: 1.25; text-align: center;
  padding: 7px 14px; border-radius: 999px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .35);
}
/* near miss in cool blue (E2c): gold is kept for success only. The pill is
   dark in both themes, so the light blue reads on either. */
.miss-pill.close { color: #9fc3ea; }
.miss-pill.hidden { display: none; }

/* The lower zone budgets for the largest keyboard (4 rows since 2026-10-26:
   letters + actions, digits behind the 123 key) AND the result.
   676px: 16 padding + 42 header + 298 photo + 24 stake + 8 gap + 288 lower.
   800px: 16 + 42 + 344 photo + 24 + 22 gap + 352 lower (360px wide).
   Only the native edge-to-edge app subtracts system insets. */
#app:has(section[data-screen="game"]:not(.hidden)) {
  --game-insets: 0px;
  --base-key-height: clamp(36px, calc(40px + (var(--vvh, 100dvh) - 676px) * .111111), 48px);
  --sheet-height: 352px;
  --lower-height: max(var(--sheet-height), calc(4 * var(--base-key-height) + 88px));
  height: var(--vvh, 100dvh); min-height: 0; overflow: hidden;
  padding: 8px;
}
html.native-android #app:has(section[data-screen="game"]:not(.hidden)) {
  --game-insets: calc(var(--safe-area-inset-top, env(safe-area-inset-top, 0px)) + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)));
  padding: calc(var(--safe-area-inset-top, env(safe-area-inset-top, 0px)) + 8px)
           max(8px, var(--safe-area-inset-right, env(safe-area-inset-right, 0px)))
           calc(var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)) + 8px)
           max(8px, var(--safe-area-inset-left, env(safe-area-inset-left, 0px)));
}
#app.sheet-compact { --sheet-height: 288px !important; }
section[data-screen="game"]:not(.hidden) {
  display: flex; flex-direction: column; flex: 1; min-height: 0; overflow: clip;
}
.game-lower {
  position: relative; flex: none; height: var(--lower-height); margin-top: auto;
  overflow: clip; overflow-anchor: none;
}
.round-controls { height: 100%; display: flex; flex-direction: column; }
section[data-screen="game"]:not(.hidden) .round-controls { will-change: transform, opacity; }
.answer { display: flex; gap: 8px; height: 46px; flex: none; }
#answer-input {
  flex: 1; min-width: 0; height: 46px; border-radius: 14px;
  border: 1px solid var(--input-border); background: var(--panel);
  color: var(--text); font-size: 18px; line-height: 24px; padding: 10px 12px;
  white-space: pre; overflow: hidden; touch-action: none;
}
#answer-input.empty::before { content: attr(data-placeholder); color: var(--muted); }
#answer-input.shake { animation: shake .3s ease; }
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-7px); }
  50% { transform: translateX(6px); }
  75% { transform: translateX(-4px); }
}
.btn-go {
  height: 46px; padding: 0 16px; border: none; border-radius: 14px;
  background: var(--accent); color: var(--on-accent);
  font-size: 16px; font-weight: 700; cursor: pointer;
}
.btn-go:active, .btn-go.pressed { filter: brightness(1.18); }
#app.game-keyboard .desktop-go { display: none; }
.feedback {
  position: absolute; top: 1px; left: 12px; right: 12px; z-index: 1;
  height: 44px; display: flex; align-items: center; justify-content: center;
  font-size: 12px; line-height: 14px; text-align: center; color: var(--muted);
  pointer-events: none; overflow: hidden;
}
.has-feedback #answer-input.empty::before { content: ''; }
/* Keep the live region audible, but never paint it over a nonempty buffer. */
section[data-screen="game"]:has(#answer-input:not(.empty)):not(.result-uploading) .feedback {
  width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%);
}
.feedback.ok { color: var(--accent); }
.feedback.wrong { color: var(--danger); font-weight: 700; }
.feedback.wrong.close { color: var(--warn); }
#app:not(.game-keyboard) .feedback { right: 108px; }
#game-keyboard {
  font-family: system-ui;
  --key-rows: 4;
  --key-gap: 5px;
  --key-unit: calc((100% + 3px) / var(--key-columns));
  /* Four rows may grow to 56px; on tall phones (result sheet 352px) the
     spare height stays ABOVE the keys, which sit at the bottom like the
     system keyboard instead of drifting apart. */
  --key-height: min(56px, calc((var(--lower-height) - 72px - (var(--key-rows) - 1) * var(--key-gap)) / var(--key-rows)));
  position: relative; display: none; flex-direction: column; flex: 1; min-height: 0;
  gap: var(--key-gap); justify-content: flex-end;
  touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
}
#app.game-keyboard #game-keyboard { display: flex; }
.key-row { display: flex; flex: none; justify-content: center; gap: 3px; }
.key-row > .game-key, .key-spacer { flex: 0 0 calc(var(--key-unit) * var(--key-span, 1) - 3px); }
.game-key {
  position: relative; height: var(--key-height); min-height: 36px; min-width: 0; padding: 0;
  border: 1px solid var(--input-border); border-radius: 6px;
  background: var(--panel-2); color: var(--text); font: 500 18px/1 system-ui;
  touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  cursor: pointer;
}
.game-key.pressed { background: var(--text); color: var(--bg); }
.key-shift-space, .key-row [data-key="backspace"] { --key-span: 1.5; }
.key-row [data-key="backspace"] { font-size: 23px; }
.key-actions .game-key { font-size: 14px; }
.key-actions .key-toggle { font-weight: 700; color: var(--muted); }
.key-actions [data-key="space"] { --key-span: calc(var(--key-columns) - 3); }
.key-actions .btn-go { --key-span: 2; background: var(--accent); color: var(--on-accent); font-weight: 700; }
.key-actions .btn-go.pressed { background: var(--accent-2); }
.key-hint { position: absolute; top: 2px; right: 3px; font-size: 10px; line-height: 11px; opacity: .6; pointer-events: none; }
.key-popup {
  position: absolute; z-index: 5; display: flex; gap: 3px; padding: 0 4px;
  border: 1px solid #595564; border-radius: 9px; background: #292630;
  box-shadow: 0 3px 10px #0006;
}
.key-popup .game-key { flex: none; width: var(--popup-key-width); background: transparent; color: #f1f0f4; border-color: transparent; }
.key-popup .game-key.selected { background: var(--accent); color: var(--on-accent); }

/* Level and category hints stay in the top bar in every phase. */
/* Proposal 1: the level is the line under the title, plain text in the
   level colours (amber 3, red 4) — no second grey pill. */
.diff-chip {
  flex-shrink: 0; font-size: 11.5px; font-weight: 600; white-space: nowrap;
  color: var(--muted);
}
.diff-chip[data-level="3"] { color: #c98a2e; }
.diff-chip[data-level="4"] { color: var(--danger); }
/* The other half of the .hidden audit that found .cat-chip: the markup ships
   this chip hidden and startRound only ever takes the class off, so nothing
   renders wrong today — the game screen is itself hidden until the first round
   has already filled the chip in. The rule exists so the class means what it
   says, and so the empty pill cannot surface the day something puts it back. */
.diff-chip.hidden { display: none; }

.skip-row { display: flex; justify-content: space-evenly; height: 26px; flex: none; }
.skip { background: none; border: none; color: var(--muted); font-size: 13px; text-decoration: underline; cursor: pointer; padding: 3px 12px; line-height: 20px; }

/* ================= RESULT OVERLAY ================= */
.overlay {
  position: fixed; inset: 0; z-index: 10;
  /* phones: keep sheets clear of the status and navigation bars */
  padding: max(16px, var(--safe-area-inset-top, env(safe-area-inset-top, 0px)))
           var(--safe-area-inset-right, env(safe-area-inset-right, 0px))
           max(16px, var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)))
           var(--safe-area-inset-left, env(safe-area-inset-left, 0px));
  display: flex; align-items: center; justify-content: center;
  background: rgba(8, 10, 14, .72); backdrop-filter: blur(6px);
}
html[data-theme="light"] .overlay { background: rgba(240, 243, 248, .78); }
.overlay.hidden { display: none; }

.card {
  width: min(92vw, 380px); background: var(--panel);
  border: 1px solid var(--border); border-radius: 22px;
  padding: 26px 22px 20px; text-align: center;
  box-shadow: 0 24px 80px rgba(0, 0, 0, .6);
  animation: rise .22s cubic-bezier(.2, .9, .3, 1.2);
  /* A tall card scrolls inside itself instead of pushing its own confirm
     button below the fold — the calendar card is the one that found this. */
  max-height: calc(100dvh - 32px); overflow-y: auto; overscroll-behavior: contain;
}
@keyframes rise {
  from { transform: translateY(24px) scale(.96); opacity: 0; }
  to { transform: none; opacity: 1; }
}

.result-title { font-size: 15px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
.result-title.gold { color: var(--success-text); }
.result-thumb {
  width: 108px; height: 108px; object-fit: cover; border-radius: 16px;
  display: block; margin: 12px auto 0;
  box-shadow: 0 8px 28px rgba(0, 0, 0, .4), 0 0 0 1px rgba(255, 255, 255, .07);
}
.result-thumb.hidden { display: none; }
.result-answer { font-size: 34px; font-weight: 800; margin: 6px 0 2px; text-transform: none; }
.answer-label { text-transform: none; }
/* English source answers are lowercase, including proper names. */
.result-answer[lang|=en], .answer-label[lang|=en] { text-transform: capitalize; }
/* The flag stands next to the answer itself — "Udon 🇯🇵" — so it is sized to
   the word, not to the 11px chip it comes from: 25px tall is about the cap
   height of this 34px line, which is what makes the pair read as one thing
   rather than as an icon dropped beside it. A long answer plus two flags wraps
   on its own; the line-height keeps a wrapped row from colliding. */
.result-answer .origin-flag { width: 34px; height: 25px; vertical-align: -4px; }
/* The whole group moves together or not at all. An <img> offers a wrap
   opportunity on both sides of itself no matter what space sits next to it —
   a non-breaking space between the flags was tried and measured still
   splitting yerba mate's four countries 3 + 1 — so the binding has to be
   nowrap on the wrapper, not the character between them. */
.result-answer .origin-flags { white-space: nowrap; }
.result-answer:has(.origin-flag) { line-height: 1.25; }
.result-meta { font-size: 12px; color: var(--muted); }
.result-meta.hidden { display: none; }
.result-score { font-size: 56px; font-weight: 800; color: var(--accent); margin: 10px 0 2px; font-variant-numeric: tabular-nums; }
.result-score.zero { color: var(--muted); }
.result-stats { font-size: 13px; color: var(--muted); white-space: pre-line; }
.result-score-block { margin: 0; }
.result-session { font-size: 12px; color: var(--muted); margin: 6px 0 16px; padding-top: 6px; border-top: 1px solid var(--border); white-space: pre-line; }
/* "A new puzzle lands tomorrow" — the line that closes the Daily. Sits under
   the session line and pulls up into its bottom margin so the card keeps its
   spacing whether or not the note is shown. */
.result-note { font-size: 12.5px; font-weight: 600; color: var(--accent); margin: -10px 0 14px; }
/* There is no global .hidden here — every element brings its own rule. */
.result-note.hidden { display: none; }

/* ================= REPORT SHEET ================= */
/* ⚑ link in the result card (below the session line) and the sheet it opens.
   The sheet overlays the result card — it sits later in the DOM on purpose. */
.report-link {
  display: block; margin: -10px 0 14px; padding: 0;
  background: none; border: none; cursor: pointer;
  font-size: 11.5px; color: var(--muted); text-decoration: underline dotted;
}
/* Hidden on cards with no just-played round behind them (the daily
   "already played" card): there would be nothing to report. */
.report-link.hidden { display: none; }
/* after sending: a quiet confirmation in place of the link */
.report-link.done { text-decoration: none; color: var(--accent); cursor: default; }

/* E2b: the report is a bottom sheet — pinned to the bottom edge, which the
   soft keyboard lifts (interactive-widget=resizes-content shrinks the
   layout viewport), so the comment and the send button ride above it. */
.sheet-overlay { align-items: flex-end; padding-bottom: 0; }
.report-card {
  text-align: left; width: min(100%, 480px);
  border-bottom: 0; border-radius: 22px 22px 0 0;
  padding: 8px 16px calc(14px + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px)));
  max-height: calc(100dvh - 24px - var(--safe-area-inset-top, env(safe-area-inset-top, 0px)));
  animation: sheet-up .28s cubic-bezier(.2, .9, .25, 1.05);
}
@keyframes sheet-up { from { transform: translateY(40px); opacity: 0; } to { transform: none; opacity: 1; } }
.report-grab { display: block; width: 38px; height: 4px; border-radius: 4px; background: var(--border); margin: 0 auto 10px; }
.report-head { display: flex; align-items: center; gap: 10px; }
.report-thumb { flex: none; width: 44px; height: 44px; border-radius: 10px; object-fit: cover; background: var(--panel-2); }
.report-thumb.hidden { display: none; }
.report-head-text { flex: 1; min-width: 0; }
.report-title { font-size: 18px; font-weight: 800; line-height: 1.15; color: var(--text); }
.report-puzzle { font-size: 12.5px; color: var(--muted); font-weight: 600; margin-top: 2px; overflow-wrap: anywhere; }
.report-puzzle.hidden { display: none; }
.report-x {
  flex: none; width: 32px; height: 32px; border-radius: 10px; cursor: pointer;
  background: var(--panel-2); border: 0; color: var(--muted); font-size: 15px;
}
.report-label { font-size: 12px; color: var(--muted); margin: 12px 0 8px; }
.report-reasons { display: grid; gap: 8px; }
.report-reason {
  text-align: left; padding: 11px 14px; cursor: pointer;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 12px;
  color: var(--text); font-size: 14px; font-weight: 600;
}
.report-reason[aria-pressed="true"] { border-color: var(--accent); }
/* Bez kontekstu zagadki (otwarcie z Ustawień) pomiar trudności nie ma sensu —
   ui/report.js chowa powód razem z linią "Zagadka: …". */
.report-reason.hidden, .report-reason.folded-out { display: none; }
.report-change {
  justify-self: start; display: block; margin-top: 6px; padding: 4px 0;
  background: none; border: 0; cursor: pointer;
  color: var(--accent); font-size: 13px; font-weight: 700;
}
.report-change.hidden, #report-comment.hidden { display: none; }
/* Compact slider (keyboard up under the difficulty reason): only the
   summary line stays; a tap on it brings the slider back. */
.rj-wrap.compact .rj-box > .report-label, .rj-wrap.compact .rj-scale { display: none; }
.rj-wrap.compact .rj-summary { cursor: pointer; }
#report-comment {
  width: 100%; margin-top: 12px; padding: 10px 12px; box-sizing: border-box;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 12px;
  color: var(--text); font: inherit; font-size: 14px; resize: vertical;
}
#report-comment:focus { outline: none; border-color: var(--accent); }
.report-actions { display: flex; gap: 10px; margin-top: 14px; }
.report-actions .btn-secondary, .report-actions .btn-primary { flex: 1; }
/* Sent state: the form folds away and the thanks line is the whole card. */
.report-status { text-align: center; font-size: 16px; font-weight: 700; padding: 10px 2px 2px; }
.report-status.hidden { display: none; }
.report-status:focus { outline: none; }
.report-card.sent .report-head,
.report-card.sent .report-label,
.report-card.sent .report-change,
.report-card.sent .report-reasons,
.report-card.sent .rj-wrap,
.report-card.sent #report-comment,
.report-card.sent .report-actions { display: none; }
.report-card.sent .report-status { padding: 18px 0 14px; }
.report-card.sent .report-status::before {
  content: '✓'; display: block; margin-bottom: 8px;
  font-size: 40px; line-height: 1; font-weight: 800; color: var(--accent);
}

/* Difficulty slider (.rj-*, makieta docs/mockups/zglos-blad-trudnosc-2026-09-13.html).
   Rozwija się tylko pod powodem "difficulty"; rodzimy input[type=range] daje
   strzałki i czytniki za darmo. Kciuk startuje na poziomie zagadki, a ten
   stopień trzyma kreskowy pierścień "obecny" — zgłoszenie zawsze czyta się
   jako "ta konkretna zagadka jest źle zaszuflankowana". */
.rj-wrap { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .24s cubic-bezier(.2, .9, .3, 1); }
.rj-wrap.open { grid-template-rows: 1fr; }
.rj-inner { overflow: hidden; min-height: 0; }
.rj-box { margin-top: 10px; padding: 0 2px; }
.rj-box .report-label { margin-bottom: 2px; }
/* Padding daje miejsce skrajnym etykietom ("Łatwe"/"Ekspert") i podpisowi
   "obecny": centrowane na środkach stopni, na stopniu 1 i 4 wystają poza
   tor, a .rj-inner wyżej (overflow:hidden dla animacji zwijania) ucinałby je
   na krawędzi karty (zgłoszone przez właściciela po wydaniu 2301). Tor i
   pozycje stopni liczą się z szerokości inputu, więc zwężenie jest spójne
   automatycznie — bez zmian w ui/report.js. */
.rj-scale { position: relative; padding: 0 28px; }
/* podpis "obecny" nad osią, nad stopniem zagadki */
.rj-caps { position: relative; height: 20px; }
.rj-cap {
  position: absolute; top: 4px; transform: translateX(-50%);
  font-size: 9.5px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); border: 1px dashed var(--muted); border-radius: 7px; padding: 1px 7px;
  white-space: nowrap;
}
.rj-range {
  -webkit-appearance: none; appearance: none;
  display: block; width: 100%; height: 30px; margin: 0;
  background: transparent; cursor: pointer;
  /* wypełnienie toru kończy się na środku kciuka: --p = (wybrany-1)/3 */
  --thumb: 24px; --p: 0;
}
.rj-range:focus { outline: none; }
.rj-range::-webkit-slider-runnable-track {
  height: 6px; border-radius: 999px; border: 1px solid var(--border);
  background: linear-gradient(to right,
    var(--accent) 0,
    var(--accent) calc(12px + (100% - var(--thumb)) * var(--p)),
    var(--panel-2) calc(12px + (100% - var(--thumb)) * var(--p)));
}
.rj-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: var(--thumb); height: var(--thumb); border-radius: 50%;
  background: var(--panel); border: 3px solid var(--accent);
  margin-top: -10px; box-shadow: 0 2px 10px rgba(0, 0, 0, .5);
}
.rj-range::-moz-range-track { height: 6px; border-radius: 999px; border: 1px solid var(--border); background: var(--panel-2); }
.rj-range::-moz-range-progress { height: 6px; border-radius: 999px; background: var(--accent); }
.rj-range::-moz-range-thumb {
  width: calc(var(--thumb) - 6px); height: calc(var(--thumb) - 6px); border-radius: 50%;
  background: var(--panel); border: 3px solid var(--accent);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .5);
}
/* stopnie pod osią; pozycje (środki kciuków) ustawia ui/report.js inline */
.rj-stops { position: relative; height: 34px; margin-top: 2px; }
.rj-stop {
  position: absolute; top: 0; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 4px;
}
.rj-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--panel-2); border: 1px solid var(--border);
  transition: background .15s, border-color .15s;
}
.rj-stop.on .rj-dot { background: var(--accent); border-color: var(--accent); }
.rj-stop.cur .rj-dot {
  background: var(--panel); border: 1px dashed var(--muted);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--muted) 22%, transparent);
}
.rj-lab { font-size: 10.5px; font-weight: 600; color: var(--muted); white-space: nowrap; }
/* wybrany poziom podświetla nazwę tintem diff-chip (1–2 akcent, 3 bursztyn, 4 czerwień) */
.rj-stop.sel .rj-lab { color: var(--accent); font-weight: 800; }
.rj-stop.sel[data-level="3"] .rj-lab { color: #c98a2e; }
.rj-stop.sel[data-level="4"] .rj-lab { color: var(--danger); }
.rj-summary { margin-top: 8px; font-size: 12.5px; color: var(--muted); }
.rj-hint { margin-top: 6px; font-size: 12px; font-weight: 600; color: var(--warn); display: none; }
.rj-hint.show { display: block; }

/* ================= HOW TO PLAY + BETA CARDS =================
   The pre-game how-to card appears at each start until opted out; the beta
   card greets a freshly picked beta language once per language; the extended
   help opens from Settings. The wordmark replaces a text "REVEAL" overline
   and inverts for the light theme like .logo-img. */
.ht-logo { height: 20px; width: auto; display: block; margin: 0 auto 10px; }
html[data-theme="light"] .ht-logo, html[data-theme="light"] .bt-logo { filter: invert(1); }
.howto-card h2, .beta-card h2, .ht-extended h2 { font-size: 24px; font-weight: 800; margin: 4px 0 0; }
/* Miniature of the covered board with one corner already cleared. */
.ht-board {
  width: 108px; height: 108px; margin: 16px auto 4px; border-radius: 16px;
  background: linear-gradient(135deg, #2d7562 0%, #3f9c82 45%, #1d7f9e 100%);
  overflow: hidden; position: relative;
  box-shadow: 0 8px 28px rgba(0, 0, 0, .4), 0 0 0 1px rgba(255, 255, 255, .07);
}
.ht-board .g { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(6, 1fr); grid-template-rows: repeat(6, 1fr); }
.ht-board .g i { background: var(--tile); box-shadow: inset 0 0 0 1px var(--tile-edge); }
.ht-board .g i.off { opacity: 0; }
.ht-list { display: flex; flex-direction: column; gap: 13px; margin: 16px 0 6px; text-align: left; }
.ht-item { display: flex; gap: 11px; font-size: 14px; line-height: 1.5; }
.ht-item .ico { font-size: 17px; flex: none; line-height: 1.3; }
/* The dismiss-for-good checkbox for how-to, beta and Daily intro cards: a div
   with role=checkbox; one tap toggles it, and confirmation reads the state. */
.ht-check {
  display: flex; gap: 10px; align-items: center; text-align: left;
  margin: 14px 2px; cursor: pointer; font-size: 13px; font-weight: 600; color: var(--muted);
}
.ht-check .box {
  width: 21px; height: 21px; border-radius: 6px; flex: none;
  border: 1.5px solid var(--input-border); background: var(--panel-2);
  display: grid; place-items: center; font-size: 13px; font-weight: 800; color: var(--on-accent);
}
.ht-check.checked .box { background: var(--accent); border-color: var(--accent); }
.ht-check.checked .box::after { content: '✓'; }
.ht-check.checked { color: var(--text); }
.howto-card .btn-primary, .beta-card .btn-primary { width: 100%; }
.howto-card .btn-primary { margin-top: 0; }
/* Leave room for the opt-out and longer translations on short phones. */
@media (max-height: 700px) {
  .howto-card { padding: 22px 20px 18px; }
  .howto-card .ht-board { width: 88px; height: 88px; margin-top: 12px; }
  .howto-card .ht-list { gap: 10px; margin-top: 12px; }
  .howto-card .ht-item { font-size: 13px; }
  .howto-card .ht-check { margin: 10px 2px; }
}
/* Beta card: badge beside the language name, thanks line carrying the inline
   wordmark ({logo} in beta.thanks, built by ui/howto.js). */
.beta-big {
  display: inline-block; font-size: 11px; font-weight: 800; letter-spacing: .08em;
  color: var(--warn); border: 1px solid var(--warn); border-radius: 8px;
  padding: 2px 8px; vertical-align: 4px; margin-left: 8px; white-space: nowrap;
}
.beta-body { font-size: 14px; line-height: 1.55; margin-top: 14px; text-align: left; }
.beta-thanks { font-size: 13.5px; font-weight: 700; color: var(--accent); margin-top: 12px; }
.bt-logo { height: 14px; width: auto; vertical-align: -2px; margin: 0 2px; }
/* Extended help: same card, longer text — the sections scroll, the Close
   button stays put. */
.ht-extended { display: flex; flex-direction: column; max-height: min(76dvh, 640px); }
.ht-scroll { overflow-y: auto; text-align: left; margin-top: 10px; }
.ht-sec { padding: 11px 0; border-top: 1px solid var(--border); }
.ht-sec:first-child { border-top: none; padding-top: 2px; }
.ht-sec h4 { font-size: 11px; text-transform: uppercase; letter-spacing: .12em; color: var(--muted); margin-bottom: 5px; }
.ht-sec p { font-size: 13.5px; line-height: 1.55; }
.ht-extended .btn-secondary { width: 100%; margin-top: 14px; }



.btn-next {
  width: 100%; height: 56px; border: none; border-radius: 16px;
  background: var(--accent); color: var(--on-accent);
  font-size: 17px; font-weight: 800; cursor: pointer;
}
.btn-next:active { transform: scale(.97); }
.btn-end-session {
  width: 100%; height: 44px; margin-top: 8px; border-radius: 14px;
  background: none; border: 1px solid var(--border); color: var(--muted);
  font-size: 14px; font-weight: 700; cursor: pointer;
}
.btn-end-session:active { transform: scale(.98); }
.btn-end-session.hidden { display: none; }

/* ================= REDUCED MOTION ================= */
html.reduced-motion *,
html.reduced-motion .tile {
  animation: none !important;
}
html.reduced-motion .tile { transition-duration: 0ms !important; }
html.reduced-motion .progress-fill,
html.reduced-motion .stake-drop { transition: none; }

@media (prefers-reduced-motion: reduce) {
  .tile { transition-duration: 40ms; }
  .board.correct, #answer-input.shake, .card, .report-card { animation: none; }
  /* E2c: the system preference stills the result just like the in-game
     setting — no rise, no confetti (the id beats the .card rule) */
  /* :root lifts it above the later #overlay.as-sheet .card rule */
  :root #overlay.as-sheet .card, :root .di-card, .confetti i { animation: none; }
  .progress-fill, .stake-drop { transition: none; }
  .rj-wrap { transition: none; }
}

/* ---- share (Phase B): ranked daily result card ---- */
.result-best {
  font-size: 12.5px; font-weight: 800; color: var(--accent);
  margin: 2px 0 0; letter-spacing: .04em;
}
.result-best.hidden { display: none; }
.btn-share {
  width: 100%; height: 44px; margin: 2px 0 10px; border-radius: 14px;
  background: none; border: 1.5px solid var(--accent); color: var(--accent);
  font-size: 14.5px; font-weight: 700; cursor: pointer;
}
.btn-share:active { transform: scale(.98); }
.btn-share:disabled { opacity: .6; }
.btn-share.hidden { display: none; }

/* ---- Daily intro sheet: the same fixed lower zone as controls/result. ---- */
.intro-slot { position: absolute; inset: 0; }
.intro-slot.hidden { display: none; }
.di-card {
  height: 100%; padding: 12px 16px 10px; border-radius: 20px; background: var(--panel);
  border: 1px solid var(--border);
  display: flex; flex-direction: column; justify-content: space-between; gap: 4px;
  text-align: left; will-change: transform, opacity;
  animation: intro-rise 220ms ease-out, intro-appear 220ms linear;
}
.di-card.leaving { pointer-events: none; }
@keyframes intro-rise { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes intro-appear { 0% { opacity: 0; } 10% { opacity: .7; } 45%, 100% { opacity: 1; } }
.di-card > * { flex-shrink: 0; }
.di-kicker {
  font-size: 11.5px; line-height: 16px; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent);
}
.di-category {
  display: flex; align-items: center; flex-wrap: wrap; gap: 5px;
  font-size: 20px; font-weight: 800; line-height: 23px;
}
.di-category .origin-flags { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.di-category .origin-flag { width: 27px; height: 20px; vertical-align: 0; }
.di-meta { display: flex; flex-wrap: wrap; gap: 6px; }
.di-meta:has(.di-level.hidden):has(.di-pace.hidden) { display: none; }
.di-pace { display: contents; }
.di-level, .di-pace-row {
  padding: 4px 10px; border-radius: 999px; background: var(--panel-2);
  font-size: 12.5px; line-height: 17px; font-weight: 700; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.di-category.hidden, .di-level.hidden, .di-pace.hidden, .di-pace-note.hidden { display: none; }
.di-pace-note { font-size: 12.5px; line-height: 17px; color: var(--muted); }
.di-card .ht-check { margin: 0; min-height: 32px; font-size: 13px; line-height: 17px; }
.di-card .btn-next { width: 100%; height: 52px; margin: 0; }
section[data-screen="game"].as-intro .round-controls,
section[data-screen="game"].as-intro .stake,
section[data-screen="game"].as-intro .feedback { visibility: hidden; }

/* ---- Daily Calendar block on the result card ----------------------------
   Two lines and nothing else: what today is, in bold, then why it is worth
   knowing. Everything that used to sit here — the shouted date caption, the
   folded explanation, the teaser for tomorrow — came off on owner feedback
   that the card still carried too much text.

   Only Daily compacts the head. In other modes the same block carries the
   fact without its dated occasion and keeps the ordinary head proportions. */
.card.has-cal .result-thumb { width: 84px; height: 84px; }
.card.has-cal .result-answer { font-size: 26px; line-height: 1.25; margin: 4px 0 2px; }
.card.has-cal .result-score-block { margin: 8px 0 4px; padding: 8px 12px 9px; border-radius: 13px; background: var(--panel-2); }
.card.has-cal .result-score { font-size: 40px; line-height: 1; margin: 0 0 2px; }
.card.has-cal .result-stats { font-size: 12px; line-height: 1.4; }
.card.has-cal .result-session { margin: 8px 0 12px; }

.result-cal { margin: 0 0 4px; text-align: left; }
.rc-occasion { font-size: 14px; font-weight: 700; line-height: 1.35; margin-bottom: 6px; }
.rc-occasion.hidden { display: none; }
.rc-text { font-size: 13.5px; line-height: 1.55; color: var(--muted); }
.result-cal.hidden { display: none; }


/* ================= RESULT SHEET (Endless) ================= */
.result-head { display: block; }
.result-status.hidden, .result-session.hidden { display: none; }
.result-foot { display: contents; }
.result-more.hidden { display: none; }
.result-slot { position: absolute; inset: 0; pointer-events: none; }
section[data-screen="game"].as-result .result-slot { pointer-events: auto; }
section[data-screen="game"].controls-gone .round-controls { visibility: hidden; }
/* W2 (owner 2026-10-31): the session score stays in view under the photo
   while the result is up, so the round's points can fly into it; the stake
   itself (bar and "still to win") is over. Daily has no session row. */
section[data-screen="game"].result-wait .stake .progress,
section[data-screen="game"].result-wait .stake-num,
section[data-screen="game"].as-result .stake .progress,
section[data-screen="game"].as-result .stake-num { visibility: hidden; }
/* Preserve the live region outside inert controls. Hide success visually;
   an upload uses this same space until the server has answered. */
section[data-screen="game"].result-wait:not(.result-uploading) .feedback,
section[data-screen="game"].controls-gone:not(.result-uploading) .feedback {
  width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%);
}
section[data-screen="game"].result-uploading .feedback {
  top: 8px; font-size: 14px; line-height: 20px; max-height: none; text-align: center;
}

#overlay.as-sheet {
  position: static; inset: auto; z-index: auto; padding: 0;
  display: block; background: none; backdrop-filter: none; margin: 0; height: 100%;
}
#overlay.as-sheet.hidden { display: none; }
#overlay.as-sheet .card {
  width: 100%; height: 100%; max-height: 100%; overflow: auto; text-align: left;
  padding: 12px 16px 10px; border-radius: 20px; box-shadow: none;
  display: flex; flex-direction: column; gap: 4px; justify-content: space-between;
  will-change: transform, opacity;
  animation: none; /* game.js sequences the two compositor animations */
}
#overlay.as-sheet .result-thumb { display: none; }
#overlay.as-sheet .card > * { flex-shrink: 0; }
#overlay.as-sheet .result-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; order: 1; line-height: 1.2; }
#overlay.as-sheet .result-title {
  font-size: 26px; font-weight: 800; letter-spacing: -.01em; text-transform: none; color: var(--accent);
}
#overlay.as-sheet .result-title.gold { color: var(--success-text); }
#overlay.as-sheet .result-title.neutral { color: var(--text); font-size: 22px; }
#overlay.as-sheet .result-answer { order: 2; font-size: 22px; margin: 0; line-height: 1.15; min-height: 26px; flex: none; overflow-wrap: anywhere; }
#overlay.as-sheet .result-meta { order: 3; margin: 0; line-height: 15px; }
#overlay.as-sheet .result-score-block {
  order: 4; display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--panel-2); border-radius: 14px; padding: 6px 12px; margin: 0;
}
#overlay.as-sheet .result-score { font-size: 32px; line-height: 1; margin: 0; }
#overlay.as-sheet .result-stats { font-size: 12.5px; text-align: right; line-height: 1.35; }
#overlay.as-sheet .result-best { margin: 0; font-size: 12px; line-height: 15px; text-align: right; width: 42%; flex: none; letter-spacing: normal; }
#overlay.as-sheet .result-note { order: 6; margin: 0; }
#overlay.as-sheet .btn-next { order: 7; height: 52px; margin: 2px 0 0; }
#overlay.as-sheet .btn-end-session { order: 8; height: 40px; margin: 0; }
#overlay.as-sheet .result-foot { display: flex; order: 9; align-items: center; justify-content: space-between; gap: 10px; min-height: 20px; line-height: 16px; }
#overlay.as-sheet .result-session { order: 10; display: none; margin: 0; padding: 8px 10px; border-top: none; border-radius: 12px; background: var(--panel-2); text-align: left; }
#overlay.as-sheet .card.more-open .result-session { display: block; }
/* Calendar facts use the spare space in the fixed lower zone. Neither long
   prose nor expanded details can push the actions out of that zone. */
#overlay.as-sheet:not(.daily-sheet) .result-cal {
  order: 5; flex: 1 1 0; min-height: 0; margin: 0; padding: 0 0 4px 9px;
  border-left: 3px solid var(--success-bar); overflow-y: auto; overscroll-behavior: contain;
}
#overlay.as-sheet:not(.daily-sheet) .result-cal.overflowing {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 10px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 10px), transparent);
}
#overlay.as-sheet:not(.daily-sheet) .rc-text { font-size: 12.5px; line-height: 1.4; }
#overlay.as-sheet:not(.daily-sheet) .card:has(.result-cal:not(.hidden)) .result-session {
  order: 5; flex: 1 1 0; min-height: 0; overflow-y: auto; padding: 0 10px;
}
#overlay.as-sheet .report-link { margin: 0; }
.result-more {
  background: none; border: none; padding: 2px 0; cursor: pointer;
  color: var(--muted); font-size: 13px; font-weight: 600; line-height: 16px;
}
html.reduced-motion #overlay.as-sheet .card { animation: none; }

/* ================= UPDATE BANNER ================= */
/* Sits above the result overlay (z-index 10) so it is still reachable when a
   round has just ended — that is the calmest moment to take a reload. Bottom
   centre keeps it clear of the HUD chips and the board. Like every component
   in this stylesheet it brings its own .hidden; the toast is markup that
   starts hidden, so forgetting that rule would show it to everyone forever. */
.update-toast {
  /* centred between the side insets, not on the whole screen (a side system bar is not free space) */
  position: fixed; left: calc(50% + (var(--safe-area-inset-left, env(safe-area-inset-left, 0px)) - var(--safe-area-inset-right, env(safe-area-inset-right, 0px))) / 2);
  bottom: calc(14px + var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px))); transform: translateX(-50%);
  z-index: 20; display: flex; align-items: center; gap: 8px;
  max-width: calc(100vw - 24px - var(--safe-area-inset-left, env(safe-area-inset-left, 0px)) - var(--safe-area-inset-right, env(safe-area-inset-right, 0px))); box-sizing: border-box;
  padding: 7px 8px 7px 14px; border-radius: 999px;
  background: var(--panel-2); border: 1px solid var(--border);
  color: var(--text); font-size: 13px; font-weight: 600;
  box-shadow: 0 8px 28px rgba(0, 0, 0, .5);
}
.update-toast.hidden { display: none; }
.update-toast-go {
  flex-shrink: 0; border: none; cursor: pointer;
  background: var(--accent); color: var(--on-accent);
  font-size: 13px; font-weight: 700; padding: 5px 13px; border-radius: 999px;
}
.update-toast-x {
  flex-shrink: 0; border: none; background: none; cursor: pointer;
  color: var(--muted); font-size: 17px; line-height: 1; padding: 2px 6px;
}

/* ================= ADS (plan F3): "save the streak" offer + HUD streak ================= */
.streak-save { z-index: 60; }
.streak-save-card { text-align: center; padding-top: 22px; }
.streak-save-flame { font-size: 64px; line-height: 1; animation: streak-flame 1.1s ease-in-out infinite alternate; }
.streak-save-count {
  font-size: 56px; font-weight: 900; line-height: 1.05; margin: 2px 0 8px;
  background: linear-gradient(180deg, #ffd166, #f0635a); -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: streak-pop .6s cubic-bezier(.2, 1.6, .4, 1) both;
}
.streak-save-card h2 { margin: 0 0 6px; }
.streak-save-body { color: var(--muted); margin: 0 0 16px; }
.streak-save-watch { width: 100%; margin-bottom: 8px; font-size: 16px; }
.streak-save-decline { width: 100%; }
.streak-save-timer { height: 4px; border-radius: 2px; background: var(--border); margin-top: 14px; overflow: hidden; }
.streak-save-timer i { display: block; height: 100%; background: var(--accent); transform-origin: left; animation: streak-timer linear forwards; }
.streak-save.still .streak-save-flame, .streak-save.still .streak-save-count { animation: none; }
@keyframes streak-flame { from { transform: scale(1) rotate(-4deg); } to { transform: scale(1.12) rotate(4deg); } }
@keyframes streak-pop { from { transform: scale(.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes streak-timer { from { transform: scaleX(1); } to { transform: scaleX(0); } }

.hud-stat.streak-warm b { color: #ffb347; }
/* Filled pill with even padding: flame and count sit centred (owner decision 2026-10-23, variant C). */
.hud-stat.streak-fire {
  display: inline-flex; align-items: center; gap: 3px; padding: 2px 8px;
  border-radius: 999px; line-height: 1.2; background: rgba(255, 122, 69, .16);
  box-shadow: inset 0 0 0 1px rgba(255, 122, 69, .5);
}
.hud-stat.streak-fire b { color: #ff7a45; }
.hud-stat.streak-milestone { animation: streak-milestone .7s ease-out; }
.hud-stat.streak-saved { animation: streak-milestone .9s ease-out 2; }
@keyframes streak-milestone { 0% { transform: scale(1); } 35% { transform: scale(1.35); } 100% { transform: scale(1); } }
html.reduced-motion .hud-stat.streak-milestone, html.reduced-motion .hud-stat.streak-saved { animation: none; }
/* the system preference too — the pill pulses on the web now (W3, Codex/Muse r1) */
@media (prefers-reduced-motion: reduce) { .hud-stat.streak-milestone, .hud-stat.streak-saved { animation: none; } }
.streak-save.timer-stopped .streak-save-timer { visibility: hidden; }
#ad-privacy.hidden { display: none; }

/* Short viewport: answer and metadata stay in the fixed lower zone.
   A long answer may wrap. Expanded details
   scroll inside the card and cannot resize the photo or the zone. */
#app.sheet-compact #overlay.as-sheet .card { padding: 6px 12px; gap: 4px; }
#app.sheet-compact #overlay.as-sheet .result-title { font-size: 22px; }
#app.sheet-compact #overlay.as-sheet .result-answer { font-size: 20px; min-height: 25px; }
#app.sheet-compact #overlay.as-sheet .result-score { font-size: 28px; }
#app.sheet-compact #overlay.as-sheet .result-score-block { padding: 4px 10px; }
#app.sheet-compact #overlay.as-sheet .result-stats { font-size: 12px; }
#app.sheet-compact #overlay.as-sheet .btn-next { height: 44px; margin: 0; }
#app.sheet-compact #overlay.as-sheet .btn-end-session { height: 36px; }
#overlay.as-sheet .result-answer .origin-flag { width: 23px; height: 17px; vertical-align: -2px; }
#overlay.as-sheet .result-answer:has(.origin-flag) { line-height: 1.25; }

/* Daily round: only the calendar story grows; without it, spread the rows.
   Named areas keep the original DOM/order and styles of both modal cards. */
#overlay.as-sheet.daily-sheet .card {
  display: grid; overflow: clip; column-gap: 8px;
  grid-template-columns: minmax(0, 7fr) minmax(0, 3fr);
  grid-template-rows: auto auto auto minmax(0, 1fr) auto auto;
  grid-template-areas: "head head" "answer answer" "score score" "fact fact" "share next" "footer footer";
}
#overlay.as-sheet.daily-sheet .card:has(.btn-share.hidden) {
  grid-template-areas: "head head" "answer answer" "score score" "fact fact" "next next" "footer footer";
}
#overlay.as-sheet.daily-sheet .card:has(.result-cal.hidden) {
  grid-template-rows: auto auto auto auto auto;
  grid-template-areas: "head head" "answer answer" "score score" "share next" "footer footer";
  align-content: space-between;
}
#overlay.as-sheet.daily-sheet .card:has(.result-cal.hidden):has(.btn-share.hidden) {
  grid-template-areas: "head head" "answer answer" "score score" "next next" "footer footer";
}
#overlay.as-sheet.daily-sheet .result-head { grid-area: head; line-height: 1; }
#overlay.as-sheet.daily-sheet .result-status {
  font-size: 11.5px; line-height: 16px; font-weight: 800; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted); text-align: right;
}
#overlay.as-sheet.daily-sheet .result-answer { grid-area: answer; }
#overlay.as-sheet.daily-sheet .result-score-block { grid-area: score; }
#overlay.as-sheet.daily-sheet .result-score { flex: none; }
#overlay.as-sheet.daily-sheet .result-stats { flex: 1 1 auto; min-width: 0; white-space: pre-line; text-wrap-style: balance; }
#overlay.as-sheet.daily-sheet .result-cal {
  grid-area: fact; min-height: 0; margin: 0; padding: 0 0 4px 9px;
  border-left: 3px solid var(--success-bar); overflow-y: auto; overscroll-behavior: contain;
}
#overlay.as-sheet.daily-sheet .result-cal.overflowing {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 10px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 10px), transparent);
}
#overlay.as-sheet.daily-sheet .rc-occasion { font-size: 13px; line-height: 1.35; margin-bottom: 2px; }
#overlay.as-sheet.daily-sheet .rc-text { font-size: 12.5px; line-height: 1.4; }
#overlay.as-sheet.daily-sheet .btn-share {
  grid-area: share; height: 52px; margin: 0; padding: 0 4px; white-space: nowrap;
}
#overlay.as-sheet.daily-sheet .btn-next { grid-area: next; margin: 0; padding: 0 4px; white-space: nowrap; }
/* P8 (owner 2026-10-30): the message preview takes the story's row on a plain
   day (game.js hides it on calendar days, so the two never compete), and a
   result better than half the field makes Share the filled button while Done
   steps back to the outlined one. */
#overlay.as-sheet.daily-sheet .card:has(.result-cal.hidden):has(.share-preview:not(.hidden)) {
  grid-template-rows: auto auto auto minmax(0, 1fr) auto auto;
  grid-template-areas: "head head" "answer answer" "score score" "preview preview" "share next" "footer footer";
  align-content: stretch;
}
#overlay.as-sheet.daily-sheet .share-preview { grid-area: preview; align-self: start; }
.share-preview {
  min-height: 0; overflow: hidden; margin: 0; padding: 7px 10px; border-radius: 12px;
  background: var(--panel-2); color: var(--text); font-size: 12.5px; line-height: 1.35; text-align: left;
}
.share-preview.hidden { display: none; }
.share-preview .sp-text { white-space: pre-line; font-variant-numeric: tabular-nums; }
.share-preview .sp-note { font-size: 11px; line-height: 14px; color: var(--muted); margin-top: 3px; }
#app.sheet-compact .share-preview { padding: 5px 9px; font-size: 12px; line-height: 1.3; }
.btn-share.primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
#overlay .card:has(.btn-share.primary) .btn-next {
  background: var(--panel); color: var(--text); border: 1px solid var(--border);
}
/* W4 (owner 2026-10-31): "Level 7 · 11/20" under the round's numbers; the
   level's bar runs along the score block's bottom edge, inside its rounded
   corners, so the block keeps its height. */
#overlay.as-sheet .result-score-block { position: relative; overflow: hidden; }
.result-stats .rs-level { display: block; font-weight: 700; color: var(--text); }
.level-bar { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: var(--border); }
.level-bar.hidden { display: none; }
.level-bar b { display: block; height: 100%; background: var(--accent); transform-origin: 0 50%; }
/* the new level's number beside "Level up! Level 8" */
.lvl-badge {
  display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; margin-right: 6px;
  border-radius: 6px; background: var(--accent); color: var(--on-accent); font-size: 12px; font-weight: 800; vertical-align: -4px;
}
/* P2: the shield cue's ten-step bar beside "Shield in N" — accent, no gold. */
.cue-bar { display: inline-flex; gap: 2px; margin-left: 6px; vertical-align: middle; }
.cue-bar i { width: 8px; height: 5px; border-radius: 2px; background: var(--panel-2); box-shadow: inset 0 0 0 1px var(--border); transform-origin: 50% 100%; }
.cue-bar i.on { background: var(--accent); box-shadow: none; }
/* W3: the soft landing's sign — three covered tiles, the last one open. */
.cue-ez { display: inline-grid; grid-template-columns: repeat(3, 7px); gap: 2px; margin-right: 6px; vertical-align: -1px; }
.cue-ez i { width: 7px; height: 7px; border-radius: 2px; background: rgba(150, 154, 166, .45); }
html[data-theme="light"] .cue-ez i:not(.on) { background: var(--tile); }
.cue-ez i.on { background: var(--accent); }
/* W8 (owner 2026-10-31): three dots "type" the message before it appears;
   the text keeps its room meanwhile, so nothing below it moves. */
.share-preview { position: relative; }
.sp-typing { position: absolute; left: 10px; top: 10px; display: none; gap: 4px; }
.sp-typing i { width: 6px; height: 6px; border-radius: 50%; background: var(--muted); }
.share-preview.typing .sp-typing { display: inline-flex; }
.share-preview.typing .sp-text { visibility: hidden; }
#overlay:not(.as-sheet) .share-preview { margin: 10px 0 8px; }
/* W8: on a shareable Daily the day's story folds to one line above the
   message; opened, it takes the message's room until it is folded again. */
.rc-toggle {
  display: block; width: 100%; padding: 0; background: none; border: none; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 700; line-height: 20px; color: var(--text); text-align: left;
}
.rc-toggle.hidden { display: none; }
.result-cal.folded .rc-occasion, .result-cal.folded .rc-text { display: none; }
#overlay .card.fact-open .share-preview { display: none; }
#overlay.as-sheet.daily-sheet .card:not(.fact-open):has(.result-cal.folded:not(.hidden)):has(.share-preview:not(.hidden)) {
  grid-template-rows: auto auto auto auto minmax(0, 1fr) auto auto;
  grid-template-areas: "head head" "answer answer" "score score" "fact fact" "preview preview" "share next" "footer footer";
  align-content: stretch;
}
#overlay.as-sheet.daily-sheet .result-cal.folded { overflow: visible; padding-bottom: 0; }
/* W8: on the Daily sheet the preview fills its row exactly: "No answer, no
   picture" sits on the title line, and a message taller than the row scrolls
   inside it, faded at the bottom — the buttons below are never covered.
   :where keeps the display rule weaker than .hidden and .fact-open. */
:where(#overlay.as-sheet.daily-sheet) .share-preview { display: flex; flex-direction: column; }
#overlay.as-sheet.daily-sheet .share-preview { align-self: stretch; }
#overlay.as-sheet.daily-sheet .sp-text { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; }
#overlay.as-sheet.daily-sheet .sp-text::-webkit-scrollbar { display: none; }
#overlay.as-sheet.daily-sheet .sp-note { position: absolute; top: 7px; right: 10px; margin: 0; }
#app.sheet-compact #overlay.as-sheet.daily-sheet .sp-note { top: 5px; right: 9px; }
#overlay.as-sheet.daily-sheet .share-preview.overflowing .sp-text {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 10px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 10px), transparent);
}
/* W7 (owner 2026-10-31): the session summary's best catch — the picture with
   its tiles as they stood at the solve — and the Daily it leads to. */
.summary-best, .summary-daily {
  display: flex; align-items: center; gap: 12px; margin: 10px 0 0; padding: 9px 12px;
  border-radius: 14px; background: var(--panel-2); text-align: left;
}
.summary-best.hidden, .summary-daily.hidden, .summary-menu.hidden, .sd-sub:empty { display: none; }
.sb-thumb { position: relative; flex: none; width: 60px; height: 60px; border-radius: 10px; overflow: hidden; }
.sb-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.sb-tiles { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(6, 1fr); grid-template-rows: repeat(6, 1fr); }
.sb-tiles i { background: var(--tile); box-shadow: inset 0 0 0 .5px var(--tile-edge); }
.sb-tiles i.off { opacity: 0; }
.sb-body, .sd-body { flex: 1 1 auto; min-width: 0; }
.sb-title, .sd-title { font-size: 13.5px; font-weight: 800; line-height: 1.3; }
.sb-sub, .sd-sub { font-size: 12px; line-height: 1.35; color: var(--muted); }
.sb-bar { display: block; height: 4px; margin: 6px 0 3px; border-radius: 2px; background: var(--border); overflow: hidden; }
.sb-bar b { display: block; height: 100%; background: var(--accent); transform-origin: 0 50%; }
.sb-level { font-size: 11.5px; line-height: 1.3; font-weight: 700; color: var(--muted); }
.sd-tiles { display: grid; flex: none; grid-template-columns: repeat(3, 12px); grid-auto-rows: 12px; gap: 2px; }
.sd-tiles i { background: var(--tile); border-radius: 3px; box-shadow: inset 0 0 0 1px var(--tile-edge); }
.sd-tiles i.peek { background: var(--accent); box-shadow: none; }
.summary-menu {
  width: 100%; height: 44px; border-radius: 14px; background: none; border: 1px solid var(--border);
  color: var(--text); font-size: 14.5px; font-weight: 700; cursor: pointer;
}
.summary-menu:active { transform: scale(.98); }
#overlay .card.summary-rich { padding-top: 20px; }
/* the solved count is already in the stats line under the score (mockup W7) */
#overlay .card.summary-rich .result-answer { display: none; }
#overlay .card.summary-rich .result-score { font-size: 44px; margin: 6px 0 2px; }
@media (max-height: 660px) {
  #overlay .card.summary-rich .result-session { display: none; }
}
#overlay .card.summary-rich .result-session { margin: 10px 0 0; }
/* The Daily is the main button; Share and "Back to menu" share the row under it. */
/* "Back to menu" takes what its label needs, Share the rest: both stay on one
   line in every locale down to a 360 px wide phone. */
#overlay .card.summary-invite { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 8px; }
#overlay .card.summary-invite > * { grid-column: 1 / -1; }
#overlay .card.summary-invite .btn-next { order: 1; margin-top: 10px; }
#overlay .card.summary-invite .btn-share { order: 2; grid-column: 1; margin: 8px 0 0; padding: 0 4px; }
#overlay .card.summary-invite .summary-menu { order: 2; grid-column: 2; margin: 8px 0 0; padding: 0 10px; }
#overlay .card.summary-invite :is(.btn-share, .summary-menu) {
  font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#overlay.as-sheet.daily-sheet .result-foot { display: contents; }
#overlay.as-sheet.daily-sheet .report-link {
  grid-area: footer; max-width: 100%; justify-self: end;
  font-size: 12.5px; line-height: 16px; text-align: right; align-self: center;
}
#app.sheet-compact #overlay.as-sheet.daily-sheet .card { row-gap: 3px; }
#app.sheet-compact #overlay.as-sheet.daily-sheet .btn-share { height: 44px; font-size: 14px; }
#app.sheet-compact #overlay.as-sheet.daily-sheet .btn-next { font-size: 14px; }
