/* /Components/UI/ServerUnreachableBanner.razor.rz.scp.css */
/* The design system's banner is one 44 px line; Portuguese ("Sem ligação ao FrostMath — a tentar de novo") needs two at
   320 px, so the line may wrap from a 44 px minimum, centred. */
[b-9pr587ua2g] .fm-banner { height: auto; min-height: 44px; padding-top: var(--space-2); padding-bottom: var(--space-2); text-align: center; }
/* /Components/UI/SnowBackdrop.razor.rz.scp.css */
/* The prototype's .snow and body.bg-wash: the accent washes in from the top over the page's own surface. The canvas fills
   its page's box (the page is position: relative) and sits under the page's content. */
.snow-backdrop[b-erlzjq2hzh] { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; pointer-events: none;
    background: radial-gradient(80% 40% at 50% 0%, var(--accent-soft), transparent 70%), var(--surface-0); }
/* /Components/UI/Solo/GhostRace.razor.rz.scp.css */
/* The ghost race on v2 (redesign step 6), from the prototype's ghost screens: loading centred on its own screen (no bars),
   the run is SprintRun's, the result and a failure are pages in the shell, clear of its bottom bar. */
.ghost-race[b-zcxwhr9k9q] { display: contents; }

.ghost-loading[b-zcxwhr9k9q] { height: 100dvh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-3);
    padding: var(--space-6) var(--space-4); text-align: center; color: var(--accent-text); }
.ghost-loading__title[b-zcxwhr9k9q] { margin: 0; font: 500 15px/1.5 var(--font-body); color: var(--ink); }

.ghost-page[b-zcxwhr9k9q] { width: 100%; max-width: 560px; margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .ghost-page[b-zcxwhr9k9q] { padding: var(--space-10) var(--space-6) var(--space-16); } }
.ghost-page--result[b-zcxwhr9k9q] { max-width: none; align-items: center; }
@media (min-width: 768px) { .ghost-page--result[b-zcxwhr9k9q] { min-height: calc(100dvh - var(--top-bar-height)); justify-content: center; } }

.ghost-time[b-zcxwhr9k9q] { min-height: 18px; }
.ghost-actions[b-zcxwhr9k9q] { display: flex; flex-direction: column; gap: var(--space-2); }
/* The two small actions side by side, each on one line; where both don't fit (pt-PT at 320 px) they stack. */
.ghost-row[b-zcxwhr9k9q] { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); }
.ghost-row[b-zcxwhr9k9q]  .fm-btn { flex: 1 1 auto; }

/* Below 400 px the secondary actions take PostMatch's smaller type (13 px, tighter tracking), so their labels keep one
   line in English and Portuguese; the dominant action keeps its own. */
@media (max-width: 399px) {
    .ghost-actions[b-zcxwhr9k9q]  .fm-btn:not(.fm-btn--lg) { padding-inline: var(--space-3); font-size: 13px; letter-spacing: 0.5px; }
    /* The dominant action on one line inside the card ("PROCURAR ADVERSÁRIO"): the page and the card give it 12 px each
       side instead of 16. */
    .ghost-actions[b-zcxwhr9k9q]  .fm-btn--lg { padding-inline: var(--space-3); font-size: 14px; letter-spacing: 0.5px; }
    .ghost-page--result[b-zcxwhr9k9q] { padding-inline: var(--space-3); }
    .ghost-page--result[b-zcxwhr9k9q]  .fm-solo { padding: var(--space-4) var(--space-3); }
}
@media (max-width: 359px) {
    .ghost-actions[b-zcxwhr9k9q]  .fm-btn--lg { font-size: 13px; }
}
/* /Components/UI/Solo/SprintRun.razor.rz.scp.css */
/* ─────────────────────────────────────────────────────────────────
   SprintRun.razor.css — the solo run on v2 (redesign step 6), from the prototype's app.css (".solo"), laid out like the
   match's .mx: one screen, never scrolled, the input at the bottom on touch.

   The animations (answer flashes, question card, race, timer urgency) live in wwwroot/css/frost-motion.css, global.
   data-input says which input the run uses: touch (the NumPad) or keyboard (the answer field).
   ───────────────────────────────────────────────────────────────── */

.solo[b-h0ieanpynv] { position: relative; height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }

.solo-play[b-h0ieanpynv] { flex: 1; min-height: 0; display: flex; flex-direction: column; align-items: center; gap: var(--space-3);
    padding: calc(env(safe-area-inset-top, 0px) + var(--space-4)) max(var(--space-3), env(safe-area-inset-right, 0px)) var(--space-3) max(var(--space-3), env(safe-area-inset-left, 0px)); }
@media (min-width: 768px) {
    .solo-play[b-h0ieanpynv] { justify-content: center; gap: var(--space-4); padding-bottom: var(--space-8); }
}
.solo[data-input="touch"] .solo-play[b-h0ieanpynv] { padding-bottom: 0; }

/* The page's header (a race) and the grade squares share the run's width. */
.solo-header[b-h0ieanpynv], .solo-top[b-h0ieanpynv] { width: 100%; max-width: 512px; }
.solo-top[b-h0ieanpynv] { display: flex; justify-content: center; }
/* The prototype's squares in a run: 20 px at most below 400 px (GradeSquares' own rule), 22 px from there. */
@media (min-width: 400px) {
    .solo-top[b-h0ieanpynv]  .fm-grades { grid-template-columns: repeat(12, 22px); }
    .solo-top[b-h0ieanpynv]  .fm-grades .fm-grade { width: 22px; height: 22px; }
}
/* Below md the first rows clear the leave control in the top corner (the prototype's Q2). */
@media (max-width: 767px) {
    .solo-header[b-h0ieanpynv], .solo-top[b-h0ieanpynv] { padding-right: 40px; }
}

.solo-ring[b-h0ieanpynv] { display: flex; justify-content: center; }
.solo-ring[b-h0ieanpynv]  .fm-timer { width: 64px; height: 64px; }
.solo-ring[b-h0ieanpynv]  .fm-timer__num { font-size: 22px; }

