/* * Design tokens — pure CSS custom properties, no framework, no image/font/SVG * assets. Light is the default; dark is applied either by the OS * (prefers-color-scheme) or by an explicit [data-theme] set from Settings. A * Telegram Mini App can override these same variables at runtime from * WebApp.themeParams (see lib/theme — SDK wiring lands in the Telegram stage), so * the whole UI re-themes without touching components. */ :root { --bg: #f3f4f6; --bg-elev: #ffffff; --surface: #ffffff; --surface-2: #eef0f3; --ad-bg: #e3e7ee; /* announcement banner: a subtle accent, darker in light theme */ --text: #14181f; --text-muted: #6b7280; --border: #d8dce2; --accent: #2f6df6; --accent-text: #ffffff; --danger: #d6453d; --ok: #1f9d57; --warn: #c9881b; /* board + tiles (all drawn with CSS primitives) */ --board-bg: #cdd6cf; --cell-bg: #e7ece8; --cell-line: #7f8d83; --tile-bg: #f4e2b8; --tile-edge: #d8c190; --tile-text: #2a2113; --tile-pending: #f2cf73; /* Last-word highlight letter — a lighter burgundy than the dark theme on purpose: against the lighter tile the perceived contrast needs it, so the two are tuned per theme. */ --tile-recent: #9c5849; --prem-tw: #e06a5b; /* triple word */ --prem-dw: #efa6a0; /* double word + centre */ --prem-tl: #4f8fd6; /* triple letter */ --prem-dl: #a8cdec; /* double letter */ --prem-text: #2a2113; /* shape + type */ --radius: 10px; --radius-sm: 6px; --gap: 8px; --pad: 12px; /* Height Telegram's native nav overlays at the top in fullscreen; set from the SDK's content-safe-area inset, 0 elsewhere. */ --tg-content-top: 0px; /* Telegram device safe-area top (the notch); TG's own nav controls sit between it and --tg-content-top, so the in-app header aligns to that band, 0 elsewhere. */ --tg-safe-top: 0px; --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif; --shadow: 0 1px 2px rgba(0, 0, 0, 0.08), 0 6px 16px rgba(0, 0, 0, 0.06); } @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --bg: #0f1115; --bg-elev: #171a21; --surface: #171a21; --surface-2: #1f242d; --ad-bg: #272f3c; /* announcement banner: a subtle accent, lighter in dark theme */ --text: #e7eaf0; --text-muted: #9aa3b2; --border: #2a313c; --accent: #5b8cff; --accent-text: #0b0e13; --danger: #f0635a; --ok: #44c87f; --warn: #e0a93a; --board-bg: #2a3330; --cell-bg: #222a27; --cell-line: #56655c; --tile-bg: #d9c79a; --tile-edge: #b6a473; --tile-text: #20190d; --tile-pending: #d8b75e; --tile-recent: #8c4a3c; --prem-tw: #9c3f34; /* 3x word: a touch darker red */ --prem-dw: #a8636b; /* 2x word: softer, pinker */ --prem-tl: #2c527a; /* 3x letter: a touch darker blue */ --prem-dl: #4a779b; /* 2x letter: softer, sky blue */ --prem-text: #e7eaf0; } } /* Explicit dark chosen in Settings (overrides OS preference). */ :root[data-theme="dark"] { --bg: #0f1115; --bg-elev: #171a21; --surface: #171a21; --surface-2: #1f242d; --ad-bg: #272f3c; /* announcement banner: a subtle accent, lighter in dark theme */ --text: #e7eaf0; --text-muted: #9aa3b2; --border: #2a313c; --accent: #5b8cff; --accent-text: #0b0e13; --danger: #f0635a; --ok: #44c87f; --warn: #e0a93a; --board-bg: #2a3330; --cell-bg: #222a27; --cell-line: #38433d; --tile-bg: #d9c79a; --tile-edge: #b6a473; --tile-text: #20190d; --tile-pending: #f0d98f; /* Last-word highlight letter — a warm burgundy whose red hue stays distinct from both the near-black glyph and the warm tile. The light theme uses a lighter burgundy (tuned per theme; perceived contrast depends on the surrounding board). */ --tile-recent: #8c4a3c; --prem-tw: #9c3f34; /* 3x word: a touch darker red */ --prem-dw: #a8636b; /* 2x word: softer, pinker */ --prem-tl: #2c527a; /* 3x letter: a touch darker blue */ --prem-dl: #4a779b; /* 2x letter: softer, sky blue */ --prem-text: #e7eaf0; } * { box-sizing: border-box; } html, body { margin: 0; height: 100%; } body { background: var(--bg); color: var(--text); font-family: var(--font); font-size: 16px; line-height: 1.4; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; /* Stop iOS/Safari from auto-inflating text (e.g. the long marquee message). */ text-size-adjust: 100%; -webkit-text-size-adjust: 100%; /* never let the page scroll/zoom out from under the board */ overscroll-behavior: none; touch-action: manipulation; } /* The game SPA (main.ts adds .app-shell to ) pins the document so iOS/WKWebView — notably the Telegram Mini App — cannot rubber-band ("stretch") the whole page on a vertical drag; overscroll-behavior alone does not stop the root-document bounce there. Every screen fits the visual viewport (--vvh) and scrolls its own inner areas, so the document never needs to scroll. The standalone landing page (landing.ts) omits the class and scrolls normally. */ html.app-shell { overflow: hidden; } html.app-shell body { position: fixed; inset: 0; overflow: hidden; } #app { height: 100%; /* No text selection anywhere by default; inputs opt back in below. */ user-select: none; -webkit-user-select: none; } input, textarea { user-select: text; -webkit-user-select: text; } button { font: inherit; color: inherit; cursor: pointer; user-select: none; -webkit-user-select: none; } .reduce-motion * { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }