/* Inter is served locally; see fonts/OFL-Inter.txt for the license. */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../fonts/inter-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

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

:root {
    --bg: #f4f6fa;
    --header: #ffffff;
    --surface: #ffffff;
    --surface-2: #f0f3f8;
    --border: #e0e5ee;
    --text: #1a2740;
    --muted: #596780;
    --primary: #315fe9;
    --primary-strong: #244bc5;
    --primary-soft: #eaf0ff;
    --on-primary: #ffffff;
    --success: #12773f;
    --success-strong: #0d5c30;
    --success-soft: #e0f3e8;
    --on-success: #ffffff;
    --warning: #8a5a00;
    --warning-soft: #fff2d6;
    --danger: #b9202f;
    --danger-soft: #fde6e9;
    --banker: #8a94a8;
    --chart-bar: #315fe9;
    --chart-muted: #c3cbdb;
    --chart-band: rgb(31 91 255 / 10%);
    --chart-stripe: rgb(255 255 255 / 55%);
    --chart-ghost: rgb(91 104 130 / 8%);
    --shadow: 0 2px 6px rgb(24 39 70 / 3%);
    --radius: 14px;
    --mono: ui-monospace, "Cascadia Mono", "SFMono-Regular", Consolas, monospace;
    color-scheme: light;
}

:root[data-theme="dark"] {
    --bg: #3b424f;
    --header: #161f30;
    --surface: #000000;
    --surface-2: #1c283c;
    --border: #2b374c;
    --text: #e8edf7;
    --muted: #a0adc3;
    --primary: #88a7ff;
    --primary-strong: #abc0ff;
    --primary-soft: #243558;
    --on-primary: #0d1320;
    --success: #59c98f;
    --success-strong: #82dbac;
    --success-soft: #12301f;
    --on-success: #0d1320;
    --warning: #f0c060;
    --warning-soft: #33280f;
    --danger: #ff7d88;
    --danger-soft: #3a1820;
    --banker: #6f7a92;
    --chart-bar: #6487f2;
    --chart-muted: #3a4866;
    --chart-band: rgb(111 147 255 / 20%);
    --chart-stripe: rgb(13 19 32 / 50%);
    --chart-ghost: rgb(155 168 195 / 10%);
    --shadow: 0 2px 6px rgb(0 0 0 / 12%);
    color-scheme: dark;
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

/* Let the header and footer fill the viewport when no scrollbar is needed. */
html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    min-width: 320px;
    background: var(--bg);
    color: var(--text);
    font-family: 'Inter', sans-serif;
    font-weight: 600;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
}

h1, h2, p {
    margin: 0;
}

/* Blazor focuses the page heading after navigation; keep focus rings on interactive controls. */
h1[tabindex="-1"]:focus {
    outline: none;
}

button, input {
    font: inherit;
    color: inherit;
}

/* Hidden whatever display its classes give it, such as the panel of the tab that isn't chosen. */
[hidden] {
    display: none !important;
}

/* The header, the page and the footer under each other, at least as tall as the window, so that the footer is at the
   bottom of the window also when the page is shorter. */
#app {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}

/* Header */

.app-header {
    background: var(--header);
    border-bottom: 1px solid var(--border);
}

/* One row as wide as the window: the brand at the left, the game where the coupon starts when it is in the middle
   (see .layout and below), and the page's tools and the theme at the right edge.
   The tabs are as tall as the header, so the active one's line covers its border. */
.app-header-inner {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--column-gap);
    min-height: 76px;
    padding: 0 28px;
}

/* With the coupon in the middle, the brand takes up the page's column to the left of it, so the game is above it. */
@media (min-width: 1321px) {
    .app-header-inner {
        grid-template-columns: minmax(max-content, var(--lead)) minmax(0, 1fr);
    }
}

.header-start,
.header-end {
    display: flex;
    align-items: center;
    gap: 28px;
    min-width: 0;
}

/* How much fits beside the brand depends on how wide the window is; see the container queries below. */
.header-end {
    container-type: inline-size;
}

/* At the right edge, after the game. */
.header-tools {
    display: flex;
    align-items: center;
    gap: 28px;
    flex: none;
    margin-left: auto;
}

.theme-toggle {
    flex: none;
    font-size: 13px;
    min-height: 40px;
}

.theme-icon {
    width: 18px;
    height: 18px;
    flex: none;
}

.theme-icon-sun,
:root[data-theme="dark"] .theme-icon-moon {
    display: none;
}

:root[data-theme="dark"] .theme-icon-sun {
    display: block;
}

/* The labels differ in width, so the hidden one still takes up room and the button doesn't change size. */
.theme-labels {
    display: grid;
}

.theme-labels > span {
    grid-area: 1 / 1;
}

.theme-label-light,
:root[data-theme="dark"] .theme-label-dark {
    visibility: hidden;
}

:root[data-theme="dark"] .theme-label-light {
    visibility: visible;
}

.brand {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.brand-mark {
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: 13px;
    background: var(--primary);
    color: var(--on-primary);
    font-weight: 800;
    font-size: 14px;
    letter-spacing: 0.02em;
    flex: none;
}

.brand h1 {
    font-size: 20px;
    font-weight: 700;
    letter-spacing: -0.6px;
    line-height: 1.2;
}

.brand p {
    color: var(--muted);
    margin-top: 3px;
    font-size: 13px;
}

/* Rätta, beside the theme. */
.header-actions {
    display: flex;
    gap: 8px;
}

.header-actions .btn {
    min-height: 42px;
    padding: 9px 16px;
    font-size: 13px;
}

.header-actions .btn svg {
    width: 20px;
    height: 20px;
    flex: none;
}

/* The game above the coupon in a wide window (see .app-header-inner). */
.header-tabs {
    display: flex;
    flex: 1;
    justify-content: flex-start;
    align-self: stretch;
    align-items: center;
    gap: 20px;
}

.header-tabs:empty {
    display: none;
}

.tabs {
    display: flex;
    align-self: stretch;
    gap: 4px;
    margin-bottom: -1px;
}

.tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 48px;
    padding: 8px 14px;
    border: 0;
    border-bottom: 3px solid transparent;
    background: transparent;
    color: var(--muted);
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
}

.tab svg {
    width: 20px;
    height: 20px;
    flex: none;
}

.tab:hover:not(:disabled, .active) {
    color: var(--text);
}

.tab.active {
    border-bottom-color: var(--primary);
    color: var(--text);
}

.tab:disabled {
    cursor: not-allowed;
}

.tab:disabled:not(.active) {
    opacity: 0.5;
}

/* Less room beside the brand: the theme's label goes, then the tools move closer together. */
@container (max-width: 720px) {
    .theme-toggle {
        width: 40px;
        padding: 8px;
    }

    .theme-toggle span {
        display: none !important;
    }
}

@container (max-width: 460px) {
    .header-tools {
        gap: 16px;
    }
}

/* With the panels under the coupon, the brand and the tools go in a row, and the game goes under them. */
@media (max-width: 1100px) {
    .app-header-inner {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 4px 20px;
        min-height: 0;
        padding-top: 14px;
    }

    .header-start,
    .header-end {
        display: contents;
        container-type: normal;
    }

    /* Its text wraps rather than the tools going under it. */
    .brand {
        flex: 1 1 0;
    }

    .header-tools {
        order: 1;
    }

    /* Ends the row after the tools. */
    .app-header-inner::after {
        content: "";
        order: 2;
        flex-basis: 100%;
    }

    .header-tabs {
        order: 3;
        flex-basis: 100%;
        justify-content: flex-start;
    }
}

@media (max-width: 600px) {
    .header-tabs,
    .tabs {
        flex: 1;
    }

    .tab {
        flex: 1;
        justify-content: center;
        min-height: 44px;
    }
}

/* Give the coupon room for single-line names; add columns only when the remaining panels fit. */

.app-main {
    position: relative;
    flex: 1 0 auto;
    width: 100%;
    padding: 0 28px 56px;
}

.privacy-policy-link {
    position: absolute;
    bottom: 12px;
    left: 28px;
    color: var(--muted);
    font-size: 11px;
    font-weight: 400;
    text-decoration: none;
}

.privacy-policy-link:hover,
.privacy-policy-link:focus-visible {
    color: var(--text);
    text-decoration: underline;
}

/* Urval is left of the coupon, with U-rows to its right. At narrow widths Urval moves below it and the coupon
   and U-rows scroll together. The header uses these widths to align the game tabs with the coupon. */
:root {
    /* Text plus name padding, number, MG, signs, kind, gaps and the card's padding/borders. */
    --coupon-width: max(585px, calc(var(--coupon-name-width, 202px) + 326px));
    /* A U-row beside the coupon. */
    --urow-width: 180px;
    /* Between the page's columns. */
    --column-gap: 32px;
}

.layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 24px var(--column-gap);
    align-items: start;
}

.group,
.stack {
    display: grid;
    gap: 24px;
    align-items: start;
    min-width: 0;
}

/* At intermediate widths Urval uses 400 pixels at the left and the coupon shares the remaining room with U-rows. */
@media (min-width: 1101px) and (max-width: 1320px) {
    html:has(.layout) .app-header-inner {
        grid-template-columns: 400px minmax(0, 1fr);
    }

    .layout {
        grid-template-columns: [reduction] 400px [system] minmax(0, 1fr);
    }

    .system-group {
        grid-area: 1 / system;
    }

    .side-group {
        grid-area: 1 / reduction;
    }
}

/* A wide window: the coupon in the middle, Urval at the left and U-rows filling the remaining room on the right. */
@media (min-width: 1321px) {
    :root {
        /* No wider than leaves room for a U-row and the narrowest panels: longer names scroll in their fields. */
        --coupon: min(var(--coupon-width), 100% - 3 * var(--column-gap) - var(--urow-width) - 400px);
        /* Left of the coupon: so much that it is in the middle, or less when a U-row and the narrowest panels need more
           room than is left at its right, but no less than Urval needs under Reducera. */
        --lead: max(var(--lead-least, 0px), min((100% - var(--coupon)) / 2 - var(--column-gap), 100% - var(--coupon) - 3 * var(--column-gap) - var(--urow-width) - 400px));
    }

    /* On the root, as the header lines the game up with the coupon. */
    html:has(.layout) {
        --lead-least: 400px;
    }

    /* Under Reducera nothing is in the column at the right edge, as Urval is at the left, so the U-rows go on into it and
       more of them fit beside the coupon. */
    .layout {
        grid-template-columns:
            [lead] var(--lead)
            [coupon] var(--coupon)
            [urows] minmax(var(--urow-width), 1fr)
            [reduction] 0;
    }

    /* The coupon and the U-rows in the page's columns. */
    .system-group {
        grid-area: 1 / coupon / auto / reduction;
        grid-template-columns: subgrid;
        column-gap: normal;
    }

    .coupon-card {
        grid-column: coupon;
    }

    .urows-panel {
        grid-column: urows;
    }

    .side-group {
        display: contents;
    }

    .selection-group {
        grid-area: 1 / lead;
    }

    .layout .system-group {
        grid-column: coupon / -1;
    }

    .layout .urows-panel {
        grid-column: urows / -1;
    }
}