/* The question and its status line: the line is reserved (the design system's --status-line), empty or not. */
.solo-q[b-h0ieanpynv] { width: 100%; max-width: 512px; display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
.solo-status[b-h0ieanpynv] { width: 100%; }
.solo-status[b-h0ieanpynv]  .fm-status { min-height: var(--status-line); margin-inline: auto; font-size: 14px; }

/* The input's place: the NumPad at the bottom on touch, the answer field and Submit on a keyboard. */
.solo-act[b-h0ieanpynv] { width: 100%; display: flex; flex-direction: column; align-items: center; }
.solo[data-input="touch"] .solo-act[b-h0ieanpynv] { margin-top: auto; }
.solo-pad[b-h0ieanpynv] { width: 100%; display: flex; justify-content: center; }
.solo-pad[b-h0ieanpynv]  .fm-pad { max-width: 480px; }
/* The question is always the largest element (§15): the typed digits stay smaller than its longest expressions. */
.solo-pad[b-h0ieanpynv]  .fm-pad__display { font-size: 24px; }
.solo-input[b-h0ieanpynv] { width: 100%; display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
.solo-input[b-h0ieanpynv]  .fm-field { max-width: 360px; }
.solo-input[b-h0ieanpynv]  .fm-help { text-align: center; }

/* The way out, at every width: the top corner, over the screen, never in its flow. */
/* The 3-2-1 before the first question, on a scrim over the run (the match's .mx-overlay); the leave control is above it. */
.solo-overlay[b-h0ieanpynv] { position: absolute; inset: 0; z-index: 20; display: grid; place-items: center; padding: var(--space-4); background: var(--scrim); }
.solo-leave[b-h0ieanpynv] { position: absolute; z-index: 21; top: calc(env(safe-area-inset-top, 0px) + 4px); right: max(4px, env(safe-area-inset-right, 0px)); }

/* A short phone held upright (320 x 568, the first iPhone SE): the whole NumPad must stay on screen, so the column
   tightens and the ring shrinks. */
@media (max-height: 599px) and (orientation: portrait) {
    .solo-play[b-h0ieanpynv] { gap: var(--space-2); padding-top: calc(env(safe-area-inset-top, 0px) + var(--space-2)); }
    .solo-ring[b-h0ieanpynv]  .fm-timer { width: 48px; height: 48px; }
    .solo-ring[b-h0ieanpynv]  .fm-timer__num { font-size: 17px; }
}

/* A race on top (the ghost race, a counted link run) on a phone of up to 720 px: the column tightens, the ring and the
   pad shrink a little, so the whole NumPad stays on screen (the prototype's own race run overflows a 320 x 640 phone). */
@media (max-height: 719px) and (orientation: portrait) {
    .solo--race .solo-play[b-h0ieanpynv] { gap: var(--space-2); padding-top: calc(env(safe-area-inset-top, 0px) + var(--space-2)); }
    .solo--race .solo-ring[b-h0ieanpynv]  .fm-timer { width: 48px; height: 48px; }
    .solo--race .solo-ring[b-h0ieanpynv]  .fm-timer__num { font-size: 17px; }
    .solo--race .solo-pad[b-h0ieanpynv]  .fm-pad { height: max(266px, 44dvh); }
}

/* A race on a short phone (320 x 568): its caption goes too (what the race is was said on the way in, and the leave
   dialog says it again), so the NumPad still fits under the race, the squares, the ring and the question. */
@media (max-height: 599px) and (orientation: portrait) {
    .solo--race .solo-header[b-h0ieanpynv]  .fm-racetrack__rule { display: none; }
}

/* A phone on its side: the header, the squares, the ring and the question on the left, the whole NumPad on the right. */
@media (orientation: landscape) and (max-height: 500px) {
    .solo[data-input="touch"] .solo-play[b-h0ieanpynv] { display: grid; grid-template-columns: minmax(0, 1fr) min(46%, 340px);
        grid-template-rows: repeat(4, auto) minmax(0, 1fr); align-items: start; justify-items: center; column-gap: var(--space-4); row-gap: var(--space-2); }
    .solo[data-input="touch"] .solo-play > :not(.solo-act)[b-h0ieanpynv] { grid-column: 1; }
    .solo[data-input="touch"] .solo-act[b-h0ieanpynv] { grid-column: 2; grid-row: 1 / -1; align-self: end; margin-top: 0; }
    .solo[data-input="touch"] .solo-pad[b-h0ieanpynv]  .fm-pad { height: calc(100dvh - var(--space-3)); min-height: 0; }
    .solo[data-input="touch"] .solo-play[b-h0ieanpynv] { padding-top: calc(env(safe-area-inset-top, 0px) + var(--space-3)); }
    /* With a race on the left: tighter, a smaller ring and no caption, so the column stays within the screen. */
    .solo--race[data-input="touch"] .solo-play[b-h0ieanpynv] { row-gap: 4px; }
    .solo--race .solo-ring[b-h0ieanpynv]  .fm-timer { width: 44px; height: 44px; }
    .solo--race .solo-ring[b-h0ieanpynv]  .fm-timer__num { font-size: 16px; }
    .solo--race .solo-header[b-h0ieanpynv]  .fm-racetrack__rule { display: none; }
}
/* /Components/UI/v2/AnswerField.razor.rz.scp.css */
/* The answer box (not an input, owner's decision 27 Oct 2026): it fills the field as ds.css's input does, in the
   field's mono face, centred. The field's own ring (.fm-input:focus-within) is its focus mark, so the box draws no outline. */
.fm-answer[b-1vih4cwz94] { flex: 1; align-self: stretch; min-width: 0; display: flex; align-items: center; justify-content: center;
    color: var(--ink); white-space: nowrap; overflow: hidden; cursor: text; }
.fm-answer:focus[b-1vih4cwz94], .fm-answer:focus-visible[b-1vih4cwz94] { outline: none; }
.fm-answer__placeholder[b-1vih4cwz94] { color: var(--ink-subtle); overflow: hidden; text-overflow: ellipsis; }
.fm-input.is-disabled[b-1vih4cwz94] { opacity: var(--opacity-disabled); }
.fm-input.is-disabled .fm-answer[b-1vih4cwz94] { cursor: default; }

/* The caret, drawn: shown while the box has focus, blinking (held still under reduced motion), none when locked. */
.fm-answer__caret[b-1vih4cwz94] { flex: none; width: 2px; height: 1.1em; margin: 0 1px; background: currentColor; visibility: hidden; }
.fm-answer:focus .fm-answer__caret[b-1vih4cwz94] { visibility: visible; animation: fm-caret-blink-b-1vih4cwz94 1s steps(1) infinite; }
.fm-answer[aria-disabled="true"] .fm-answer__caret[b-1vih4cwz94] { visibility: hidden; }
:where(:root[data-reduced-motion]) .fm-answer:focus .fm-answer__caret[b-1vih4cwz94] { animation: none; }
@keyframes fm-caret-blink-b-1vih4cwz94 { 50% { opacity: 0; } }
/* /Components/UI/v2/AppShell.razor.rz.scp.css */
/* From the prototype's app.css ("Shell"): the top bar fixed from md, the bottom bar fixed below md over the home
   indicator, and the main column padded clear of both. --bottom-bar-height already holds the inset (app.css; SafeAreaTests),
   so it is never added again: the bar pads its own items above it. */
.fm-shell__top[b-inm29brht9] { display: none; }
.fm-shell__bottom[b-inm29brht9] { position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-status-bar);
    padding: 0 env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
    height: var(--bottom-bar-height); }
/* A phone on its side (the notch at one end) keeps the bar's items clear of it, as v1's bars did. */
.fm-shell__top[b-inm29brht9] { padding-left: max(var(--space-6), env(safe-area-inset-left, 0px)); padding-right: max(var(--space-6), env(safe-area-inset-right, 0px)); }
/* The prototype's main also takes z-index 1, to sit over its page-wide snow layer. FrostMath's snow is drawn by each page,
   and a stacking context here would keep a page's own dialog under the bars (the Settings log-out sheet), so none. */
.fm-shell__main[b-inm29brht9] { position: relative; min-height: 100dvh; padding-bottom: calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) {
    .fm-shell__top[b-inm29brht9] { display: flex; position: fixed; top: 0; left: 0; right: 0; z-index: var(--z-top-bar); }
    .fm-shell__bottom[b-inm29brht9] { display: none; }
    .fm-shell__main[b-inm29brht9] { padding-top: var(--top-bar-height); padding-bottom: var(--space-16); }
}

/* MainLayout, by convention (redesign step 7g): the main column clears only the top bar, from md, and the safe-area
   sides; every page clears the bottom bar itself with --bottom-bar-height, so padding it here too would add scroll to
   the pages that fit the viewport exactly. Under <InGame Playing> the top bar goes and so does its
   clearance (app.css). */
.fm-shell--pages-pad .fm-shell__main[b-inm29brht9] { min-height: 0; padding: 0 env(safe-area-inset-right, 0px) 0 env(safe-area-inset-left, 0px); }
@media (min-width: 768px) { .fm-shell--pages-pad .fm-shell__main[b-inm29brht9] { padding-top: var(--top-bar-height); } }

/* The closed beta's badge by the brand (card #288). Between md and lg the word is hidden and the bar is already full
   (768 px), so the badge waits for lg; below md the top bar is not drawn at all (Home carries the badge there). */
@media (min-width: 768px) and (max-width: 1023px) { .fm-topbar__brand[b-inm29brht9]  .fm-shell__beta { display: none; } }

/* Auth unknown: the bottom bar's fourth tab keeps its box and shows nothing. */
.fm-shell__tab-hold[b-inm29brht9] { visibility: hidden; }

/* The language menu opens under its own button: the bar's side padding, the 88 px slot and the gap before it. */
.fm-shell__overlays[b-inm29brht9]  .fm-shell__langmenu.fm-menu--anchored { right: calc(var(--space-6) + 88px + var(--space-2)); min-width: 180px; }
@media (min-width: 768px) and (max-width: 1023px) {
    .fm-shell__overlays[b-inm29brht9]  .fm-shell__langmenu.fm-menu--anchored { right: calc(var(--space-4) + 88px + var(--space-2)); }
}

/* Between md and lg the top bar gives up some padding and gap, so four links, the environment badge, sound, language and
   the 88 px slot fit 768 px (the prototype's 24 px ran 8 px past it). */
@media (min-width: 768px) and (max-width: 1023px) {
    .fm-topbar[b-inm29brht9] { padding-left: max(var(--space-4), env(safe-area-inset-left, 0px)); padding-right: max(var(--space-4), env(safe-area-inset-right, 0px)); gap: var(--space-2); }
}

/* The playground's static shell: the bars at their own widths (the top bar from md, the bottom bar below md), in the
   flow around a short main instead of fixed. */
.fm-shell--static[b-inm29brht9] { display: flex; flex-direction: column; gap: var(--space-4); }
.fm-shell--static .fm-shell__bottom[b-inm29brht9] { position: static; display: grid; padding: 0; }
.fm-shell--static .fm-shell__main[b-inm29brht9] { min-height: 0; padding: 0; }
@media (min-width: 768px) { .fm-shell--static .fm-shell__top[b-inm29brht9] { position: static; } .fm-shell--static .fm-shell__bottom[b-inm29brht9] { display: none; } }
.fm-shell__overlays[b-inm29brht9]  .fm-shell__menu-static { margin-left: auto; }

.fm-brandmark[b-inm29brht9] { display: block; width: 28px; height: 28px; }
.fm-brandmark--light[b-inm29brht9] { display: none; }
[data-theme="light"] .fm-brandmark--light[b-inm29brht9] { display: block; }
[data-theme="light"] .fm-brandmark--dark[b-inm29brht9] { display: none; }

.fm-shell__avatar[b-inm29brht9] { display: grid; place-items: center; min-width: var(--touch-target); min-height: var(--touch-target);
    border: 0; background: none; padding: 0; cursor: pointer; border-radius: var(--radius-md); }
.fm-shell__menu-who[b-inm29brht9] { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
/* /Components/UI/v2/Avatar.razor.rz.scp.css */
.fm-avatar[b-1ihnfjg8rv] {
    display: inline-flex;
    flex: none;
    line-height: 0;
}

.fm-avatar-initials[b-1ihnfjg8rv] {
    display: inline-grid;
    place-items: center;
    flex: none;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    background: var(--ice-900);
    color: var(--on-primary);
    font-family: var(--font-body);
    font-weight: 700;
    letter-spacing: 0.5px;
    line-height: 1;
}
/* /Components/UI/v2/Badge.razor.rz.scp.css */
/* known-issues.md #3: in Polar day, white on --accent is 4.08:1, under the 4.5:1 a 12 px label needs; the solid badge
   fills with --accent-text (5.8:1) there. Polar night is unchanged. */
[data-theme="light"] .fm-badge--solid[b-t9q11sqpxy] { background: var(--accent-text); border-color: var(--accent-text); }
/* /Components/UI/v2/Button.razor.rz.scp.css */
/* From the prototype's app.css (Q2): below 400 px a Large label keeps one line by giving up some padding and tracking. */
@media (max-width: 399px) {
    .fm-btn--lg[b-wur9y4xez6] { padding: 0 var(--space-4); font-size: 15px; letter-spacing: 1px; }
}
/* /Components/UI/v2/ChipGroup.razor.rz.scp.css */
/* Segmented (the prototype's .seg): one pill track, the chips inside it at 36 px, the chosen one filled. The track's 4 px
   padding counts toward each chip's 44 px target (its ::after reaches over it). Before the Polar day rule below, which
   wins for the chosen chip. */
.fm-chips--seg[b-sg68ba8t9y] { display: inline-flex; flex-wrap: nowrap; gap: 4px; padding: 4px; border-radius: var(--radius-full); background: var(--surface-2); border: 1px solid var(--border-control); }
.fm-chips--seg .fm-chip[b-sg68ba8t9y] { height: 36px; border: 0; background: transparent; position: relative; }
.fm-chips--seg .fm-chip[b-sg68ba8t9y]::after { content: ""; position: absolute; inset: -4px 0; }
.fm-chips--seg .fm-chip[aria-checked="true"][b-sg68ba8t9y] { background: var(--accent); }

/* known-issues.md #3: a selected chip's white label on --accent is 4.08:1 in Polar day; it fills with --accent-text. */
[data-theme="light"] .fm-chip[aria-checked="true"][b-sg68ba8t9y],
[data-theme="light"] .fm-chip[aria-pressed="true"][b-sg68ba8t9y] { background: var(--accent-text); border-color: var(--accent-text); }
/* /Components/UI/v2/ComboChip.razor.rz.scp.css */
/* known-issues.md #3: the solid 5+ chip's count on --accent is 4.08:1 in Polar day; it fills with --accent-text. */
[data-theme="light"] .fm-combo--hot[b-1g2qrdcnt3] { background: var(--accent-text); }
/* /Components/UI/v2/ConsentBanner.razor.rz.scp.css */
/* Over the bottom of the page: fixed, so it takes no space and nothing moves. Above the page and the bars, under the
   toasts and dialogs. On phones it sits on top of the bottom bar. */
.consent-banner[b-kz2c0emv39] {
    position: fixed;
    inset-inline: 0;
    bottom: var(--bottom-bar-height);
    z-index: 46;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2, 8px) var(--space-4, 16px);
    padding: var(--space-3, 12px) var(--space-4, 16px);
    background: var(--bar);
    border-top: 1px solid var(--border-subtle);
    animation: consent-fade-b-kz2c0emv39 160ms ease-out both;
}

@media (min-width: 768px) {
    .consent-banner[b-kz2c0emv39] { bottom: 0; padding-bottom: calc(var(--space-3, 12px) + env(safe-area-inset-bottom, 0px)); }
}

.consent-banner__text[b-kz2c0emv39] { margin: 0; flex: 1 1 280px; }

.consent-banner__text a[b-kz2c0emv39] { color: inherit; text-decoration: underline; }

.consent-banner__actions[b-kz2c0emv39] { display: flex; gap: var(--space-2, 8px); }

/* Opacity only: it appears without any movement. */
@keyframes consent-fade-b-kz2c0emv39 {
    from { opacity: 0; }
    to { opacity: 1; }
}

:where(:root[data-reduced-motion]) .consent-banner[b-kz2c0emv39] { animation: none; }
/* /Components/UI/v2/Countdown.razor.rz.scp.css */
.fm-countdown-wrap[b-owlg8xc4bo] { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
/* The design system's Countdown: 96 px below md, 120 px from md. */
@media (max-width: 767px) { .fm-countdown__num[b-owlg8xc4bo] { font-size: 96px; } }
/* /Components/UI/v2/Dialog.razor.rz.scp.css */
/* From the prototype's app.css ("Overlays"): fixed over everything (z-dialog, above the bars); a bottom sheet below md
   with the safe-area inset, a centred 440 px panel from md. Centred with translate, not transform: the entrance
   (frost-motion.css's sheet-in, dialog-in from md) animates transform, which adds to it instead of undoing it (the
   prototype switched its desktop entrance off for that reason). */
.fm-overlay[b-8mile7ggmd] { position: fixed; inset: 0; z-index: var(--z-dialog); }
.fm-overlay__scrim[b-8mile7ggmd] { position: absolute; inset: 0; background: var(--scrim); }
.fm-overlay__dialog[b-8mile7ggmd] { position: absolute; left: 0; right: 0; bottom: 0; max-width: none;
    border-radius: var(--radius-xl) var(--radius-xl) 0 0; padding-bottom: calc(var(--space-6) + env(safe-area-inset-bottom, 0px)); }
@media (min-width: 768px) {
    .fm-overlay__dialog[b-8mile7ggmd] { left: 50%; top: 50%; bottom: auto; width: 440px; translate: -50% -50%;
        border-radius: var(--radius-lg); padding-bottom: var(--space-6); }
}
/* /Components/UI/v2/GameStatusBar.razor.rz.scp.css */
.fm-statusbar__warn[b-0ouykbdabv] { color: var(--warn); }
.fm-statusbar__context[b-0ouykbdabv] { color: var(--ink-muted); overflow: hidden; text-overflow: ellipsis; min-width: 0; }
/* From the prototype's app.css (.mm-page): at 320 px the bar gives up some gap and padding. */
@media (max-width: 399px) { .fm-statusbar[b-0ouykbdabv] { gap: var(--space-2); padding: 0 var(--space-3); } }
/* /Components/UI/v2/GameTimer.razor.rz.scp.css */
/* The number sits over the ring and its ping. */
.fm-timer__num[b-7ocleqtyxr] { z-index: 1; }
/* /Components/UI/v2/GradeSquares.razor.rz.scp.css */
.fm-gradesquares[b-jqntdwnem9] { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
/* From the prototype's app.css (.solo): below 400 px the twelve squares share the width (20 px at most, gap 3 px), so
   the row fits 320 px. */
@media (max-width: 399px) {
    .fm-grades[b-jqntdwnem9] { grid-template-columns: repeat(12, minmax(0, 20px)); gap: 3px; }
    .fm-grades .fm-grade[b-jqntdwnem9] { width: 100%; aspect-ratio: 1; height: auto; }
}
.fm-gradekey[b-jqntdwnem9] { justify-content: center; }
/* ds.css's `.fm-gradekey span` (inline-flex, no justify) also catches the key's own squares, which are spans, and beats
   `.fm-grade`'s grid: the icon sat at the square's left edge (known-issues #7). */
.fm-gradekey .fm-grade[b-jqntdwnem9] { justify-content: center; }
/* /Components/UI/v2/HelpCard.razor.rz.scp.css */
/* The help card (redesign step 7f), from the prototype's first-match card: the head centred over rows read from the left
   (the prototype centres the rows' text too, inherited from its .page--center; a rule reads better from the left). */
.help-card[b-9nuc8xc1wd] { width: 100%; max-width: 520px; }
.help-card[b-9nuc8xc1wd]  .fm-card { display: flex; flex-direction: column; gap: var(--space-5); }

.help-card__head[b-9nuc8xc1wd] { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); text-align: center; }
.help-card__title[b-9nuc8xc1wd] { font-size: 22px; }

.help-card__rows[b-9nuc8xc1wd] { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-4); }
.help-card__row[b-9nuc8xc1wd] { display: flex; align-items: flex-start; gap: var(--space-3); }
.help-card__icon[b-9nuc8xc1wd] { width: 40px; height: 40px; flex: none; }
.help-card__text[b-9nuc8xc1wd] { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.help-card__row-title[b-9nuc8xc1wd] { color: var(--ink); font: 600 14px/1.4 var(--font-body); }
.help-card__row-line[b-9nuc8xc1wd] { font-size: 13px; }
/* /Components/UI/v2/Icon.razor.rz.scp.css */
.fm-icon[b-zo5tcp84lr] {
    display: block;
    flex: none;
}
/* /Components/UI/v2/InputNote.razor.rz.scp.css */
/* From the prototype's app.css ("Input type"): one centred line of muted text after an accent info icon. */
.inp-note[b-7ysqpuhguv] { min-height: 20px; display: flex; gap: 6px; align-items: flex-start; justify-content: center; text-align: left;
    font: 500 12px/1.45 var(--font-body); color: var(--ink-muted); max-width: 420px; margin: 0; }
.inp-note[b-7ysqpuhguv]  .fm-icon { color: var(--accent-text); margin-top: 1px; }
/* /Components/UI/v2/InputTag.razor.rz.scp.css */
/* From the prototype's app.css ("Input type"): the compact tag sits just after a name, in ink-subtle. */
.fm-inputtag[b-4dpl61xqmy] { gap: 4px; }
.fm-inputtag--compact[b-4dpl61xqmy] { display: inline-flex; align-items: center; justify-content: center; color: var(--ink-subtle);
    line-height: 0; vertical-align: middle; margin-left: 6px; }
/* /Components/UI/v2/LeaderboardGap.razor.rz.scp.css */
.fm-lb__gap--dots[b-0hefryv79z]::before { content: "· · ·"; }
/* /Components/UI/v2/LeaderboardRow.razor.rz.scp.css */
/* The rank's column grows for a rank wider than it (your pinned row's "212"); the name's 1fr absorbs it, so the columns
   right of it still line up with every other row (known-issues.md #5). */
.fm-lbrow[b-x5rcbo7k41] { grid-template-columns: minmax(44px, max-content) minmax(0, 1fr) 150px 80px 64px 56px; }
.fm-lbrow__name[b-x5rcbo7k41] { min-width: 0; white-space: nowrap; }
.fm-lbrow__who[b-x5rcbo7k41] { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.fm-lbrow__name[b-x5rcbo7k41]  .fm-inputtag--compact { margin-left: 2px; }
/* From the prototype's app.css: below 768 px the row is rank · name · tier emblem · ELO · W/L; the tier's name and the
   streak go. */
@media (max-width: 767px) {
    .fm-lbrow[b-x5rcbo7k41] { grid-template-columns: minmax(30px, max-content) minmax(0, 1fr) 20px 52px 50px; gap: var(--space-2); padding: 0 var(--space-3); }
    .fm-lbrow__tier[b-x5rcbo7k41]  .fm-tier__name { display: none; }
    .fm-lbrow[b-x5rcbo7k41]  .fm-winstreak { display: none; }
}
/* Below 400 px your row drops its YOU badge (the highlight says it), and every row its avatar: it is the same bear for
   everyone, and at 320 px the name would keep a letter or two beside it (known-issues.md #5). */
@media (max-width: 399px) {
    .fm-lbrow--you[b-x5rcbo7k41]  .fm-badge { display: none; }
    .fm-lbrow__name[b-x5rcbo7k41]  .fm-avatar { display: none; }
}
/* known-issues.md #3: in Polar day the gold tier name on your row's accent-soft tint is 4.45:1; it reads in ink-strong
   there (the emblem keeps the tier's colour). */
[data-theme="light"] .fm-lbrow--you .fm-lbrow__tier[b-x5rcbo7k41]  .fm-tier__name { color: var(--ink-strong) !important; }
/* /Components/UI/v2/MasteryEmblem.razor.rz.scp.css */
.fm-emblem[b-k6k1ev4zpq] {
    display: inline-flex;
    flex: none;
    line-height: 0;
}

/* The design system's MROLE styles (ds.js). The ring and the cut lines take the surface colour, so they read as holes
   in the emblem on either theme. */
.fm-role-ring[b-k6k1ev4zpq]    { fill: var(--surface-3); stroke: currentColor; stroke-width: 2; stroke-linejoin: bevel; }
.fm-role-line[b-k6k1ev4zpq]    { fill: none; stroke: currentColor; stroke-width: 2; }
.fm-role-fill[b-k6k1ev4zpq]    { fill: currentColor; }
.fm-role-cutline[b-k6k1ev4zpq] { fill: none; stroke: var(--surface-3); stroke-width: 2; }
/* /Components/UI/v2/MatchmakingPanel.razor.rz.scp.css */
.fm-mm__status[b-c1rychqado] { text-align: center; min-height: 44px; }
/* The line keeps two lines' height in every phase: "Your first match is against IceBot, our practice bot." wraps at
   320 px and "Opponent found" does not, so a one-line reserve moved the VS row by a line when the match was found. */
.fm-mm__line[b-c1rychqado] { margin: 6px 0 0; min-height: calc(2 * 1.4em); font: 600 15px/1.4 var(--font-body); color: var(--ink); }
.fm-mm__chips[b-c1rychqado] { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 6px; }
.fm-mm__name--searching[b-c1rychqado] { color: var(--ink-subtle); }
.fm-mm__found[b-c1rychqado] { margin: 0; min-height: 20px; text-align: center; color: var(--correct); font: 600 15px/1.3 var(--font-body); }
.fm-mm__warn[b-c1rychqado] { color: var(--warn); }
.fm-mm__slot[b-c1rychqado] { display: grid; }
.fm-mm__info[b-c1rychqado] { display: flex; flex-direction: column; gap: var(--space-4); }
.fm-mm__slot > *[b-c1rychqado] { grid-row: 1; grid-column: 1; align-self: start; min-width: 0; }
.fm-mm__hidden[b-c1rychqado] { visibility: hidden; }
/* The scoring rule takes two lines at 320 px (its full wording; owner's decision, 26 Oct 2026); its box keeps two
   lines' height at every width, so the rule reads the same wherever it wraps. */
.fm-mm__rule > span[b-c1rychqado] { display: flex; align-items: center; min-height: calc(2 * 1.45em); }
.fm-mm[b-c1rychqado]  .fm-mm__note { min-height: 36px; }
.fm-mm__card[b-c1rychqado]  .fm-inputtag { margin-top: 2px; }

/* known-issues.md #2: at 320 px both cards share the row equally and stay inside the gutters; names ellipsize; below
   400 px the VS mark is 14 px, the gap 8 px, and the InputTag 22 px tall with 12 px text, 6 px padding and a 12 px icon. */
.fm-mm__vs[b-c1rychqado] { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
.fm-mm__card[b-c1rychqado] { min-width: 0; }
.fm-mm__card .fm-mm__name[b-c1rychqado] { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 400px) {
    .fm-mm__card[b-c1rychqado] { min-height: 132px; padding: var(--space-3); }
    .fm-mm__facts[b-c1rychqado] { gap: 6px; }
    .fm-fact[b-c1rychqado] { padding: var(--space-2) 4px; }
    .fm-fact b[b-c1rychqado] { font-size: 12px; }
}
@media (max-width: 399px) {
    .fm-mm__vs[b-c1rychqado] { gap: var(--space-2); }
    /* The offer's two full-width buttons keep one line in pt-PT ("JOGAR VS ICEBOT · 20", "CONTINUAR À ESPERA"). */
    .fm-offer[b-c1rychqado]  .fm-btn { font-size: 13px; letter-spacing: 1px; }
    .fm-mm__vsmark[b-c1rychqado] { font-size: 14px; letter-spacing: 1px; }
    .fm-mm__card[b-c1rychqado]  .fm-inputtag { height: 22px; padding: 0 6px; font-size: 12px; letter-spacing: .3px; gap: 4px; }
    .fm-mm__card[b-c1rychqado]  .fm-inputtag svg { width: 12px; height: 12px; }
}
/* /Components/UI/v2/MatchResult.razor.rz.scp.css */
.fm-result__vs[b-85pibnkicq] { display: inline-flex; align-items: center; gap: 2px; font: 500 13px/1.4 var(--font-body); color: var(--ink-muted); }
.fm-result__vs[b-85pibnkicq]  .fm-inputtag--compact { margin-left: 4px; }
.fm-result__vssep[b-85pibnkicq] { margin: 0 6px; color: var(--ink-faint); }
.fm-result__them[b-85pibnkicq] { color: var(--ink-muted); }
.fm-result__micro[b-85pibnkicq] { display: inline-flex; align-items: center; gap: 6px; min-height: 20px; font: 500 13px/1.4 var(--font-body); color: var(--ink-muted); }
.fm-result[b-85pibnkicq]  .fm-rating { flex-wrap: wrap; justify-content: center; }
.fm-result[b-85pibnkicq]  .fm-result__inpnote { text-align: left; width: 100%; font-size: 13px; padding: var(--space-3); }

/* known-issues.md #1: the three stat tiles fit inside the card at 320 px: equal columns that can shrink; below 400 px the
   value drops to 16 px and the label is 12 px with no tracking, tiles padded 8 × 4 px, gap 6 px, labels on one line. */
.fm-stats[b-85pibnkicq] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.fm-stat[b-85pibnkicq] { min-width: 0; }
@media (max-width: 399px) {
    .fm-result[b-85pibnkicq] { padding: var(--space-4); }
    .fm-stats[b-85pibnkicq] { gap: 6px; }
    .fm-stat[b-85pibnkicq] { padding: var(--space-2) 4px; }
    .fm-stat b[b-85pibnkicq] { font-size: 16px; white-space: nowrap; }
    .fm-stat span[b-85pibnkicq] { font-size: 12px; letter-spacing: 0; }
}
/* /Components/UI/v2/MatchRow.razor.rz.scp.css */
.fm-mrow__what[b-jsa4ou1miv] { display: flex; flex-direction: column; min-width: 0; }
/* The name truncates; the opponent's input tag after it never does. */
.fm-mrow__opp[b-jsa4ou1miv] { display: flex; align-items: center; min-width: 0; white-space: nowrap; }
.fm-mrow__name[b-jsa4ou1miv] { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.fm-mrow__meta[b-jsa4ou1miv] { display: inline-flex; align-items: center; gap: 6px; }
.fm-mrow__elo--up[b-jsa4ou1miv] { color: var(--correct); }
.fm-mrow__elo--down[b-jsa4ou1miv] { color: var(--wrong); }
.fm-mrow__elo--none[b-jsa4ou1miv] { color: var(--ink-subtle); }
/* From the prototype's app.css: below 768 px the ELO, the chevron and the end reason go. The meta line keeps two lines
   there (it wraps on a narrow phone; a third is cut with an ellipsis), so every row, and its loading shape, has one height. */
@media (max-width: 767px) {
    .fm-mrow[b-jsa4ou1miv] { grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--space-3); }
    .fm-mrow__elo[b-jsa4ou1miv], .fm-mrow[b-jsa4ou1miv]  .fm-mrow__chev, .fm-mrow__reason[b-jsa4ou1miv] { display: none; }
    .fm-mrow__meta[b-jsa4ou1miv] { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
        line-height: 1.35; min-height: 2.7em; }
    .fm-mrow__meta[b-jsa4ou1miv]  svg { display: inline-block; vertical-align: -2px; margin-right: 6px; }
    .fm-mrow--loading .fm-mrow__meta[b-jsa4ou1miv] { display: flex; align-items: flex-start; }
}
/* /Components/UI/v2/Menu.razor.rz.scp.css */
/* A click outside closes the menu: a transparent backdrop under the panel. From the prototype's app.css ("Overlays"). */
.fm-menu-scrim[b-abhru3ea38] { position: fixed; inset: 0; z-index: var(--z-dialog); background: transparent; }
.fm-menu[b-abhru3ea38] { position: relative; z-index: var(--z-dialog); }
/* ds.css's fixed 220 px wraps a longer label ("Histórico de partidas"): the menu takes its longest item, from 220 px,
   and never more than the screen less its gutters (step 7f). */
.fm-menu[b-abhru3ea38] { width: max-content; min-width: 220px; max-width: calc(100vw - 2 * var(--space-4)); }
.fm-menu--anchored[b-abhru3ea38] { position: fixed; top: calc(var(--top-bar-height) - 4px); right: var(--space-6); }
@media (max-width: 767px) {
    .fm-menu--anchored[b-abhru3ea38] { top: auto; bottom: calc(var(--bottom-bar-height) + 8px); right: var(--space-4); }
}
/* /Components/UI/v2/ModeTile.razor.rz.scp.css */
/* From the prototype's app.css: the wide tile spans its row, and below 480 px it wraps, its aside under the body. */
.fm-tile--wide[b-t2ssnksvwb] { max-width: none; }
@media (max-width: 479px) {
    .fm-tile--wide[b-t2ssnksvwb] { flex-wrap: wrap; }
    .fm-tile--wide .fm-tile__aside[b-t2ssnksvwb] { width: 100%; text-align: left; }
}
.fm-tile__aside[b-t2ssnksvwb] { font-variant-numeric: tabular-nums; }

/* A tile with a control of its own (the VS BOT tile's difficulty): the press covers the tile under its content, so a tap
   anywhere but the control starts the mode, and its focus ring is the tile's outline; the control sits above it. */
.fm-tile__press[b-t2ssnksvwb] { position: absolute; inset: 0; z-index: 0; padding: 0; border: 0; border-radius: inherit; background: none; cursor: pointer; }
.fm-tile--split > :not(.fm-tile__press)[b-t2ssnksvwb] { position: relative; pointer-events: none; }
.fm-tile__control[b-t2ssnksvwb] { position: relative; z-index: 1; display: inline-flex; min-width: 0; pointer-events: auto; }
/* /Components/UI/v2/Notice.razor.rz.scp.css */
/* A Block's action sits a little below its text, as in the design system's preview (margin-top 8px). */
.fm-notice__action[b-s5zzp8y9tr] { margin-top: var(--space-2); }
/* /Components/UI/v2/NumPad.razor.rz.scp.css */
/* The pad's only pressed look is numpad.js's data-pressed (frost-motion.css): ds.css's :active is taken away, since on
   Chromium/Android it came on again for ~130 ms after a quick tap had lifted (a second, darker press). */
.fm-key:active[b-pqfqkcks4r] { transform: none; background: var(--surface-3); border-color: var(--border-subtle); }
.fm-key--clear:active[b-pqfqkcks4r] { background: var(--warn-soft); border-color: var(--warn); }
.fm-key--submit:active[b-pqfqkcks4r] { background: var(--accent); border-color: var(--accent); }
/* From the prototype's app.css: the display centres its digits. */
.fm-pad__display[b-pqfqkcks4r] { display: flex; align-items: center; justify-content: center; }
.fm-pad__digits[b-pqfqkcks4r] { display: inline-flex; }
/* /Components/UI/v2/PlayerCard.razor.rz.scp.css */
/* The card in the match HUD (the prototype's app.css, ".hud"): two cards share the row with the timer between them, so
   the card is compact (40 px avatar from 640 px, a 22 px score, 20 px chips) and never wider than its half. */
.fm-player[b-slxdtstsxu] { max-width: none; padding: var(--space-2); gap: var(--space-2); position: relative; }
.fm-player__avatar[b-slxdtstsxu] { display: none; flex: none; line-height: 0; }
.fm-player__meta[b-slxdtstsxu] { min-width: 0; }
.fm-player__name[b-slxdtstsxu] { font-size: 14px; }
.fm-player__score[b-slxdtstsxu] { position: relative; font-size: 22px; width: 1.6ch; }
.fm-player__chips[b-slxdtstsxu] { min-height: 20px; overflow: hidden; flex-wrap: nowrap; }
.fm-player__chips[b-slxdtstsxu]  .fm-badge { height: 20px; font-size: 12px; padding: 0 5px; letter-spacing: 0.4px; }
@media (min-width: 640px) {
    .fm-player[b-slxdtstsxu] { padding: var(--space-3); gap: var(--space-3); }
    .fm-player__avatar[b-slxdtstsxu] { display: inline-flex; }
}
@media (min-width: 768px) { .fm-player__score[b-slxdtstsxu] { font-size: 28px; } }
/* Below 640 px the name and the score share the first row and the chips span the card under them, so NOT READY fits. */
@media (max-width: 639px) {
    .fm-player[b-slxdtstsxu] { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "name score" "chips chips"; align-items: center; row-gap: 4px; }
    .fm-player--right[b-slxdtstsxu] { grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "score name" "chips chips"; }
    .fm-player__meta[b-slxdtstsxu] { display: contents; }
    .fm-player__namerow[b-slxdtstsxu] { grid-area: name; }
    .fm-player__chips[b-slxdtstsxu] { grid-area: chips; }
    .fm-player__score[b-slxdtstsxu] { grid-area: score; }
    .fm-player--tworows .fm-player__chips[b-slxdtstsxu] { flex-wrap: wrap; align-content: flex-start; row-gap: 4px; min-height: 44px; }
}
/* Compact up to 374 px, so every "Guest-" plus 2 characters name fits the card (card #254, measured in a browser);
   375–399 px tightens the name's tracking a little for the same reason. */
@media (max-width: 374px) {
    .fm-player[b-slxdtstsxu] { padding: 6px; gap: 4px; }
    .fm-player__name[b-slxdtstsxu] { font-size: 13px; }
    .fm-player__score[b-slxdtstsxu] { font-size: 20px; width: 1.3ch; }
    .fm-player__chips[b-slxdtstsxu]  .fm-badge { padding: 0 4px; letter-spacing: .2px; }
}
.fm-player__value[b-slxdtstsxu] { display: inline-block; }
/* Centred with translate, so score-float's transform (its rise) adds to it. */
.fm-player__float[b-slxdtstsxu] { position: absolute; top: -12px; left: 50%; translate: -50% 0; font: 600 14px/1 var(--font-display);
    color: var(--correct); pointer-events: none; }
.fm-player__float.fm-delta--rival[b-slxdtstsxu] { color: var(--ink-subtle); }
/* The name row keeps the compact InputTag beside the name, mirrored on the right. */
.fm-player__namerow[b-slxdtstsxu] { display: flex; align-items: center; min-width: 0; }
.fm-player--right .fm-player__namerow[b-slxdtstsxu] { flex-direction: row-reverse; }
.fm-player--right .fm-player__namerow[b-slxdtstsxu]  .fm-inputtag--compact { margin: 0 6px 0 0; }
@media (min-width: 375px) and (max-width: 399px) { .fm-player__name[b-slxdtstsxu] { letter-spacing: -0.25px; } }
@media (max-width: 374px) { .fm-player__namerow[b-slxdtstsxu]  .fm-inputtag--compact { margin-left: 4px; } }
/* /Components/UI/v2/QuestionCard.razor.rz.scp.css */
/* Never truncated, always the largest element: the expression takes the design system's size (36 / 48 / 60 px at base
   / md / xl) or the size that fits its length in the card, whichever is smaller. The card is a size container, and
   --q-len (the expression's characters, set by the component) with ~0.9 em per Orbitron character gives the fit.
   The line keeps the full size's height whatever the fit, the blank and the skeleton too, so the card is one height
   from question to question and nothing under it moves (CLAUDE.md §15). */
.fm-q[b-qpvdgeglo4] { container-type: inline-size; --q-size: 36px; }
@media (min-width: 768px) { .fm-q[b-qpvdgeglo4] { --q-size: 48px; } }
@media (min-width: 1280px) { .fm-q[b-qpvdgeglo4] { --q-size: 60px; } }
.fm-q__text[b-qpvdgeglo4] { font-size: min(var(--q-size), calc(100cqi / (var(--q-len, 6) * 0.9))); height: var(--q-size);
    display: flex; align-items: center; justify-content: center; }
/* From the prototype's app.css (.mx-q): below 400 px the card is a little tighter. */
@media (max-width: 399px) {
    .fm-q[b-qpvdgeglo4] { padding: var(--space-4) var(--space-4) var(--space-6); --q-size: clamp(28px, 10vw, 36px); }
}
.fm-q__skel[b-qpvdgeglo4] { display: flex; justify-content: center; align-items: center; height: var(--q-size); }
/* The label row keeps the operation icon's height (18 px) with or without it, so the blank card before the first
   question is the playing card's height. */
.fm-q__label[b-qpvdgeglo4] { min-height: 18px; }
/* /Components/UI/v2/RaceTrack.razor.rz.scp.css */
/* The v2 lane layout from the prototype's motion.css (each lane labelled, its own bar and finish), over the race
   classes in frost-motion.css, which hold the colours and the motion. */
.fm-racetrack[b-8vrt82u87d] { width: 100%; max-width: 560px; display: flex; flex-direction: column; gap: 6px; isolation: isolate; }
.race-row[b-8vrt82u87d] { position: relative; display: grid; grid-template-columns: 44px 1fr; align-items: center; gap: var(--space-2); height: auto; }
.race-who[b-8vrt82u87d] { font: 600 12px/1 var(--font-body); color: var(--ink-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.race-row-me .race-who[b-8vrt82u87d] { color: var(--accent-text); }
.race-bar[b-8vrt82u87d] { position: relative; height: 6px; }
.race-row-opp .race-bar[b-8vrt82u87d] { height: 3px; }
.race-head.is-miss[b-8vrt82u87d] { opacity: 0.35; }
.fm-racetrack__rule[b-8vrt82u87d] { margin: var(--space-1) 0 0; font: 500 12px/1.4 var(--font-body); color: var(--ink-subtle); text-align: center; }
/* /Components/UI/v2/RatingBlock.razor.rz.scp.css */
.fm-rating__move[b-86lmqh4ol3] { display: flex; align-items: center; gap: 4px; margin-top: 2px; }
.fm-rating__move--up[b-86lmqh4ol3] { color: var(--correct); }
.fm-rating__move--down[b-86lmqh4ol3] { color: var(--wrong); }
/* /Components/UI/v2/RematchButton.razor.rz.scp.css */
/* The drain's easing and the accept state's pulse (still under reduced motion) are frost-motion.css's. */
.fm-rematch__reason[b-yutb0b5zt7] { margin: var(--space-1) 0 0; min-height: 20px; text-align: center; font: 500 12px/20px var(--font-body); color: var(--ink-subtle); }
.fm-rematch__caption[b-yutb0b5zt7] { margin: 0; text-align: center; }
/* The label keeps one line and truncates in all four states (CLAUDE.md §15): the Button's label span may shrink. */
.fm-rematch[b-yutb0b5zt7]  .fm-btn { min-width: 0; }
/* /Components/UI/v2/RoundStatus.razor.rz.scp.css */
.fm-status__answer[b-7bb7je5l8e] { font-family: var(--font-mono); }
/* /Components/UI/v2/ShareBox.razor.rz.scp.css */
.fm-share__status-manual[b-t2q3dgb4zl] { font: 600 13px/20px var(--font-body); color: var(--ink-muted); }
.fm-share__status[b-t2q3dgb4zl] { margin: 0; }
/* /Components/UI/v2/SkillsGrid.razor.rz.scp.css */
.fm-skillsgrid[b-pb91oj6v3q] { display: flex; flex-direction: column; gap: var(--space-4); width: 100%; max-width: 720px; }
.fm-skills-wrap[b-pb91oj6v3q] { overflow-x: auto; }
.fm-skillsgrid__weakest[b-pb91oj6v3q] { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); min-height: 44px; }
.fm-skillsgrid__weakline[b-pb91oj6v3q] { font: 600 14px/1.4 var(--font-body); color: var(--ink); }
.fm-skillsgrid__mastery[b-pb91oj6v3q] { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; font: 500 12px/1.45 var(--font-body); color: var(--ink-muted); }
.fm-skillsgrid__mastery li[b-pb91oj6v3q] { min-height: 17px; }
.fm-skillsgrid__mop[b-pb91oj6v3q] { font-weight: 600; color: var(--ink); }
.fm-skills__short[b-pb91oj6v3q] { display: none; }
/* From the prototype's app.css: below 640 px the grid fits 320 px (an 84 px row head, cells that shrink). A band's head
   says its range alone there: "difficulty 7–10" ran past its column (pt-PT's "dificuldade" by 18 px). */
@media (max-width: 639px) {
    .fm-skills__long[b-pb91oj6v3q] { display: none; }
    .fm-skills__short[b-pb91oj6v3q] { display: inline; }
    .fm-skills[b-pb91oj6v3q] { grid-template-columns: 84px repeat(3, minmax(0, 1fr)); }
    .fm-cell[b-pb91oj6v3q] { min-width: 0; min-height: 64px; padding: 6px; }
    .fm-cell b[b-pb91oj6v3q] { font-size: 14px; flex-wrap: wrap; gap: 2px 4px; }
    .fm-skills__op[b-pb91oj6v3q] { font-size: 12px; flex-wrap: wrap; gap: 4px; }
}
/* /Components/UI/v2/SoloResult.razor.rz.scp.css */
/* The prototype's result card: centred, the big time in the display face (44 px below md, 56 px from md). */
.fm-solo-wrap[b-j3y6f8nibd] { display: contents; }
.fm-solo-wrap[b-j3y6f8nibd]  .fm-solo { width: 100%; max-width: 480px; display: flex; flex-direction: column; align-items: center; gap: var(--space-3); text-align: center; }
.fm-solo__time[b-j3y6f8nibd] { font: 600 44px/1 var(--font-display); color: var(--ink-strong); font-variant-numeric: tabular-nums; }
@media (min-width: 768px) { .fm-solo__time[b-j3y6f8nibd] { font-size: 56px; } }
.fm-solo__caption[b-j3y6f8nibd] { margin-top: calc(-1 * var(--space-2)); }
.fm-solo__correct[b-j3y6f8nibd] { font: 600 15px/1.4 var(--font-body); color: var(--ink); }
/* Balanced, so a wrapped verdict never leaves its unit alone on the second line ("… by 39.8 / s"). */
.fm-solo__cmp[b-j3y6f8nibd] { min-height: 22px; font: 600 15px/1.45 var(--font-body); color: var(--ink); text-wrap: balance; }
.fm-solo__next[b-j3y6f8nibd] { min-height: 20px; font: 500 13px/1.5 var(--font-mono); color: var(--ink-muted); }
.fm-solo__actions[b-j3y6f8nibd] { width: 100%; display: flex; flex-direction: column; gap: var(--space-2); }
/* /Components/UI/v2/StatTile.razor.rz.scp.css */
.fm-stattile__sub[b-m1qor3lwyr] { min-height: 17px; }
.fm-stattile__live[b-m1qor3lwyr] { display: flex; align-items: center; gap: 4px; min-width: 0; }
/* A held sub-line: the longest line it can say sits unseen in the live line's cell, so the tile keeps its height. */
.fm-stattile__sub--held[b-m1qor3lwyr] { display: grid; }
.fm-stattile__sub--held > *[b-m1qor3lwyr] { grid-area: 1 / 1; }
.fm-stattile__reserve[b-m1qor3lwyr] { visibility: hidden; }
/* /Components/UI/v2/StreakCard.razor.rz.scp.css */
.fm-streakcard__freeze[b-s44h7dp5oo] { margin-left: auto; align-self: center; }
.fm-streakcard__help[b-s44h7dp5oo] { margin: var(--space-4) 0 var(--space-3); }
.fm-streakcard__gap[b-s44h7dp5oo] { height: var(--space-4); }
/* The share slot is held whether a milestone is earned yet or not, and while the card loads, so the card keeps one
   height and nothing under it moves (§15). */
.fm-streakcard__share[b-s44h7dp5oo] { min-height: var(--fm-streakcard-share, 76px); }
/* On a narrow phone "Freeze ready" takes its own line under the numbers rather than wrapping beside them (quality-pass);
   the line is held while the freeze is unknown or not held. */
@media (max-width: 399px) {
    .fm-streak__nums[b-s44h7dp5oo] { flex-wrap: wrap; row-gap: var(--space-2); }
    .fm-streakcard__freeze[b-s44h7dp5oo] { flex-basis: 100%; margin-left: 0; min-height: 22px; display: flex; align-items: center; }
}
/* /Components/UI/v2/Tabs.razor.rz.scp.css */
/* A tab's label keeps one line; on a narrow phone the tabs give up some padding so three fit 288 px in pt-PT too. */
.fm-tab[b-0lsgxn9aub] { white-space: nowrap; }
@media (max-width: 399px) { .fm-tab[b-0lsgxn9aub] { padding: 0 var(--space-3); } }
/* /Components/UI/v2/TextField.razor.rz.scp.css */
/* The design system's Input has a Disabled state (opacity-disabled) that ds.css doesn't style. */
.fm-input.is-disabled[b-lm3gkrjvjs] { opacity: var(--opacity-disabled); }
.fm-input.is-disabled:hover[b-lm3gkrjvjs] { border-color: var(--border-control); }
/* /Components/UI/v2/TierEmblem.razor.rz.scp.css */
.fm-emblem[b-tiffpkdj9c] {
    display: inline-flex;
    flex: none;
    line-height: 0;
}

/* The design system's ROLE styles (ds.js). The tier colour is currentColor; the white and black at fixed opacities are
   the emblem's own light and shade over it, the same in both themes. */
.fm-role-base[b-tiffpkdj9c] { fill: currentColor; stroke: rgba(0, 0, 0, 0.38); stroke-width: 1.4; stroke-linejoin: bevel; }
.fm-role-hi[b-tiffpkdj9c]   { fill: #ffffff; fill-opacity: 0.28; }
.fm-role-lo[b-tiffpkdj9c]   { fill: #000000; fill-opacity: 0.18; }
.fm-role-cut[b-tiffpkdj9c]  { fill: rgba(0, 0, 0, 0.45); }
.fm-role-cut2[b-tiffpkdj9c] { fill: #ffffff; fill-opacity: 0.55; }
.fm-role-edge[b-tiffpkdj9c] { fill: none; stroke: rgba(0, 0, 0, 0.3); stroke-width: 1; }
.fm-role-line[b-tiffpkdj9c] { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linejoin: bevel; }
.fm-role-dash[b-tiffpkdj9c] { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linejoin: bevel; stroke-dasharray: 4.2 2.6; }
/* /Components/UI/v2/Toast.razor.rz.scp.css */
/* The drain bar's animation (and its stillness under reduced motion) is frost-motion.css's; this component sets its
   duration and pauses it while hovered. */
.fm-toast__action[b-9p4ymhbtjl] { margin: var(--space-1) 0 0 calc(-1 * var(--space-2)); }
/* /Components/UI/v2/ToastHost.razor.rz.scp.css */
/* From the prototype's app.css (#toasts): top-centre, full width but 12 px gutters, on phones; top-right under the top
   bar from md. The host lets clicks through except on the toasts themselves. */
.fm-toasts[b-5acq55kngw] { position: fixed; z-index: var(--z-toast); top: calc(env(safe-area-inset-top, 0px) + var(--space-3)); left: var(--space-3);
    right: var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); align-items: center; pointer-events: none; }
.fm-toasts[b-5acq55kngw] >  * { pointer-events: auto; }
@media (min-width: 768px) {
    .fm-toasts[b-5acq55kngw] { left: auto; right: var(--space-6); top: calc(var(--top-bar-height) + var(--space-3)); align-items: flex-end; width: 360px; }
}
/* /Components/UI/v2/XpBar.razor.rz.scp.css */
/* The design system's level-up chip (its preview): filled xp, dark text. A capped 0's gain reads quiet. */
.fm-xp__lvl--up[b-2apmv97lvi] { background: var(--xp); color: var(--surface-0); }
.fm-xp__gain--zero[b-2apmv97lvi] { color: var(--ink-subtle); }
.fm-xp__note[b-2apmv97lvi] { min-height: 17px; }
/* /Pages/Authentication/AuthPanel.razor.rz.scp.css */
/* From the prototype's app.css (.page--narrow .page--center, .auth-card, .auth-brand) and its password cards: the text
   centred, a field's label at its left, the Primary action across the card, the Text links centred under it. The page
   clears the shell's bottom bar itself, as every page does by the shell's convention (AppShell, PadMain off). */
.auth-panel-page[b-13vjfu7hpg] { width: 100%; display: flex; justify-content: center;
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .auth-panel-page[b-13vjfu7hpg] { padding: var(--space-10) var(--space-6) var(--space-16); } }

.auth-panel-col[b-13vjfu7hpg] { width: 100%; max-width: 440px; display: flex; flex-direction: column; gap: var(--space-4); }
.auth-panel-brand[b-13vjfu7hpg] { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); text-align: center; }
.auth-panel-brand img[b-13vjfu7hpg] { width: 56px; height: 56px; }
.auth-panel-brand__name[b-13vjfu7hpg] { font-size: 22px; }

.auth-panel-col[b-13vjfu7hpg]  .auth-panel { display: flex; flex-direction: column; gap: var(--space-3); text-align: center; }
.auth-panel-col[b-13vjfu7hpg]  .auth-panel form { display: flex; flex-direction: column; gap: var(--space-3); }
.auth-panel-col[b-13vjfu7hpg]  .auth-panel .fm-field { text-align: left; }
.auth-panel-col[b-13vjfu7hpg]  .auth-panel__icon { align-self: center; }
.auth-panel-col[b-13vjfu7hpg]  .auth-panel__icon--accent { color: var(--accent-text); }
.auth-panel-col[b-13vjfu7hpg]  .auth-panel__icon--correct { color: var(--correct); }
.auth-panel-col[b-13vjfu7hpg]  .auth-panel__icon--wrong { color: var(--wrong); }
.auth-panel-col[b-13vjfu7hpg]  .auth-panel__title { margin: 0; }
.auth-panel-col[b-13vjfu7hpg]  .auth-panel__title:focus { outline: none; }
.auth-panel-col[b-13vjfu7hpg]  .auth-lede { margin: 0; font: 400 15px/1.55 var(--font-body); color: var(--ink-muted); overflow-wrap: anywhere; }
.auth-panel-col[b-13vjfu7hpg]  .auth-lede b { color: var(--ink-strong); font-weight: 600; }
.auth-panel-col[b-13vjfu7hpg]  .auth-panel__link { align-self: center; }
/* Confirm email's new-link form: the address and the Secondary send, under the Primary. */
.auth-panel-col[b-13vjfu7hpg]  .auth-newlink { display: flex; flex-direction: column; gap: var(--space-3); margin-top: var(--space-2); }
/* Below 400 px a full-width button keeps 12 px a side, so every label fits one line at 320 px ("Request a new link" is
   219 px against 217). */
@media (max-width: 399px) { .auth-panel-col[b-13vjfu7hpg]  .auth-panel .fm-btn--full { padding-inline: var(--space-3); } }
/* /Pages/Authentication/Index.razor.rz.scp.css */
/* Sign in / Register on v2 (redesign step 7e), from the prototype's app.css (.page--narrow .page--center, .auth-card,
   .auth-brand): a narrow column, top-aligned, so the brand never moves. The page clears the shell's bottom bar itself,
   as every page does by the shell's convention (AppShell, PadMain off). */
.auth[b-82xibcld6v] { width: 100%; display: flex; justify-content: center;
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .auth[b-82xibcld6v] { padding: var(--space-10) var(--space-6) var(--space-16); } }

.auth-card[b-82xibcld6v] { width: 100%; max-width: 440px; display: flex; flex-direction: column; gap: var(--space-4); }
.auth-brand[b-82xibcld6v] { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); text-align: center; }
.auth-brand img[b-82xibcld6v] { width: 56px; height: 56px; }
.auth-brand__name[b-82xibcld6v] { font-size: 22px; }

.auth[b-82xibcld6v]  .auth-form-card { display: flex; flex-direction: column; }
.auth[b-82xibcld6v]  .auth-form-card .fm-tabs { margin-bottom: var(--space-2); }
/* EditForm draws the <form>, so it carries EditForm's scope, not this page's: reached through ::deep. */
.auth[b-82xibcld6v]  .auth-form { display: flex; flex-direction: column; gap: var(--space-3); }
.auth-links[b-82xibcld6v] { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0 var(--space-3); margin-top: var(--space-2); }
.auth-links[b-82xibcld6v]  .fm-btn { white-space: nowrap; }

/* Check your inbox: centred, the card's own column. */
.auth[b-82xibcld6v]  .auth-inbox { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); text-align: center; }
.auth[b-82xibcld6v]  .auth-inbox__icon { color: var(--accent-text); }
.auth-inbox__title[b-82xibcld6v] { margin: 0; }
.auth-inbox__title:focus[b-82xibcld6v] { outline: none; }
.auth-lede[b-82xibcld6v] { margin: 0; font: 400 15px/1.55 var(--font-body); color: var(--ink-muted); overflow-wrap: anywhere; }
.auth-lede b[b-82xibcld6v] { color: var(--ink-strong); font-weight: 600; }

.auth-footer[b-82xibcld6v] { text-align: center; }
.auth[b-82xibcld6v]  .auth-settings { align-self: center; }

/* Below 400 px a full-width button keeps 12 px a side, as on the other account pages. */
@media (max-width: 399px) { .auth[b-82xibcld6v]  .fm-btn--full { padding-inline: var(--space-3); } }

/* The 13+ and Terms box (card #286): ds.css has no checkbox, so a native one in the accent colour, on the TextField's
   rhythm (the row, then the one reserved help line, so an error moves nothing). The box is the 44 px touch target's
   visible part; the whole label is the target. */
.auth[b-82xibcld6v]  .auth-terms { max-width: none; }
.auth-terms__row[b-82xibcld6v] { display: flex; align-items: flex-start; gap: var(--space-3); min-height: 44px; cursor: pointer;
    font: 400 13px/1.5 var(--font-body); color: var(--ink-muted); }
.auth[b-82xibcld6v]  .auth-terms__box { flex: none; width: 20px; height: 20px; margin: 2px 0 0; accent-color: var(--accent); cursor: pointer; }
.auth-terms__row a[b-82xibcld6v] { color: var(--accent-text); text-decoration: underline; }
.auth-legal[b-82xibcld6v] { display: flex; justify-content: center; flex-wrap: wrap; gap: 0 var(--space-3); }
/* /Pages/Challenge/ChallengeInvite.razor.rz.scp.css */
/* The friend's page on v2 (redesign step 7d), from the prototype's app.css (.page, .page--narrow, .stack, .lede): one
   card, top-aligned at 560 px, so a state change only moves what is under the card (nothing). The page clears the
   shell's bottom bar itself, as every page does by the shell's convention (AppShell, PadMain off). */
.chal[b-0yzlwm8frc] { width: 100%; max-width: 560px; margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .chal[b-0yzlwm8frc] { padding: var(--space-10) var(--space-6) var(--space-16); } }

.chal[b-0yzlwm8frc]  .chal__card { display: flex; flex-direction: column; gap: var(--space-3); }

/* The card's head: the bear (or the state's icon), the line, then the friendly badge and the rules, centred. */
.chal__hero[b-0yzlwm8frc] { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); text-align: center; }
.chal__title[b-0yzlwm8frc] { font-size: 22px; line-height: 1.25; text-wrap: balance; }
.chal__hero[b-0yzlwm8frc]  .chal__hero-icon { color: var(--ink-subtle); }
.chal__lede[b-0yzlwm8frc] { margin: 0; font: 400 15px/1.55 var(--font-body); color: var(--ink-muted); }

.chal__loading[b-0yzlwm8frc] { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); color: var(--accent-text); padding: var(--space-4) 0; }
.chal__center[b-0yzlwm8frc] { text-align: center; }
.chal[b-0yzlwm8frc]  .chal__center { align-self: center; }

/* Below 400 px a full-width button in the card keeps 12 px a side, so every label fits one line at 320 px in pt-PT too. */
@media (max-width: 399px) { .chal[b-0yzlwm8frc]  .chal__card .fm-btn--full { padding-inline: var(--space-3); } }
/* "Challenge Ana": a long name is cut with an ellipsis rather than wrapping the button. */
.chal__label[b-0yzlwm8frc] { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Under 360 px the Friendly badge drops its icon: with it, "Friendly · no rating change" is 3 px wider than the card. */
@media (max-width: 359px) { .chal__hero[b-0yzlwm8frc]  .fm-badge [data-icon] { display: none; } }
/* /Pages/Challenge/NewChallenge.razor.rz.scp.css */
/* Challenge a friend on v2 (redesign step 7d), from the prototype's app.css (.page, .page--narrow, .head, .stack, .row,
   .lede): the head, then one card, top-aligned at 560 px so a state change only moves what is under the card (nothing).
   The page clears the shell's bottom bar itself, as every page does by the shell's convention (AppShell, PadMain off). */
.chal[b-ecab1mbgcb] { width: 100%; max-width: 560px; margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .chal[b-ecab1mbgcb] { padding: var(--space-10) var(--space-6) var(--space-16); gap: var(--space-8); } }

.chal__head[b-ecab1mbgcb] { display: flex; flex-direction: column; gap: var(--space-2); }
.chal[b-ecab1mbgcb]  .chal__card { display: flex; flex-direction: column; gap: var(--space-3); }
.chal__lede[b-ecab1mbgcb] { margin: 0; font: 400 15px/1.55 var(--font-body); color: var(--ink-muted); }
.chal[b-ecab1mbgcb]  .chal__share { max-width: none; }

/* The clock and Cancel on one line; on a narrow phone Cancel keeps its place at the end. */
.chal__row[b-ecab1mbgcb] { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3); }
.chal__row[b-ecab1mbgcb]  .fm-btn { white-space: nowrap; }
/* Who is looking: its row is held before a name arrives, so the line appearing moves nothing. */
.chal__looking[b-ecab1mbgcb] { margin: 0; min-height: 20px; display: flex; align-items: center; gap: 6px; color: var(--accent-text); }
.chal[b-ecab1mbgcb]  .chal__start { align-self: flex-start; }

/* Below 400 px a full-width button in the card keeps 12 px a side, so every label fits one line at 320 px in pt-PT too. */
@media (max-width: 399px) { .chal[b-ecab1mbgcb]  .chal__card .fm-btn--full { padding-inline: var(--space-3); } }
/* /Pages/Daily/DailySprint.razor.rz.scp.css */
/* The Daily on v2 (redesign step 6), from the prototype's app.css: Before is a narrow page (.page--narrow: the head, a
   link's notice, then the day's feature card); the results are SoloResult's card, centred. Both clear the shell's bottom
   bar themselves, as every page does by the shell's convention (AppShell, PadMain off). The run is SprintRun's own screen. */
.daily-page[b-62ghfy12pa] { width: 100%; max-width: 560px; margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .daily-page[b-62ghfy12pa] { padding: var(--space-10) var(--space-6) var(--space-16); gap: var(--space-8); } }
.daily-page--result[b-62ghfy12pa] { max-width: none; align-items: center; }
@media (min-width: 768px) { .daily-page--result[b-62ghfy12pa] { min-height: calc(100dvh - var(--top-bar-height)); justify-content: center; } }

/* Loading: the day's lines wait in their boxes, unseen. */
.daily-hidden[b-62ghfy12pa] { visibility: hidden; }

.daily-head[b-62ghfy12pa] { display: flex; flex-direction: column; gap: var(--space-2); }
.daily-lede[b-62ghfy12pa] { margin: 0; font: 400 15px/1.55 var(--font-body); color: var(--ink-muted); max-width: 60ch; }

.daily-page[b-62ghfy12pa]  .daily-card { display: flex; flex-direction: column; gap: var(--space-3); }
/* The reset clock and the streak share a row; below 400 px they stack (the streak line would wrap beside the clock),
   each in its own reserved line. */
.daily-card__top[b-62ghfy12pa] { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); min-height: 24px; }
@media (max-width: 399px) { .daily-card__top[b-62ghfy12pa] { flex-direction: column; align-items: flex-start; gap: var(--space-2); } }
.daily-card__top .fm-clock[b-62ghfy12pa] { min-height: 20px; }
.daily-streak[b-62ghfy12pa] { min-height: 20px; display: inline-flex; align-items: center; }
.daily-rule[b-62ghfy12pa] { margin: 0; font: 400 15px/1.55 var(--font-body); color: var(--ink-muted); }
.daily-rule b[b-62ghfy12pa] { color: var(--ink); font-weight: 600; }
.daily-guest[b-62ghfy12pa] { margin: 0; text-align: center; }

/* The results' own lines, each in a box that keeps its height whatever it holds (§15). */
.daily-race-outcome[b-62ghfy12pa] { margin: 0; min-height: 22px; font: 600 15px/1.45 var(--font-body); color: var(--ink); }
.daily-race-outcome.is-won[b-62ghfy12pa] { color: var(--correct); }
.daily-streak-box[b-62ghfy12pa] { min-height: 24px; display: flex; align-items: center; justify-content: center; }
.daily-xp[b-62ghfy12pa] { width: 100%; min-height: 28px; display: flex; align-items: center; }
.daily-xp[b-62ghfy12pa]  .fm-xp { width: 100%; }
.daily-actions[b-62ghfy12pa] { display: flex; flex-direction: column; gap: var(--space-2); }
.daily-ghost-slot[b-62ghfy12pa] { min-height: 48px; display: flex; }
.daily-share-status[b-62ghfy12pa] { margin: 0; min-height: 20px; text-align: center; font: 600 13px/20px var(--font-body); color: var(--correct); }
.daily-share-manual[b-62ghfy12pa] { display: flex; flex-direction: column; gap: var(--space-1); text-align: left; font: 500 12px/1.4 var(--font-body); color: var(--ink-muted); }
.daily-share-manual textarea[b-62ghfy12pa] { width: 100%; padding: var(--space-2); border-radius: var(--radius-sm); border: 1px solid var(--border-control);
    background: var(--surface-inset); color: var(--ink); font: 400 14px/1.4 var(--font-mono); resize: none; }

/* Below 400 px the secondary actions take PostMatch's smaller type (13 px, tighter tracking), so their labels keep one
   line in English and Portuguese; the dominant action keeps its own. */
@media (max-width: 399px) {
    .daily-actions[b-62ghfy12pa]  .fm-btn:not(.fm-btn--lg) { padding-inline: var(--space-3); font-size: 13px; letter-spacing: 0.5px; }
    /* The dominant action on one line inside the card ("PROCURAR ADVERSÁRIO"): the page and the card give it 12 px each
       side instead of 16. */
    .daily-actions[b-62ghfy12pa]  .fm-btn--lg { padding-inline: var(--space-3); font-size: 14px; letter-spacing: 0.5px; }
    .daily-page--result[b-62ghfy12pa] { padding-inline: var(--space-3); }
    .daily-page--result[b-62ghfy12pa]  .fm-solo { padding: var(--space-4) var(--space-3); }
}
@media (max-width: 359px) {
    .daily-actions[b-62ghfy12pa]  .fm-btn--lg { font-size: 13px; }
}

/* A guest's account link may wrap and shrink inside the card (Portuguese "Guardar a sequência…" scrolled the page
   sideways at 344 px and below, card #254, N-4). */
.daily-actions[b-62ghfy12pa]  .fm-btn--text { min-width: 0; max-width: 100%; height: auto; min-height: 44px; white-space: normal; overflow-wrap: anywhere; text-align: center; }

/* A short phone (402×710, 375×667; card #254): the results give back padding and gaps so a guest's account link, the last
   line, starts above the bottom bar at first view. Reserved boxes keep their heights; only the space around them shrinks. */
@media (max-width: 767px) and (max-height: 760px) {
    .daily-page--result[b-62ghfy12pa] { padding-top: var(--space-3); padding-bottom: calc(var(--bottom-bar-height) + var(--space-3)); gap: var(--space-3); }
    .daily-page--result[b-62ghfy12pa]  .fm-solo { padding-block: var(--space-3); gap: var(--space-2); }
    .daily-actions[b-62ghfy12pa] { gap: var(--space-1); }
}
/* /Pages/Debug/AnalyticsTest.razor.rz.scp.css */
/* The analytics smoke test (Development only): one centred column, clear of the bottom bar like every page. */
.analytics-test[b-lecpnsxzde] { min-height: 100dvh; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: var(--space-6); padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); text-align: center; }
.analytics-test__lede[b-lecpnsxzde] { max-width: 28rem; margin: 0; color: var(--ink-muted); }
.analytics-test__actions[b-lecpnsxzde] { display: flex; flex-direction: column; gap: var(--space-3); width: 100%; max-width: 20rem; }
/* /Pages/Debug/Playground.razor.rz.scp.css */
/* The design system's guideline arrives as HTML (DesignGuides.g.cs), so its elements carry no scope attribute: reach
   them through the wrapper. */
