:root {
    --bg: #0e121c;
    --panel: #171d2c;
    --panel-2: #1f2739;
    --line: #2a3450;
    --text: #e9edf7;
    --muted: #8f9bb6;
    --accent: #ff5a4e;
    --accent-dk: #e04438;
    --correct: #3fa34d;
    --present: #c9a227;
    --absent: #3b4358;
}

html, body {
    background: var(--bg);
    color: var(--text);
    font-family: 'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;
    min-height: 100%;
}

body { display: flex; flex-direction: column; min-height: 100vh; }

h1, h2, h3, .brand, .code, .tile, .num {
    font-family: 'Oswald', 'Helvetica Neue', Helvetica, Arial, sans-serif;
    letter-spacing: 0.02em;
}

h1 { font-size: 2rem; font-weight: 700; text-transform: uppercase; }
h2 { font-size: 1.25rem; font-weight: 600; text-transform: uppercase; }
h1:focus { outline: none; }

a { color: #ff8a80; }
a:hover { color: #ffb0a8; }

.muted { color: var(--muted); }
.small { font-size: 0.85rem; }
.inline { display: inline; }

/* --- Top bar --- */

.topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 1.5rem;
    background: #0a0d15;
    border-bottom: 1px solid var(--line);
}

.brand {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    color: var(--text);
    text-decoration: none;
    font-size: 1.35rem;
    font-weight: 700;
    text-transform: uppercase;
}

.brand:hover { color: #fff; }
.brand-tiles { display: inline-flex; gap: 3px; }

.mini-tile {
    width: 24px; height: 24px;
    display: grid; place-items: center;
    border-radius: 4px;
    font-size: 0.85rem; color: #fff;
}

.topnav { display: flex; align-items: center; gap: 1.25rem; }
.topnav a { color: var(--muted); text-decoration: none; font-weight: 500; }
.topnav a:hover, .topnav a.active { color: var(--text); }
.topnav .btn { color: #fff; }
.who { color: var(--text); font-weight: 600; }

.linkish {
    background: none; border: 0; padding: 0;
    color: var(--muted); cursor: pointer; text-decoration: underline;
}
.linkish:hover { color: var(--text); }

.content { flex: 1; width: 100%; max-width: 1180px; margin: 0 auto; padding: 1.75rem 1.5rem 3rem; }

/* The bottom stripe stays on screen while the page scrolls, so Feedback and Privacy are always in reach. */
:root { --footer-h: 2.9rem; }

.site-footer {
    min-height: var(--footer-h);
    position: sticky; bottom: 0; z-index: 30;
    display: flex; justify-content: space-between; align-items: center;
    padding: 0.65rem 1.5rem; border-top: 1px solid var(--line);
    background: var(--bg);
    color: var(--text); font-size: 0.9rem;
    flex-wrap: wrap; gap: 0.25rem 1.5rem;
}
.site-footer a { color: var(--text); }

@media (max-width: 600px) {
    /* One fixed-height row, so the pinned guess box on the game screen can sit exactly above it. */
    :root { --footer-h: 2.5rem; }
    .site-footer { height: var(--footer-h); box-sizing: border-box; padding: 0 1rem; flex-wrap: nowrap; font-size: 0.8rem; }
    .site-footer .muted { display: none; }
}

.prose { max-width: 760px; margin: 0 auto; }
.prose h2 { font-size: 1.25rem; margin-top: 1.5rem; }
.prose li { margin-bottom: 0.4rem; }

/* --- Buttons & forms --- */

.btn { font-weight: 600; border-radius: 8px; }
.btn-accent { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-accent:hover, .btn-accent:focus { background: var(--accent-dk); border-color: var(--accent-dk); color: #fff; }
.btn-accent:disabled { background: #5a3a3a; border-color: #5a3a3a; color: #bbb; }
.btn-ghost { background: transparent; border: 1px solid var(--line); color: var(--text); }
.btn-ghost:hover { background: var(--panel-2); color: #fff; }
.btn-lg { padding: 0.7rem 1.6rem; font-size: 1.05rem; }

.form-control, .form-select {
    background: var(--panel-2);
    border: 1px solid var(--line);
    color: var(--text);
    border-radius: 8px;
}
.form-control:focus, .form-select:focus {
    background: var(--panel-2);
    color: var(--text);
    border-color: var(--accent);
    box-shadow: 0 0 0 0.15rem rgba(255, 90, 78, 0.25);
}
.form-control::placeholder { color: #66728e; }
.form-control:disabled { opacity: 0.55; }

.field { display: block; margin-bottom: 1rem; }
.field > span { display: block; font-size: 0.85rem; font-weight: 600; color: var(--muted); margin-bottom: 0.3rem; }
.form-ok { color: #8fd694; font-weight: 500; margin: 0.5rem 0; }
.form-error { color: #ff8a80; font-weight: 500; margin: 0.5rem 0; }

.page-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 0.75rem; }
.page-head h1 { margin: 0; }
.plan-chip { border: 1px solid var(--line); border-radius: 999px; padding: 0.2rem 0.8rem; font-size: 0.85rem; color: var(--muted); }
.plan-chip.plus { background: var(--present); border-color: var(--present); color: #1a1500; font-weight: 700; }
.queue-place { font-family: 'Oswald', sans-serif; font-size: 1.6rem; margin: 0.25rem 0; }
.queue-place strong { color: var(--accent); }

/* Lobby: game list, create form, invitations. */
.game-list { list-style: none; padding: 0; margin: 0.75rem 0 0; display: flex; flex-direction: column; gap: 0.5rem; }
.game-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; background: var(--panel-2); border: 1px solid var(--line); border-radius: 10px; padding: 0.7rem 1rem; }
.game-main { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.game-main small { font-size: 0.82rem; }
.game-time { color: var(--present); }
.game-actions { display: flex; gap: 0.5rem; }
.check { display: flex; align-items: flex-start; gap: 0.5rem; margin-bottom: 0.6rem; font-size: 0.95rem; cursor: pointer; }
.check input { margin-top: 0.25rem; accent-color: var(--accent); }
.mini-head { font-size: 1rem; margin: 1rem 0 0.5rem; }
.tag { display: inline-block; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; border: 1px solid var(--line); border-radius: 999px; padding: 0.1rem 0.6rem; margin-right: 0.35rem; color: var(--text); }
.saved-row, .save-row { display: flex; gap: 0.5rem; align-items: flex-end; margin-bottom: 0.75rem; }
.saved-row .field { flex: 1; margin-bottom: 0; }
.save-row { margin-top: 1rem; align-items: center; }
.lobby-actions { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-top: 1rem; }
/* In a staging area, Start / Cancel stay pinned just above the footer, so they're always within reach however far down the
   settings and invitation list you've scrolled (and right where you were tapping Create game). */
.stage > .lobby-actions {
    position: sticky; bottom: var(--footer-h); z-index: 6;
    margin-top: 0.5rem; padding: 0.7rem 0;
    background: var(--bg); border-top: 1px solid var(--line);
    box-shadow: 0 -8px 16px rgba(0, 0, 0, 0.3);
}

.chips { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.6rem; }
.chip-user { display: inline-flex; align-items: center; gap: 0.35rem; background: var(--panel-2); border: 1px solid var(--line); border-radius: 999px; padding: 0.15rem 0.35rem 0.15rem 0.8rem; font-size: 0.9rem; }
.chip-user small { color: var(--muted); }
.chip-user.joined { border-color: var(--correct); }
.chip-user button { background: none; border: 0; color: var(--muted); font-size: 1.1rem; line-height: 1; cursor: pointer; padding: 0 0.3rem; }
.chip-user button:hover { color: var(--accent); }

.picker-list { list-style: none; padding: 0; margin: 0.5rem 0 0; max-height: 15rem; overflow-y: auto; border: 1px solid var(--line); border-radius: 10px; }
.picker-list li { display: flex; align-items: center; gap: 0.6rem; padding: 0.4rem 0.75rem; border-bottom: 1px solid var(--line); }
.picker-list li:last-child { border-bottom: 0; }
.picker-name { flex: 1; font-weight: 500; }

/* Banner ad slot (free accounts only). Kept out of the way and clearly labelled. */
.ad-banner {
    position: relative;
    margin: 0 auto 1.25rem;
    max-width: 728px;
    min-height: 60px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 1.1rem 0.75rem 0.5rem;
    text-align: center;
    overflow: hidden;
}
.ad-label {
    position: absolute; top: 0.2rem; left: 0.6rem;
    font-size: 0.6rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted);
}
.ad-house { display: flex; align-items: center; justify-content: center; gap: 0.75rem; color: var(--text); text-decoration: none; font-weight: 500; }
.ad-house:hover { color: #fff; text-decoration: underline; }
.ad-house img { max-width: 100%; max-height: 90px; border-radius: 6px; }

.panel {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 14px;
    padding: 1.5rem;
    margin-bottom: 1.25rem;
}
.panel.narrow { max-width: 560px; margin-left: auto; margin-right: auto; }

/* --- Tiles --- */

.tile, .mini-tile {
    color: #fff;
    font-weight: 700;
    text-transform: uppercase;
}

.tile {
    display: inline-grid; place-items: center;
    width: 3.4rem; height: 3.4rem;
    border-radius: 8px;
    font-size: 1.8rem;
}
.tile.sm { width: 1.9rem; height: 1.9rem; font-size: 1.1rem; border-radius: 5px; }

.t-correct { background: var(--correct); }
.t-present { background: var(--present); }
.t-absent { background: var(--absent); }

/* --- Landing --- */

.hero { text-align: center; padding: 2.5rem 0 2rem; }
.hero-tiles { display: flex; justify-content: center; gap: 0.4rem; margin-bottom: 1.5rem; }
.hero h1 { font-size: 3.2rem; margin-bottom: 0.75rem; }
.lead { color: var(--muted); font-size: 1.15rem; max-width: 640px; margin: 0 auto 1.5rem; }
.hero-actions { display: flex; justify-content: center; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 1.5rem; }

.join-box { display: flex; justify-content: center; gap: 0.5rem; max-width: 380px; margin: 0 auto; }
.code-input { text-transform: uppercase; letter-spacing: 0.25em; text-align: center; font-family: 'Oswald', sans-serif; font-size: 1.1rem; }

.how { margin: 2rem 0; }
.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 1rem; margin-top: 1rem; }
.step { background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 1.25rem; }
.step h3 { font-size: 1.1rem; text-transform: uppercase; margin: 0.6rem 0 0.35rem; }
.step p { color: var(--muted); margin: 0; font-size: 0.95rem; }
.num { display: inline-grid; place-items: center; width: 2rem; height: 2rem; border-radius: 50%; background: var(--accent); color: #fff; font-weight: 700; }

.board-preview { margin: 2rem 0; }
.section-head { display: flex; justify-content: space-between; align-items: baseline; }

/* The top 3: a row, 1st in the middle and taller, like a real podium. A min-height (rather than just extra padding)
   keeps 1st reliably the tallest even when a longer name wraps the "sample" tag onto its own line in 2nd or 3rd. */
.podium { list-style: none; display: flex; align-items: flex-end; gap: 0.75rem; padding: 0; margin: 1rem 0 0; max-width: 520px; }
.podium-spot {
    flex: 1; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 0.2rem;
    background: var(--panel); border: 1px solid var(--line); border-radius: 12px 12px 0 0;
    padding: 1rem 0.5rem 0.85rem; min-height: 7rem; box-sizing: border-box;
}
.podium-spot .rank { font-size: 1.6rem; line-height: 1; }
.podium-spot .name { font-weight: 700; }
.podium-spot .stat { color: var(--muted); font-size: 0.85rem; }
.spot-1 { min-height: 8.75rem; border-color: var(--accent); order: 2; }
.spot-2 { order: 1; }
.spot-3 { order: 3; }

.top-list { list-style: none; padding: 0; margin: 0.75rem 0 0; max-width: 520px; }
.top-list li { display: flex; align-items: center; gap: 1rem; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 0.55rem 1rem; margin-bottom: 0.5rem; }
.top-list .rank { font-family: 'Oswald', sans-serif; font-weight: 700; color: var(--accent); width: 1.5rem; }
.top-list .name { flex: 1; font-weight: 600; }
.top-list .stat { color: var(--muted); }

/* --- Auth --- */

.auth-card { max-width: 420px; margin: 2rem auto; background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 2rem; }
.auth-card h1 { font-size: 1.6rem; margin-bottom: 1.25rem; }
.auth-alt { text-align: center; margin: 1rem 0 0; color: var(--muted); }

/* --- Play / staging --- */

.play-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.25rem; }
.resume { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.stat-row { display: flex; gap: 2rem; flex-wrap: wrap; }
.stat-row div { display: flex; flex-direction: column; }
.stat-row strong { font-family: 'Oswald', sans-serif; font-size: 1.8rem; }
.stat-row span { color: var(--muted); font-size: 0.85rem; }
.plus-note { margin: 1rem 0 0; font-size: 0.85rem; }

.stage-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem; }
.eyebrow { color: var(--accent); font-weight: 600; text-transform: uppercase; letter-spacing: 0.12em; font-size: 0.8rem; }
.codebox { text-align: center; background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 0.5rem 1.5rem; }
.code { font-size: 2.2rem; letter-spacing: 0.2em; display: block; }
.code.urgent { color: var(--accent); }
.share { margin-top: 0.4rem; max-width: 520px; }

.roster { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 0.6rem; margin: 1.25rem 0; }
.roster.compact { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.slot { display: flex; align-items: center; gap: 0.5rem; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 0.6rem 0.9rem; font-weight: 600; }
.slot.empty { border-style: dashed; background: transparent; }
.slot.ready { border-color: var(--correct); }
.slot .state { margin-left: auto; font-weight: 400; color: var(--muted); font-size: 0.85rem; }
.slot.ready .state { color: #7fd48b; }

.badge-host, .badge-you, .badge-cracked { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; border-radius: 999px; padding: 0.1rem 0.5rem; }
.badge-cpu { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; border-radius: 999px; padding: 0.1rem 0.5rem; background: #34405f; color: #c9d4f0; }
.remove-btn { margin-left: auto; background: none; border: 0; color: var(--muted); font-size: 1.3rem; line-height: 1; cursor: pointer; padding: 0 0.25rem; }
.remove-btn:hover { color: var(--accent); }
.bot-row { align-items: flex-end; margin-top: 0.5rem; }
.bot-row .add-bot { margin-bottom: 1rem; }
.badge-host { background: var(--present); color: #1a1500; }
.badge-you { background: var(--accent); color: #fff; }
.badge-cracked { background: var(--correct); color: #fff; }

.settings-row { display: flex; gap: 1rem; flex-wrap: wrap; }
.settings-row .field { min-width: 200px; }

.word-form { display: flex; gap: 0.6rem; max-width: 480px; }
.word-input { text-transform: uppercase; letter-spacing: 0.3em; font-family: 'Oswald', sans-serif; font-size: 1.4rem; text-align: center; }
.locked { color: #7fd48b; }

/* --- Playing --- */

.play-layout { display: grid; grid-template-columns: 1fr 260px; gap: 1.5rem; align-items: start; }
/* A grid item's min-width defaults to auto - the size its content needs - not the width of its own track. .boards
   inside here is a non-wrapping, horizontally-scrolling row that can be far wider than the screen (every opponent's
   card side by side, uncollapsed); without min-width:0 that full width becomes this column's own minimum, forcing
   the 1fr track - and the whole page - wider than the viewport instead of leaving the overflow to .boards' own
   scrollbar, where it belongs. */
.boards-col { min-width: 0; }
.guess-bar { position: sticky; top: 0; z-index: 5; background: var(--bg); padding: 0.25rem 0 0.9rem; }
/* The typed letters, the guess box and the counters share one column, so they line up whatever the window width. */
.guess-bar > * { max-width: 480px; }
/* The custom on-screen keyboard (touch devices only, replacing the real one - see the guess input's
   inputmode="none") stays hidden until the mobile rules below turn it on; a desktop or laptop types with its own
   physical keyboard. */
.type-kb { display: none; }
.guess-meta { display: flex; gap: 1.5rem; color: var(--muted); margin-top: 0.5rem; }
.guess-meta strong { color: var(--text); }

.board-dots { display: flex; gap: 0.5rem; justify-content: center; padding: 0.5rem 0 0.75rem; }
.board-dot { width: 10px; height: 10px; padding: 0; border: 0; border-radius: 50%; background: var(--line); cursor: pointer; }
.board-dot.current { background: var(--accent); transform: scale(1.4); }
.board-dot.cracked { background: var(--correct); }

/* One opponent fills the screen at a time, on any size screen - not just phones. Swipe, the dots, or the Left/Right
   arrow keys move between them, each move landing exactly on the next board via CSS scroll-snap ("screen flipping",
   not a free scroll) - see mobile.js, despite the name it now runs everywhere. */
.boards {
    display: flex; overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
    /* none, not contain: contain only stops an over-scroll from chaining to the page - it still lets this element
       rubber-band/bounce against its own edges, which only ever happens at the first or last card (nowhere else is
       there an edge to pull against). That bounce-and-settle animation is exactly what read as the first and last
       cards being slow or laggy to swipe away from - none removes the bounce outright, so there's nothing to wait
       out at either end. */
    scrollbar-width: none; touch-action: pan-x; overscroll-behavior: none;
    /* Capping the container itself to one card's width, instead of letting it fill the wider desktop column, is
       what actually keeps this to "one opponent at a time" on desktop - otherwise the container would show a
       sliver of the next board too, and a swipe/arrow-key step (mobile.js measures the board's own width) would
       leave that sliver behind instead of landing flush on the next card. */
    max-width: 560px; margin: 0 auto;
}
.boards::-webkit-scrollbar { display: none; }
/* While a game is being played the page uses the whole window instead of the usual centred column. */
.content:has(.play-layout) { max-width: none; }
.board {
    flex: 0 0 100%; scroll-snap-align: start; scroll-snap-stop: always;
    box-sizing: border-box; background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 0.9rem;
    display: flex; flex-direction: column;
}
.board:has(.badge-cracked) { border-color: var(--correct); background: #14251a; }
.board-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.6rem; flex: 0 0 auto; }
.board-summary { font-weight: 400; }
/* touch-action:pan-y - not the default "auto" - tells a touch device this element only ever wants to claim a
   vertical drag for itself, so a horizontal one passes through to .boards' own pan-x swipe instead of being eaten
   here. Without it, once a board is cracked (its keyboard below disappears, so this area expands to fill most of
   the card) almost every touch starts inside a scrollable element with unclaimed direction, and the swipe stops
   registering outside a sliver of the card that isn't .board-guesses. */
.board-guesses { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; }
.tile-row { display: flex; gap: 4px; margin-bottom: 4px; }

/* Per-opponent keyboard showing which letters have been tried. Every key is a tenth of its card, and the cards grow
   with the window, so on a big screen the keyboard is big too. Shorter rows sit centred, like a real keyboard. */
.kb { margin-top: 0.7rem; padding-top: 0.6rem; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: clamp(3px, 0.4vw, 6px); }
.kb-row { display: flex; justify-content: center; gap: clamp(3px, 0.4vw, 6px); }
.key {
    flex: 0 1 9.4%; min-width: 0; height: clamp(1.7rem, 3.4vw, 3rem);
    display: grid; place-items: center;
    background: var(--panel-2); border-radius: 4px;
    font-size: clamp(0.72rem, 1.5vw, 1.15rem); font-weight: 600; text-transform: uppercase; color: var(--text);
}
.key.k-correct { background: var(--correct); color: #fff; }
.key.k-present { background: var(--present); color: #1a1500; }
.key.k-absent { background: #10141f; color: #4b566f; }

.scoreboard { background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 1rem; position: sticky; top: 1rem; }
.score-row { margin-bottom: 0.9rem; }
.score-row.you .score-top { color: #ffb0a8; }
.score-row.dropped { opacity: 0.45; }
.score-top { display: flex; justify-content: space-between; font-weight: 600; }
.meter { height: 6px; background: var(--absent); border-radius: 3px; margin: 0.3rem 0; overflow: hidden; }
.meter div { height: 100%; background: var(--correct); transition: width 0.3s; }

/* --- Results & leaderboard --- */

.winner-banner { text-align: center; background: linear-gradient(135deg, #1c3a24, #172b1b); border: 1px solid var(--correct); border-radius: 14px; padding: 1.5rem; margin-bottom: 1.5rem; }
.winner-banner.none { background: var(--panel); border-color: var(--line); }
.winner-banner h1 { font-size: 2.6rem; margin-bottom: 0.25rem; }

.results { width: 100%; border-collapse: collapse; margin-bottom: 1.5rem; }
.results th { text-align: left; color: var(--muted); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.08em; padding: 0.5rem 0.75rem; border-bottom: 1px solid var(--line); }
.results td { padding: 0.65rem 0.75rem; border-bottom: 1px solid var(--line); }
.results tr.you td { background: rgba(255, 90, 78, 0.1); }
.results .code { font-size: 1.1rem; letter-spacing: 0.2em; display: table-cell; }

.filters { display: flex; flex-wrap: wrap; gap: 1.5rem; margin-bottom: 1.25rem; }
.filter-group { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.chip { padding: 0.25rem 0.8rem; border: 1px solid var(--line); border-radius: 999px; color: var(--text); text-decoration: none; font-size: 0.9rem; }
.chip:hover { background: var(--panel-2); color: #fff; }
.chip.on { background: var(--accent); border-color: var(--accent); color: #fff; }

/* --- Errors --- */

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    color: #222;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss { cursor: pointer; position: absolute; right: 0.75rem; top: 0.5rem; }

.blazor-error-boundary { background: #b32121; padding: 1rem 1rem 1rem 1rem; color: white; }
.blazor-error-boundary::after { content: "An error has occurred." }

.validation-message { color: #ff8a80; }

.topnav a, .who, .linkish, .brand { white-space: nowrap; }

@media (max-width: 820px) {
    .results { display: block; overflow-x: auto; }
    .results th, .results td { padding: 0.5rem 0.5rem; white-space: nowrap; }
    .brand { font-size: 1.05rem; }
    .brand-tiles { display: none; }
    .word-input { font-size: 1.15rem; letter-spacing: 0.15em; }
    .play-layout { grid-template-columns: 1fr; }
    .scoreboard { position: static; }
    .hero h1 { font-size: 2.2rem; }
    .tile { width: 2.7rem; height: 2.7rem; font-size: 1.4rem; }
    .topbar { padding: 0.6rem 1rem; flex-wrap: wrap; gap: 0.4rem 1rem; }
    .topnav { gap: 0.8rem; font-size: 0.9rem; flex-wrap: wrap; }
    .who { max-width: 7rem; overflow: hidden; text-overflow: ellipsis; }
}

/* --- Admin panel --- */

.tabs { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.tabs .chip { cursor: pointer; font: inherit; font-size: 0.9rem; background: transparent; }
.tabs .chip.on { background: var(--accent); }
.stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 0.75rem; margin-bottom: 0.75rem; }
.stat-card { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 0.9rem 1rem; display: flex; flex-direction: column; }
.stat-card strong { font-family: 'Oswald', sans-serif; font-size: 1.9rem; line-height: 1.1; }
.stat-card span { color: var(--muted); font-size: 0.85rem; }
.chart-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1rem; margin-bottom: 1rem; }
.chart-grid .panel { margin-bottom: 0; }
.chart-grid h2 { font-size: 1.1rem; }
.bars { display: flex; align-items: flex-end; gap: 2px; height: 90px; }
.bars .bar { flex: 1; background: var(--correct); border-radius: 2px 2px 0 0; min-width: 2px; }
.bars .bar.zero { background: var(--line); }
.bars-note { margin: 0.4rem 0 0; }
.table-wrap { overflow-x: auto; scrollbar-color: var(--line) transparent; }
.results.compact td, .results.compact th { padding: 0.35rem 0.5rem; }
.row-actions { white-space: nowrap; text-align: right; }
.search-row { display: flex; gap: 0.5rem; margin-bottom: 1rem; }
.search-row .form-control { flex: 1; }
.pager { display: flex; align-items: center; justify-content: center; gap: 1rem; margin-top: 0.75rem; }

.tag-bad { border-color: #ff8a80; color: #ff8a80; }
.tag-warn { border-color: #e0b84a; color: #e0b84a; }
.manage-panel { border-color: var(--accent); }
.manage { display: flex; flex-wrap: wrap; gap: 0.75rem 2rem; padding: 0.5rem 0.25rem; }
.manage > p { flex-basis: 100%; margin: 0; }
.manage-group { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4rem; }
.manage-group strong { min-width: 4.5rem; }
.manage-group .form-control { width: 14rem; }

/* --- Your own guesses (private to you) --- */

.typed-row { justify-content: center; margin-bottom: 0.6rem; }
.tile.typed { background: var(--panel-2); border: 2px solid var(--line); color: #fff; }
.tile.typed.on { border-color: var(--muted); }
.my-guesses { margin-bottom: 1rem; }
.my-guesses h3 { font-size: 0.95rem; margin: 0 0 0.4rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; }
.my-guesses-list { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.guess-chip { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 0.15rem 0.6rem; font-family: 'Oswald', sans-serif; letter-spacing: 0.15em; }

.hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
textarea.form-control { resize: vertical; }

.tabs.sub { margin-bottom: 0.75rem; }
.inbox-item { padding: 0.9rem 0; border-bottom: 1px solid var(--line); }
.inbox-item:last-of-type { border-bottom: 0; }
.inbox-head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 0.7rem; }
.inbox-body { white-space: pre-wrap; margin: 0.5rem 0; overflow-wrap: anywhere; }
.inbox-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; }

.notice { background: var(--panel-2); border: 1px solid var(--present); border-radius: 10px; padding: 0.5rem 0.9rem; font-size: 0.9rem; }

.beta-switch { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem 1rem; margin-bottom: 0.75rem; }

/* --- Confirmation toast (share / copy buttons) --- */

#cw-toast { position: fixed; left: 50%; bottom: 4.5rem; transform: translate(-50%, 1rem); background: var(--panel-2); color: #fff;
    border: 1px solid var(--line); border-radius: 999px; padding: 0.55rem 1.1rem; font-size: 0.9rem; box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
    opacity: 0; pointer-events: none; transition: opacity 0.2s ease, transform 0.2s ease; z-index: 2000; max-width: 90vw; text-align: center; }
#cw-toast.show { opacity: 1; transform: translate(-50%, 0); }

.price { font-family: 'Oswald', sans-serif; font-size: 1.6rem; letter-spacing: 0.04em; margin: 0.25rem 0 0.75rem; }
.share-row { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.share-row .share { flex: 1 1 16rem; margin-top: 0; }

/* --- Finished, and waiting for the others (score card games) --- */

.finish-note { display: flex; flex-direction: column; align-items: flex-start; gap: 0.35rem; margin-top: 0.7rem; padding: 0.7rem 0.9rem;
    background: var(--panel); border: 1px solid var(--correct); border-radius: 10px; }
.score-place { margin: -0.2rem 0 0.3rem; }
.badge-place { display: inline-block; background: var(--correct); color: #fff; border-radius: 999px; padding: 0.05rem 0.6rem; font-size: 0.75rem; font-weight: 600; }

/* --- Groups --- */

.group-invite { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin: 0.5rem 0; }
.group-invite .form-select { max-width: 18rem; }
.code-inline { font-family: 'Oswald', sans-serif; letter-spacing: 0.15em; }
button.chip { cursor: pointer; font: inherit; font-size: 0.9rem; background: transparent; color: var(--text); }

/* --- Open beta note on the front page --- */

.beta-banner { max-width: 760px; margin: 0 auto 1.25rem; padding: 0.75rem 1rem; background: var(--panel); border: 1px solid var(--present); border-radius: 12px; }
.beta-banner strong { display: inline-block; margin-bottom: 0.2rem; font-family: 'Oswald', sans-serif; letter-spacing: 0.06em; text-transform: uppercase; color: var(--present); }
.beta-banner p { margin: 0; font-size: 0.92rem; }

/* --- Desktop/laptop: room for more than one opponent at a time --- */

@media (min-width: 601px) {
    /* A phone shows one full-width card at a time because there's nowhere to put a second one; a bigger screen has
       room for several, so every opponent just wraps onto as many rows as it takes - nothing ever needs sideways
       scrolling or dragging to see. That also makes the dots (mobile's way of saying "which one, out of the one
       visible at a time, is this") meaningless here, since nothing is ever off-screen to point at. */
    .board-dots { display: none; }
    .boards {
        max-width: none; flex-wrap: wrap; overflow-x: visible; scroll-snap-type: none;
        touch-action: auto; gap: 1rem; cursor: auto;
    }
    .board { flex: 0 0 300px; }
    /* A narrower card can't always fit an 8-letter word's row of tiles at their fixed 1.9rem size - shrink-to-fit
       instead, the same way the phone's cards already have to. */
    .board .tile.sm { flex: 1 1 0; min-width: 0; max-width: 1.9rem; aspect-ratio: 1; }
    .board-guesses, .tile-row { overflow-x: hidden; }
}

/* --- Phones: the game screen has to fit above the pinned guess box without endless scrolling --- */

@media (max-width: 600px) {
    .content { padding: 0.75rem 0.75rem 2rem; }

    /* A slimmer header: one tidy row of links. */
    .topbar { padding: 0.4rem 0.75rem; gap: 0.2rem 0.75rem; }
    .brand { font-size: 0.95rem; }
    .topnav { gap: 0.2rem 0.75rem; font-size: 0.85rem; }
    .who { display: none; }

    /* The guess box is pinned to the true bottom of the screen, always, so it's never something you have to scroll
       to reach. While playing, the footer stripe steps aside for it entirely (there's nowhere else useful to put
       it on a screen this size); the create/start bars still just sit above the footer as normal. */
    html:has(.guess-bar) .site-footer { display: none; }
    .guess-bar {
        position: fixed; top: auto; left: 0.75rem; right: 0.75rem; bottom: var(--kb-offset, 0px); z-index: 20;
        margin: 0; padding: 0.5rem 0.75rem; background: var(--bg);
        border-top: 1px solid var(--line); border-radius: 12px 12px 0 0; box-shadow: 0 -8px 16px rgba(0, 0, 0, 0.35);
    }
    /* --kb-offset (mobile.js, from the VisualViewport API) is the real gap the on-screen keyboard leaves at the
       bottom of the screen - fixed positioning alone doesn't reliably track that gap on every browser, so this
       follows the measured value directly (0 when the keyboard is closed). */
    .kb-open .stage > .lobby-actions, .kb-open .create-bar {
        position: fixed; left: 0.75rem; right: 0.75rem; bottom: var(--kb-offset, 0px); margin: 0;
    }
    /* The pinned bar stays slim: the guess box already shows what you type, so the big typed tiles are left out, and
       each board's own scrollable history (below) covers what the "Your guesses" chip list used to. */
    .typed-row, .my-guesses { display: none; }
    /* The per-board "letters tried" keyboard is redundant now that there's a custom typing keyboard pinned at the
       bottom (see .type-kb) - showing the same letter-by-letter feedback twice, once per board, was most of what
       made this screen feel like it needed constant scrolling. The typing keyboard shows that feedback itself now,
       aggregated across every opponent instead of repeated per card. */
    .kb { display: none; }
    .word-form { gap: 0.4rem; }
    .word-input { font-size: 1.05rem; padding-top: 0.3rem; padding-bottom: 0.3rem; }
    .guess-meta { flex-wrap: wrap; gap: 0.1rem 0.9rem; margin-top: 0.3rem; font-size: 0.82rem; }

    /* The custom keyboard that replaces the phone's own (see the guess input's inputmode="none"): three rows,
       Enter and Backspace flanking the bottom row the way a real keyboard does. Buttons, not the read-only spans
       the per-opponent "letters tried" keyboard uses elsewhere on this page - these actually do something. */
    .type-kb { display: flex; flex-direction: column; gap: 6px; margin-top: 0.5rem; }
    .type-kb-row { display: flex; justify-content: center; gap: 4px; }
    .type-key {
        flex: 1 1 0; min-width: 0; height: 2.5rem; padding: 0; border: 0; border-radius: 6px;
        background: var(--panel-2); color: #fff; font: inherit; font-weight: 700; font-size: 0.95rem; text-transform: uppercase;
        display: flex; align-items: center; justify-content: center; touch-action: manipulation;
    }
    .type-key:active { background: var(--line); }
    .type-key:disabled { opacity: 0.45; }
    /* The same per-letter feedback the old per-board keyboard showed - green beats yellow beats gray - just on the
       one keyboard that's left, aggregated across every opponent (see AggregateLetterStates). */
    .type-key.k-correct { background: var(--correct); color: #fff; }
    .type-key.k-present { background: var(--present); color: #1a1500; }
    .type-key.k-absent { background: #10141f; color: #4b566f; }
    .type-key.wide { flex: 1.7 1 0; font-size: 0.8rem; text-transform: none; }

    /* Staging and secret-word screens: a slimmer title row with the code / countdown beside it, and seats two to a row. */
    .stage-head { flex-wrap: nowrap; align-items: center; gap: 0.75rem; margin-bottom: 0.6rem; }
    .stage-head h1 { font-size: 1.7rem; margin: 0; }
    .codebox { flex: none; padding: 0.3rem 0.8rem; }
    .codebox .code { font-size: 1.5rem; }
    .roster { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.4rem; margin: 0.75rem 0; }
    .roster.compact { grid-template-columns: 1fr; }
    .slot { flex-wrap: wrap; padding: 0.45rem 0.65rem; gap: 0.3rem 0.4rem; }

    /* Snugger cards, so more of each screen is content. */
    .panel { padding: 1rem; margin-bottom: 0.9rem; }

    /* The game setup forms: short settings sit two to a row instead of one long column. */
    .settings-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 0.75rem; }
    .settings-row .field { min-width: 0; }
    .settings-row .field.wide { grid-column: 1 / -1; }

    /* Create game stays pinned above the footer while you scroll the setup form. */
    .create-bar {
        position: sticky; bottom: var(--footer-h); z-index: 6;
        margin: 1rem -1rem -1rem; padding: 0.6rem 1rem;
        background: var(--panel); border-top: 1px solid var(--line); border-radius: 0 0 14px 14px;
        box-shadow: 0 -8px 16px rgba(0, 0, 0, 0.3);
    }
    /* Phone-specific overrides on top of the universal carousel rules above: each card is capped at 99% of the
       viewport width - not a full 100%, and not left to whatever its content happens to need - with overflow-x
       guards on everything inside so a card can never be forced wider than that by its own content (which is
       exactly how the kb-open tile rule below used to go wrong: dropping its width cap let guess tiles grow
       unbounded instead of shrinking to fit, stretching the row, the card, and the page out past the screen edge).
       Dots run smaller, and each card's height is pinned to whatever's left between the topbar/dots and the pinned
       guess box, rather than the desktop's natural content height. */
    .boards { max-width: none; margin: 0; }
    .board-dots { gap: 0.4rem; padding: 0.35rem 0 0.5rem; }
    .board-dot { width: 9px; height: 9px; }
    .board {
        flex-basis: 99vw; max-width: 99vw; padding: 0.6rem 0.75rem; border-radius: 10px; overflow-x: hidden;
        height: calc(100dvh - 400px);   /* topbar + dots + the pinned guess box (now with its own keyboard), roughly */
    }
    .board-head { margin-bottom: 0.5rem; font-size: 0.95rem; }
    .board-guesses, .tile-row { overflow-x: hidden; }
    .board .tile.sm { flex: 1 1 0; width: auto; min-width: 0; height: auto; max-width: 2.4rem; aspect-ratio: 1; font-size: 0.95rem; border-radius: 5px; }
    /* The phone's own keyboard should never open for the guess box any more (inputmode="none"), so kb-open
       shouldn't normally fire during play at all - kept as a defensive fallback in case some other control on this
       screen ever needs the room-making treatment. */
    .kb-open .board { height: calc(100dvh - 480px); }
    .kb-open .board .tile.sm { max-width: 1.6rem; aspect-ratio: 1; height: auto; }

    .scoreboard { padding: 0.7rem; }
    .score-row { margin-bottom: 0.5rem; }
    .finish-note { margin-top: 0.4rem; padding: 0.5rem 0.7rem; }
}

/* --- Post-to-social buttons on the results screen (behind Features:SocialShare) --- */

.share-targets { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.4rem 0.5rem; margin-top: 0.9rem; }

/* --- AdSense slot with a house banner underneath until Google fills it --- */

/* Google sets data-ad-status on the slot: "filled" when an ad arrived, "unfilled" when it has nothing to show. */
ins.adsbygoogle[data-ad-status="filled"] ~ .ad-fallback { display: none; }
ins.adsbygoogle[data-ad-status="unfilled"] { display: none !important; }

/* --- Gold members show in gold in the admin panel --- */

.gold-name { color: #f5c542 !important; }