/* Keep enough room for Urval and a U-row on wide screens by limiting the coupon width. */
@media (min-width: 1720px) {
    :root {
        --coupon: min(var(--coupon-width), 100% - 3 * var(--column-gap) - var(--urow-width) - 800px);
    }
}

/* Beside the coupon, Urval doesn't reach the header as the coupon does, but is as far from it as from the left edge of
   the window. */
@media (min-width: 1101px) {
    .selection-card {
        margin-top: 28px;
    }
}

/* U-rows share the coupon's rows: the U-rows' heads go level with the draw and their 13 matches with the coupon's, so
   each match of a U-row is level with its match on the coupon. They have no card and nothing above them, as the rest of
   them is in the Urval card. */
.layout .system-group {
    grid-template-rows: [heads] auto [matches] repeat(13, auto) [end];
    row-gap: 2px;
}

.layout :is(.coupon-card, .urows-panel, .coupon, .urows, .urow, .urow-signs) {
    display: grid;
    grid-template-rows: subgrid;
    row-gap: 2px;
}

.layout :is(.coupon-card, .urows-panel) {
    grid-row: heads / end;
}

/* The draw goes level with the U-rows' heads. With the margin under it, the matches stay where they are without U-rows,
   where the card's gap is between them. */
.layout .coupon-draw {
    grid-row: heads;
    align-self: start;
    margin-bottom: 16px;
}

.layout .coupon {
    grid-row: matches / end;
}

/* A taller row when a U-row is taller than it doesn't spread its lines apart. */
.layout .coupon-row {
    align-content: start;
}

.layout .urows {
    grid-row: heads / end;
    align-items: stretch;
}

.layout .urow {
    grid-row: 1 / -1;
    scroll-snap-align: start;
}

.layout .urow-head {
    align-self: stretch;
    align-content: end;
    margin-bottom: 6px;
}

.layout .urow-signs {
    grid-row: 2 / -1;
}

/* As tall as its row on the coupon, so that the stripes are level with the coupon's, with the signs at the top. */
.layout .urow-match {
    align-content: start;
}

/* In a wide window, as many U-rows as there is room for between the coupon and the right edge, and the rest sideways: no
   wider than a whole number of U-rows, so that none is cut short at the edge. The padding is room for the scrollbar,
   which would otherwise cover the bottom of the U-rows. */
@media (min-width: 1321px) {
    .layout .urows {
        max-width: calc(round(down, 100% + 10px, var(--urow-width) + 10px) - 10px);
        padding-bottom: 12px;
        overflow: auto hidden;
        overscroll-behavior-x: contain;
        scroll-snap-type: x mandatory;
        scrollbar-width: thin;
    }
}

/* In a narrower window the coupon scrolls sideways with the U-rows, which come after it: on a phone the coupon is as wide
   as the screen, and the U-rows are a swipe away. */
@media (max-width: 1320px) {
    .layout .system-group {
        grid-template-columns: [coupon] min(var(--coupon-width), 100%) [urows] max-content;
        padding-bottom: 12px;
        overflow: auto hidden;
        overscroll-behavior-x: contain;
        scroll-snap-type: x mandatory;
        scrollbar-width: thin;
    }

    .layout .coupon-card {
        grid-column: coupon;
        scroll-snap-align: start;
    }

    .layout .urows-panel {
        grid-column: urows;
    }
}

/* With the panels under the coupon, the coupon is in the middle of the window, together with the U-rows after it as long
   as they fit beside it. app.js centers Urval under the coupon itself. */
@media (max-width: 1100px) {
    .coupon-card,
    .selection-card {
        width: 100%;
        margin-inline: auto;
    }

    .layout .system-group {
        justify-content: safe center;
    }

    .selection-card {
        translate: var(--coupon-selection-offset, 0px);
    }
}

/* A screen at least 1200 pixels high (.tall-screen, from app.js), with the panels beside the coupon: the coupon reaches
   from the header to the footer, whose heights app.js keeps on the root, however high the window is, and its matches
   share the room equally. A match is at least as tall as its signs and the line under them, Svenska folket and the odds
   on the coupon, and has up to 4 pixels over and under them as there is room for, and the rest under them. Only in a
   window too low for that much does the page scroll. With U-rows the room is the system's, whose matches the U-rows
   share (see above), each of them laid out like the coupon's, so that its signs stay level with those on the coupon,
   and the matches stay where they are when U-rows come and go. Nothing under the page, so that the coupon meets the
   footer. */
@media (min-width: 1101px) {
    .tall-screen {
        --room: calc(100dvh - var(--header-height, 77px) - var(--footer-height, 73px));
    }

    .tall-screen .app-main {
        padding-bottom: 0;
    }

    .tall-screen .coupon {
        row-gap: 0;
    }

    /* The match asks for no more room than its signs and the line under them (contain: size), and gets its share. */
    .tall-screen :is(.coupon-row, .urow-match) {
        contain: size;
        contain-intrinsic-block-size: calc(32px + 28px);
        grid-template-rows: minmax(0, 4px) 32px 28px minmax(0, 4px);
        align-content: start;
        row-gap: 0;
        padding-block: 0;
    }

    .tall-screen .coupon .coupon-row > *,
    .tall-screen .urow-match > * {
        grid-row: 2;
    }

    .tall-screen .coupon .coupon-row > :is(.match-info, .match-stats, .match-value),
    .tall-screen .urow-match > .urow-teams {
        grid-row: 3;
    }

    .tall-screen .urow-teams {
        align-self: center;
    }

    .tall-screen .layout .system-group {
        min-height: var(--room);
        grid-template-rows: [heads] max-content [matches] repeat(13, auto) [end];
    }

    .tall-screen .layout :is(.system-group, .coupon-card, .urows-panel, .coupon, .urows, .urow, .urow-signs) {
        row-gap: 0;
    }

    /* As far from the matches as the draw is without U-rows, where the card's gap is between them. */
    .tall-screen .layout .coupon-draw {
        margin-bottom: 18px;
    }

    /* As in a wide window, also in a narrower one, so that the last match of a U-row is as tall as the coupon's, and its
       signs as high up in it. */
    .tall-screen .layout .urows {
        padding-bottom: 12px;
    }

    /* Without U-rows not even the gap before them, which in a narrower window is under the coupon. */
    .tall-screen .urows-panel:empty {
        display: none;
    }
}

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 22px;
    display: grid;
    gap: 18px;
    min-width: 0;
    max-width: 500px;
}

/* As wide as --coupon-width, so that the names fit on one line, but no wider than there is room for, and at least as wide
   as the least --coupon-width. */
.coupon-card {
    min-width: min(572px, 100%);
    max-width: var(--coupon-width);
}

/* A card's heading with a small round button beside it, such as its info icon. */
.card-title {
    display: flex;
    align-items: center;
    gap: 6px;
}

.info-button {
    display: inline-grid;
    place-items: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
    transition: background-color 0.15s, color 0.15s;
}

.info-button:hover {
    background: var(--surface-2);
    color: var(--primary-strong);
}

.info-button svg {
    width: 20px;
    height: 20px;
}

.card h2,
.dialog h2 {
    font-size: 18px;
    line-height: 1.35;
    letter-spacing: -0.3px;
}

.card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--border);
    padding: 10px;
}

.card-subtitle {
    margin-top: 5px;
    font-size: 13px;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.hint {
    color: var(--muted);
    font-size: 13px;
    line-height: 1.65;
}

/* Info: the icon beside a heading opens a box under the header that explains the card (InfoTip), and the icon after the
   name of a setting one under it that explains the setting, or in the footer one over it. The box is a popover in the
   top layer, which app.js places with the arrow at the icon. */

.info-button {
    display: inline-grid;
    place-items: center;
    flex: none;
    width: 30px;
    height: 30px;
    padding: 0;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
    transition: background-color 0.15s, color 0.15s;
}

.info-button svg {
    width: 20px;
    height: 20px;
}

.info-button:hover,
.info-button:has(+ .info-popover:popover-open) {
    background: var(--primary-soft);
    color: var(--primary-strong);
}

/* The name of a setting with its info icon right after it, such as U-rader in the Urval card and Garanti in the footer.
   The icon is smaller than beside a heading, to go with the smaller name. */
.field-name {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    min-width: 0;
}

.field-name .info-button {
    width: 24px;
    height: 24px;
}

.field-name .info-button svg {
    width: 18px;
    height: 18px;
}

.info-popover {
    position: fixed;
    inset: auto;
    width: min(560px, calc(100vw - 24px));
    margin: 0;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    color: var(--text);
    box-shadow: 0 12px 32px rgb(16 24 40 / 18%);
    overflow: visible;
}

/* Only while open: closed, the browser hides it. */
.info-popover:popover-open {
    display: flex;
    flex-direction: column;
}

/* The arrow up at the icon. */
.info-popover::before {
    content: "";
    position: absolute;
    top: -7px;
    left: calc(var(--info-arrow, 24px) - 6px);
    width: 12px;
    height: 12px;
    border-top: 1px solid var(--border);
    border-left: 1px solid var(--border);
    background: var(--surface);
    transform: rotate(45deg);
}

/* In the footer the box is over the icon, with the arrow down at it. */
.info-popover.over::before {
    top: auto;
    bottom: -7px;
    border: 0;
    border-right: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
}

.info-body {
    min-height: 0;
    padding: 14px 18px 16px;
    overflow-y: auto;
    overscroll-behavior: contain;
    font-family: system-ui, "Segoe UI", Arial, sans-serif;
    font-size: 15px;
    font-weight: 400;
    line-height: 1.6;
    letter-spacing: normal;
    text-align: left;
}

.info-body h3 {
    margin: 14px 0 4px;
    font-size: 14px;
}

.info-close + h3 {
    margin-top: 0;
}

.info-body p + p {
    margin-top: 8px;
}

/* The text runs beside the close button, which floats at the top right. */
.info-close {
    float: right;
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    margin: -6px -10px 4px 10px;
    padding: 0;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
}

.info-close:hover {
    background: var(--surface-2);
    color: var(--text);
}

.info-close svg {
    width: 18px;
    height: 18px;
}

/* Buttons */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 40px;
    padding: 8px 14px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--surface);
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.15s, border-color 0.15s, color 0.15s;
}

.btn:hover:not(:disabled) {
    border-color: var(--primary);
    color: var(--primary-strong);
}

.btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.btn-ghost {
    border-color: transparent;
    background: transparent;
    color: var(--muted);
}

.btn-ghost:hover:not(:disabled) {
    background: var(--surface-2);
    border-color: transparent;
}

.btn-primary {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary);
}

.btn-primary:hover:not(:disabled) {
    background: var(--primary-strong);
    border-color: var(--primary-strong);
    color: var(--on-primary);
}

.btn-small {
    min-height: 30px;
    padding: 2px 10px;
    font-size: 14px;
}