.playground-guide[b-chdx78fi0l]  p { margin: 0 0 0.75rem; }
.playground-guide[b-chdx78fi0l]  ul { margin: 0 0 0.75rem; padding-left: 1.25rem; list-style: disc; }
.playground-guide[b-chdx78fi0l]  li { margin-bottom: 0.25rem; }
.playground-guide[b-chdx78fi0l]  strong { color: var(--ink-strong); font-weight: 600; }
.playground-guide[b-chdx78fi0l]  code { font-family: var(--font-mono); font-size: 0.85em; color: var(--ink); background: var(--surface-2); border-radius: 4px; padding: 0 4px; }
.playground-guide[b-chdx78fi0l]  table { display: block; overflow-x: auto; border-collapse: collapse; margin: 0 0 0.75rem; }
.playground-guide[b-chdx78fi0l]  th,
.playground-guide[b-chdx78fi0l]  td { border-top: 1px solid var(--border-subtle); padding: 6px 12px 6px 0; text-align: left; vertical-align: top; }
/* /Pages/Game/Multiplayer/Matchmaking.razor.rz.scp.css */
/* From the prototype's app.css (.mm-page): one centred column over the game status bar, which is fixed at the bottom at
   every width. From md the shell's top bar shows, so the column fills the screen below it and never scrolls by 60 px. */
