/* The lobby (/play): a slim bar with your streak; one live board; the call under it; the end screen; the
   leaderboard; and, on request, the chances chart and move review. White page, few borders: hairlines where
   something needs an edge, green for a right call and red for a wrong one. Motion is transform/opacity only;
   site.css stills it all under prefers-reduced-motion. */

/* ---------- the bar ---------- */
.lobby-bar {
  position: sticky; top: 0; z-index: 30; display: flex; align-items: center; gap: 10px; padding: 8px 12px;
  background: var(--bg); border-bottom: 1px solid var(--line);
}
.mark-link { display: grid; place-items: center; width: 44px; height: 44px; flex: none; border-radius: var(--r-2); }
.progress { flex: 1; min-width: 0; display: flex; align-items: center; justify-content: center; gap: 12px; }
.prog-streak { margin: 0; display: flex; align-items: baseline; gap: 6px; flex: none; }
.prog-streak b { font-family: var(--f-display); font-size: var(--fs-28); font-weight: 900; line-height: 1; font-variant-numeric: tabular-nums; }
.prog-streak small { font-size: var(--fs-12); color: var(--muted); }
.prog-streak.pop { animation: pop .14s var(--ease-out); }
@keyframes pop { 0% { transform: scale(.95); } 60% { transform: scale(1.04); } }
.icon-btn { display: grid; place-items: center; width: 44px; height: 44px; flex: none; border: 0; border-radius: var(--r-2); background: none; color: var(--muted); cursor: pointer; }
.icon-btn:hover { color: var(--text); background: var(--panel); }
.sound-btn .x { display: none; }
.sound-btn[data-level='off'] .w1, .sound-btn[data-level='off'] .w2 { display: none; }
.sound-btn[data-level='off'] .x { display: inline; }