/* The download becomes the main action once the reduced rows are ready. */
.btn-download {
    border-color: var(--success);
    background: var(--success);
    color: var(--on-success);
}

.btn-download:hover:not(:disabled) {
    border-color: var(--success-strong);
    background: var(--success-strong);
    color: var(--on-success);
}

.btn-download:active:not(:disabled) {
    transform: translateY(1px);
    box-shadow: none;
}

.btn-download:disabled {
    box-shadow: none;
    background: var(--surface-2);
    border-color: var(--border);
    color: var(--muted);
    opacity: 1;
}

button:focus-visible,
input:focus-visible,
summary:focus-visible,
.rows:focus-visible,
.dist-plot:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* Draw */

/* At the top of the coupon, in line with the team names under it: when the draw closes, the question mark that opens
   what stands out in the draw, any extra jackpot, Rensa at the end of the line, and any error on a line of its own. As tall as the draw's
   number field was there, so that the matches stay where they were. */
.coupon-draw {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    min-height: 32px;
    margin-top: 0;
    padding-inline: 10px;
}

.coupon-draw .message {
    flex-basis: 100%;
}

.coupon-jackpot {
    margin-left: auto;
    white-space: nowrap;
}

.coupon-clear {
    margin-left: auto;
}

/* The draw's number, at the top of the header's right-click menu. */
.draw-form {
    padding-left: 12px;
}

.draw-field {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    font-size: 14px;
}

.draw-number {
    flex: none;
    width: 88px;
    height: 32px;
    padding: 4px 8px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}

.draw-number::placeholder {
    color: var(--muted);
    opacity: 0.8;
}

.draw-number:disabled {
    cursor: not-allowed;
}

/* Coupon */

.coupon {
    --sign-width: 38px;
    --mg-width: 30px;
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 2px;
}

/* The MG box has a column of its own, empty in the matches that aren't hedges, so the signs stay where they are when it
   comes and goes. */
.coupon-row {
    display: grid;
    grid-template-columns: 28px minmax(0, 1fr) var(--mg-width) auto 38px;
    align-items: center;
    gap: 0 8px;
    padding: 3px 6px;
    border-radius: 8px;
}

.coupon-row:nth-child(odd) {
    background: var(--surface-2);
}

.match-number {
    grid-column: 1;
    grid-row: 1;
    font-weight: 700;
    color: var(--muted);
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-size: 12px;
}

.match-name-field {
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

/* Keep names on one line beside the signs; unusually long names can still scroll independently. */
.match-name-content {
    display: grid;
    width: max-content;
    min-width: 100%;
}

.match-name,
.match-name-sizing {
    grid-area: 1 / 1;
    width: 100%;
    min-width: 0;
    min-height: 32px;
    margin: 0;
    padding: 4px 8px;
    border: 1px solid transparent;
    border-radius: 8px;
    background: transparent;
    font-size: 14px;
    line-height: 1.5;
    white-space: pre;
}

.match-name {
    height: 32px;
    color: var(--text);
    text-align: left;
    cursor: pointer;
}

.match-name-sizing {
    visibility: hidden;
    pointer-events: none;
}

.coupon-row > .signs {
    grid-column: 4;
    grid-row: 1;
}

.coupon .sign {
    height: 32px;
}

/* A mathematical hedge: smaller than a sign, and when on tinted rather than filled, so it isn't taken for one. */
.mg {
    grid-column: 3;
    grid-row: 1;
    width: var(--mg-width);
    height: 32px;
    padding: 0;
    border-radius: 6px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--muted);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.02em;
    cursor: pointer;
    transition: background-color 0.12s, border-color 0.12s, color 0.12s;
}

.mg:hover:not(:disabled) {
    border-color: var(--primary);
    color: var(--primary-strong);
}

.mg.on {
    background: var(--primary-soft);
    border-color: var(--primary);
    color: var(--primary-strong);
}

.mg:disabled {
    cursor: not-allowed;
}

.mg.blocked {
    opacity: 0.7;
}

.match-name:hover:not(:disabled),
.match-name:focus-visible {
    border-color: var(--border);
    background: var(--surface);
}

.match-name:disabled {
    color: var(--muted);
    opacity: 0.85;
    cursor: default;
}

.signs {
    display: flex;
    gap: 4px;
}

.sign {
    width: var(--sign-width, 38px);
    height: 36px;
    border-radius: 6px;
    border: 1px solid var(--border);
    background: var(--surface);
    font-weight: 700;
    font-family: var(--mono);
    cursor: pointer;
    transition: background-color 0.12s, border-color 0.12s, color 0.12s;
}

.sign:hover:not(:disabled) {
    border-color: var(--primary);
}

.sign.on {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary);
}

.sign:disabled {
    cursor: not-allowed;
    opacity: 0.7;
}

/* Lock the coupon during a search without dimming and restoring it on every reduction. */
.coupon .sign:disabled,
.coupon-clear:disabled {
    opacity: 1;
}

.match-kind {
    grid-column: 5;
    grid-row: 1;
    font-size: 12px;
    color: var(--muted);
    text-align: center;
}

.kind-full .match-kind,
.kind-half .match-kind {
    color: var(--primary-strong);
    font-weight: 600;
}

.kind-empty .match-kind {
    color: var(--danger);
}