.mm-page[b-9lnkdnfoa8] { min-height: 100dvh; display: flex; flex-direction: column; align-items: center; gap: var(--space-4);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .mm-page[b-9lnkdnfoa8] { min-height: calc(100dvh - var(--top-bar-height)); justify-content: center; } }
/* A phone: a little tighter than the prototype, which pays for the status line's reserved second line, so a 320 x 640
   screen still holds the whole page without scrolling, in pt-PT too (its offer card, reserved under the facts, is a
   line taller). */
@media (max-width: 399px) {
    .mm-page[b-9lnkdnfoa8] { gap: var(--space-3); padding-top: var(--space-4); padding-bottom: calc(var(--bottom-bar-height) + var(--space-2)); }
    .mm-page[b-9lnkdnfoa8]  .fm-mm { gap: var(--space-3); }
}
.mm-mark[b-9lnkdnfoa8] { width: 56px; height: 56px; }

/* --bottom-bar-height holds the home indicator's inset: the bar's items sit above it. */
.mm-page[b-9lnkdnfoa8]  .fm-statusbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    padding-bottom: env(safe-area-inset-bottom, 0px); }

.mm-force--off[b-9lnkdnfoa8] { visibility: hidden; }
/* /Pages/Game/Multiplayer/MatchPostMatch.razor.rz.scp.css */
/* From the prototype's app.css (.pm): one column, at most 460 px, centred from md. The shell's top bar shows from md, so
   the column fills the screen below it. */