/* the chain: a green ✓ per right call, a red ✗ for the miss, a dashed link for the call on the line */
.chain { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-height: 18px; }
.chain li { width: 18px; height: 18px; border-radius: var(--r-1); display: grid; place-items: center; font-size: var(--fs-12); line-height: 1; color: #fff; font-weight: 700; }
.chain .correct { background: var(--green); }
.chain .wrong { background: var(--red); }
.chain .open { border: 2px dashed var(--ink); }
.chain .more { width: auto; color: var(--muted); font-weight: 500; padding-right: 2px; }
.lobby-bar .chain { flex-wrap: nowrap; overflow: hidden; }
/* lives: hearts left alternate black and white like the pieces, striped ones lost. Every few seconds the hearts left
   bob in a little wave, like Minecraft's. A lost one jolts, the last one left beats, and after a run they fill
   back in one by one. */
.lives { display: flex; gap: 2px; flex: none; }
.lives svg { fill: var(--ink); transform-origin: 50% 60%; }
.lives svg.white { fill: #fff; stroke: var(--comic-ink); stroke-width: 1.3; stroke-linejoin: round; }
.lives svg:not(.lost) { animation: heart-wave 7s ease-in-out infinite; }
.lives svg:nth-child(2) { animation-delay: .12s; }
.lives svg:nth-child(3) { animation-delay: .24s; }
@keyframes heart-wave { 0%, 6%, 100% { transform: none; } 2% { transform: translateY(-3px); } 4% { transform: translateY(1px); } }
.lives svg.lost { fill: url(#heart-stripes); }
.lives svg.just-lost { animation: heart-jolt .45s; }
.lives svg.refill { animation: heart-refill .4s cubic-bezier(.2, 1.6, .4, 1) both; }
.lives.last svg:not(.lost) { animation: heart-beat 1.1s ease-in-out infinite; }
@keyframes heart-jolt { 20% { transform: translateX(-3px) rotate(-12deg); } 40% { transform: translateX(3px) rotate(10deg); } 60% { transform: translateX(-2px); } }
@keyframes heart-refill { from { transform: scale(0); } }
@keyframes heart-beat { 0%, 56%, 100% { transform: scale(1); } 14% { transform: scale(1.25); } 28% { transform: scale(1); } 42% { transform: scale(1.14); } }

/* losing a life: a big heart, the colour of the one lost, pops up in the middle of the screen, a blade slices it, and
   the halves fall off */
.heart-break { position: fixed; inset: 0; z-index: 60; display: grid; place-content: center; justify-items: center; gap: 14px; pointer-events: none; overflow: hidden; }
.heart-break[hidden] { display: none; }
.hb-heart { position: relative; width: min(42vw, 180px); aspect-ratio: 1; }
.hb-heart svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; fill: var(--comic-ink); stroke: var(--comic-ink); stroke-width: .7; stroke-linejoin: round; }
.hb-l { clip-path: polygon(-10% -10%, 62% -10%, 38% 110%, -10% 110%); }
.hb-r { clip-path: polygon(62% -10%, 110% -10%, 110% 110%, 38% 110%); }
.heart-break.white .hb-heart svg { fill: #fff; }
.hb-slash { position: absolute; left: 50%; top: -18%; width: 6px; height: 136%; margin-left: -3px; background: #fff; border-radius: 3px; box-shadow: 0 0 0 2px var(--comic-ink); transform: rotate(13.5deg) scaleY(0); }
.hb-text { font-family: var(--f-display); font-weight: 900; font-style: italic; font-size: clamp(32px, 7vw, 52px); line-height: 1; text-transform: uppercase; color: #fff; -webkit-text-stroke: 4px var(--comic-ink); paint-order: stroke fill; text-shadow: 4px 4px 0 var(--comic-ink); transform: skewX(-10deg); }
.heart-break.go .hb-heart { animation: hb-pop .3s cubic-bezier(.2, 1.6, .4, 1) both; }
.heart-break.go .hb-slash { animation: hb-slash .5s .32s ease-out both; }
.heart-break.go .hb-l { animation: hb-fall-l 1.1s .45s cubic-bezier(.4, 0, .9, .6) both; }
.heart-break.go .hb-r { animation: hb-fall-r 1.1s .45s cubic-bezier(.4, 0, .9, .6) both; }
.heart-break.go .hb-text { animation: hb-text 1.7s .2s ease-out both; }
@keyframes hb-pop { from { transform: scale(0); } }
@keyframes hb-slash { 0% { transform: rotate(13.5deg) scaleY(0); opacity: 1; } 30% { transform: rotate(13.5deg) scaleY(1); opacity: 1; } 100% { transform: rotate(13.5deg) scaleY(1); opacity: 0; } }
@keyframes hb-fall-l { 0% { transform: none; } 20% { transform: translate(-14px, -4px) rotate(-8deg); } 100% { transform: translate(-80px, 75vh) rotate(-75deg); } }
@keyframes hb-fall-r { 0% { transform: none; } 20% { transform: translate(14px, -10px) rotate(8deg); } 100% { transform: translate(90px, 75vh) rotate(80deg); } }
@keyframes hb-text { 0% { opacity: 0; transform: skewX(-10deg) translateY(10px); } 15% { opacity: 1; transform: skewX(-10deg); } 80% { opacity: 1; } 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .lives svg { animation: none !important; } }

/* ---------- the stage: as wide as the screen allows while the call still fits under the board ---------- */
.lobby { flex: 1; width: 100%; max-width: 680px; margin: 0 auto; padding: 16px 16px 8px; overflow-x: clip; } /* a move badge on the edge file never widens the page */
.stage { width: 100%; max-width: max(320px, min(600px, calc(100svh - 400px))); margin: 0 auto; }
.stage[hidden] { display: none; }
.stage-title { margin: 0 0 2px; padding-left: 22px; font: 600 var(--fs-16)/1.3 var(--f-text); letter-spacing: normal; }
.stage-title small { color: var(--muted); font-weight: 500; font-size: var(--fs-14); margin-left: 4px; }

.board-wrap { display: flex; gap: 10px; padding: 4px 0; }
.board-box { position: relative; flex: 1; min-width: 0; border-radius: 2px; overflow: visible; }
#board { aspect-ratio: 1 / 1; }
.cg-wrap { border-radius: 2px; overflow: hidden; }
/* the board in Lichess's light browns: reads on white without a frame */
.cg-wrap cg-board { background-color: #f0d9b5; background-image: repeating-conic-gradient(#b58863 0 25%, #f0d9b5 0 50%); background-size: 25% 25%; }
.cg-wrap cg-board square.last-move { background-color: rgba(26, 95, 180, .28); }
.cg-wrap coords coord { color: #4d3a26 !important; font-weight: 600; opacity: .85; }
.evalbar { width: 12px; flex: none; position: relative; background: var(--ebony); border-radius: 2px; overflow: hidden; box-shadow: inset 0 0 0 1px var(--ui-line); }
.evalbar-white, .evalbar-draw { position: absolute; inset: 0; transform-origin: bottom; transform: scaleY(.5); transition: transform .4s var(--ease-out); }
.evalbar-white { background: #fff; }
.evalbar-draw { background: var(--slate); }
.eval-text { position: absolute; left: -2px; right: -2px; text-align: center; font-size: 8px; font-weight: 800; bottom: 4px; color: var(--ebony); }
.eval-text.top { bottom: auto; top: 4px; color: #fff; }

.player { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 4px 0 4px 22px; min-height: 44px; }
.player .name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.player .title { color: var(--text); margin-right: 4px; font-weight: 800; }
.player .rating { color: var(--muted); font-weight: 500; margin-left: 6px; font-variant-numeric: tabular-nums; }
.clock { font-family: var(--f-mono); font-weight: 500; font-size: var(--fs-16); color: var(--muted); padding: 3px 10px; border-radius: var(--r-1); min-width: 72px; text-align: right; background: var(--panel); }
.clock.active { background: var(--ink); color: var(--on-ink); }
.clock.low { background: var(--red); color: #fff; }
.board-foot { display: flex; justify-content: space-between; align-items: center; padding: 2px 0 0 22px; font-size: var(--fs-14); }
.status { font-weight: 600; display: inline-flex; align-items: center; gap: 6px; min-width: 0; white-space: nowrap; }
.status.live { color: var(--text); }
.status.live::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--ink); animation: pulse 1.6s infinite; }
.status.closed { color: var(--muted); }
@keyframes pulse { 50% { opacity: .25; } }

/* ---------- the call: under the board; on phones it stays at the bottom of the screen ---------- */
.call { margin-top: 14px; }
.call-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 8px; }
.call-q { font-size: var(--fs-20); }
.chip { display: inline-block; font-size: var(--fs-12); font-weight: 600; line-height: 1.2; padding: 3px 9px; border-radius: 999px; background: var(--panel); color: var(--text); }
.meter-text { font-size: var(--fs-12); color: var(--muted); text-align: right; }
/* a tick per move of the call window: it closes on a move, not at a time */
.move-meter { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 3px; height: 4px; margin-bottom: 12px; }
.move-meter i { border-radius: 1px; background: var(--line); }
.move-meter i.done { background: var(--ink); }
.call-sides { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.side-btn {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; padding: 8px 2px; min-height: 64px; border-radius: var(--r-2); cursor: pointer;
  border: 1px solid var(--ui-line); color: var(--text); background: var(--bg); font-size: var(--fs-14); font-weight: 600;
  transition: background-color .12s, transform .09s var(--ease-out);
}
.side-btn b { font-family: var(--f-display); font-size: var(--fs-28); font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.side-btn:hover:not(:disabled, [aria-disabled='true']) { background: var(--panel); }
.side-btn:active:not(:disabled, [aria-disabled='true']) { transform: scale(.97); }
/* a mark of the piece colour across the top, so the three read apart before their labels do */
.side-btn[aria-pressed='true'] { background: var(--ink); border-color: var(--ink); color: var(--on-ink); }
.side-btn:disabled, .side-btn[aria-disabled='true'] { opacity: .5; cursor: progress; }
.call-confirm { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; margin-top: 10px; }
.call-confirm .btn-go { min-height: 52px; font-size: var(--fs-16); }
.call-confirm .btn-go span { font-variant-numeric: tabular-nums; }
/* your call's chance now: big, moving with every move */
.call-now { margin: 0; display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.call-now > span { font-size: var(--fs-16); font-weight: 600; }
.call-now > b { font-family: var(--f-display); font-size: var(--fs-40, 40px); font-weight: 900; line-height: 1; font-variant-numeric: tabular-nums; }
.call-now > small { font-size: var(--fs-14); color: var(--muted); }
.call-body > .btn { margin-top: 12px; }
/* your other calls waiting on their games */
.my-calls { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--line); }
.my-calls[hidden] { display: none; }
.my-calls h3 { margin: 0 0 6px; font-size: var(--fs-14); color: var(--muted); font-weight: 600; }
.my-calls ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.my-call { width: 100%; display: flex; align-items: baseline; gap: 8px; padding: 8px 10px; border: 1px solid var(--ui-line); border-radius: var(--r-2); background: var(--bg); color: var(--text); font: inherit; font-size: var(--fs-14); cursor: pointer; text-align: left; }
.my-call:hover { background: var(--panel); }
.my-call span { color: var(--muted); font-variant-numeric: tabular-nums; }
.my-call .my-call-now { margin-left: auto; color: var(--text); font-weight: 600; }
.call-line { margin: 4px 0 0; font-size: var(--fs-16); line-height: 1.45; }
.d-msg { margin: 10px 0 0; font-size: var(--fs-14); }
.d-msg:empty { display: none; }
.d-msg.ok { color: var(--green); }
.d-msg.error { color: var(--red); }
.t-note { margin: 10px 0 0; font-size: var(--fs-12); color: var(--muted); }
.t-note:empty { display: none; }

/* ---------- result stamp (inline, not a pop-up) ---------- */
.stamp { display: flex; align-items: center; gap: 12px; margin-top: 14px; padding: 8px 0; border-top: 1px solid var(--line); perspective: 600px; }
.stamp-mark { font-family: var(--f-display); font-weight: 900; font-size: var(--fs-28); line-height: 1; min-width: 44px; height: 44px; padding: 0 6px; display: grid; place-items: center; border-radius: var(--r-2); flex: none; color: #fff; }
.stamp.right .stamp-mark { background: var(--green); }
.stamp.wrong .stamp-mark { background: var(--red); }
.stamp.void .stamp-mark { background: var(--panel); color: var(--muted); }
.stamp-text { flex: 1; min-width: 0; }
.stamp-text b { display: block; font-size: var(--fs-16); }
.stamp-text small { display: block; color: var(--muted); font-size: var(--fs-14); }
.stamp-x { border: 0; background: none; color: var(--muted); cursor: pointer; width: 44px; height: 44px; display: grid; place-items: center; border-radius: 50%; flex: none; }
.stamp-x:hover { color: var(--text); background: var(--panel); }
.stamp.reveal { animation: flip-in .5s ease-in; }
.stamp.reveal.wrong .stamp-mark { animation: shake .4s .5s; }
@keyframes flip-in { 0% { transform: rotateX(0); } 50% { transform: rotateX(-90deg); } 100% { transform: rotateX(0); } }
@keyframes shake { 20%, 60% { transform: translateX(-4px); } 40%, 80% { transform: translateX(4px); } }

/* one-time asks under the call (notifications, sign-up, the iOS home-screen hint): quiet, easy to dismiss */
.ask { margin: 12px 0 0; padding: 12px 14px; border-radius: var(--r-2); background: var(--panel); display: flex; align-items: center; justify-content: space-between; gap: 10px 16px; flex-wrap: wrap; font-size: var(--fs-14); }
.ask[hidden] { display: none; }
.ask p { margin: 0; flex: 1 1 260px; }
.ask small { display: block; color: var(--muted); font-size: var(--fs-14); margin-top: 2px; }
.ask-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* ---------- the end of a streak, centred: a verdict, the chain, Share, then the numbers ---------- */
.over { max-width: 440px; margin: 32px auto 0; }
.over[hidden] { display: none; }
.over h2 { font-family: var(--f-display); font-size: var(--fs-40); font-weight: 900; line-height: 1; margin: 0 0 8px; }
.cs-rank { margin: 0 0 8px; font-size: var(--fs-20); font-weight: 700; color: var(--text); }
.cs-rank[hidden] { display: none; }
.cs-over-detail { margin: 0 0 12px; font-size: var(--fs-14); color: var(--muted); }
.over .chain { margin-top: 4px; }
.over .btn-block { min-height: 52px; margin-top: 20px; }
.ledger { display: grid; grid-template-columns: 1fr auto; gap: 8px 16px; margin: 20px 0 0; }
.ledger dt { font-size: var(--fs-14); color: var(--muted); }
.ledger dd { margin: 0; font-family: var(--f-mono); font-size: var(--fs-16); line-height: 1.3; text-align: right; font-variant-numeric: tabular-nums; }
.cs-best { margin: 14px 0 0; font-weight: 600; }
.cs-best[hidden] { display: none; }
.over-links { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px; margin: 20px 0 0; }
.over-links [hidden] { display: none; }

/* ---------- the move review, under the board on request ---------- */
.swatch { width: 12px; height: 12px; border-radius: var(--r-1); display: inline-block; flex: none; background: var(--line); }
.swatch.white { background: var(--ivory); box-shadow: inset 0 0 0 1px var(--ui-line); }
.swatch.draw { background: var(--slate); }
.swatch.black { background: var(--ebony); }

.up { color: var(--green); } .down { color: var(--red); } .flat { color: var(--muted); }
.tick-up { animation: tick-up .6s ease-out; }
.tick-down { animation: tick-down .6s ease-out; }
@keyframes tick-up { from { background: rgba(30, 122, 60, .18); } }
@keyframes tick-down { from { background: rgba(198, 40, 40, .15); } }

/* each verdict keeps its colour in the board badge, and nowhere else;
   the mark is near-black on every fill (5.07:1 on blunder up to 15.7:1 on best) */
.move-badge {
  --c: var(--slate);
  display: inline-grid; place-items: center; flex: none; border-radius: 50%; background: var(--c); color: var(--comic-ink);
  font-family: var(--f-text); font-weight: 800; line-height: 1; letter-spacing: -.06em;
  box-shadow: inset 0 0 0 1px rgba(7, 13, 10, .35); /* a hairline so pale fills hold their edge on white and light squares */
}
.move-badge svg { width: 68%; height: 68%; display: block; }
.move-badge { position: absolute; z-index: 3; width: 30px; height: 30px; margin: -15px 0 0 -17px; pointer-events: none; font-size: 14px; box-shadow: inset 0 0 0 1px rgba(7, 13, 10, .35), 0 2px 5px rgba(0, 0, 0, .3); }
.move-badge[hidden] { display: none; }

/* callouts: the big moments over the board, anime / Ace Attorney style. A band streaks across the board (red for
   BLUNDER!, light blue for BRILLIANT!) with tiny black speed lines racing through it, the piece that moved rides in
   as a silhouette, and the word slams on. About two seconds, then the band shoots off. A blunder also shakes the board. */
.callout { position: absolute; inset: 0; z-index: 4; pointer-events: none; overflow: hidden; border-radius: 2px; }
.callout[hidden] { display: none; }
.callout.blunder { --cc: #e02424; background: rgba(110, 0, 0, .3); }
.callout.brilliant { --cc: #8fd3fb; background: rgba(20, 80, 130, .26); }
/* the end of the game, like a comic's title: the reason in a yellow narration box, a ribbon with who won (ivory with
   black letters when White wins, ebony when Black does, slate for a draw) and your call. About three seconds. */
.ending { position: absolute; inset: 0; z-index: 5; pointer-events: none; overflow: hidden; --rib: #26292c; --rib-text: #fff; }
.ending[hidden] { display: none; }
.ending.win-white { --rib: #f4efe2; --rib-text: #121212; }
.ending.draw { --rib: #6c7a89; }
.ending-shade { position: absolute; inset: 0; background: rgba(0, 0, 0, .3); }
/* the ribbon: a long banner that waves like cloth, the words riding the wave (drawn by ribbon.js) */
.ending-ribbon { position: absolute; left: 1%; right: 1%; top: 28%; }
.ending-ribbon svg { display: block; width: 100%; height: auto; overflow: visible; filter: drop-shadow(0 5px 0 rgba(7, 13, 10, .9)); }
.ending-ribbon path { stroke: var(--comic-ink); stroke-width: 4; stroke-linejoin: round; }
.ending-ribbon .r-body { fill: var(--rib); stroke: none; }
.ending-ribbon .r-shade { stroke: none; }
.ending-ribbon .r-edge { fill: none; }
.ending-ribbon .r-shine { fill: none; stroke: rgba(255, 255, 255, .35); stroke-width: 5; stroke-linecap: round; }
.ending.win-white .ending-ribbon .r-shine { stroke: rgba(255, 255, 255, .9); }
.ending-ribbon #ending-arc { stroke: none; }
.ending-ribbon .r-word { font-family: var(--f-comic); font-size: 46px; letter-spacing: 2px; fill: var(--rib-text); stroke: var(--comic-ink); stroke-width: 6px; paint-order: stroke fill; stroke-linejoin: round; }
.ending.win-white .ending-ribbon .r-word { stroke: none; }
.ending-why { position: absolute; left: 8%; top: 13%; max-width: 76%; font-family: var(--f-comic); font-size: clamp(18px, 6.4vw, 30px); letter-spacing: .05em; line-height: 1.1; color: #121212; background: var(--comic-yellow); border: 3px solid var(--comic-ink); box-shadow: 4px 4px 0 var(--comic-ink); padding: 4px 12px 2px; rotate: -2deg; }
.ending-call { position: absolute; right: 8%; bottom: 15%; font-weight: 800; font-size: clamp(12px, 3.4vw, 15px); color: #fff; padding: 6px 12px; border: 3px solid var(--comic-ink); border-radius: 6px; box-shadow: 4px 4px 0 var(--comic-ink); rotate: 2deg; }
.ending-call[hidden] { display: none; }
.ending-call.v-right { background: var(--green); }
.ending-call.v-wrong { background: var(--red); }
.ending.go { animation: ending-life 3.2s both; }
.ending.go .ending-shade { animation: ending-fade .25s both; }
.ending.go .ending-why { animation: ending-pop .4s .35s cubic-bezier(.2, 1.6, .4, 1) both; }
.ending.go .ending-call { animation: ending-in-right .3s .5s cubic-bezier(.2, 1.3, .4, 1) both; }
@keyframes ending-life { 0%, 90% { opacity: 1; } 100% { opacity: 0; } }
@keyframes ending-fade { from { opacity: 0; } }
@keyframes ending-pop { 0% { scale: 0; rotate: -14deg; } 70% { scale: 1.1; rotate: 1deg; } 100% { scale: 1; rotate: -2deg; } }
@keyframes ending-in-right { from { translate: 150% 0; } }
@media (prefers-reduced-motion: reduce) { .ending.go, .ending.go * { animation-duration: 1ms !important; animation-delay: 0s !important; } }
.callout-band {
  position: absolute; left: -8%; right: -8%; top: 30%; height: 40%; background: var(--cc); overflow: hidden;
  border-block: 5px solid var(--comic-ink); box-shadow: 0 12px 0 rgba(7, 13, 10, .35); transform: rotate(-6deg);
}
/* the speed lines: two layers of short black dashes running right to left at different speeds */
.callout-band::before, .callout-band::after { content: ''; position: absolute; inset: 0; background-repeat: repeat; }
.callout-band::before { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='84'%3E%3Cg stroke='%23070d0a' stroke-width='2.4' stroke-linecap='round'%3E%3Cline x1=%2210%22 y1=%228%22 x2=%2256%22 y2=%228%22 stroke-opacity=%221%22/%3E%3Cline x1=%22120%22 y1=%2221%22 x2=%22144%22 y2=%2221%22 stroke-opacity=%221%22/%3E%3Cline x1=%22205%22 y1=%2212%22 x2=%22269%22 y2=%2212%22 stroke-opacity=%220.9%22/%3E%3Cline x1=%2240%22 y1=%2235%22 x2=%2260%22 y2=%2235%22 stroke-opacity=%221%22/%3E%3Cline x1=%22160%22 y1=%2245%22 x2=%22198%22 y2=%2245%22 stroke-opacity=%220.85%22/%3E%3Cline x1=%22250%22 y1=%2231%22 x2=%22280%22 y2=%2231%22 stroke-opacity=%221%22/%3E%3Cline x1=%2280%22 y1=%2257%22 x2=%22134%22 y2=%2257%22 stroke-opacity=%220.9%22/%3E%3Cline x1=%22222%22 y1=%2267%22 x2=%22248%22 y2=%2267%22 stroke-opacity=%221%22/%3E%3Cline x1=%2215%22 y1=%2273%22 x2=%2247%22 y2=%2273%22 stroke-opacity=%220.8%22/%3E%3Cline x1=%22132%22 y1=%2276%22 x2=%22150%22 y2=%2276%22 stroke-opacity=%221%22/%3E%3C/g%3E%3C/svg%3E"); background-size: 300px 84px; }
.callout-band::after { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='76'%3E%3Cg stroke='%23070d0a' stroke-width='2.4' stroke-linecap='round'%3E%3Cline x1=%2230%22 y1=%2215%22 x2=%2248%22 y2=%2215%22 stroke-opacity=%220.55%22/%3E%3Cline x1=%22150%22 y1=%226%22 x2=%22180%22 y2=%226%22 stroke-opacity=%220.5%22/%3E%3Cline x1=%2295%22 y1=%2240%22 x2=%22109%22 y2=%2240%22 stroke-opacity=%220.6%22/%3E%3Cline x1=%22230%22 y1=%2250%22 x2=%22252%22 y2=%2250%22 stroke-opacity=%220.5%22/%3E%3Cline x1=%2260%22 y1=%2266%22 x2=%2286%22 y2=%2266%22 stroke-opacity=%220.55%22/%3E%3Cline x1=%22185%22 y1=%2228%22 x2=%22197%22 y2=%2228%22 stroke-opacity=%220.6%22/%3E%3C/g%3E%3C/svg%3E"); background-size: 260px 76px; background-position: 40px 30px; }
.callout-piece { position: absolute; left: 0; top: 22%; width: 48%; aspect-ratio: 1; border-radius: 0; overflow: visible; z-index: 1; }
.callout-piece piece { position: absolute; inset: 0; width: 100%; height: 100%; transform: none; filter: brightness(0) drop-shadow(6px 6px 0 rgba(255, 255, 255, .35)); }
.callout-text { position: absolute; left: 30%; right: 3%; top: 30%; height: 40%; display: grid; place-content: center; justify-items: center; gap: 8px; z-index: 2; transform: rotate(-6deg); }
.callout-word {
  font-family: var(--f-display); font-weight: 900; font-style: italic; text-transform: uppercase;
  font-size: clamp(40px, 9vw, 84px); line-height: .9; letter-spacing: .01em; color: #fff;
  -webkit-text-stroke: 4px var(--comic-ink); paint-order: stroke fill; text-shadow: 5px 5px 0 var(--comic-ink);
  transform: skewX(-10deg);
}
.callout-sub { max-width: 100%; font-family: var(--f-mono); font-weight: 600; font-size: clamp(11px, 2.4vw, 14px); line-height: 1.3; text-align: center; background: var(--comic-ink); color: #fff; padding: 5px 12px; border-radius: 14px; }
.callout.go { animation: callout-life 2s ease-out both; }
.callout.go .callout-band { animation: callout-band-in .26s cubic-bezier(.2, .9, .3, 1) both, callout-band-out .28s 1.62s cubic-bezier(.6, 0, .9, .4) forwards; }
.callout.go .callout-band::before { animation: callout-lines-near .28s linear infinite; }
.callout.go .callout-band::after { animation: callout-lines-far .5s linear infinite; }
.callout.go .callout-piece { animation: callout-piece-in .34s .06s cubic-bezier(.2, .9, .3, 1) both, callout-piece-out .28s 1.6s cubic-bezier(.6, 0, .9, .4) forwards; }
.callout.go .callout-word { animation: callout-slam .36s .14s cubic-bezier(.2, 1.6, .4, 1) both; }
.callout.go .callout-sub { animation: callout-sub .28s .3s ease-out both; }
.callout.go .callout-text { animation: callout-piece-out .28s 1.6s cubic-bezier(.6, 0, .9, .4) forwards; }
@keyframes callout-life { 0% { opacity: 0; } 4% { opacity: 1; } 90% { opacity: 1; } 100% { opacity: 0; } }
@keyframes callout-band-in { from { transform: rotate(-6deg) translateX(-115%); } to { transform: rotate(-6deg) translateX(0); } }
@keyframes callout-band-out { to { transform: rotate(-6deg) translateX(115%); } }
@keyframes callout-lines-near { to { background-position: -300px 0; } }
@keyframes callout-lines-far { from { background-position: 40px 30px; } to { background-position: -220px 30px; } }
@keyframes callout-piece-in { from { transform: translateX(-120%); } to { transform: none; } }
@keyframes callout-piece-out { to { transform: translateX(160%); opacity: 0; } }
@keyframes callout-slam { 0% { transform: skewX(-10deg) scale(2.6); opacity: 0; } 60% { transform: skewX(-10deg) scale(.92); opacity: 1; } 100% { transform: skewX(-10deg) scale(1); } }
@keyframes callout-sub { from { opacity: 0; transform: translateY(12px); } }
.board-card.shake { animation: board-shake .42s cubic-bezier(.36, .07, .19, .97); }
/* a brilliant move: the board punches toward you with a white flash, a glint sweeps across it, and stars burst out */
.board-card.punch { animation: board-punch .5s cubic-bezier(.2, 1.5, .4, 1); }
@keyframes board-punch { 0% { transform: scale(1); } 22% { transform: scale(1.06); } 100% { transform: scale(1); } }
.fx-layer { position: absolute; inset: 0; z-index: 5; pointer-events: none; overflow: hidden; border-radius: 2px; }
.fx-flash { background: #fff; animation: fx-flash .45s ease-out both; }
@keyframes fx-flash { 0% { opacity: .95; } 100% { opacity: 0; } }
.fx-shine::before {
  content: ''; position: absolute; top: -20%; bottom: -20%; left: -60%; width: 45%;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, .85) 45%, #fff 50%, rgba(255, 255, 255, .85) 55%, rgba(255, 255, 255, 0));
  transform: skewX(-20deg); animation: fx-shine .75s .05s cubic-bezier(.5, 0, .3, 1) both;
}
.fx-shine::after { content: ''; position: absolute; inset: 0; box-shadow: inset 0 0 0 6px #8fd3fb, inset 0 0 40px rgba(143, 211, 251, .9); animation: fx-glow 1.4s ease-out both; }
@keyframes fx-shine { to { left: 120%; } }
@keyframes fx-glow { 0% { opacity: 0; } 20% { opacity: 1; } 100% { opacity: 0; } }
.fx-spark {
  position: absolute; left: 50%; top: 50%; width: var(--s); height: var(--s); margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2);
  background: var(--c); clip-path: polygon(50% 0, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0 50%, 39% 39%);
  filter: drop-shadow(0 0 6px #56b4e9) drop-shadow(0 0 2px var(--comic-ink)); animation: fx-spark .9s var(--d) cubic-bezier(.15, .8, .3, 1) both;
}
@keyframes fx-spark { 0% { transform: translate(0, 0) scale(.2) rotate(0); opacity: 1; } 70% { opacity: 1; } 100% { transform: translate(var(--x), var(--y)) scale(1) rotate(160deg); opacity: 0; } }
@keyframes board-shake { 10%, 90% { transform: translateX(-2px); } 20%, 80% { transform: translateX(4px); } 30%, 50%, 70% { transform: translateX(-9px) rotate(-.4deg); } 40%, 60% { transform: translateX(9px) rotate(.4deg); } }
@media (prefers-reduced-motion: reduce) {
  .callout.go, .callout.go * { animation: none !important; }
}
.move-badge.pop-in { animation: badge-in .32s var(--ease-out-quint); }
@keyframes badge-in { from { opacity: 0; transform: scale(.3); } }

/* ---------- leaderboard: tabs, rows, your own row pinned ---------- */
.cs-board { max-width: 600px; margin: 40px auto 0; padding-top: 24px; border-top: 1px solid var(--line); scroll-margin-top: 72px; }
.cs-board[hidden] { display: none; }
.cs-board-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; }
.cs-board-head h2 { font-size: var(--fs-28); margin: 0; flex-basis: 100%; }
.tabs { display: flex; gap: 4px; overflow-x: auto; scrollbar-width: none; }
.tabs button { border: 0; background: none; color: var(--muted); font-weight: 600; font-size: var(--fs-14); padding: 8px 12px; min-height: 44px; border-radius: 999px; cursor: pointer; white-space: nowrap; }
.tabs button:hover { color: var(--text); }
.tabs button[aria-selected='true'] { background: var(--ink); color: var(--on-ink); }
.board { list-style: none; margin: 10px 0 0; padding: 0; }
.board li { display: grid; grid-template-columns: 2.5em minmax(0, 1fr) auto; align-items: center; gap: 4px 12px; padding: 10px 4px; border-bottom: 1px solid var(--line); font-size: var(--fs-14); }
.board .rank { font-family: var(--f-mono); color: var(--muted); }
.board .n { font-family: var(--f-display); font-size: var(--fs-28); font-weight: 900; line-height: 1; font-variant-numeric: tabular-nums; text-align: right; }
.board .who { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board .sub { grid-column: 2 / 4; color: var(--muted); font-size: var(--fs-12); display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.board .swatch { display: inline-block; width: 10px; height: 10px; vertical-align: -1px; }
.board .slot-link { border: 0; background: none; color: var(--text); font-weight: 600; font-size: var(--fs-12); cursor: pointer; padding: 0 6px; text-decoration: underline; text-underline-offset: 2px; display: inline-flex; align-items: center; min-height: 44px; margin-block: -12px; }
.board .n.none { font-family: var(--f-text); font-size: var(--fs-16); font-weight: 500; color: var(--muted); }
.board .empty-row { display: block; color: var(--muted); padding: 14px 4px; border: 0; }
.board-you { margin: 0; padding: 10px 12px; font-size: var(--fs-14); font-weight: 600; background: var(--panel); border-radius: var(--r-2); }
.board-you[hidden] { display: none; }

/* the first-visit explainer: a dialog on desktop, a bottom sheet on phones */
dialog.intro { width: min(420px, calc(100vw - 32px)); padding: 24px; border-radius: var(--r-3); }
dialog.intro h2 { font-size: var(--fs-28); margin: 0 0 14px; }
.intro-rows { list-style: none; margin: 0 0 18px; padding: 0; display: grid; gap: 14px; }
.intro-rows li { display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 14px; align-items: center; }
.intro-rows p { margin: 0; font-size: var(--fs-16); line-height: 1.4; }
.mini-box { width: 56px; height: 56px; border-radius: var(--r-2); display: grid; place-items: center; font-family: var(--f-display); font-weight: 900; font-size: var(--fs-28); color: #fff; }
.mini-box.open { background: var(--bg); box-shadow: inset 0 0 0 1px var(--ui-line); grid-template-columns: repeat(3, 12px); gap: 3px; place-content: center; }
.mini-box.open i { width: 12px; height: 22px; border-radius: 2px; background: var(--ivory); box-shadow: inset 0 0 0 1px var(--ui-line); }
.mini-box.open i:nth-child(2) { background: var(--slate); box-shadow: none; }
.mini-box.open i:nth-child(3) { background: var(--ebony); box-shadow: none; }
.mini-box.wrong { background: var(--red); }
.mini-box.right { background: var(--green); }
dialog.intro .btn-block { min-height: 48px; }
dialog.intro .btn:focus:not(:focus-visible) { outline: 0; }

.call-crowd { margin: 2px 0 0; font-size: var(--fs-14); color: var(--muted); }
.confetti { position: fixed; inset: 0; width: 100vw; height: 100vh; pointer-events: none; z-index: 100; }
.correct { color: var(--green); font-weight: 700; } .wrong { color: var(--red); font-weight: 600; } .void { color: var(--muted); }
.chain .correct, .chain .wrong { color: #fff; }

/* ---------- the arena: one column (in reading order) until the screen is wide, then the board on the left and
   the call and leaderboard beside it ---------- */
.arena, .arena-main, .arena-side, .call-area { display: contents; }
.call-area[hidden] { display: none; }
@media (min-width: 1000px) {
  .lobby { max-width: 1200px; padding-top: 24px; }
  .arena { display: grid; grid-template-columns: auto minmax(320px, 400px); justify-content: center; align-items: start; column-gap: 56px; }
  .arena-main, .arena-side, .call-area { display: block; }
  .call-area[hidden] { display: none; }
  /* the call is beside the board now, so the board can take nearly the full height */
  .stage { width: max(380px, min(720px, calc(100svh - 230px))); max-width: none; }
  .arena-side { padding-top: 26px; } /* line the call up with the top of the board */
  .call { margin-top: 0; }
  .over { width: min(520px, 100%); margin-top: 0; }
  .cs-board { max-width: none; margin-top: 32px; }
}

/* ---------- phones: the board fills the width, the call sits at the bottom of the screen ---------- */
@media (max-width: 600px) {
  .lobby-bar { gap: 6px; padding: 6px 8px; }
  .mark-link { width: 36px; }
  .lobby { padding: 10px 8px 8px; }
  .stage { max-width: none; }
  .call { position: sticky; bottom: 0; z-index: 5; margin: 10px -8px 0; padding: 12px 12px calc(12px + env(safe-area-inset-bottom)); background: var(--bg); border-top: 1px solid var(--line); }
  .move-badge { width: 24px; height: 24px; margin: -12px 0 0 -14px; font-size: var(--fs-12); }
  dialog.intro[open] { margin: auto 0 0; width: 100%; max-width: none; border-radius: var(--r-3) var(--r-3) 0 0; padding-bottom: calc(24px + env(safe-area-inset-bottom)); }
  .over { margin-top: 20px; }
}

/* Ranked or practice: the run on the go (or the next one a call would start) */
.run-kind { flex: none; font-size: var(--fs-12); font-weight: 600; line-height: 1.2; padding: 4px 10px; border-radius: 999px; background: var(--ink); color: var(--on-ink); }
.run-kind.practice { background: var(--panel); color: var(--muted); }
.finding { display: grid; justify-items: center; align-content: center; gap: 16px; min-height: min(480px, 70vw); text-align: center; }
.finding[hidden] { display: none; }
.finding p { margin: 0; }
.finding b { display: block; font-size: var(--fs-20); }
.finding small { display: block; color: var(--muted); font-size: var(--fs-14); margin-top: 4px; }
.finding-dots { display: flex; gap: 8px; }
.finding-dots i { width: 14px; height: 14px; border-radius: 3px; background: var(--green); animation: pulse 1.2s infinite; }
.finding-dots i:nth-child(2) { animation-delay: .2s; }
.finding-dots i:nth-child(3) { animation-delay: .4s; }
@media (prefers-reduced-motion: reduce) { .finding-dots i { animation: none; } }
.over .fine { margin-top: 16px; }

/* duels: who's playing, the link to send, the outcome */
.duel-h { margin: 0 0 6px; font-family: var(--f-display); font-weight: 800; font-size: var(--fs-28); line-height: 1.05; }
.duel-vs { margin: 0 0 8px; font-size: var(--fs-16); }
.duel-btns { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.duel-btns .btn { min-height: 48px; }
.duel-link { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; margin-top: 10px; }
.duel-link .input { min-width: 0; font-size: var(--fs-14); }
.duel-them { color: var(--muted); }
.duel-outcome { margin: 6px 0 10px; font-family: var(--f-comic); font-size: var(--fs-40); line-height: 1; letter-spacing: .03em; }
.duel-outcome.win { color: var(--green); }
.duel-outcome.loss { color: var(--red); }
.duel-outcome.tie, .duel-outcome.void { color: var(--text); }

/* guess the move: the line under the board, and today's right guesses under the hearts */
.lives-col { display: flex; flex-direction: column; align-items: center; gap: 2px; flex: none; }
.guess-line.pop { animation: pop .3s var(--ease-out); }
.guess-line { margin: 8px 0 0; padding: 8px 12px; border-radius: var(--r-2); background: var(--panel); font-size: var(--fs-14); font-weight: 600; }
.guess-line[hidden] { display: none; }
.guess-line.right { background: var(--green); color: #fff; }
.guess-line.wrong { color: var(--muted); }
.duel-score { margin: 8px 0 0; font-size: var(--fs-14); }
.duel-table { margin-top: 10px; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.duel-table th, .duel-table td { padding: 4px 14px 4px 0; text-align: left; }
.duel-table th { font-size: var(--fs-12); color: var(--muted); font-weight: 600; }

/* the day streak: days in a row with a run (hollow while today's run is still to play) */
.day-streak { flex: none; display: inline-flex; align-items: center; gap: 2px; font-family: var(--f-display); font-weight: 900; font-size: var(--fs-20); line-height: 1; font-variant-numeric: tabular-nums; }
.day-streak[hidden] { display: none; }
.day-streak svg { fill: var(--ink); }
.day-streak.pending { color: var(--muted); }
.day-streak.pending svg { fill: none; stroke: var(--muted); stroke-width: 1.4; }
.cs-days { display: flex; align-items: center; gap: 6px; margin: 14px 0 0; font-weight: 700; }
.cs-days[hidden] { display: none; }
.cs-days svg { fill: var(--ink); }
.mini-box.days { background: var(--ink); }
.mini-box.days svg { fill: var(--on-ink); }
/* a duel has no run: no count, lives or chain in the bar */
.duel-mode .prog-streak, .duel-mode .lives-col, .duel-mode .lobby-bar .chain { display: none; }

/* friends */
.board .row-days { display: inline-flex; align-items: center; gap: 2px; color: var(--text); font-weight: 600; }
.board .row-days svg { fill: var(--ink); }
.board li.you { background: var(--panel); }
.board li.fr-ask { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px 12px; }
.board .slot-link.muted { color: var(--muted); font-weight: 500; }
#cs-pause[hidden], .friend-tools[hidden] { display: none; }
.friend-tools { margin-top: 12px; }
.duel-friends { list-style: none; margin: 14px 0 0; padding: 0; }
.duel-friends li { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 8px 0; border-top: 1px solid var(--line); font-weight: 600; }
.done-today .lives { display: none; }
.ask small:empty { display: none; }

/* a duel won: YOU WIN! in the ending's comic lettering on a yellow starburst with a black outline */
.duel-win { position: fixed; inset: 0; z-index: 70; display: grid; place-items: center; background: rgba(0, 0, 0, .35); overflow: hidden; cursor: pointer; }
.duel-win[hidden] { display: none; }
.duel-win > * { grid-area: 1 / 1; }
.dw-burst { width: min(96vw, 560px); aspect-ratio: 1; background: var(--comic-ink); --star: polygon(50.0% 0.0%, 58.0% 14.9%, 71.7% 5.0%, 72.4% 21.9%, 89.1% 18.8%, 82.4% 34.4%, 98.7% 38.9%, 86.0% 50.0%, 98.7% 61.1%, 82.4% 65.6%, 89.1% 81.2%, 72.4% 78.1%, 71.7% 95.0%, 58.0% 85.1%, 50.0% 100.0%, 42.0% 85.1%, 28.3% 95.0%, 27.6% 78.1%, 10.9% 81.2%, 17.6% 65.6%, 1.3% 61.1%, 14.0% 50.0%, 1.3% 38.9%, 17.6% 34.4%, 10.9% 18.8%, 27.6% 21.9%, 28.3% 5.0%, 42.0% 14.9%); clip-path: var(--star); position: relative; }
.dw-burst::after { content: ''; position: absolute; inset: 7px; clip-path: var(--star); background: repeating-conic-gradient(var(--comic-yellow) 0 7.5deg, var(--comic-yellow-2) 7.5deg 15deg); }
.dw-word { font-family: var(--f-comic); font-weight: 400; font-size: clamp(64px, 19vw, 132px); line-height: .9; letter-spacing: .03em; text-transform: uppercase; color: #fff; -webkit-text-stroke: 7px var(--comic-ink); paint-order: stroke fill; text-shadow: 6px 7px 0 var(--comic-ink); rotate: -6deg; white-space: nowrap; }
.dw-score { align-self: end; margin-bottom: 18vh; font-family: var(--f-comic); font-size: clamp(20px, 6vw, 30px); letter-spacing: .05em; color: #fff; background: var(--green); border: 3px solid var(--comic-ink); box-shadow: 4px 4px 0 var(--comic-ink); padding: 4px 14px 2px; rotate: 3deg; }
.duel-win.go { animation: dw-life 4.2s both; }
.duel-win.go .dw-burst { animation: dw-burst .5s cubic-bezier(.2, 1.5, .4, 1) both, dw-spin 14s linear infinite; }
.duel-win.go .dw-word { animation: dw-pop .45s .15s cubic-bezier(.2, 1.7, .4, 1) both; }
.duel-win.go .dw-score { animation: ending-in-right .35s .5s cubic-bezier(.2, 1.3, .4, 1) both; }
@keyframes dw-life { 0% { opacity: 0; } 6%, 90% { opacity: 1; } 100% { opacity: 0; } }
@keyframes dw-burst { from { scale: 0; } }
@keyframes dw-spin { to { rotate: 360deg; } }
@keyframes dw-pop { 0% { scale: 0; rotate: -30deg; } 70% { scale: 1.12; rotate: -3deg; } 100% { scale: 1; rotate: -6deg; } }
@media (prefers-reduced-motion: reduce) { .duel-win.go, .duel-win.go * { animation-duration: 1ms !important; animation-delay: 0s !important; animation-iteration-count: 1 !important; } }
/* the board from Black's side (a duel player guessing Black's moves): White's row on top, Black's below, the eval bar turned over */
.board-card.flipped { display: flex; flex-direction: column; }
.board-card.flipped #player-white { order: -2; }
.board-card.flipped .board-wrap { order: -1; }
.board-card.flipped .evalbar { rotate: 180deg; }
.board-card.flipped .eval-text { rotate: 180deg; }
/* the smallest phones: the board tabs wrap to a second line instead of hiding off the edge */
@media (max-width: 359px) { .tabs { flex-wrap: wrap; } }

/* ads (public/js/ads.js): a quiet "Advertisement" label over each space; rails only where they clear the game */
.ad-slot { margin: 16px 0 0; min-height: 100px; }
.ad-slot[hidden], .ad-rail[hidden] { display: none; }
.ad-slot::before, .ad-rail::before { content: 'Advertisement'; display: block; margin-bottom: 4px; font-size: var(--fs-12); color: var(--muted); }
.ad-rail { position: fixed; top: 84px; width: 160px; z-index: 1; }
.ad-rail-left { left: 16px; }
.ad-rail-right { right: 16px; }
@media (max-width: 1439px) { .ad-rail { display: none !important; } }
/* no ad to show (AdSense marks the unit unfilled): the space and its label go */
.ad-slot:has(ins[data-ad-status='unfilled']), .ad-rail:has(ins[data-ad-status='unfilled']) { display: none; }