/* Under the team names, lined up with their text. */
.match-info {
    grid-column: 2;
    grid-row: 2;
    align-self: start;
    display: flex;
    flex-wrap: wrap;
    gap: 0 8px;
    padding-left: 9px;
    font-size: 12px;
    line-height: 16px;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.match-note {
    font-weight: 600;
    color: var(--warning);
}

.match-stats {
    grid-column: 4;
    grid-row: 2;
    display: grid;
    grid-template-columns: repeat(3, var(--sign-width));
    column-gap: 4px;
    font-size: 12px;
    line-height: 14px;
    text-align: center;
    white-space: nowrap;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.match-stats .on {
    color: var(--text);
    font-weight: 600;
}

/* Under the kind of a banker or half hedge: green when the odds give its signs a higher chance than Svenska folket's
   share of the bets, on average for a half hedge, and red when lower. */
.match-value {
    grid-column: 5;
    grid-row: 2;
    align-self: start;
    font-size: 12px;
    line-height: 16px;
    text-align: center;
    white-space: nowrap;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.match-value.up {
    color: var(--success);
    font-weight: 600;
}

.match-value.down {
    color: var(--danger);
    font-weight: 600;
}

@media (max-width: 600px) {
    .coupon {
        --sign-width: 32px;
        --mg-width: 28px;
    }

    .coupon-row {
        grid-template-columns: 20px minmax(0, 1fr) var(--mg-width) auto;
        align-items: start;
        column-gap: 4px;
        padding-inline: 2px;
    }

    .match-number {
        line-height: 32px;
    }

    .match-kind {
        display: none;
    }

    /* Both teams stay visible on phones, with long names wrapping within the name column. */
    .match-name-field {
        overflow: visible;
    }

    .match-name-content {
        width: 100%;
    }

    .match-name,
    .match-name-sizing {
        padding-inline: 4px;
    }

    .match-name-sizing {
        overflow: hidden;
    }

    .match-name {
        height: auto;
        white-space: normal;
        overflow-wrap: anywhere;
    }

    .match-team {
        display: block;
    }

    .match-separator {
        display: none;
    }

    .match-info {
        padding-left: 5px;
        font-size: 11px;
    }

    .match-value {
        grid-column: 1;
        font-size: 10px;
    }
}

/* U-rows: side by side to the right of the coupon, each a column with the matches from top to bottom like on the coupon,
   under its title, switch and limits, with a remove button at the top right. The same controls are in the Urval card. */

.urows {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: var(--urow-width);
    gap: 10px;
    align-items: start;
}

/* The add button stays after the last U-row, at the top beside the draw, including before the first U-row. */
.urow-add-slot {
    grid-row: 1 / -1;
    align-self: start;
    justify-self: start;
    padding: 10px 6px;
    scroll-snap-align: start;
}

/* Up to 1300px U-rows are added in Urval, without an empty add column beside the coupon. */
@media (max-width: 1300px) {
    .urow-add-slot,
    .layout .urows-panel:not(:has(.urow)) {
        display: none;
    }

    .layout .system-group:not(:has(.urow)) {
        grid-template-columns: [coupon] min(var(--coupon-width), 100%);
    }
}

/* Framed on the cards' colour, as there is no card around the U-rows, so that the matches can be striped like the
   coupon's. */
.urow {
    position: relative;
    display: grid;
    gap: 10px;
    padding: 10px 6px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    box-shadow: var(--shadow);
}

/* As tall as the signs on the coupon, so that a match is as tall as its row there. */
.urow .sign.small {
    max-width: none;
    height: 32px;
}

.urow .sign.small:not(.on) {
    background: var(--surface);
}

/* A mathematical hedge always comes in and a banker is always right, so neither can have U-signs: their signs are grey. */
.urow .sign.small.mathematical:not(.on),
.urow .sign.small.banker:not(.on) {
    background: transparent;
    border-color: var(--border);
    color: var(--muted);
    opacity: 0.45;
}

/* The shared draw row provides room above these controls for the remove button without pushing the matches down. */
.urow-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 2px 4px;
    padding-inline: 6px;
}

.urow-remove {
    position: absolute;
    top: 2px;
    right: 4px;
    display: grid;
    place-items: center;
    width: 24px;
    height: 24px;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
}

.urow-remove svg {
    width: 16px;
    height: 16px;
}

.urow-remove:hover:not(:disabled) {
    background: var(--surface-2);
    color: var(--danger);
}

.urow-remove:disabled {
    opacity: 0.45;
    cursor: default;
}

@media (max-width: 600px) {
    /* The phone card's 16px gap is shared between this margin and the 2px grid gap. */
    .layout .coupon-draw {
        margin-bottom: 14px;
    }

    .layout .urow-head {
        margin-bottom: 0;
    }

    .urow-remove {
        width: 20px;
        height: 20px;
    }
}

.urow-title {
    margin: 0;
    overflow: hidden;
    font-size: 15px;
    line-height: 1.2;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.urow-head .switch {
    grid-row: 2;
}

/* The names, buttons and numbers of the two limits in columns, so that their buttons are level. */
.urow-head-limits {
    grid-column: 2;
    grid-row: 1 / span 2;
    display: grid;
    grid-template-columns: repeat(4, auto);
    align-items: center;
    gap: 2px;
    font-size: 12px;
}

.urow-head-limits .stepper {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    gap: inherit;
}

.urow-head-limits .stepper-name {
    font-size: 11px;
    color: var(--muted);
}

.urow-head-limits .stepper button {
    width: 18px;
    height: 18px;
    border-radius: 5px;
    font-size: 12px;
}

/* A U-row turned off keeps its signs and limits, which can still be changed, but faded: it takes no rows away. */
.urow.inactive .urow-title,
.urow-settings.inactive .urow-name {
    color: var(--muted);
}

.urow.inactive :is(.urow-signs, .stepper),
.urow-settings.inactive .stepper {
    opacity: 0.45;
}

.urow-signs {
    display: grid;
    gap: 2px;
}

.urow-match {
    display: grid;
    grid-template-columns: 20px repeat(3, minmax(0, 56px));
    align-items: center;
    gap: 2px 4px;
    padding: 3px 6px;
    border-radius: 8px;
}

/* The teams under the U-signs, which app.js writes and cuts short when they don't fit, for example "Manche – Liverp".
   As tall before as after, so that nothing moves when they are written. */
.urow-teams {
    grid-column: 2 / -1;
    height: 14px;
    overflow: hidden;
    white-space: nowrap;
    font-size: 11px;
    line-height: 14px;
    color: var(--muted);
}

/* Striped like the coupon's matches, so that each match has the colour of its row there. */
.urow-match:nth-child(odd) {
    background: var(--surface-2);
}

.urow-number {
    font-size: 12px;
    font-weight: 700;
    color: var(--muted);
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.stepper {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.stepper-name {
    font-weight: 600;
}

.stepper button {
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
}

.stepper button:hover:not(:disabled) {
    border-color: var(--primary);
    color: var(--primary-strong);
}

.stepper button:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.stepper output {
    min-width: 2ch;
    text-align: center;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* Reduction settings */

.field {
    display: grid;
    gap: 9px;
}

.field-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.segmented {
    display: flex;
    padding: 3px;
    gap: 3px;
    border: 1px solid var(--border);
    border-radius: 9px;
    background: var(--surface-2);
}

.segmented button {
    flex: 1;
    min-height: 36px;
    border: 0;
    padding: 6px 10px;
    border-radius: 6px;
    background: transparent;
    font-weight: 600;
    color: var(--muted);
    cursor: pointer;
    font-size: 13px;
    transition: color 0.15s, background-color 0.15s;
}

.segmented button.active {
    background: var(--surface);
    color: var(--primary-strong);
    box-shadow: 0 1px 4px rgb(16 24 40 / 10%);
}

.segmented button:hover:not(:disabled, .active) {
    color: var(--text);
}

.segmented button:disabled {
    cursor: not-allowed;
}

.progress {
    height: 8px;
    border-radius: 999px;
    background: var(--surface-2);
    overflow: hidden;
}

.progress-bar {
    height: 100%;
    background: var(--primary);
    transition: width 0.2s linear;
}

.progress-text {
    font-size: 14px;
    color: var(--muted);
}

.progress-text strong {
    color: var(--text);
}

.message {
    padding: 10px 12px;
    border-radius: 10px;
    font-size: 14px;
}

.message.ok {
    background: var(--success-soft);
    color: var(--success);
}

.message.warn {
    background: var(--warning-soft);
    color: var(--warning);
}

.message.error {
    background: var(--danger-soft);
    color: var(--danger);
}

/* Filtered and prioritized intervals: the switches, sliders and bars look the same for both */

.priority {
    gap: 10px;
}

/* Urval, the panel of Reducera: the U-rows, the filtered interval and the priority, each under a line with its name and
   what turns it on and with lines between them, and while it searches how far it has come. It has no heading, as no
   panel has, and no info icon of its own: each name has one after it (.field-name). */
.selection-card > .filter-interval,
.selection-card > .priority {
    padding-top: 18px;
    border-top: 1px solid var(--border);
}

.filter-interval {
    gap: 10px;
}

.urow-picker {
    display: grid;
    gap: 10px;
}

.urow-add {
    gap: 6px;
}

.urow-add svg {
    width: 16px;
    height: 16px;
    flex: none;
}

/* A U-row's name with the rule its limits make, its switch and its remove button, and under them its limits. Framed like
   its column beside the coupon. */
.urow-settings {
    display: grid;
    gap: 6px;
    padding: 8px 8px 10px 12px;
    border: 1px solid var(--border);
    border-radius: 10px;
}

.urow-settings-head {
    display: flex;
    align-items: center;
    gap: 10px;
}

.urow-name {
    flex: none;
    font-size: 14px;
    font-weight: 700;
}

/* On one line, so that the U-row keeps its height whatever the rule. */
.urow-rule {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    font-size: 13px;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* The switch that turns the U-row off for a while, and the remove button. */
.urow-actions {
    display: flex;
    flex: none;
    align-items: center;
    gap: 4px;
}

.urow-limits {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 18px;
    font-size: 14px;
}

.priority-head .field-label {
    color: var(--text);
    text-transform: none;
    letter-spacing: 0;
    font-size: 13px;
}

.priority-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.switch {
    -webkit-appearance: none;
    appearance: none;
    position: relative;
    flex: none;
    width: 42px;
    height: 24px;
    margin: 0;
    border-radius: 999px;
    background: var(--chart-muted);
    cursor: pointer;
    transition: background-color 0.15s;
}

.switch::after {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: #ffffff;
    box-shadow: 0 1px 2px rgb(16 24 40 / 25%);
    transition: transform 0.15s;
}

.switch:checked {
    background: var(--primary);
}

.switch:checked::after {
    transform: translateX(18px);
}

.switch:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* For where room is short, as in the head of a U-row. */
.switch.small {
    width: 32px;
    height: 18px;
}

.switch.small::after {
    top: 2px;
    left: 2px;
    width: 14px;
    height: 14px;
}

.switch.small:checked::after {
    transform: translateX(14px);
}

.priority-value {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 2px 12px;
    font-size: 14px;
    color: var(--muted);
}

.priority-value strong {
    color: var(--text);
    font-size: 15px;
}

.priority-scale {
    --thumb: 22px;
    display: grid;
    gap: 4px;
}

.priority-bars {
    display: grid;
    grid-template-rows: 100%;
    align-items: end;
    height: 48px;
    padding: 0 calc(var(--thumb) / 2);
    border-bottom: 1px solid var(--border);
}

.priority-bars span {
    background: var(--chart-muted);
    border-radius: 2px 2px 0 0;
    transition: background-color 0.12s;
}

.priority-bars span.in {
    background: var(--chart-bar);
}

.priority-ends {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: 12px;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.priority-count {
    font-size: 14px;
}

.priority-count.warn {
    color: var(--warning);
}

/* Sliders: the track and fill are drawn behind native range inputs, so two inputs can share one track. */

.range {
    --thumb: 22px;
    position: relative;
    height: var(--thumb);
}

.range-track,
.range-fill {
    position: absolute;
    top: 50%;
    height: 4px;
    margin-top: -2px;
    border-radius: 999px;
    pointer-events: none;
}

.range-track {
    left: calc(var(--thumb) / 2);
    right: calc(var(--thumb) / 2);
    background: var(--surface-2);
}

.range-fill {
    background: var(--primary);
}

.range input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    background: transparent;
    /* Only the thumbs take the pointer, so the lower input's thumb can be reached under the upper input. */
    pointer-events: none;
}

.range.single input[type="range"] {
    pointer-events: auto;
    cursor: pointer;
}

/* Firefox draws no track of its own once the appearance is none, so only WebKit needs one hidden. */
.range input[type="range"]::-webkit-slider-runnable-track {
    height: var(--thumb);
    background: transparent;
    border: 0;
}

.range input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    box-sizing: border-box;
    width: var(--thumb);
    height: var(--thumb);
    border: 2px solid var(--primary);
    border-radius: 50%;
    background: var(--surface);
    box-shadow: 0 1px 3px rgb(16 24 40 / 25%);
    pointer-events: auto;
    cursor: grab;
}

.range input[type="range"]::-moz-range-thumb {
    box-sizing: border-box;
    width: var(--thumb);
    height: var(--thumb);
    border: 2px solid var(--primary);
    border-radius: 50%;
    background: var(--surface);
    box-shadow: 0 1px 3px rgb(16 24 40 / 25%);
    pointer-events: auto;
    cursor: grab;
}

.range input[type="range"]:active::-webkit-slider-thumb {
    cursor: grabbing;
}

.range input[type="range"]:active::-moz-range-thumb {
    cursor: grabbing;
}

.range input[type="range"]:focus-visible {
    outline: none;
}

.range input[type="range"]:focus-visible::-webkit-slider-thumb {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.range input[type="range"]:focus-visible::-moz-range-thumb {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.range input[type="range"]:disabled::-webkit-slider-thumb {
    border-color: var(--chart-muted);
    cursor: not-allowed;
}

.range input[type="range"]:disabled::-moz-range-thumb {
    border-color: var(--chart-muted);
    cursor: not-allowed;
}

/* Result */

.badge {
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--primary-soft);
    color: var(--primary-strong);
    font-weight: 700;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
}

.stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

.stat {
    display: grid;
    padding: 14px 12px;
    border-radius: 8px;
    background: var(--surface-2);
    min-width: 0;
}

.stat-value {
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.6px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.stat-label {
    font-size: 13px;
    color: var(--muted);
}

@media (max-width: 520px) {
    .stat {
        padding: 8px 10px;
    }

    .stat-value {
        font-size: 18px;
    }

    .stat-label {
        font-size: 12px;
    }
}

/* How well the reductions meet the priority */

.priority-result {
    container-type: inline-size;
    display: grid;
    gap: 8px;
    padding: 12px;
    border-radius: 12px;
    background: var(--surface-2);
}

.priority-options,
.priority-choices {
    display: grid;
    gap: 4px;
}

.priority-option {
    display: grid;
    grid-template-columns: 7rem 6.5rem minmax(0, 1fr) 4rem;
    grid-template-areas: "name rows bar value";
    align-items: center;
    gap: 4px 10px;
    width: 100%;
    min-height: 40px;
    padding: 6px 10px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface);
    text-align: left;
    font-variant-numeric: tabular-nums;
}

button.priority-option {
    cursor: pointer;
    transition: background-color 0.15s, border-color 0.15s;
}

button.priority-option:hover {
    border-color: var(--primary);
}

.priority-option.active {
    border-color: var(--primary);
    background: var(--primary-soft);
}

.priority-option.reference {
    border-color: transparent;
    background: transparent;
    color: var(--muted);
}

.priority-option-name {
    grid-area: name;
    font-weight: 600;
}

.priority-option-rows {
    grid-area: rows;
    font-size: 14px;
    color: var(--muted);
}

.priority-option-bar {
    grid-area: bar;
    height: 8px;
    border-radius: 999px;
    background: var(--surface-2);
    overflow: hidden;
}

.priority-option.active .priority-option-bar {
    background: var(--surface);
}

.priority-option-bar span {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: var(--chart-bar);
}

.priority-option.reference .priority-option-bar span {
    background: var(--chart-muted);
}

.priority-option-value {
    grid-area: value;
    text-align: right;
    font-weight: 700;
}

.priority-option.reference .priority-option-value {
    font-weight: 600;
}

.priority-option-average {
    grid-column: 1 / -1;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 2px 10px;
    color: var(--muted);
    font-size: 13px;
}

.priority-option-average strong {
    color: var(--text);
    font-size: 14px;
}

.priority-option.reference .priority-option-average strong {
    color: inherit;
    font-weight: 600;
}

/* "1 på 1,23 milj." needs more room than a percentage, so the bar goes below. */
.priority-result.rarity .priority-option {
    grid-template-columns: 7rem minmax(0, 1fr) auto;
    grid-template-areas:
        "name rows value"
        "bar bar bar";
}

/* Narrow: on phones, or in a narrower card, as beside the coupon in a smaller window or in a column of the dialog. */
@container (max-width: 430px) {
    .priority-option,
    .priority-result.rarity .priority-option {
        grid-template-columns: auto minmax(0, 1fr) auto;
        grid-template-areas:
            "name rows value"
            "bar bar bar";
    }
}

@media (max-width: 600px) {
    .result-card .priority-option,
    .result-card .priority-result.rarity .priority-option {
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            "name value"
            "rows value"
            "bar bar";
        row-gap: 2px;
    }
}

/* Rows */

.rows {
    --cell: minmax(18px, 1fr);
    max-height: 450px;
    overflow-y: auto;
    scrollbar-gutter: stable;
    border: 1px solid var(--border);
    border-radius: 12px;
    font-family: var(--mono);
    font-size: 14px;
}

.rows-head,
.row-line {
    display: grid;
    grid-template-columns: 52px repeat(13, var(--cell));
    align-items: center;
    height: 30px;
    padding: 0 8px 0 0;
}

.rows-head {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--surface-2);
    border-bottom: 1px solid var(--border);
    color: var(--muted);
    font-size: 12px;
    font-weight: 700;
}

.row-line.alt {
    background: var(--surface-2);
}

/* When grading: how many correct each row has, last on the line. */
.rows.with-correct .rows-head,
.rows.with-correct .row-line {
    grid-template-columns: 52px repeat(13, var(--cell)) 44px;
}

@media (max-width: 420px) {
    .rows {
        font-size: 13px;
    }

    .rows-head,
    .row-line {
        grid-template-columns: 38px repeat(13, var(--cell));
        padding-right: 4px;
    }

    .rows.with-correct .rows-head,
    .rows.with-correct .row-line {
        grid-template-columns: 38px repeat(13, var(--cell)) 32px;
    }

    .row-number {
        padding-right: 6px;
    }
}

.row-number {
    text-align: right;
    padding-right: 10px;
    color: var(--muted);
    font-size: 12px;
}

.cell {
    text-align: center;
    font-weight: 700;
}

.cell.banker {
    color: var(--banker);
    font-weight: 400;
}

.cell.hit {
    color: var(--success);
}

.cell.miss {
    color: var(--danger);
    opacity: 0.55;
    font-weight: 400;
}

.row-correct {
    text-align: right;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.rows-head .row-correct {
    font-weight: inherit;
}

/* A row with enough correct to win something. */
.row-correct.won {
    color: var(--success);
}

/* Distribution */

.dist {
    --dist-stripes: repeating-linear-gradient(135deg, transparent 0 3px, var(--chart-stripe) 3px 5px);
    display: grid;
    gap: 12px;
}

.dist-chart {
    display: grid;
    grid-template-columns: var(--dist-y-width, 3ch) minmax(0, 1fr);
    grid-template-rows: auto 160px auto;
    column-gap: 8px;
    font-size: 12px;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.dist-axis-title {
    grid-column: 1 / -1;
    margin-bottom: 10px;
}

.dist-y {
    position: relative;
}

.dist-y span {
    position: absolute;
    right: 0;
    line-height: 1;
    transform: translateY(50%);
}

.dist-plot {
    position: relative;
    border-bottom: 1px solid var(--border);
}

.dist-grid {
    position: absolute;
    left: 0;
    right: 0;
    height: 1px;
    background: var(--surface-2);
}

.dist-band {
    position: absolute;
    top: 0;
    bottom: 0;
    background: var(--chart-band);
}

.dist-legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 8px;
    font-size: 13px;
    color: var(--muted);
}

.dist-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: 4px;
}

.dist-legend-band,
.dist-legend-gain,
.dist-legend-loss {
    flex: none;
    width: 14px;
    height: 14px;
    border-radius: 3px;
}

.dist-legend-band {
    border: 1px solid var(--chart-bar);
    background: var(--chart-band);
}

.dist-legend-gain {
    background: var(--dist-stripes), var(--chart-bar);
}

.dist-legend-loss {
    border: 1px dashed var(--muted);
    background: var(--chart-ghost);
}

/* The heights of a bar and of how it differs from the other reduction, in percent of the plot. Registered so they animate. */
@property --dist-count {
    syntax: "<number>";
    inherits: true;
    initial-value: 0;
}

@property --dist-other {
    syntax: "<number>";
    inherits: true;
    initial-value: 0;
}

.dist-bars {
    position: absolute;
    inset: 0;
    display: grid;
}

.dist-slot {
    position: relative;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    border-radius: 6px 6px 0 0;
    /* Through a variable, since Visual Studio's validator does not know that custom properties can be transitioned. */
    --dist-transition: --dist-count 0.3s ease, --dist-other 0.3s ease;
    transition: var(--dist-transition);
}

.dist-slot.active {
    background: var(--surface-2);
}

.dist-slot.has-rows {
    cursor: pointer;
}

.dist-bar,
.dist-gain,
.dist-loss {
    width: min(24px, calc(100% - 2px));
    border-radius: 4px 4px 0 0;
    transition: background-color 0.12s, opacity 0.12s;
}

.dist-bar {
    height: calc(var(--dist-count) * 1%);
    background: var(--chart-bar);
}

.dist-slot.has-rows .dist-bar {
    min-height: 2px;
}

.dist-slot.active .dist-bar {
    background: var(--primary-strong);
}

.dist-gain,
.dist-loss {
    position: absolute;
    left: 50%;
    translate: -50% 0;
    pointer-events: none;
}

/* Rows more than in the other reduction: the top of the bar, striped. */
.dist-gain {
    bottom: calc(var(--dist-other) * 1%);
    height: calc(max(0, var(--dist-count) - var(--dist-other)) * 1%);
    background: var(--dist-stripes);
}

/* Rows fewer than in the other reduction: a dashed outline up to where its bar reaches. */
.dist-loss {
    bottom: calc(var(--dist-count) * 1%);
    height: calc(max(0, var(--dist-other) - var(--dist-count)) * 1%);
    overflow: hidden;
    background: var(--chart-ghost);
}

/* The outline is clipped by its box, so it vanishes with it where the bars are as tall. */
.dist-loss::before {
    content: "";
    position: absolute;
    inset: 0;
    border: 1px dashed var(--muted);
    border-bottom: 0;
    border-radius: inherit;
}

/* With a bar's rows shown, the other bars step back. */
.dist-bars.has-selection .dist-slot:not(.selected, .active) :is(.dist-bar, .dist-gain, .dist-loss) {
    opacity: 0.35;
}

@media (prefers-reduced-motion: reduce) {
    .dist-slot {
        transition: none;
    }
}

.dist-tooltip {
    position: absolute;
    top: 4px;
    z-index: 2;
    display: grid;
    padding: 6px 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    box-shadow: var(--shadow);
    font-size: 13px;
    line-height: 1.4;
    white-space: nowrap;
    pointer-events: none;
}

.dist-tooltip strong {
    color: var(--text);
    font-size: 14px;
}

.dist-tooltip-hint {
    margin-top: 2px;
    font-size: 12px;
    color: var(--muted);
}

.dist-selection {
    display: grid;
    gap: 8px;
}

.dist-selection-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.dist-x {
    grid-column: 2;
    position: relative;
    height: 24px;
}

.dist-x span {
    position: absolute;
    top: 8px;
    line-height: 1;
    white-space: nowrap;
    transform: translateX(-50%);
}

.dist-x span::before {
    content: "";
    position: absolute;
    top: -8px;
    left: 50%;
    width: 1px;
    height: 5px;
    background: var(--border);
}

.dist-ends {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 8px 16px;
}

.dist-end {
    display: grid;
    gap: 1px;
}

.dist-end.least {
    margin-left: auto;
    text-align: right;
}

.dist-end-label {
    font-size: 12px;
    font-weight: 600;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.dist-end-row {
    font-family: var(--mono);
    font-weight: 700;
    letter-spacing: 0.08em;
}

.dist-end-row .banker {
    color: var(--banker);
    font-weight: 400;
}

.dist-end-share {
    font-size: 14px;
    color: var(--muted);
}

.dist-table summary,
.row-details summary {
    width: fit-content;
    font-size: 14px;
    font-weight: 600;
    color: var(--primary-strong);
    cursor: pointer;
}

.dist-table table {
    width: 100%;
    margin-top: 8px;
    border-collapse: collapse;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
}

.dist-table th {
    padding: 6px 10px;
    border-bottom: 1px solid var(--border);
    font-size: 12px;
    color: var(--muted);
    text-align: left;
}

.dist-table td {
    padding: 5px 10px;
}

.dist-table tbody tr:nth-child(even) {
    background: var(--surface-2);
}

.dist-table th:not(:first-child),
.dist-table td:not(:first-child) {
    text-align: right;
}

/* Too little to be paid out. */
.dist-table td.unpaid {
    color: var(--muted);
}

@media (max-width: 420px) {
    .dist-chart {
        grid-template-rows: auto 140px auto;
        column-gap: 6px;
        font-size: 11px;
    }
}

/* Chances */

.chance-table-scroll {
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

.chance-table {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}

.chance-table th,
.chance-table td {
    padding: 7px 10px;
    text-align: right;
    vertical-align: top;
}

.chance-table thead th {
    border-bottom: 1px solid var(--border);
    font-size: 12px;
    color: var(--muted);
    vertical-align: bottom;
}

.chance-table th:first-child {
    text-align: left;
    white-space: nowrap;
}

.chance-interval-condition {
    white-space: nowrap;
}

.chance-interval-toggle {
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    white-space: nowrap;
    cursor: pointer;
}

.chance-interval-toggle[aria-pressed="false"] {
    text-decoration: line-through;
    opacity: 0.65;
}

.chance-interval-toggle:hover,
.chance-interval-toggle:focus-visible {
    color: var(--text);
    opacity: 1;
}

.chance-table tbody tr:nth-child(even) {
    background: var(--surface-2);
}

.chance-table tfoot th,
.chance-table tfoot td {
    border-top: 1px solid var(--border);
}

.chance-percent {
    display: block;
    font-weight: 700;
}

.chance-table .zero .chance-percent {
    font-weight: 400;
    color: var(--muted);
}

.chance-one-in {
    display: block;
    font-size: 13px;
    color: var(--muted);
}

/* Between the chances by the odds and by Svenska folket: red down when Svenska folket give the higher chance, green up
   when the odds do. */
.chance-table .chance-compare {
    width: 1px;
    padding-left: 0;
    padding-right: 0;
    text-align: center;
    vertical-align: middle;
}

.chance-arrow {
    display: block;
    margin: 0 auto;
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.6px;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.chance-arrow.up {
    color: var(--success);
}

.chance-arrow.down {
    color: var(--danger);
}

/* Read by screen readers but not shown. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Up to three columns of chances on a phone: the numbers closer together and "Minst 10 rätt" on two lines if need be. */
@media (max-width: 420px) {
    .chance-table th,
    .chance-table td {
        padding: 7px 6px;
    }

    .chance-table tfoot th:first-child {
        white-space: normal;
    }
}

@media (max-width: 360px) {
    .chance-table {
        font-size: 13px;
    }

    .chance-table th,
    .chance-table td {
        padding: 7px 4px;
    }

    .chance-table thead th,
    .chance-one-in {
        font-size: 11px;
    }

    .chance-arrow {
        width: 14px;
        height: 14px;
    }
}

/* Payouts */

/* The jackpot to the right of the turnover. With little room the fields get narrower, and where they would get too narrow
   the labels go above them, so the two still fit side by side on a phone. */
.payout-fields {
    container-type: inline-size;
    display: flex;
    gap: 20px;
}

.payout-field {
    display: grid;
    grid-template-columns: auto minmax(56px, 96px) auto;
    align-items: center;
    gap: 6px 8px;
}

.payout-field label,
.payout-field span {
    white-space: nowrap;
}

@container (max-width: 420px) {
    .payout-field {
        grid-template-columns: minmax(56px, 96px) auto;
    }

    .payout-field label {
        grid-column: 1 / -1;
    }
}

.payout-field input {
    width: 100%;
    height: 38px;
    padding: 6px 10px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface);
    font-variant-numeric: tabular-nums;
}

.payout-field span {
    font-size: 14px;
    color: var(--muted);
}

.payout-table {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}

.payout-table th,
.payout-table td {
    padding: 7px 10px;
    text-align: right;
    white-space: nowrap;
}

.payout-table thead th {
    border-bottom: 1px solid var(--border);
    font-size: 12px;
    color: var(--muted);
}

.payout-table th:first-child {
    text-align: left;
}

.payout-table td {
    font-weight: 700;
}

/* Too little to be paid out. */
.payout-table td.unpaid {
    font-weight: 400;
    color: var(--muted);
}

.payout-table tbody tr:nth-child(even) {
    background: var(--surface-2);
}

/* Three amounts beside each other on a phone: closer together. */
@media (max-width: 420px) {
    .payout-table th,
    .payout-table td {
        padding: 7px 5px;
        font-size: 14px;
    }
}

/* Dialogs: over the page, which waits behind a backdrop. Contents that don't fit scroll under the header. */

.dialog {
    width: min(940px, calc(100% - 32px));
    max-width: none;
    max-height: calc(100% - 32px);
    max-height: calc(100dvh - 32px);
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text);
    box-shadow: 0 24px 64px rgb(16 24 40 / 24%);
    overflow: hidden;
}

.dialog[open] {
    display: flex;
    flex-direction: column;
}

/* Not every browser lets the backdrop inherit the theme's colours, so it has its own, dark in both themes. */
.dialog::backdrop {
    background: rgb(10 16 30 / 55%);
}

.dialog-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 14px 14px 22px;
    border-bottom: 1px solid var(--border);
}

.dialog-close {
    width: 40px;
    padding: 0;
}

.dialog-close svg {
    width: 20px;
    height: 20px;
}

.dialog-body {
    container-type: inline-size;
    display: grid;
    align-content: start;
    gap: 18px;
    min-height: 0;
    padding: 22px;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-gutter: stable;
}

.urow-remove-dialog {
    width: min(400px, calc(100% - 32px));
}

.urow-remove-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
}

/* The reduction on show: the reduced system with its chances under it to the left and its payouts and distribution to
   the right, or all of them under each other where two columns would squeeze the tables. The cards stand on the page's
   background, as beside the coupon, and are as wide as their column. Side by side they are all as large as the largest,
   with what they hold at their top. */
.analysis-dialog {
    width: min(1100px, calc(100% - 32px));
}

.analysis-dialog .dialog-body {
    background: var(--bg);
}

.analysis .card {
    max-width: none;
    align-content: start;
}

.result-card {
    overflow-x: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

/* What a card shows more of when asked, at its bottom: its rows, a table or the rows of a bar, with what shows them. */
.card-more {
    display: grid;
    gap: inherit;
}

@container (min-width: 900px) {
    .analysis {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-template-rows: repeat(2, 1fr);
        grid-auto-flow: column;
        align-items: stretch;
    }

    /* Showing more doesn't make the cards larger, which would move the others: it takes one line in the card, that of
       Visa rader or Visa som tabell, and the rest scrolls in the card, rows and all, with room under it as at the top. */
    .analysis .card {
        overflow-y: auto;
        scrollbar-width: thin;
        scrollbar-color: var(--border) transparent;
    }

    .analysis .card-more {
        height: 1lh;
    }

    .analysis .card-more:has(details[open], .dist-selection) > :last-child {
        padding-bottom: 22px;
    }

    .analysis .card-more .rows {
        max-height: none;
        overflow: clip;
    }
}

@media (max-width: 600px) {
    .dialog {
        width: calc(100% - 16px);
        max-height: calc(100% - 16px);
        max-height: calc(100dvh - 16px);
    }

    .dialog-header {
        padding: 10px 8px 10px 16px;
    }

    .dialog-body {
        padding: 16px;
    }
}

/* Match details and Svenska Spel's analysis, opened from a match name on the coupon. */

html:has(.match-dialog[open]) {
    overflow: hidden;
}

html:has(.match-dialog[open][data-page-scrollbar]) {
    scrollbar-gutter: stable;
}

.match-dialog {
    width: min(760px, calc(100% - 32px));
}

.match-dialog .dialog-header {
    flex-shrink: 0;
}

.match-section {
    display: grid;
    gap: 12px;
    min-width: 0;
}

.match-section + .match-section,
.match-source {
    border-top: 1px solid var(--border);
    padding-top: 18px;
}

.match-section h3 {
    margin: 0;
    font-size: 16px;
}

.match-facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px 24px;
    margin: 0;
}

.match-facts dt {
    color: var(--muted);
    font-size: 12px;
}

.match-facts dd {
    margin: 3px 0 0;
    font-size: 14px;
    overflow-wrap: anywhere;
}

.match-statistics {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
}

.match-statistics th,
.match-statistics td {
    padding: 9px 8px;
    text-align: right;
}

.match-statistics th:first-child {
    text-align: left;
    font-weight: 500;
}

.match-statistics tbody tr:nth-child(odd) {
    background: var(--surface-2);
}

.match-analysis-heading {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}

.match-analysis-heading h4 {
    margin: 0;
    font-size: 14px;
}

.match-prediction {
    color: var(--primary-strong);
    font-weight: 700;
    white-space: nowrap;
}

.match-analysis-text,
.match-comment {
    margin: 8px 0 0;
    white-space: pre-line;
    overflow-wrap: anywhere;
    font-size: 14px;
    line-height: 1.7;
}

.match-section > .btn {
    justify-self: start;
}

@media (max-width: 450px) {
    .match-facts {
        grid-template-columns: minmax(0, 1fr);
    }

    .match-statistics {
        font-size: 12px;
    }

    .match-statistics th,
    .match-statistics td {
        padding: 8px 4px;
    }
}

/* What stands out in the draw: three lists side by side with a line between them, one under the other when narrow. */
.highlights {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.highlight {
    min-width: 0;
    padding: 0 20px;
    border-left: 1px solid var(--border);
}

.highlight:first-child {
    padding-left: 0;
    border-left: none;
}

.highlight:last-child {
    padding-right: 0;
}

.highlight-heading {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 8px;
}

.highlight h3 {
    margin: 0;
    font-size: 16px;
    line-height: 1.35;
}

.highlight-heading .info-button {
    width: 24px;
    height: 24px;
}

.highlight-heading .info-button svg {
    width: 18px;
    height: 18px;
}

.highlight-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.highlight-list li {
    display: grid;
    grid-template-columns: 2.4em minmax(0, 1fr) auto;
    align-items: baseline;
    gap: 8px;
    padding: 9px 0;
    border-bottom: 1px solid var(--border);
    font-size: 14px;
}

.highlight-list li:last-child {
    border-bottom: none;
}

.highlight-match {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.highlight-name {
    overflow: hidden;
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.highlight-teams {
    color: var(--muted);
    font-size: 12px;
    font-weight: 400;
}

.highlight-value {
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}

.highlight-value.up {
    color: var(--success);
}

.highlight-value.down {
    color: var(--danger);
}

@container (max-width: 720px) {
    .highlights {
        grid-template-columns: minmax(0, 1fr);
        gap: 22px;
    }

    .highlight,
    .highlight:first-child,
    .highlight:last-child {
        padding: 0;
        border-left: none;
    }
}

/* Grading: what is graded, the buttons and the result filled in like the coupon, with the matches from top to bottom, and
   beside them from the very top, or under the matches when narrow, how many correct the rows get and what they are
   expected to win, compact enough to end about where the matches do. The rows go across the bottom. */

.grade {
    /* The matches and the table beside them are as high: 13 matches of 38 px with 2 px between them take as much room as
       the table's 14 numbers of correct and its total, with the 2 px of the rules under its heading and over its total. */
    --grade-head-height: 28px;
    --grade-match-height: 38px;
    --grade-line-height: calc((13 * var(--grade-match-height) + 13 * 2px - 2px) / 15);
    display: grid;
    gap: 18px;
    align-items: start;
}

/* The result buttons share a line when wide and stack when narrow. */
.grade-intro .actions {
    flex-wrap: nowrap;
}

.grade-intro .actions .btn {
    white-space: nowrap;
}

@container (width < 720px) {
    .grade-intro .actions {
        flex-direction: column;
        align-items: stretch;
    }

    .grade-intro .actions .btn {
        white-space: normal;
    }
}

/* Clicking the buttons and the signs fast doesn't select the text around them. */
.grade-intro,
.grade-matches,
.grade-table {
    user-select: none;
}

@container (min-width: 720px) {
    .grade {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-template-rows: auto auto 1fr auto;
        grid-template-areas:
            "source source"
            "intro intro"
            "matches outcome"
            "rows rows";
        column-gap: 28px;
    }

    .grade-source-area {
        grid-area: source;
    }

    .grade-intro {
        grid-area: intro;
    }


    .grade-matches {
        grid-area: matches;
    }

    .grade-outcome {
        grid-area: outcome;
    }

    /* As high as the matches, the space under the table and a message of five lines of 20 px with its padding. */
    .grade-outcome.reserved {
        min-height: calc(var(--grade-head-height) - 2px + 13 * (var(--grade-match-height) + 2px) + 14px + 5 * 20px + 20px);
        align-content: start;
    }

    .grade-outcome .message {
        line-height: 20px;
    }

    .grade-rows {
        grid-area: rows;
    }
}

.grade-source-area,
.grade-intro,
.grade-outcome {
    display: grid;
    gap: 14px;
    min-width: 0;
}

.grade-matches {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 2px;
}

.grade-match {
    display: grid;
    grid-template-columns: 22px minmax(0, 1fr) auto;
    align-items: center;
    gap: 0 8px;
    min-height: var(--grade-match-height);
    padding: 0 6px;
    border-radius: 8px;
}

/* After the heading, so the first match is shaded as the table's first line beside it. */
.grade-match:nth-child(even) {
    background: var(--surface-2);
}

/* As high as the table's heading, and in its style. */
.grade-matches-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    /* Less the 2 px under it, so that the matches start where the table's numbers of correct do. */
    height: calc(var(--grade-head-height) - 2px);
    padding: 0 10px 4px 36px;
    border-bottom: 1px solid var(--border);
    font-size: 12px;
    font-weight: 700;
    color: var(--muted);
}

.grade-number {
    font-size: 12px;
    font-weight: 700;
    color: var(--muted);
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* app.js stacks the teams without a dash when the full match name needs more room. */
.grade-name {
    min-width: 0;
    padding-block: 4px;
    overflow-wrap: anywhere;
    font-size: 14px;
}

.grade-separator {
    white-space: pre;
}

.grade-name.stacked .grade-team {
    display: block;
}

.grade-name.stacked .grade-separator {
    display: none;
}

.grade-signs {
    display: grid;
    grid-template-columns: repeat(3, 38px);
    gap: 4px;
}

.sign.small {
    width: 100%;
    max-width: 38px;
    height: 30px;
    padding: 0;
    font-size: 13px;
}

.sign.outside:not(.on) {
    border-style: dashed;
    color: var(--muted);
}


/* Laid out as the expected payouts, but with headers that may wrap, a muted line without rows, muted dashes where nothing
   is paid and the total under a rule. */
.grade-table {
    table-layout: fixed;
}

/* Lines low enough for the table to be as high as the matches beside it. */
.grade-table th,
.grade-table td {
    padding-block: 0;
}

.grade-table thead tr {
    height: var(--grade-head-height);
}

.grade-table thead th {
    padding-bottom: 4px;
}

.grade-table tbody tr,
.grade-table tfoot tr {
    height: var(--grade-line-height);
}

/* Shaded as the matches beside them. */
.grade-table tbody tr:nth-child(even) {
    background: none;
}

.grade-table tbody tr:nth-child(odd) {
    background: var(--surface-2);
}

/* Room for "Förväntad utdelning per rad" on one line in the dialog, so that the heading is as high as the matches'. */
.grade-col-correct {
    width: 20%;
}

.grade-col-rows {
    width: 14%;
}

.grade-col-payout {
    width: 44%;
}

.grade-col-win {
    width: 22%;
}

.grade-table thead th {
    white-space: normal;
    vertical-align: bottom;
}

.grade-table tr.none td,
.grade-table td.unpaid {
    font-weight: 400;
    color: var(--muted);
}

.grade-table tfoot th,
.grade-table tfoot td {
    border-top: 1px solid var(--border);
}

/* Every row graded, under the rest. */
.grade-rows {
    display: grid;
    gap: 10px;
    min-width: 0;
}

/* In a tall window, keep the matches and the summary in view and give the row list the remaining room. */
@media (min-width: 840px) and (min-height: 1024px) {
    .grading-dialog:has(.grade) {
        height: calc(100dvh - 32px);
    }

    .grading-dialog .dialog-header {
        flex-shrink: 0;
    }

    .grading-dialog .dialog-body:has(.grade) {
        flex: 1;
        grid-template-rows: minmax(0, 1fr);
    }

    .grading-dialog .grade {
        min-height: 0;
        align-self: stretch;
        grid-template-rows: auto auto auto minmax(96px, 1fr);
    }

    .grading-dialog .grade-rows {
        min-height: 0;
        align-self: stretch;
        grid-template-rows: auto minmax(0, 1fr);
    }

    .grading-dialog .grade-rows .rows {
        min-height: 0;
        max-height: none;
    }
}

/* Over the grading: the reduction or a file to grade, and the button for another file. */
.grade-source {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

/* As wide as there is room for beside the file's button, which stays on the same line. */
.grade-source .segmented {
    flex: 1 1 auto;
    max-width: 380px;
}

/* At the right edge, also without the choice beside it. */
.grade-source .file-button {
    margin-left: auto;
}

.file-button svg {
    width: 18px;
    height: 18px;
}

/* The file input in a button or the upload area is out of sight, so they show its focus instead. */
.file-button:has(input:focus-visible) {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

/* Before a file is chosen: an area to click or drop a file on. The file input covers all of it, so a file dropped
   anywhere on it is chosen. */
.upload {
    position: relative;
    display: grid;
    justify-items: center;
    gap: 6px;
    padding: 36px 20px;
    border: 2px dashed var(--border);
    border-radius: 12px;
    background: var(--surface-2);
    color: var(--muted);
    text-align: center;
    cursor: pointer;
    transition: border-color 0.15s;
}

.upload:hover,
.upload:has(input:focus-visible) {
    border-color: var(--primary);
}

.upload strong {
    color: var(--text);
    font-size: 16px;
}

.upload svg {
    width: 34px;
    height: 34px;
    color: var(--primary);
}

.upload input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

/* Footer: the coupon's system (CouponFooter), also before any match has a sign. In windows at least 1024 pixels high it
   stays along the bottom while the page scrolls; in shorter windows it follows the page. */

.app-footer {
    position: relative;
    z-index: 10;
    border-top: 1px solid var(--border);
    background: var(--header);
    box-shadow: 0 -6px 20px rgb(16 24 40 / 8%);
}

@media (min-height: 1024px) {
    .app-footer {
        position: sticky;
        bottom: 0;
    }

    /* Keyboard focus and scrolling into view stop above the sticky footer instead of under it. */
    html:has(.app-footer) {
        scroll-padding-bottom: calc(var(--footer-height, 120px) + 16px);
    }
}

/* Wrapped lines: counts at the left, and the settings and then the cost and download centered under the coupon. As tall
   from the start as with the 48 pixel buttons once every match has a sign, so that the single line doesn't grow then. */
.app-footer-inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-start;
    gap: 10px 36px;
    min-height: 72px;
    padding: 12px 28px;
}

.footer-counts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-start;
    gap: 10px 24px;
}

/* The bankers and hedges, on one line together, spaced as the counts are. */
.footer-kinds {
    display: flex;
    align-items: center;
    gap: inherit;
}

.footer-count {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
}

.footer-count svg {
    width: 18px;
    height: 18px;
    flex: none;
}

/* The rows of the whole system, first and larger than the rest. */
.footer-rows {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -0.2px;
    white-space: nowrap;
}

/* The names as short as on the coupon, only on phones. */
.footer-short {
    display: none;
}

/* A number with room for the largest it can be, which is hidden under it, so that nothing beside it moves when it grows:
   1 594 323 rows and what they cost, or 13 matches. The digits are all as wide. */
.footer-number {
    display: inline-grid;
    font-variant-numeric: tabular-nums;
}

.footer-number > span {
    grid-area: 1 / 1;
}

.footer-number > span + span {
    visibility: hidden;
}

.footer-progress-text {
    font-variant-numeric: tabular-nums;
}

.footer-progress {
    display: flex;
    align-items: center;
    gap: 16px;
    flex: 1 1 240px;
    min-width: 0;
}

.footer-progress .progress {
    flex: 1;
    height: 6px;
    background: var(--border);
}

.footer-progress-text {
    font-size: 13px;
    white-space: nowrap;
}

/* Analysis, cost and download share the bottom line whenever the footer wraps, centered under the coupon like the settings, as
   far as the line has room for them (app.js). */
.footer-end {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 16px;
    order: 2;
    flex-basis: 100%;
}

/* With translate, not transform, which the download's own press uses. */
.footer-end > * {
    translate: var(--coupon-footer-end-offset, 0px);
}

/* A status message above the footer at the left edge of the page, over what is there when the page reaches down to it:
   showing what the search does while reducing (Home's SearchStatus). */
.footer-status {
    position: absolute;
    bottom: calc(100% + 16px);
    left: 28px;
    max-width: min(640px, 100% - 56px);
    padding: 10px 14px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    box-shadow: 0 6px 20px rgb(16 24 40 / 12%);
}

.footer-status .progress-text {
    margin: 0;
}

/* With Urval at the left of the coupon, no wider than Urval is at its narrowest, so that it stays beside the coupon. */
@media (min-width: 1101px) {
    .footer-status {
        max-width: 400px;
    }
}

/* What the rows cost, written as on Svenska Spel's coupon, for example "648 KR", next to the download. */
.footer-cost {
    justify-items: end;
    font-weight: 700;
    text-transform: uppercase;
    white-space: nowrap;
}

.app-footer .btn {
    min-height: 48px;
    padding: 10px 16px;
    font-size: 15px;
}

.app-footer .btn svg {
    width: 20px;
    height: 20px;
    flex: none;
}

/* The settings and actions follow the coupon's center, measured by app.js, including when it is beside Urval. */
.footer-middle {
    display: flex;
    justify-content: center;
    order: 1;
    flex-basis: 100%;
}

/* Center only the settings. Analysis sits beside them and keeps its space before a result is ready. */
.footer-center {
    --footer-analysis-gap: 20px;
    position: relative;
    max-width: min(100%, var(--coupon-footer-room, 100%));
    transform: translateX(var(--coupon-footer-offset, 0px));
}

.footer-center > .footer-analysis {
    display: none;
    position: absolute;
    left: calc(100% + var(--footer-analysis-gap));
    bottom: 0;
    white-space: nowrap;
}

.footer-analysis .btn[aria-hidden="true"] {
    visibility: hidden;
}

/* Keep each action's labels in the same space, including while it is busy. */
.analysis-button-label,
.reduction-button-label {
    display: inline-grid;
    min-width: 0;
}

.analysis-button-label > span,
.reduction-button-label > span {
    grid-area: 1 / 1;
}

.analysis-button-label > span + span,
.reduction-button-label > span + span {
    visibility: hidden;
}

.reduction-button-label {
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* Keep Stoppa in place when the countdown changes from two digits to one. */
.reduction-countdown-seconds {
    display: inline-block;
    width: 2ch;
    text-align: right;
}

.button-spinner {
    animation: button-spin 0.8s linear infinite;
}

/* The icon is outside the label's flow so the text stays centered in the whole button. */
.reduction-button > .button-spinner {
    position: absolute;
    left: 10px;
    top: 50%;
    translate: 0 -50%;
}

.reduction-button:not([aria-busy="true"]) .button-spinner {
    visibility: hidden;
    animation: none;
}

@keyframes button-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .button-spinner {
        animation: none;
    }
}

/* On wide screens without room to the right, reserve a centered line below the settings. */
.footer-middle.analysis-below .footer-center {
    padding-bottom: 60px;
}

.footer-middle.analysis-below .footer-analysis {
    left: 50%;
    transform: translateX(-50%);
}

/* The settings and then the buttons, level with the middle of each other and of the rest of the footer. */
.footer-settings {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    max-width: 100%;
    gap: 12px 20px;
}

/* The guarantee on the first line, and under it the coverage and the actions side by side, half the width each. From
   1920 pixels they are all on the footer's one line instead (see further down). */
@media (max-width: 1919px) {
    .footer-settings:has(> .footer-coverage) {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-template-areas: "field field" "coverage actions";
    }

    .footer-settings:has(> .footer-coverage) > .footer-field {
        grid-area: field;
    }

    .footer-settings:has(> .footer-coverage) > .footer-actions {
        grid-area: actions;
    }

    /* Reducera fills its half of the centered settings. */
    .footer-settings:has(> .footer-coverage) > .footer-actions > .btn {
        flex: 1 1 100%;
        min-width: 0;
    }

    .footer-settings:has(> .footer-coverage) > .range.footer-coverage {
        grid-area: coverage;
        width: auto;
        min-width: 0;
    }
}

/* A setting's name to the left of its buttons. */
.footer-field {
    display: flex;
    align-items: center;
    gap: 10px;
}

/* Separate, generously sized choices, with a solid accent for the selected guarantee in either theme. */
.footer-middle .segmented {
    gap: 6px;
    padding: 0;
    border: 0;
    background: transparent;
}

.footer-middle .segmented button {
    flex: 1 0 auto;
    min-height: 48px;
    padding: 10px 12px;
    border: 1px solid color-mix(in srgb, var(--muted) 45%, var(--border));
    border-radius: 8px;
    background: var(--surface-2);
    color: var(--text);
    font-size: 16px;
    font-weight: 700;
    white-space: nowrap;
}

.footer-middle .segmented button.active {
    border-color: var(--primary);
    background: var(--primary);
    color: var(--on-primary);
    box-shadow: none;
}

.footer-middle .segmented button:hover:not(:disabled, .active) {
    border-color: var(--primary);
    background: var(--primary-soft);
    color: var(--primary-strong);
}

.footer-middle .segmented button:disabled {
    opacity: 0.55;
}

/* Garantiprocent: a slider whose thumb is wide enough for the percent, which is written on it and lets the pointer through
   to the browser's own thumb under it. */
.range.footer-coverage {
    --thumb: 54px;
    flex: none;
    width: 190px;
    height: 28px;
}

.footer-coverage input[type="range"]::-webkit-slider-runnable-track {
    height: 28px;
}

.footer-coverage input[type="range"]::-webkit-slider-thumb {
    height: 28px;
    border-radius: 999px;
}

.footer-coverage input[type="range"]::-moz-range-thumb {
    height: 28px;
    border-radius: 999px;
}

.range-value {
    position: absolute;
    top: 50%;
    transform: translate(-50%, -50%);
    font-size: 12px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    pointer-events: none;
}

.footer-coverage:has(input:disabled) .range-value {
    color: var(--muted);
}

.footer-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    max-width: 100%;
    gap: 12px;
}

/* Reducera, or Stoppa while it searches. */
.footer-middle .btn-primary {
    min-width: 140px;
    padding-inline: 20px;
}

.footer-middle .reduction-button {
    position: relative;
    padding-inline: 36px;
}

/* The header's right-click menu for system modes, draw, search time and status visibility, placed by app.js. */
.context-menu {
    position: fixed;
    inset: auto;
    margin: 0;
    padding: 12px;
    max-height: calc(100dvh - 24px);
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    color: var(--text);
    box-shadow: 0 12px 32px rgb(16 24 40 / 18%);
}

/* Only while open: closed, the browser hides it. */
.context-menu:popover-open {
    display: grid;
    gap: 8px;
}

.context-choices {
    display: grid;
    gap: 2px;
}

.context-section {
    display: grid;
    gap: 8px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
}

.context-status-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    cursor: pointer;
}

.context-choice {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 28px;
    min-height: 36px;
    padding: 6px 12px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    font-size: 14px;
    text-align: left;
    cursor: pointer;
}

.context-choice span {
    font-size: 13px;
    color: var(--muted);
}

.context-choice:hover:not(:disabled, .active) {
    background: var(--surface-2);
}

.context-choice.active {
    background: var(--primary-soft);
    color: var(--primary-strong);
}

.context-choice.active span {
    color: inherit;
}

.context-choice:disabled {
    cursor: not-allowed;
    opacity: 0.5;
}

/* At desktop widths with wrapped controls, the counts form a left column so the settings can start on the first line.
   The settings and the final actions still follow the coupon's center (app.js). */
@media (min-width: 1101px) and (max-width: 1919px) {
    .app-footer-inner:has(.footer-middle) {
        display: grid;
        grid-template-columns: max-content minmax(0, 1fr);
        align-items: start;
    }

    .app-footer-inner:has(.footer-middle) > .footer-counts {
        grid-area: 1 / 1 / 3 / 2;
        flex-direction: column;
        align-items: flex-start;
        gap: 16px;
    }

    .app-footer-inner:has(.footer-middle) > .footer-middle {
        grid-area: 1 / 2;
    }

    .app-footer-inner:has(.footer-middle) > .footer-end {
        grid-area: 2 / 2;
    }

    .app-footer-inner:has(.footer-middle) .footer-kinds {
        display: grid;
        grid-template-columns: max-content 18px max-content;
        gap: 4px 8px;
    }

    .app-footer-inner:has(.footer-middle) .footer-count {
        display: grid;
        grid-template-columns: subgrid;
        grid-column: 1 / -1;
    }
}

/* From 1920 pixels, keep counts, settings and actions, and the cost and download on one line. Actions stay in the flow,
   so longer Stoppa labels can wrap inside their button without overlapping another footer control. */
@media (min-width: 1920px) {
    .app-footer-inner:has(.footer-middle) {
        display: grid;
        grid-template-columns: max-content minmax(0, 1fr) max-content;
        column-gap: 12px;
    }

    .app-footer-inner:has(.footer-middle) > .footer-counts {
        grid-area: 1 / 1;
        flex-wrap: nowrap;
    }

    .app-footer-inner:has(.footer-middle) > .footer-middle {
        grid-area: 1 / 2;
    }

    .app-footer-inner:has(.footer-middle) > .footer-end {
        grid-area: 1 / 3;
        flex-wrap: nowrap;
    }

    .footer-center > .footer-analysis {
        display: block;
    }

    .footer-end > .footer-analysis {
        display: none;
    }

    .footer-settings,
    .footer-actions {
        flex-wrap: nowrap;
    }

    /* Reducera, or Stoppa, as wide as the coverage before it. */
    .footer-middle .btn-primary {
        width: 190px;
    }

    .footer-cost {
        justify-items: end;
    }

}

/* Compact spacing at the first single-line widths preserves the larger buttons and their text size. */
@media (min-width: 1920px) and (max-width: 2079px) {
    .app-footer-inner {
        padding-inline: 20px;
    }

    .app-footer-inner:has(.footer-middle) {
        column-gap: 8px;
    }

    .footer-counts {
        column-gap: 8px;
    }

    .footer-settings {
        column-gap: 12px;
    }

    .footer-actions {
        gap: 8px;
    }

    .range.footer-coverage {
        width: 170px;
    }

    .footer-middle .btn-primary {
        min-width: 128px;
        width: 170px;
    }
}

/* Short names leave room to center the settings under the coupon while everything shares one line. */
@media (min-width: 1920px) and (max-width: 2559px) {
    .footer-counts .footer-long {
        display: none;
    }

    .footer-counts .footer-short {
        display: inline;
    }
}

@media (max-width: 600px) {
    .app-footer-inner,
    .footer-counts {
        gap: 8px 20px;
    }

    .app-footer-inner {
        min-height: 0;
        padding: 10px 12px;
        font-size: 14px;
    }

    .footer-count {
        gap: 7px;
    }

    /* The rows on a line of their own, and the bankers and hedges, with room for 13 of each, on the next. */
    .footer-rows {
        flex-basis: 100%;
        justify-content: flex-start;
        font-size: 14px;
        font-weight: 400;
    }

    .footer-rows .footer-number {
        font-weight: inherit;
    }

    .footer-cost {
        font-size: 16px;
    }

    .footer-settings {
        flex: 1;
        gap: 12px;
    }

    .footer-center {
        flex: 1;
    }

    .footer-field,
    .footer-actions {
        flex: 1 1 100%;
    }

    /* The setting's name over its buttons, which are as wide as the screen. */
    .footer-field {
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
    }

    .footer-field > .field-name {
        justify-content: center;
    }

    .footer-middle .segmented button {
        padding-inline: 6px;
        font-size: 15px;
    }

    .footer-actions .btn {
        flex: 1 1 auto;
    }

    .footer-long {
        display: none;
    }

    .footer-short {
        display: inline;
    }

    /* The bankers and hedges on the first line, and the rest on lines of their own under them. */
    .footer-progress,
    .footer-end {
        flex-basis: 100%;
    }

    .footer-end {
        flex-wrap: wrap;
        gap: 12px 16px;
    }

    .footer-end > .footer-analysis {
        flex: 1 1 auto;
    }

    .footer-end > .footer-analysis .btn {
        width: 100%;
    }

    .footer-status {
        left: 12px;
        max-width: calc(100% - 24px);
    }

    .app-footer .btn-download {
        flex: 1 1 auto;
    }
}

/* Blazor loading and error UI */

#blazor-error-ui {
    background: var(--warning-soft);
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    color: var(--warning);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui a {
    color: inherit;
}

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

.blazor-error-boundary {
    background: #b32121;
    padding: 1rem;
    color: white;
}

.blazor-error-boundary::after {
    content: "Ett fel har inträffat.";
}

.loading-progress {
    position: absolute;
    display: block;
    width: 8rem;
    height: 8rem;
    inset: 20vh 0 auto 0;
    margin: 0 auto 0 auto;
}

.loading-progress circle {
    fill: none;
    stroke: var(--border);
    stroke-width: 0.6rem;
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
}

.loading-progress circle:last-child {
    stroke: var(--primary);
    stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
    transition: stroke-dasharray 0.05s ease-in-out;
}

.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: bold;
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

.loading-progress-text:after {
    content: var(--blazor-load-percentage-text, "Laddar");
}

@media (max-width: 600px) {
    .app-header-inner {
        column-gap: 12px;
        padding: 12px 16px 0;
    }

    .brand {
        gap: 9px;
    }

    .brand-mark {
        width: 38px;
        height: 38px;
        font-size: 12px;
        border-radius: 10px;
    }

    .brand h1 {
        font-size: 17px;
    }

    .brand p {
        font-size: 11px;
    }

    .theme-toggle {
        width: 40px;
        padding: 8px;
    }

    .theme-toggle span {
        display: none !important;
    }

    .header-tools {
        gap: 12px;
    }

    .header-actions .btn {
        padding-inline: 12px;
    }

    .app-main {
        padding: 0 12px 36px;
    }

    .privacy-policy-link {
        left: 12px;
    }

    .layout,
    .group,
    .stack {
        gap: 18px;
    }

    .card {
        padding: 16px;
        gap: 16px;
    }

    /* A phone is narrower than the coupon's minimum width, so it takes the screen's width instead. */
    .coupon-card {
        min-width: 0;
    }

    .card h2 {
        font-size: 17px;
    }

    .segmented button {
        padding-inline: 7px;
    }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        transition: none !important;
    }
}