.pm[b-3dzhg49qcg] { min-height: 100dvh; display: flex; flex-direction: column; align-items: center; gap: var(--space-4);
    padding: var(--space-6) var(--space-4) var(--space-8); }
.pm > *[b-3dzhg49qcg] { width: 100%; max-width: 460px; }
@media (min-width: 768px) { .pm[b-3dzhg49qcg] { min-height: calc(100dvh - var(--top-bar-height)); justify-content: center; } }
.pm[b-3dzhg49qcg]  .fm-result { padding: var(--space-4); }
@media (min-width: 768px) { .pm[b-3dzhg49qcg]  .fm-result { padding: var(--space-6); } }
.pm[b-3dzhg49qcg]  .fm-rating { flex-wrap: wrap; justify-content: center; }

/* known-issues.md #1 is MatchResult's own; the boxes under it keep one height whatever they hold. */
.pm-xp[b-3dzhg49qcg] { min-height: 28px; display: flex; align-items: center; }
.pm-xp[b-3dzhg49qcg]  .fm-xp { width: 100%; }
.pm-streak[b-3dzhg49qcg] { min-height: 24px; display: flex; align-items: center; justify-content: center; }

.pm-actions[b-3dzhg49qcg] { display: flex; flex-direction: column; gap: var(--space-3); margin-top: var(--space-2); }
.pm-actions[b-3dzhg49qcg]  .fm-rematch { max-width: none; }
.pm-row[b-3dzhg49qcg] { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-3); }
/* The prototype's row: smaller text, so FIND ANOTHER MATCH and its Portuguese fit beside Home at 320 px. */
.pm-row[b-3dzhg49qcg]  .fm-btn { padding: 0 var(--space-3); letter-spacing: 1px; font-size: 13px; min-width: 0; }
/* "PROCURAR OUTRA PARTIDA", the pt-PT dominant action after an opponent who left or a cancelled match, needs a little less
   tracking until the column reaches its 460 px. */
@media (max-width: 459px) {
    .pm-actions[b-3dzhg49qcg]  .fm-btn--lg { letter-spacing: 1px; }
}
/* Below 360 px the pt-PT labels ("PROCURAR OUTRA PARTIDA", "ENCONTRAR UMA PESSOA") would wrap beside Home: the secondary
   button tightens to the 12 px floor; Home keeps its 44 px. */
@media (max-width: 359px) {
    .pm-row[b-3dzhg49qcg]  .fm-btn--secondary { padding: 0 var(--space-2); letter-spacing: 0.5px; font-size: 12px; }
    /* The dominant "PROCURAR OUTRA PARTIDA" (an opponent who left, a cancelled match) on one line too. */
    .pm-actions[b-3dzhg49qcg]  .fm-btn--lg { font-size: 14px; letter-spacing: 0.5px; }
}
.pm-links[b-3dzhg49qcg] { display: flex; justify-content: center; gap: var(--space-4); flex-wrap: wrap; }
.pm-share-status[b-3dzhg49qcg] { margin: 0; min-height: 20px; text-align: center; font: 600 13px/20px var(--font-body); color: var(--correct); }
.pm-share-manual[b-3dzhg49qcg] { display: flex; flex-direction: column; gap: var(--space-1); text-align: left; font: 500 12px/1.4 var(--font-body); color: var(--ink-muted); }
.pm-share-manual textarea[b-3dzhg49qcg] { width: 100%; padding: var(--space-2); border-radius: var(--radius-sm); border: 1px solid var(--border-control);
    background: var(--surface-inset); color: var(--ink); font: 400 14px/1.4 var(--font-mono); resize: none; }

/* A short phone (402×710, 375×667; card #254): a guest after IceBot fits without scrolling. Only the space around the
   boxes shrinks; every reserved box keeps its height and the dominant action its size. */
@media (max-width: 767px) and (max-height: 760px) {
    .pm[b-3dzhg49qcg] { gap: var(--space-3); padding-top: var(--space-3); padding-bottom: var(--space-3); }
    .pm[b-3dzhg49qcg]  .fm-result { padding: var(--space-3); }
    .pm-actions[b-3dzhg49qcg] { gap: var(--space-2); margin-top: 0; }
}
/* /Pages/Game/Multiplayer/QuickPlay.razor.rz.scp.css */
/* ─────────────────────────────────────────────────────────────────
   QuickPlay.razor.css — the match on v2 (redesign step 5), from the prototype's app.css (".mx").

   The match's animations (answer flashes, question card, score roll, race track, timer urgency, PostMatch) live in
   wwwroot/css/frost-motion.css, global, so the playground's Motion tab plays exactly the same rules.
   data-input says which input the screen uses: touch (the NumPad) or keyboard (the answer field and the strip).
   ───────────────────────────────────────────────────────────────── */

.mx[b-61tnrmygrn] { position: relative; height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }

.mx-play[b-61tnrmygrn] { flex: 1; min-height: 0; display: flex; flex-direction: column; align-items: center; gap: var(--space-3);
    padding: calc(env(safe-area-inset-top, 0px) + var(--space-3)) max(var(--space-3), env(safe-area-inset-right, 0px)) var(--space-3) max(var(--space-3), env(safe-area-inset-left, 0px)); }
@media (min-width: 768px) {
    .mx-play[b-61tnrmygrn] { justify-content: center; gap: var(--space-4); padding-bottom: calc(var(--bottom-bar-height) + var(--space-4)); }
}
.mx[data-input="touch"] .mx-play[b-61tnrmygrn] { padding-bottom: 0; }

/* The HUD: the two cards share the row with the round ring, the match clock and the target between them. */
.hud[b-61tnrmygrn] { width: 100%; max-width: 720px; display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); gap: var(--space-2); align-items: center; }
.hud-mid[b-61tnrmygrn] { display: flex; flex-direction: column; align-items: center; gap: 4px; width: 84px; }
.hud-target[b-61tnrmygrn] { font: 600 12px/1.25 var(--font-body); color: var(--ink-subtle); text-align: center; }
/* MatchClock is the timer (its own role and name); this box only holds it, without a line box of its own. */
.hud-clock[b-61tnrmygrn] { display: flex; }
.hud[b-61tnrmygrn]  .fm-timer { width: 56px; height: 56px; }
.hud[b-61tnrmygrn]  .fm-timer__num { font-size: 20px; }
@media (min-width: 768px) {
    .hud-mid[b-61tnrmygrn] { width: 126px; }
    .hud[b-61tnrmygrn]  .fm-timer { width: 72px; height: 72px; }
    .hud[b-61tnrmygrn]  .fm-timer__num { font-size: 24px; }
}
@media (max-width: 359px) {
    .mx-play[b-61tnrmygrn] { padding-inline: max(var(--space-2), env(safe-area-inset-left, 0px)) max(var(--space-2), env(safe-area-inset-right, 0px)); }
    .hud[b-61tnrmygrn] { gap: 4px; }
    /* 64 px, not the prototype's 60: "Primeiro a 6 pontos" breaks after "Primeiro a" (63 px) in two lines, as the
       English does, so the HUD keeps its height and the NumPad stays on screen in pt-PT too. */
    .hud-mid[b-61tnrmygrn] { width: 64px; }
    .hud[b-61tnrmygrn]  .fm-timer { width: 48px; height: 48px; }
    .hud[b-61tnrmygrn]  .fm-timer__num { font-size: 17px; }
}

.mx-play[b-61tnrmygrn]  .mx-race { width: 100%; max-width: 560px; }

/* The question and its status line: the line is reserved (the design system's --status-line), empty or not. */
.mx-q[b-61tnrmygrn] { width: 100%; max-width: 512px; display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
.mx-status[b-61tnrmygrn] { width: 100%; }
.mx-status[b-61tnrmygrn]  .fm-status { min-height: var(--status-line); margin-inline: auto; font-size: 14px; }

/* The input's place: READY before the first question, then the NumPad or the answer field. On touch it sits at the
   bottom; on a keyboard it keeps the answer field's height in both states, so the centred column never moves. */
.mx-act[b-61tnrmygrn] { width: 100%; display: flex; flex-direction: column; align-items: center; }
.mx[data-input="touch"] .mx-act[b-61tnrmygrn] { margin-top: auto; }
.mx[data-input="keyboard"] .mx-act[b-61tnrmygrn] { min-height: 184px; }
.mx-lobby[b-61tnrmygrn] { width: 100%; max-width: 420px; display: flex; flex-direction: column; align-items: center; gap: var(--space-2); padding-bottom: var(--space-6); }
/* The Large READY's height (ds.css --h: 60px), so "Waiting for Ana" in its place moves nothing under it. */
.mx-lobby__main[b-61tnrmygrn] { width: 100%; min-height: 60px; display: flex; align-items: center; justify-content: center; }
.mx-lobby__note[b-61tnrmygrn] { margin: 0; min-height: 20px; font: 500 13px/20px var(--font-body); color: var(--ink-muted); text-align: center; }
.mx-wait[b-61tnrmygrn] { margin: 0; display: inline-flex; align-items: center; gap: var(--space-2); font: 500 14px/1.4 var(--font-body); color: var(--ink); }
.stakes[b-61tnrmygrn] { margin: 0; min-height: 20px; font: 600 13px/20px var(--font-body); font-variant-numeric: tabular-nums; color: var(--ink-muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
/* The input note's box: two 12 px lines, reserved (the prototype's 36 px). */
.mx-lobby__input[b-61tnrmygrn] { width: 100%; min-height: 36px; }
.stakes b[b-61tnrmygrn] { color: var(--correct); font-weight: 700; }
.stakes i[b-61tnrmygrn] { color: var(--wrong); font-style: normal; font-weight: 700; }

.mx-pad[b-61tnrmygrn] { width: 100%; display: flex; justify-content: center; }
.mx-pad[b-61tnrmygrn]  .fm-pad { max-width: 480px; }
/* The question is always the largest element (§15): on a phone its longest expressions fit the card at about 26 px, so
   the typed digits stay smaller. */
.mx-pad[b-61tnrmygrn]  .fm-pad__display { font-size: 24px; }
.mx-input[b-61tnrmygrn] { width: 100%; display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
.mx-input[b-61tnrmygrn]  .fm-field { max-width: 360px; }
.mx-input[b-61tnrmygrn]  .fm-help { text-align: center; }

/* Over the screen, never in its flow: the countdown and the lost connection on a scrim; the banners at the top. */
.mx-overlay[b-61tnrmygrn] { position: absolute; inset: 0; z-index: 20; display: grid; place-items: center; padding: var(--space-4); background: var(--scrim); }
.mx-overlay[b-61tnrmygrn]  .mx-lost { max-width: 360px; }
.mx-banner[b-61tnrmygrn] { position: absolute; top: 0; left: 0; right: 0; z-index: 25; }

/* The exits: Quit on the keyboard's strip from md; the leave icon on touch, and on a keyboard below md, where the strip
   would sit over the input. */
.mx[b-61tnrmygrn]  .mx-strip { display: none; }
@media (min-width: 768px) {
    .mx[b-61tnrmygrn]  .mx-strip { display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; padding-bottom: env(safe-area-inset-bottom, 0px); }
}
.mx-strip__vs[b-61tnrmygrn] { color: var(--ink-faint); }
.mx-leave[b-61tnrmygrn] { position: absolute; z-index: 21; top: calc(env(safe-area-inset-top, 0px) + 4px); right: max(4px, env(safe-area-inset-right, 0px)); }
@media (min-width: 768px) { .mx[data-input="keyboard"] .mx-leave[b-61tnrmygrn] { display: none; } }

/* A short phone held upright (320 x 568, the first iPhone SE): the whole NumPad must stay on screen, so the race track
   goes (the cards keep both scores) and the column tightens. The prototype cuts the pad's bottom row off here. */
@media (max-height: 599px) and (orientation: portrait) {
    .mx-play[b-61tnrmygrn] { gap: var(--space-2); padding-top: calc(env(safe-area-inset-top, 0px) + var(--space-2)); }
    .mx-play[b-61tnrmygrn]  .mx-race { display: none; }
}

/* A phone on its side while playing: HUD, race and question on the left, the whole NumPad on the right (one column of
   390 px cannot hold both). */
@media (orientation: landscape) and (max-height: 500px) {
    .mx[data-input="touch"] .mx-play[b-61tnrmygrn] { display: grid; grid-template-columns: minmax(0, 1fr) min(46%, 340px);
        grid-template-rows: auto auto minmax(0, 1fr); align-items: start; column-gap: var(--space-4); row-gap: var(--space-2); }
    .mx[data-input="touch"] .hud[b-61tnrmygrn],
    .mx[data-input="touch"] .mx-play[b-61tnrmygrn]  .mx-race,
    .mx[data-input="touch"] .mx-q[b-61tnrmygrn] { grid-column: 1; }
    .mx[data-input="touch"] .mx-act[b-61tnrmygrn] { grid-column: 2; grid-row: 1 / -1; align-self: end; margin-top: 0; }
    .mx[data-input="touch"] .mx-pad[b-61tnrmygrn]  .fm-pad { height: calc(100dvh - var(--space-3)); min-height: 0; }
}
/* /Pages/Help/FirstMatch.razor.rz.scp.css */
/* The first-match card, centred in the page column as the prototype's .page--center; the page clears the shell's bottom
   bar itself, as every page does by the shell's convention (AppShell, PadMain off). */
.first-match[b-j6m0wuvry4] { width: 100%; max-width: var(--content-max); margin: 0 auto; display: flex; justify-content: center;
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .first-match[b-j6m0wuvry4] { padding: var(--space-10) var(--space-6) var(--space-16); } }

.first-match__bot[b-j6m0wuvry4] { display: flex; align-items: center; gap: var(--space-3); }
/* /Pages/Help/HelpPage.razor.rz.scp.css */
/* Help on v2 (redesign step 7f), from the prototype's app.css (.page, .head, .grid-stats, .backlink): the index is one
   column to the content width with the topics 2 across (4 from md); a topic is a narrow column with the way back above
   its card. The page clears the shell's bottom bar itself, as every page does by the shell's convention (AppShell, PadMain off). */
.help[b-qw5rob27lm] { width: 100%; max-width: var(--content-max); margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .help[b-qw5rob27lm] { padding: var(--space-10) var(--space-6) var(--space-16); gap: var(--space-8); } }
@media (min-width: 1280px) { .help[b-qw5rob27lm] { padding-inline: var(--space-10); } }

.help--topic[b-qw5rob27lm] { max-width: calc(520px + 2 * var(--space-4)); align-items: center; gap: var(--space-4); }
@media (min-width: 768px) { .help--topic[b-qw5rob27lm] { max-width: calc(520px + 2 * var(--space-6)); } }
.help[b-qw5rob27lm]  .help__back { align-self: flex-start; }

.help__head[b-qw5rob27lm] { display: flex; flex-direction: column; gap: var(--space-2); }

.help__grid[b-qw5rob27lm] { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
@media (min-width: 768px) { .help__grid[b-qw5rob27lm] { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); } }

.help__grid[b-qw5rob27lm]  .help__tile { display: flex; flex-direction: column; gap: var(--space-3); text-decoration: none; }
.help__tile-name[b-qw5rob27lm] { color: var(--ink); font: 600 14px/1.4 var(--font-body); }

/* The foot of the index (card #286): Privacy and Terms, small, after the grid. */
.help__foot[b-qw5rob27lm] { display: flex; flex-wrap: wrap; gap: 0 var(--space-3); }
/* /Pages/Home/Index.razor.rz.scp.css */
/* Home on v2 (redesign step 7a), from the prototype's app.css (.home): one centred column over the snow, filling the
   screen above the bottom bar (phones) or under the top bar (md up). The page clears the bottom bar itself, as every
   page does by the shell's convention (AppShell, PadMain off). */
.home[b-zcbcmx9gl8] { position: relative; min-height: 100dvh; padding-bottom: var(--bottom-bar-height); }
@media (min-width: 768px) { .home[b-zcbcmx9gl8] { min-height: calc(100dvh - var(--top-bar-height)); padding-bottom: 0; } }
.home__hero[b-zcbcmx9gl8] { position: relative; z-index: 1; min-height: calc(100dvh - var(--bottom-bar-height));
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-4);
    text-align: center; padding: var(--space-10) var(--space-4); }
@media (min-width: 768px) { .home__hero[b-zcbcmx9gl8] { min-height: calc(100dvh - var(--top-bar-height)); } }

.home__mark[b-zcbcmx9gl8] { width: clamp(88px, 22vw, 140px); height: auto; }
@media (max-height: 500px) { .home__mark[b-zcbcmx9gl8] { display: none; } }

/* The wordmark is text, "Frost" and "Math" in the accent, in the display face (never the class typo v1 had below md). */
.home__wordmark[b-zcbcmx9gl8] { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: clamp(40px, 12vw, 96px); line-height: 1;
    letter-spacing: clamp(2px, 1vw, 8px); color: var(--ink-strong); }
.home__wordmark b[b-zcbcmx9gl8] { color: var(--accent); font-weight: 700; }

/* The closed beta's badge (card #288) sits on the wordmark's top right corner, out of the flow: it takes no width (the
   wordmark fills 320 px) and no height, so nothing moves whether it shows or not. It rides the wordmark's top margin. */
.home__brand[b-zcbcmx9gl8] { position: relative; }
.home__brand[b-zcbcmx9gl8]  .home__beta { position: absolute; right: 0; bottom: 100%; margin-bottom: var(--space-1); }
.home__tagline[b-zcbcmx9gl8] { margin: 0; font: 600 16px/1.4 var(--font-body); letter-spacing: 0.5px; color: var(--ink-subtle); }
.home__lede[b-zcbcmx9gl8] { margin: 0; font: 400 15px/1.55 var(--font-body); color: var(--ink-muted); max-width: 60ch; }

/* The line under PLAY NOW keeps its height whatever it says (§15): a caption, a Text link, or nothing yet. The link may
   take two lines (pt-PT at 320 px) inside the same box. */
.home__next[b-zcbcmx9gl8] { min-height: var(--touch-target); display: flex; align-items: center; justify-content: center; }
.home__next[b-zcbcmx9gl8]  .fm-btn--text { white-space: normal; text-align: center; }

/* Short screens (an SE): less padding, so the column fits without a scroll. */
@media (max-height: 600px) { .home__hero[b-zcbcmx9gl8] { padding-block: var(--space-6); } }

/* Short landscape (a phone on its side): a smaller wordmark and tighter gaps, so PLAY NOW stays on screen. */
@media (max-height: 430px) {
    .home__hero[b-zcbcmx9gl8] { padding-block: var(--space-4); gap: var(--space-2); }
    .home__wordmark[b-zcbcmx9gl8] { font-size: 48px; }
}
/* /Pages/Leaderboard.razor.rz.scp.css */
/* The leaderboard on v2 (redesign step 7c), from the prototype's app.css (.page, .head) and ds.css (.fm-lb): one column
   to the content width, the head, the tabs over the list (860 px at most, the design system's), the caption and the
   legend. The page clears the shell's bottom bar itself, as every page does by the shell's convention (AppShell, PadMain off). */
.lb[b-zoadq4sc3z] { width: 100%; max-width: var(--content-max); margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .lb[b-zoadq4sc3z] { padding: var(--space-10) var(--space-6) var(--space-16); gap: var(--space-8); } }
@media (min-width: 1280px) { .lb[b-zoadq4sc3z] { padding-inline: var(--space-10); } }

.lb__head[b-zoadq4sc3z] { display: flex; flex-direction: column; gap: var(--space-2); }
.lb__panel[b-zoadq4sc3z] { display: flex; flex-direction: column; gap: var(--space-4); max-width: 860px; }

/* A tab switch: the rows (or the empty notice) it keeps dim until the new list arrives (opacity only, nothing moves). */
.lb__list[b-zoadq4sc3z], .lb__panel[b-zoadq4sc3z]  .fm-notice { transition: opacity 150ms var(--ease-out); }
.lb__busy[b-zoadq4sc3z], .lb__panel[b-zoadq4sc3z]  .lb__busy { opacity: 0.6; }

.lb__rank[b-zoadq4sc3z] { text-align: center; }
.lb__num[b-zoadq4sc3z] { text-align: right; }
/* The header row takes the rows' phone columns (LeaderboardRow's own rule is scoped to it): rank · player · the tier's
   emblem (its word hidden) · the two numbers; the streak's column goes. */
@media (max-width: 767px) {
    .lb__colhead[b-zoadq4sc3z] { grid-template-columns: 30px minmax(0, 1fr) 20px 52px 50px; gap: var(--space-2); padding: 0 var(--space-3); }
    .lb__colhead > :nth-child(3)[b-zoadq4sc3z] { font-size: 0; }
    .lb__colhead > :nth-child(6)[b-zoadq4sc3z] { display: none; }
}

.lb__notes[b-zoadq4sc3z] { display: flex; flex-direction: column; gap: var(--space-1); max-width: 860px; }
.lb__notes p[b-zoadq4sc3z] { margin: 0; }
.lb__legend[b-zoadq4sc3z] { display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--space-3); row-gap: 2px; }
.lb__key[b-zoadq4sc3z] { display: inline-flex; align-items: center; gap: 4px; }
.lb__key[b-zoadq4sc3z]  svg { display: inline-block; }
/* /Pages/Legal/LegalPage.razor.rz.scp.css */
/* Privacy and Terms on v2 (card #286): a reading column, top-aligned, in the Help page's rhythm. The prose is in child
   components, so its elements are reached through ::deep. The page clears the shell's bottom bar itself (AppShell, PadMain off). */
.legal[b-sinkx8wqsp] { width: 100%; max-width: calc(720px + 2 * var(--space-4)); margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-4);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .legal[b-sinkx8wqsp] { padding: var(--space-10) var(--space-6) var(--space-16); } }

.legal__head[b-sinkx8wqsp] { display: flex; flex-direction: column; gap: var(--space-2); }
.legal[b-sinkx8wqsp]  p, .legal[b-sinkx8wqsp]  li { margin: 0; font: 400 15px/1.6 var(--font-body); color: var(--ink-muted); overflow-wrap: anywhere; }
.legal[b-sinkx8wqsp]  p + p { margin-top: var(--space-3); }
.legal[b-sinkx8wqsp]  b { color: var(--ink-strong); font-weight: 600; }
.legal[b-sinkx8wqsp]  a { color: var(--accent-text); text-decoration: underline; }
.legal[b-sinkx8wqsp]  ul, .legal__list[b-sinkx8wqsp] { margin: var(--space-2) 0 0; padding-left: var(--space-5); display: flex; flex-direction: column; gap: var(--space-2); }
/* /Pages/MatchDetail.razor.rz.scp.css */
/* Match review on v2 (redesign step 7c), from the prototype's app.css (.page, .backlink, .grid-stats, .rounds, .round): one
   column to the content width, the back link, the summary, the race card, the rounds. The page clears the shell's bottom
   bar itself, as every page does by the shell's convention (AppShell, PadMain off). */
.rev[b-e221k8j54j] { width: 100%; max-width: var(--content-max); margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .rev[b-e221k8j54j] { padding: var(--space-10) var(--space-6) var(--space-16); gap: var(--space-8); } }
@media (min-width: 1280px) { .rev[b-e221k8j54j] { padding-inline: var(--space-10); } }

.rev[b-e221k8j54j]  .rev__back { align-self: flex-start; }
/* A private or missing match: the notice alone, at the prototype's narrow width. */
.rev[b-e221k8j54j]  .rev__blocked { width: 100%; max-width: 560px; margin-inline: auto; }

.rev-up[b-e221k8j54j] { color: var(--correct); }
.rev-down[b-e221k8j54j] { color: var(--wrong); }
.rev-none[b-e221k8j54j] { color: var(--ink-subtle); }

/* The summary: the name and the result on one line, the meta and the inputs each on their own, every line holding its
   height while it loads (the name truncates; the full name is its title). */
.rev[b-e221k8j54j]  .rev-sum { display: flex; flex-direction: column; gap: var(--space-4); }
.rev-sum__head[b-e221k8j54j] { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "name badge" "meta meta" "inputs inputs";
    column-gap: var(--space-3); row-gap: 4px; align-items: center; }
.rev-sum__name[b-e221k8j54j] { grid-area: name; min-width: 0; min-height: 26px; font-size: 22px; line-height: 26px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rev-sum__head[b-e221k8j54j]  .rev-sum__badge { grid-area: badge; }
.rev-sum__meta[b-e221k8j54j] { grid-area: meta; height: 18px; line-height: 18px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rev-sum__inputs[b-e221k8j54j] { grid-area: inputs; display: flex; align-items: center; gap: 6px; min-width: 0; min-height: 24px; margin-top: 2px; white-space: nowrap; }
.rev-sum__them[b-e221k8j54j] { margin-left: 6px; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.rev-sum__inputs[b-e221k8j54j]  .fm-inputtag { flex-shrink: 0; }

/* Four stats: two across, four from md (the prototype's .grid-stats). */
.rev-stats[b-e221k8j54j] { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
@media (min-width: 768px) { .rev-stats[b-e221k8j54j] { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); } }
.rev-stats[b-e221k8j54j]  .fm-skel { margin-inline: auto; }

/* Where you lost the race: the sentence holds two lines (three at most) and Train its button's row, so the card is one
   height loading, with a button and without. */
.rev[b-e221k8j54j]  .rev-race { display: flex; flex-direction: column; }
.rev[b-e221k8j54j]  .rev-race .fm-card__title { margin-bottom: var(--space-2); }
.rev-race__text[b-e221k8j54j] { margin: 0; min-height: 3em; font: 400 15px/1.5 var(--font-body); color: var(--ink);
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }
.rev-race__text--skel[b-e221k8j54j] { display: flex; flex-direction: column; justify-content: center; gap: 8px; }
.rev-race__action[b-e221k8j54j] { min-height: 44px; margin-top: var(--space-3); display: flex; align-items: flex-start; }

.rev-h2[b-e221k8j54j] { margin: 0; font: 600 16px/1.3 var(--font-display); letter-spacing: 0.5px; color: var(--ink-strong); }

/* The rounds: one column, two from 1280 px. */
.rev-rounds[b-e221k8j54j] { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; }
@media (min-width: 1280px) { .rev-rounds[b-e221k8j54j] { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.rev-round[b-e221k8j54j] { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; gap: var(--space-3); align-items: center;
    padding: var(--space-3); border-radius: var(--radius-md); background: var(--surface-1); border: 1px solid var(--border-subtle);
    font: 400 13px/1.4 var(--font-body); color: var(--ink-muted); }
.rev-round__n[b-e221k8j54j] { font: 700 12px/1 var(--font-mono); color: var(--ink-subtle); }
.rev-round__what[b-e221k8j54j] { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rev-round__q[b-e221k8j54j] { font: 600 15px/1.2 var(--font-display); letter-spacing: 1px; color: var(--ink-strong); overflow-wrap: anywhere; }
.rev-round__times[b-e221k8j54j] { display: flex; flex-direction: column; font: 500 12px/1.3 var(--font-mono); text-align: right; color: var(--ink-muted);
    white-space: nowrap; font-variant-numeric: tabular-nums; }
.rev-round--loading .rev-round__what[b-e221k8j54j] { gap: 6px; }
.rev-round--loading .rev-round__times[b-e221k8j54j] { align-items: flex-end; gap: 4px; }
/* /Pages/Matches.razor.rz.scp.css */
/* Match history on v2 (redesign step 7c), from the prototype's app.css (.page, .head, .backlink): one column to the
   content width, the back link, the title, the chips, the rows 6 px apart, the pager. The page clears the shell's bottom
   bar itself, as every page does by the shell's convention (AppShell, PadMain off). */
.hist[b-awhms8bho3] { width: 100%; max-width: var(--content-max); margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .hist[b-awhms8bho3] { padding: var(--space-10) var(--space-6) var(--space-16); gap: var(--space-8); } }
@media (min-width: 1280px) { .hist[b-awhms8bho3] { padding-inline: var(--space-10); } }

.hist[b-awhms8bho3]  .hist__back { align-self: flex-start; }
.hist__title[b-awhms8bho3] { margin: 0; }

.hist__list[b-awhms8bho3] { display: flex; flex-direction: column; gap: 6px; transition: opacity 150ms var(--ease-out); }
/* A page or filter change: the rows it keeps dim until the new ones arrive (opacity only, nothing moves). */
.hist__list--busy[b-awhms8bho3] { opacity: 0.6; }

/* The range on its own line on a phone, Prev and Next on the right; one line from 640 px. */
.hist__pager[b-awhms8bho3] { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-4); }
.hist__range[b-awhms8bho3] { font-variant-numeric: tabular-nums; }
.hist__pages[b-awhms8bho3] { display: flex; gap: var(--space-2); margin-left: auto; }
.hist__pages[b-awhms8bho3]  .fm-btn { white-space: nowrap; }
/* /Pages/Me.razor.rz.scp.css */
/* Profile on v2 (redesign step 7b), from the prototype's app.css (.page, .prof-head, .grid-stats): one column to the
   content width, the links, the header, the tabs. The page clears the shell's bottom bar itself, as every page does by the
   shell's convention (AppShell, PadMain off). */
.prof[b-4g62pqqls1] { width: 100%; max-width: var(--content-max); margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .prof[b-4g62pqqls1] { padding: var(--space-10) var(--space-6) var(--space-16); gap: var(--space-8); } }
@media (min-width: 1280px) { .prof[b-4g62pqqls1] { padding-inline: var(--space-10); } }

/* Match history and Settings as Text buttons, so both keep one line on a 320 px phone in either language. */
.prof__links[b-4g62pqqls1] { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: var(--space-2) var(--space-4); }

/* The header: the bear and who, then the level across. Each line keeps its box while it loads. */
.prof-head[b-4g62pqqls1] { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-4); align-items: center; }
.prof-head__who[b-4g62pqqls1] { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.prof-name[b-4g62pqqls1] { margin: 0; font: 600 20px/1.2 var(--font-display); letter-spacing: 0.5px; color: var(--ink-strong);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prof-head__tier[b-4g62pqqls1] { min-height: 28px; display: flex; align-items: center; gap: var(--space-2); }
/* The label shows from md; below it the button is the icon alone (aria-label carries the name). */
.prof-head__tier[b-4g62pqqls1]  .prof-share { flex: none; }
.prof-share__label[b-4g62pqqls1] { display: none; }
@media (min-width: 768px) { .prof-share__label[b-4g62pqqls1] { display: inline; } }
.prof-share-status[b-4g62pqqls1] { min-height: 1.2em; line-height: 1.2; }
.prof-level[b-4g62pqqls1] { grid-column: 1 / -1; min-height: 28px; display: flex; align-items: center; }
.prof-level__skel[b-4g62pqqls1] { display: flex; width: 100%; }
.prof-level[b-4g62pqqls1]  .fm-xp { max-width: none; grid-template-columns: auto minmax(3rem, 1fr) auto; }
.prof-level__next[b-4g62pqqls1] { white-space: nowrap; font-variant-numeric: tabular-nums; }
.prof-level[b-4g62pqqls1]  .fm-xp__lvl { white-space: nowrap; }

.prof-panel[b-4g62pqqls1] { display: flex; flex-direction: column; gap: var(--space-4); }
/* Per mode holds the height of its largest state, the empty notice (measured: 270 px below md, in pt-PT; 228 px from md;
   the three modes' table and caption take 222 / 205), so loading, a short table and the notice move nothing. */
.prof[b-4g62pqqls1] { --prof-modes-h: 270px; }
@media (min-width: 768px) { .prof[b-4g62pqqls1] { --prof-modes-h: 228px; } }
.prof-panel--modes[b-4g62pqqls1] { min-height: var(--prof-modes-h); }
.prof-h2[b-4g62pqqls1] { margin: 0; font: 600 16px/1.3 var(--font-display); letter-spacing: 0.5px; color: var(--ink-strong); }

/* All time: two across, four from md (the prototype's .grid-stats). */
.prof-stats[b-4g62pqqls1] { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
@media (min-width: 768px) { .prof-stats[b-4g62pqqls1] { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); } }

.prof-recent__head[b-4g62pqqls1] { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
.prof-recent[b-4g62pqqls1] { display: flex; flex-direction: column; gap: 6px; }

/* Per mode: the prototype's table, numbers right-aligned in the mono face; it scrolls sideways inside its card on a
   narrow phone rather than the page. */
.prof-panel[b-4g62pqqls1]  .prof-table-card { padding: var(--space-2) var(--space-3); overflow-x: auto; }
.prof-table[b-4g62pqqls1] { width: 100%; min-width: 420px; border-collapse: collapse; font: 400 14px/1.4 var(--font-body); color: var(--ink-muted); }
.prof-table thead th[b-4g62pqqls1] { padding: var(--space-2); text-align: right; font: 600 12px/1.3 var(--font-body); color: var(--ink-subtle); white-space: nowrap; }
.prof-table thead th:first-child[b-4g62pqqls1] { text-align: left; }
.prof-table tbody tr[b-4g62pqqls1] { border-top: 1px solid var(--border-subtle); }
.prof-table tbody th[b-4g62pqqls1] { padding: 10px var(--space-2); text-align: left; font-weight: 500; color: var(--ink); white-space: nowrap; }
.prof-table tbody th[b-4g62pqqls1]  svg { display: inline-block; vertical-align: -3px; margin-right: 6px; }
.prof-table td[b-4g62pqqls1] { padding: 10px var(--space-2); text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.prof-caption[b-4g62pqqls1] { margin: 0; }
/* /Pages/NotFound.razor.rz.scp.css */
/* The 404 on v2 (redesign step 7a), the prototype's 404: Home's centred column (.home) over the snow, "404" in the
   wordmark's face. The page clears the bottom bar itself, as every page does by the shell's convention (AppShell, PadMain off). */
.notfound[b-ou0v58yk1c] { position: relative; min-height: 100dvh; padding-bottom: var(--bottom-bar-height); }
@media (min-width: 768px) { .notfound[b-ou0v58yk1c] { min-height: calc(100dvh - var(--top-bar-height)); padding-bottom: 0; } }
.notfound__body[b-ou0v58yk1c] { position: relative; z-index: 1; min-height: calc(100dvh - var(--bottom-bar-height));
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-4);
    text-align: center; padding: var(--space-10) var(--space-4); }
@media (min-width: 768px) { .notfound__body[b-ou0v58yk1c] { min-height: calc(100dvh - var(--top-bar-height)); } }
@media (max-height: 430px) { .notfound__body[b-ou0v58yk1c] { padding-block: var(--space-4); gap: var(--space-2); } }

.notfound__code[b-ou0v58yk1c] { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: clamp(64px, 22vw, 140px); line-height: 1;
    letter-spacing: clamp(2px, 1vw, 8px); color: var(--ink-strong); }
@media (max-height: 430px) { .notfound__code[b-ou0v58yk1c] { font-size: 64px; } }
.notfound__tagline[b-ou0v58yk1c] { margin: 0; font: 600 16px/1.4 var(--font-body); letter-spacing: 0.5px; color: var(--ink-subtle); }
.notfound__lede[b-ou0v58yk1c] { margin: 0; font: 400 15px/1.55 var(--font-body); color: var(--ink-muted); max-width: 60ch; }
/* /Pages/Play/PlaySelect.razor.rz.scp.css */
/* /play on v2 (redesign step 7a), from the prototype's app.css (.page, .head, .grid-tiles): the page's column over the
   snow, the Daily across the row, the four modes, Challenge a friend centred under them. The page clears the shell's
   bottom bar itself, as every page does by the shell's convention (AppShell, PadMain off). */
.play[b-gghvygdl8c] { position: relative; min-height: 100dvh; }
@media (min-width: 768px) { .play[b-gghvygdl8c] { min-height: calc(100dvh - var(--top-bar-height)); } }
.play__page[b-gghvygdl8c] { position: relative; z-index: 1; width: 100%; max-width: var(--content-max); margin: 0 auto;
    display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .play__page[b-gghvygdl8c] { padding: var(--space-10) var(--space-6) var(--space-16); gap: var(--space-8); } }
@media (min-width: 1280px) { .play__page[b-gghvygdl8c] { padding-inline: var(--space-10); } }
.play__head[b-gghvygdl8c] { display: flex; flex-direction: column; gap: var(--space-2); }

/* One height in every state (§15): each state's content, unseen, shares the live one's cell, so the box is the tallest
   state's at this width in this language. The live content fills it. */
.play-stack[b-gghvygdl8c] { display: grid; grid-template: minmax(0, auto) / minmax(0, 1fr); }
.play-stack > *[b-gghvygdl8c] { grid-area: 1 / 1; }
.play-stack__ghost[b-gghvygdl8c] { visibility: hidden; display: grid; }
[b-gghvygdl8c] .play-stack__ghost > * { grid-area: 1 / 1; }
.play-stack__live[b-gghvygdl8c] { display: flex; min-width: 0; }

/* The Daily: the play, played and failed tiles stand unseen behind the live one (the aside wraps under the body below
   480 px, ModeTile's own rule). */
.play-daily .play-stack__live[b-gghvygdl8c]  .fm-tile { flex: 1 1 auto; }
.play-daily__skels[b-gghvygdl8c] { display: flex; flex-direction: column; gap: 6px; }
.play-daily__line[b-gghvygdl8c] { display: flex; align-items: center; min-height: 24px; }
.play-daily__line[b-gghvygdl8c]  .fm-btn--text { min-height: 24px; padding: 0; }

/* The modes: the grid undoes the standalone tile's size (ds.css: 260 px wide, 196 px tall), as the prototype's
   .grid-tiles does; four equal columns from md, each at least 210 px tall. */
.play-tiles[b-gghvygdl8c] { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-3); }
.play-tiles[b-gghvygdl8c]  .fm-tile { max-width: none; min-height: 0; }
@media (min-width: 768px) {
    .play-tiles[b-gghvygdl8c] { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); }
    .play-tiles[b-gghvygdl8c]  .fm-tile { min-height: 210px; }
}

/* Below md each tile lays its icon beside its text, so all four modes fit above the bottom bar on a phone (card #194):
   the icon spans the name, the description and the status, and a status with nothing in it takes no row. */
@media (max-width: 767px) {
    .play-tiles[b-gghvygdl8c]  .fm-tile { display: grid; grid-template-columns: 48px minmax(0, 1fr); column-gap: var(--space-4);
        row-gap: 2px; align-content: start; }
    .play-tiles[b-gghvygdl8c]  .fm-tile__icon { grid-row: 1 / span 3; }
    .play-tiles[b-gghvygdl8c]  .fm-tile__name { grid-column: 2; margin-top: 0; }
    .play-tiles[b-gghvygdl8c]  .fm-tile__desc,
    .play-tiles[b-gghvygdl8c]  .fm-tile__status { grid-column: 2; }
    .play-tiles[b-gghvygdl8c]  .fm-tile__status:empty { display: none; }
}

/* A short phone (card #254; the target is 402×710, an iPhone 16 Pro with Safari's toolbars, and 375×667): the four modes
   and Challenge a friend end above the bottom bar. The saving is padding, gaps, the eyebrow and one line for
   the title, never a body or tile font size or a 44 px target. Every state still stacks in one cell, so each tile keeps one height. */
@media (max-width: 767px) and (max-height: 760px) {
    .play__page[b-gghvygdl8c] { gap: var(--space-3); padding: var(--space-2) var(--space-4) calc(var(--bottom-bar-height) + var(--space-3)); }
    .play__head .fm-eyebrow[b-gghvygdl8c] { display: none; }
    /* The title stays one line at 375 px ("How do you want to play?" wrapped to two at 24 px, putting Practice 18 px
       under the bar): 22 px with no tracking, the one size the short rule gives back, still the page's heading. */
    .play__head .fm-h1[b-gghvygdl8c] { font-size: 22px; letter-spacing: 0; }
    .play-tiles[b-gghvygdl8c] { gap: var(--space-2); }
    .play-tiles[b-gghvygdl8c]  .fm-tile { padding: var(--space-3); column-gap: var(--space-3); row-gap: 0; }
    .play-tiles[b-gghvygdl8c]  .fm-tile__icon { width: 40px; height: 40px; }
    /* Each mode's description is one line, cut with an ellipsis: two or three lines (pt Quick Play) put Practice and
       Challenge a friend under the bar. Ranked's lock line and IceBot's difficulty line are controls and stay whole. */
    .play-tiles[b-gghvygdl8c]  .fm-tile__desc { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1;
        line-clamp: 1; overflow: hidden; }
    .play-daily .play-stack__live[b-gghvygdl8c]  .fm-tile,
    .play-daily .play-stack__ghost[b-gghvygdl8c]  .fm-tile { padding: var(--space-3); }
}

/* Ranked's status says why it is locked, with the count, or what to do, over every state's content unseen, so the tiles
   never move when the check lands. Its Text buttons sit in the line (the hit area stays 44 px). */
.play-ranked__status[b-gghvygdl8c] { width: 100%; align-self: stretch; }
.play-ranked__status .play-stack__live[b-gghvygdl8c] { align-items: flex-start; }
.play-ranked__text[b-gghvygdl8c] { display: inline-flex; align-items: flex-start; gap: 6px; }
.play-ranked__text[b-gghvygdl8c]  svg { flex: none; margin-top: 1px; }
.play-ranked__text--ok[b-gghvygdl8c] { color: var(--correct); }
.play-tiles[b-gghvygdl8c]  .play-ranked__action { min-height: 0; padding: 0; align-items: flex-start; justify-content: flex-start; text-align: left; white-space: normal; }
.play-ranked__skel[b-gghvygdl8c] { display: flex; align-items: center; width: 100%; height: 17px; }

.play__challenge[b-gghvygdl8c] { display: flex; justify-content: center; }

/* vs IceBot's difficulty line (step 8): one line in every state (Ranked's stacking), its Text button sitting in the
   line like Ranked's actions. The sheet's note reserves the longest tier's line, so choosing moves nothing. */
.play-bot__line[b-gghvygdl8c] { width: 100%; }
.play-bot__line .play-stack__live[b-gghvygdl8c] { align-items: center; }
.play-bot__text[b-gghvygdl8c] { display: inline-flex; align-items: center; min-height: 22px; }
/* The touch target is 44 px tall while the line stays 22 px: the negative margins give the extra height back. */
.play-tiles[b-gghvygdl8c]  .play-bot__action { min-height: 44px; margin-block: -11px; padding: 0; justify-content: flex-start; text-align: left; }
.play-bot__skel[b-gghvygdl8c] { display: flex; align-items: center; width: 100%; height: 22px; }
.play-bot__note[b-gghvygdl8c] { margin: var(--space-3) 0 0; color: var(--ink-muted); }
/* /Pages/Practice/Practice.razor.rz.scp.css */
/* Practice on v2 (redesign step 6), from the prototype's app.css: setup is a narrow page (.page--narrow: a head, then the
   drill's card); the results are SoloResult's card, centred. Both clear the shell's bottom bar themselves, as every page
   does by the shell's convention (AppShell, PadMain off). The run is SprintRun's own screen. */
.practice-page[b-3uqy6gz1ko] { width: 100%; max-width: 560px; margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .practice-page[b-3uqy6gz1ko] { padding: var(--space-10) var(--space-6) var(--space-16); gap: var(--space-8); } }
.practice-page--result[b-3uqy6gz1ko] { max-width: none; align-items: center; }
@media (min-width: 768px) { .practice-page--result[b-3uqy6gz1ko] { min-height: calc(100dvh - var(--top-bar-height)); justify-content: center; } }

.practice-head[b-3uqy6gz1ko] { display: flex; flex-direction: column; gap: var(--space-2); }
.practice-lede[b-3uqy6gz1ko] { margin: 0; font: 400 15px/1.55 var(--font-body); color: var(--ink-muted); max-width: 60ch; }

.practice-page[b-3uqy6gz1ko]  .practice-card { display: flex; flex-direction: column; gap: var(--space-3); }
.practice-label[b-3uqy6gz1ko] { margin-top: var(--space-2); }
/* The band note: two lines reserved (the raised note wraps at 320 px), so a choice never moves START. */
.practice-note[b-3uqy6gz1ko] { margin: 0; min-height: calc(2 * 1.45em); }
.practice-page p.fm-cap[b-3uqy6gz1ko] { margin: 0; }

/* The results' own lines, each in a box that keeps its height whatever it holds (§15). */
.practice-average[b-3uqy6gz1ko] { min-height: 18px; }
.practice-streak[b-3uqy6gz1ko] { min-height: 24px; display: flex; align-items: center; justify-content: center; }
.practice-xp[b-3uqy6gz1ko] { width: 100%; min-height: 28px; display: flex; align-items: center; }
.practice-xp[b-3uqy6gz1ko]  .fm-xp { width: 100%; }
.practice-actions[b-3uqy6gz1ko] { display: flex; flex-direction: column; gap: var(--space-2); }
/* The two small actions side by side, each on one line; where both don't fit (pt-PT at 320 px) they stack. */
.practice-row[b-3uqy6gz1ko] { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); }
.practice-row[b-3uqy6gz1ko]  .fm-btn { flex: 1 1 auto; }

/* Below 400 px the secondary actions take PostMatch's smaller type (13 px, tighter tracking), so their labels keep one
   line in English and Portuguese; the dominant action keeps its own. */
@media (max-width: 399px) {
    .practice-actions[b-3uqy6gz1ko]  .fm-btn:not(.fm-btn--lg) { padding-inline: var(--space-3); font-size: 13px; letter-spacing: 0.5px; }
    /* The dominant action on one line inside the card ("PROCURAR ADVERSÁRIO"): the page and the card give it 12 px each
       side instead of 16. */
    .practice-actions[b-3uqy6gz1ko]  .fm-btn--lg { padding-inline: var(--space-3); font-size: 14px; letter-spacing: 0.5px; }
    .practice-page--result[b-3uqy6gz1ko] { padding-inline: var(--space-3); }
    .practice-page--result[b-3uqy6gz1ko]  .fm-solo { padding: var(--space-4) var(--space-3); }
}
@media (max-width: 359px) {
    .practice-actions[b-3uqy6gz1ko]  .fm-btn--lg { font-size: 13px; }
}
/* /Pages/Settings/SettingsPage.razor.rz.scp.css */
/* The prototype's narrow page (app.css: .page, .page--narrow) and its settings rows (.set-row): a label and its hint on
   the left, the choice on the right, wrapping under it when the row is too narrow (320 px). The page clears the bottom
   bar itself, as every page does by the shell's convention (AppShell, PadMain off). */
.fm-settings[b-xrviz6mg43] { width: 100%; max-width: 560px; margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-6);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .fm-settings[b-xrviz6mg43] { padding: var(--space-10) var(--space-6) var(--space-16); gap: var(--space-8); } }
.fm-settings__head[b-xrviz6mg43] { display: flex; flex-direction: column; gap: var(--space-2); }
.fm-setrow[b-xrviz6mg43] { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); min-height: 56px;
    padding: var(--space-2) 0; border-bottom: 1px solid var(--border-subtle); flex-wrap: wrap; }
.fm-setrow:last-child[b-xrviz6mg43] { border-bottom: 0; }
.fm-setrow__text[b-xrviz6mg43] { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.fm-setrow__text b[b-xrviz6mg43] { font: 600 14px/1.3 var(--font-body); color: var(--ink); }
.fm-settings__link[b-xrviz6mg43] { display: inline-block; margin-top: var(--space-1); color: var(--accent-text); font-weight: 600; }
.fm-settings__logout[b-xrviz6mg43] { display: flex; }
/* /Shared/ProtectedPageSkeleton.razor.rz.scp.css */
/* The plain stand-in: a page head and one block, in the page column (the prototype's .page), clearing the bottom bar. */
.protected-skeleton[b-vj9ys5kwr2] { width: 100%; max-width: var(--content-max); margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-3);
    padding: var(--space-6) var(--space-4) calc(var(--bottom-bar-height) + var(--space-6)); }
@media (min-width: 768px) { .protected-skeleton[b-vj9ys5kwr2] { padding: var(--space-10) var(--space-6) var(--space-16); } }
@media (min-width: 1280px) { .protected-skeleton[b-vj9ys5kwr2] { padding-inline: var(--space-10); } }
