/*
 * Quiz Scoreboard. Mobile-first, quiet and plain: system sans for everything people read and type,
 * one condensed face (Barlow Semi Condensed, OFL) for headings and ranks, like a scoreboard.
 */
@font-face {
    font-family: "Barlow Semi Condensed";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("../lib/fonts/barlow-semi-condensed/barlow-semi-condensed-600-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;
}

@font-face {
    font-family: "Barlow Semi Condensed";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("../lib/fonts/barlow-semi-condensed/barlow-semi-condensed-600-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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/*
 * Light and dark: every colour is light-dark(light, dark). The page follows the device (color-scheme: light dark)
 * unless the visitor picked one in the header (class color-scheme-light/-dark on <html>, from a cookie).
 * --accent fills buttons (white text in both modes); --accent-text is the accent as text or line on the sheet,
 * lighter in dark mode. The accent colours are the default quiz theme's (Themes/QuizThemes.cs, ThemeTests).
 */
:root {
    color-scheme: light dark;

    --text: light-dark(#1c2430, #e4e8ec);
    --muted: light-dark(#5b6675, #9ba6b2);
    --paper: light-dark(#ffffff, #161c20);
    --surface: light-dark(#f4f6f8, #1f262b);
    --line: light-dark(#dde3ea, #313a41);
    --accent: #0f6b5c;
    --accent-hover: #0b5347;
    --accent-soft: light-dark(#e3f0ed, #14302f);
    --accent-text: light-dark(#0f6b5c, #93bcb6);
    --danger: light-dark(#b42318, #f97a70);
    --danger-soft: light-dark(#fdf1f0, #3a1f1d);
    /* A filled red button (Delete) keeps white text in both modes. */
    --danger-fill: #b42318;
    --danger-fill-hover: #8f1c13;
    --plane: light-dark(#eaf0ee, #0a231e);
    --band: #123f37;
    --band-muted: #b9d3cc;

    --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --display: "Barlow Semi Condensed", "Arial Narrow", var(--sans);
    --radius: 6px;
    --control-height: 2.5rem;
}

:root.color-scheme-light {
    color-scheme: light;
}

:root.color-scheme-dark {
    color-scheme: dark;
}

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

/* The plane is a ruled notebook page: faint lines in the theme's colour and a red margin line, drawn with gradients
   so they follow the theme and dark mode without an image. Each line fades in and out over 2px instead of being a
   hard 1px stripe: with display scaling (125%, 150%) a hard line falls on one screen pixel or two, and every few lines
   one looks thicker. */
body {
    --ruling: light-dark(
        color-mix(in srgb, var(--accent-text) 22%, transparent),
        color-mix(in srgb, var(--accent-text) 14%, transparent));
    --margin-line: light-dark(rgba(214, 69, 65, 0.35), rgba(240, 110, 100, 0.3));
    position: relative;
    margin: 0;
    background:
        linear-gradient(90deg, transparent 3.5rem, var(--margin-line) 3.5rem calc(3.5rem + 1px), transparent calc(3.5rem + 1px)),
        repeating-linear-gradient(transparent 0 calc(1.75rem - 2px), var(--ruling) calc(1.75rem - 1px), transparent 1.75rem),
        var(--plane);
    color: var(--text);
    font-family: var(--sans);
    font-size: 1rem;
    line-height: 1.5;
}

/* The scoreboard band behind the header: deep green with a faint LED dot matrix. The page sheet overlaps its lower edge. */
body::before {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    z-index: -1;
    height: 13rem;
    background-color: var(--band);
    background-image: radial-gradient(rgba(255, 255, 255, 0.09) 1.2px, transparent 1.6px);
    background-size: 14px 14px;
}

/* ---------- Type ---------- */

h1,
h2 {
    font-family: var(--display);
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: 0.005em;
}

h1 {
    margin: 0.5rem 0 1rem;
    font-size: 2rem;
}

h2 {
    margin: 2rem 0 0.75rem;
    font-size: 1.375rem;
}

p {
    margin: 0 0 1rem;
    max-width: 38rem;
}

a {
    color: var(--accent-text);
    text-underline-offset: 0.15em;
}

a:hover {
    color: light-dark(var(--accent-hover), var(--text));
}

.muted {
    color: var(--muted);
}

:focus-visible {
    outline: 2px solid var(--accent-text);
    outline-offset: 2px;
}

/* ---------- Page frame ---------- */

.site-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    max-width: 64rem;
    margin: 0 auto;
    padding: 1rem 1rem 1.25rem;
}

.site-header :focus-visible {
    outline-color: #fff;
}

.brand {
    font-family: var(--display);
    font-size: 1.5rem;
    font-weight: 600;
    color: #fff;
    text-decoration: none;
}

.brand:hover {
    color: var(--band-muted);
}

/* The quiz's logo on the audience pages: on a white tile, so a dark or transparent logo stays visible on the band. */
.quiz-logo {
    min-width: 0;
    max-width: 40%;
    max-height: 3rem;
    padding: 0.25rem 0.5rem;
    border-radius: var(--radius);
    background: #fff;
    object-fit: contain;
}

/* Right side of the header: who is signed in, Sign out and the language. */
.header-actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.signed-in {
    color: var(--band-muted);
    font-size: 0.875rem;
}

/* The name makes way on a phone; Sign out stays. */
@media (max-width: 40rem) {
    .signed-in {
        display: none;
    }
}

/* Outlined on the band, like the language switch; two classes deep to outrank the primary button style. */
.site-header .header-button {
    min-height: 2rem;
    padding: 0.2rem 0.75rem;
    border: 1px solid rgba(255, 255, 255, 0.3);
    background: transparent;
    color: #fff;
    font-size: 0.875rem;
}

.site-header .header-button:hover {
    background-color: rgba(255, 255, 255, 0.1);
}

/* Sun or moon: square, like the other header buttons. */
.site-header .header-button.icon-only {
    width: 2rem;
}

/* Light mode shows the moon (to dark), dark mode the sun (to light), whether the device or a click decided. */
.color-scheme-switch .switch-to-light {
    display: none;
}

.color-scheme-dark .color-scheme-switch .switch-to-light {
    display: inline-flex;
}

.color-scheme-dark .color-scheme-switch .switch-to-dark {
    display: none;
}

@media (prefers-color-scheme: dark) {
    :root:not(.color-scheme-light) .color-scheme-switch .switch-to-light {
        display: inline-flex;
    }

    :root:not(.color-scheme-light) .color-scheme-switch .switch-to-dark {
        display: none;
    }
}

.site-header .sign-out .header-button {
    gap: 0.4rem;
}

/* A phone: Sign out as an icon (its name is in aria-label and title), the brand a little smaller. */
@media (max-width: 40rem) {
    .site-header .sign-out .header-button {
        width: 2rem;
        padding: 0;
    }

    .sign-out .label {
        display: none;
    }

    .header-actions {
        gap: 0.5rem;
    }
}

@media (max-width: 30rem) {
    .brand {
        font-size: 1.2rem;
    }
}

/* Language menu: closed, the flag and code of the current language, outlined like the other header buttons; open,
   a list on the page's colours (readable in light and dark mode) below it. */
.culture-menu {
    position: relative;
}

.culture-menu summary {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    border-radius: var(--radius);
    list-style: none;
    cursor: pointer;
    user-select: none;
}

.culture-menu summary::-webkit-details-marker {
    display: none;
}

.culture-switch {
    position: absolute;
    top: calc(100% + 0.35rem);
    right: 0;
    z-index: 10;
    display: flex;
    flex-direction: column;
    min-width: 11rem;
    padding: 0.3rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--paper);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}

/* Two classes deep so it outranks the primary button[type="submit"] style. */
.culture-switch button[type="submit"] {
    justify-content: flex-start;
    gap: 0.6rem;
    min-height: 2.25rem;
    padding: 0 0.6rem;
    border: 0;
    background: transparent;
    color: var(--text);
    font-weight: 400;
}

.culture-switch button[type="submit"]:hover {
    background: var(--surface);
    color: var(--text);
}

/* The header's white focus ring would vanish on the menu's paper. */
.culture-switch :focus-visible {
    outline-color: var(--accent-text);
}

.culture-switch button[aria-current="true"] {
    font-weight: 600;
}

.flag-icon {
    display: inline-flex;
    flex: none;
    width: 1.35rem;
    height: 0.95rem;
    overflow: hidden;
    border-radius: 2px;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
}

.flag-icon svg {
    width: 100%;
    height: 100%;
}

/* The white sheet the content sits on. */
main {
    max-width: 64rem;
    margin: 0 0.5rem 3rem;
    padding: 1.25rem 1rem 2.5rem;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(18, 63, 55, 0.06), 0 12px 32px rgba(18, 63, 55, 0.08);
}

@media (min-width: 48rem) {
    .site-header {
        padding: 1.25rem 2rem 1.5rem;
    }

    /* Centred, but always a little plane visible on either side. */
    main {
        width: calc(100% - 2rem);
        margin: 0 auto 4rem;
        padding: 2rem 2.5rem 3rem;
    }
}

/* Below the sheet, on the plane: a quiet link to About. */
.site-footer {
    margin: -1.5rem auto 2rem;
    text-align: center;
    font-size: 0.875rem;
}

.site-footer a {
    color: var(--muted);
}

/* Wide tables (Rankings: 15 sets and long team names fit on a laptop without scrolling). */
.wide .site-header,
.wide main {
    max-width: 90rem;
}

/* ---------- Controls ---------- */

.button,
button[type="submit"] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--control-height);
    padding: 0 1rem;
    border: 1px solid var(--accent);
    border-radius: var(--radius);
    background: var(--accent);
    color: #fff;
    font: inherit;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
}

.button:hover,
button[type="submit"]:hover {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
    color: #fff;
}

/* Lucide icons from icons.svg (Icon.Render); line style, coloured by the text colour of the button. */
svg.icon {
    width: 1.15rem;
    height: 1.15rem;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* A primary button with only an icon (save, add): square, the label lives in aria-label and title. */
.button.icon-only,
button[type="submit"].icon-only {
    width: var(--control-height);
    padding: 0;
}

/* Secondary: small tools next to content (move, delete, previous/next set, team link, language). */
button.icon,
.button.icon,
.set-navigation .button {
    min-width: var(--control-height);
    padding: 0 0.6rem;
    border: 1px solid var(--line);
    background: var(--paper);
    color: var(--text);
    font-weight: 400;
}

button.icon:hover,
.button.icon:hover,
.set-navigation .button:hover {
    background: var(--surface);
    border-color: var(--muted);
    color: var(--text);
}

button.icon.danger {
    color: var(--danger);
}

button.icon.danger:hover {
    background: var(--danger-soft);
    border-color: var(--danger);
    color: var(--danger);
}

input:not([type="checkbox"]):not([type="hidden"]),
select,
textarea {
    min-height: var(--control-height);
    padding: 0 0.6rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--paper);
    color: var(--text);
    font: inherit;
}

input:hover,
select:hover,
textarea:hover {
    border-color: var(--muted);
}

input[readonly] {
    background: var(--surface);
}

/* File fields (logo, .qsb import): the browser's own button made one of our secondary buttons, inside the field.
   Its label and the file name next to it stay the browser's text, in the browser's language. Chromium ignores the
   field's vertical padding, so the button's own margins centre it: its height plus margins fill the field exactly. */
input[type="file"] {
    padding: 0 0.6rem 0 0;
    color: var(--muted);
    cursor: pointer;
}

input[type="file"]::file-selector-button {
    height: calc(var(--control-height) - 0.5rem - 2px);
    margin: 0.25rem 0.75rem 0.25rem 0.25rem;
    padding: 0 0.9rem;
    border: 1px solid var(--line);
    border-radius: calc(var(--radius) - 2px);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    cursor: pointer;
}

input[type="file"]:hover::file-selector-button {
    border-color: var(--muted);
    background: var(--plane);
}

input[type="checkbox"] {
    width: 1.1rem;
    height: 1.1rem;
    accent-color: var(--accent);
}

label.checkbox {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--muted);
}

/* ---------- Messages ---------- */

.message {
    padding: 0.6rem 0.9rem;
    border-left: 3px solid var(--accent-text);
    background: var(--accent-soft);
    border-radius: 0 var(--radius) var(--radius) 0;
}

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

.field-error {
    color: var(--danger);
    font-size: 0.875rem;
}

.validation-summary-valid {
    display: none;
}

.validation-summary ul {
    margin: 0 0 1rem;
    padding: 0.6rem 0.9rem 0.6rem 2rem;
    border-left: 3px solid var(--danger);
    background: var(--danger-soft);
    color: var(--danger);
}

.confirm {
    margin-bottom: 1.5rem;
    padding: 1rem;
    border: 1px solid var(--danger);
    border-radius: var(--radius);
    background: var(--danger-soft);
}

.confirm p {
    margin-bottom: 0.75rem;
}

/* Theme colour on the Details page: a circle per theme, accent and band split diagonally, a ring on the chosen one. */
.swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}

.swatch {
    position: relative;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--swatch) 50%, var(--swatch-band) 50%);
    box-shadow: 0 0 0 1px var(--line);
    cursor: pointer;
}

/* The radio stays in place (focusable, announced) but invisible; the circle is what you see. */
.swatch input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.swatch:has(input:checked) {
    box-shadow: 0 0 0 2px var(--paper), 0 0 0 4px var(--text);
}

.swatch:has(input:focus-visible) {
    outline: 2px solid var(--accent-text);
    outline-offset: 5px;
}

/* Viewer pages: "Highlight team" above the tabs; the select takes the rest of a phone's width. */
.team-selector {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
    margin-bottom: 1rem;
}

.team-selector > label {
    color: var(--muted);
}

/* The field with a search icon on the left and the clear / all-teams buttons inside it on the right. */
.team-search {
    position: relative;
    flex: 1 1 14rem;
    max-width: 22rem;
}

.team-search > svg.icon {
    position: absolute;
    top: 50%;
    left: 0.7rem;
    transform: translateY(-50%);
    color: var(--muted);
    pointer-events: none;
}

/* [type] makes this as specific as the general input rule, which would otherwise reset the padding. */
.team-search input[type="search"] {
    width: 100%;
    padding-left: 2.2rem;
    padding-right: 4.5rem;
}

/* Our own clear button and list replace the browser's. */
.team-search input::-webkit-search-cancel-button,
.team-search input::-webkit-calendar-picker-indicator {
    display: none;
    appearance: none;
}

.team-search-clear:not([hidden]),
.team-search-toggle:not([hidden]) {
    position: absolute;
    top: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: 0;
    border-radius: var(--radius);
    background: transparent;
    color: var(--muted);
    transform: translateY(-50%);
    cursor: pointer;
}

.team-search-toggle {
    right: 0.25rem;
}

.team-search-clear {
    right: 2.25rem;
}

.team-search-clear:hover,
.team-search-toggle:hover {
    background: var(--surface);
    color: var(--text);
}

.team-listbox:not([hidden]) {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    left: 0;
    z-index: 10;
    max-height: 18rem;
    margin: 0;
    padding: 0.3rem;
    overflow-y: auto;
    list-style: none;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--paper);
    box-shadow: 0 8px 24px rgba(18, 63, 55, 0.12);
}

.team-listbox [role="option"] {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 0.55rem;
    border-radius: 4px;
    cursor: pointer;
}

.team-listbox [role="option"]:hover,
.team-listbox [role="option"][aria-selected="true"] {
    background: var(--accent-soft);
}

/* The team number as a small badge; filled for the team the arrow keys are on. */
.team-option-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.9rem;
    height: 1.5rem;
    padding: 0 0.35rem;
    border-radius: 999px;
    background: var(--surface);
    color: var(--muted);
    font-size: 0.8125rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.team-listbox [aria-selected="true"] .team-option-number {
    background: var(--accent);
    color: #fff;
}

.team-option-name mark {
    background: transparent;
    color: var(--accent-text);
    font-weight: 700;
}

.team-option-empty {
    padding: 0.45rem 0.55rem;
    color: var(--muted);
}

/* Rankings on the projector: next to the view tabs; pressed while it scrolls. */
button.auto-scroll {
    gap: 0.4rem;
    margin: 0 0 1.25rem 0.5rem;
    vertical-align: top;
}

/* .button's display would otherwise show buttons a script reveals (auto-scroll, viewer QR) before it runs. */
.button[hidden] {
    display: none;
}

/* Rankings and Results reveal: the viewer link's QR code over the page, big enough to scan from the back of the room. */
.viewer-qr-actions {
    margin-bottom: 1rem;
}

.viewer-qr {
    gap: 0.4rem;
}

.viewer-qr-dialog {
    padding: 1.5rem 2rem 1.75rem;
    border: 0;
    border-radius: 16px;
    background: var(--paper);
    color: var(--text);
    text-align: center;
    cursor: pointer;
}

.viewer-qr-dialog::backdrop {
    background: rgba(0, 0, 0, 0.65);
}

.viewer-qr-dialog h2 {
    margin: 0 0 1rem;
}

/* The SVG has its own white background and quiet zone: readable in dark mode too. */
.viewer-qr-dialog .qr svg {
    display: block;
    width: min(60vh, 80vw);
    height: auto;
    margin: 0 auto;
    border-radius: 8px;
}

.viewer-qr-code {
    margin: 1rem 0 0.25rem;
    font-size: 1.5rem;
}

.viewer-qr-code strong {
    font-family: var(--display);
    letter-spacing: 0.12em;
}

.viewer-qr-url {
    margin: 0;
    color: var(--muted);
    overflow-wrap: anywhere;
}

button.auto-scroll[aria-pressed="true"] {
    border-color: var(--accent-text);
    background: var(--accent-soft);
    color: var(--accent-text);
}

/* Publish status and buttons above the rankings / score panels. */
.publish-controls {
    margin-bottom: 1.5rem;
}

.publish-controls p {
    margin-bottom: 0.5rem;
}

/* The delete popup (confirm.js): a small card on a dimmed page, destructive action in red. */
.confirm-dialog {
    width: min(26rem, calc(100% - 2rem));
    padding: 1.5rem;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--paper);
    color: var(--text);
    box-shadow: 0 1px 2px rgba(18, 63, 55, 0.06), 0 24px 48px rgba(18, 63, 55, 0.18);
}

.confirm-dialog::backdrop {
    background: rgba(18, 63, 55, 0.35);
}

.confirm-dialog[open] {
    animation: confirm-dialog-in 120ms ease-out;
}

@keyframes confirm-dialog-in {
    from {
        opacity: 0;
        transform: translateY(6px);
    }
}

.confirm-dialog p {
    margin: 0 0 1.25rem;
    font-size: 1.0625rem;
}

.confirm-dialog .actions {
    justify-content: flex-end;
}

.confirm-dialog button[type="submit"].danger {
    border-color: var(--danger-fill);
    background: var(--danger-fill);
}

.confirm-dialog button[type="submit"].danger:hover {
    border-color: var(--danger-fill-hover);
    background: var(--danger-fill-hover);
}

/* The logo is uploaded apart from the details form, below a rule like the delete; the export likewise. */
.logo-section,
.export-section,
.import-section {
    max-width: 28rem;
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--line);
}

.logo-section h2,
.export-section h2,
.import-section h2 {
    margin-bottom: 0.25rem;
}

.logo-preview {
    display: block;
    max-width: 12rem;
    max-height: 6rem;
    margin: 0.75rem 0;
    padding: 0.5rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: #fff;
}

.upload-logo,
.remove-logo,
.import-quiz {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.75rem;
}

.upload-logo input[type="file"],
.import-quiz input[type="file"] {
    min-width: 0;
    flex: 1;
}

.remove-logo .icon.danger {
    gap: 0.4rem;
}

/* Deleting the whole quiz sits apart from the details form, below a rule. */
.delete-quiz-section {
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--line);
}

.delete-quiz-section .icon.danger {
    gap: 0.4rem;
}

.confirm form {
    display: flex;
    align-items: center;
    gap: 1rem;
}

/* ---------- Forms (new quiz, details) ---------- */

.form {
    max-width: 28rem;
}

.form .field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin-bottom: 1.25rem;
}

.form label {
    font-weight: 600;
}

/* Tie-break section of the quiz details: a heading like the other fields, radio choices as rows. */
/* Groups of choices in a form (Scoring, Tie-break): no browser box, a heading and room below like other fields. */
.form fieldset {
    margin: 0 0 1.5rem;
    padding: 0;
    border: 0;
}

.form fieldset legend {
    margin-bottom: 0.5rem;
    padding: 0;
    font-weight: 600;
}

.form label.choice {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    margin-bottom: 0.4rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-weight: 400;
    cursor: pointer;
}

.form label.choice:has(input:checked) {
    border-color: var(--accent-text);
    background: var(--accent-soft);
}

.form label.choice input {
    margin-top: 0.25rem;
    accent-color: var(--accent);
}

.choice-label {
    display: block;
    font-weight: 600;
}

.choice-hint {
    display: block;
    color: var(--muted);
    font-size: 0.875rem;
}

fieldset.tie-break .field,
fieldset.proclamation .field {
    margin: 0.75rem 0 0;
}

fieldset.proclamation:has(input[value="TopFirst"]:not(:checked)) .proclamation-top {
    display: none;
}

/* Only the field of the chosen system; without :has() support both stay visible. */
fieldset.tie-break:has(input[value="TieBreakSet"]:not(:checked)) .tie-break-set,
fieldset.tie-break:has(input[value="GuessQuestion"]:not(:checked)) .guess-answer {
    display: none;
}

.form .actions,
.actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
}

/* ---------- Quiz navigation ---------- */

/* Above a quiz's title: back to the admin's quiz list. */
.back-link {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    margin-bottom: 0.5rem;
    color: var(--muted);
    font-size: 0.875rem;
    text-decoration: none;
}

.back-link:hover {
    color: var(--text);
}

.quiz-tabs {
    display: flex;
    gap: 1.25rem;
    margin: 0 0 1.5rem;
    border-bottom: 1px solid var(--line);
    overflow-x: auto;
    scrollbar-width: none;
}

.quiz-tabs a {
    flex: none;
    padding: 0.6rem 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    color: var(--muted);
    text-decoration: none;
    white-space: nowrap;
}

.quiz-tabs a:hover {
    color: var(--text);
}

.quiz-tabs a.current {
    border-bottom-color: var(--accent-text);
    color: var(--text);
    font-weight: 600;
}

.ranking-views {
    display: inline-flex;
    margin: 0 0 1.25rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    /* The viewer's four tabs can be wider than a phone: scroll rather than break the page. */
    max-width: 100%;
    overflow-x: auto;
}

/* Tight on phones so the viewer's four tabs fit a 360px screen. */
.ranking-views a,
.ranking-views button {
    padding: 0.4rem 0.55rem;
    border: 0;
    background: none;
    color: var(--muted);
    font: inherit;
    font-size: 0.875rem;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

@media (min-width: 30rem) {
    .ranking-views a,
    .ranking-views button {
        padding: 0.4rem 0.9rem;
        font-size: 1rem;
    }
}

.ranking-views a + a,
.ranking-views button + button {
    border-left: 1px solid var(--line);
}

/* The team groups above the Evolution charts; .ranking-views' display would otherwise show them without charts.js. */
.chart-groups[hidden] {
    display: none;
}

.ranking-views button[aria-pressed="true"],
.ranking-views a[aria-selected="true"] {
    background: var(--accent-soft);
    color: var(--accent-text);
    font-weight: 600;
}

.set-navigation {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1.25rem;
}

.set-selector select {
    min-width: 12rem;
    max-width: 100%;
}

/* ---------- Lists ---------- */

.quiz-list,
.setup-list,
.missing-teams {
    margin: 0 0 1.5rem;
    padding: 0;
    list-style: none;
    border-top: 1px solid var(--line);
}

.quiz-list li,
.setup-list li,
.missing-teams li {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--line);
}

.quiz-list li {
    justify-content: space-between;
    padding: 0.9rem 0;
}

.quiz-name {
    font-weight: 600;
    text-decoration: none;
}

.quiz-name:hover {
    text-decoration: underline;
}

.quiz-date {
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Top-aligned, as tall as a field: they stay level with the first line when an error (or a phone) makes the row taller.
   Relative for the saved check (row-status), which shows in the drag handle's place. */
.setup-list li {
    position: relative;
    align-items: flex-start;
}

.setup-list .drag-handle,
.setup-list .position {
    align-items: center;
    min-height: var(--control-height);
}

.setup-list .position {
    display: inline-flex;
    justify-content: flex-end;
    min-width: 1.75rem;
    color: var(--muted);
    font-family: var(--display);
    font-size: 1.125rem;
}

.setup-list .admin .row-actions {
    margin-left: auto;
}

.row-form {
    display: flex;
    flex: 1 1 16rem;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.row-form input[name="Name"] {
    flex: 1 1 10rem;
}

.row-form input[type="number"] {
    width: 6rem;
}

/* A set code is at most 3 letters, shown as typed in capitals. */
.row-form input.set-code {
    width: 5rem;
    text-transform: uppercase;
}

/* After an automatic save (row-save.js): a check that fades, or the errors on a line of their own under the row,
   with the field they name marked. Without errors the status is out of the flow, so the fields never move: the check
   shows in the drag handle's place (on touch screens, without handles, the row number's). */
/* Centred on the first line (the row's top padding plus half a field), where the drag handle is. */
.setup-list .row-status:not(:has(.row-error)) {
    position: absolute;
    top: calc(0.6rem + var(--control-height) / 2);
    left: 0;
    transform: translateY(-50%);
}

.setup-list li:has(.row-saved) .drag-handle {
    visibility: hidden;
}

@media (pointer: coarse) {
    .setup-list li:has(.row-saved) .position {
        visibility: hidden;
    }
}

.row-saved {
    display: inline-flex;
    color: var(--accent-text);
    animation: row-saved 2.5s ease-in forwards;
}

@keyframes row-saved {
    0%, 60% { opacity: 1; }
    100% { opacity: 0; }
}

.row-status:has(.row-error) {
    display: flex;
    flex: 1 0 100%;
    flex-direction: column;
}

.row-error {
    color: var(--danger);
    font-size: 0.875rem;
}

/* The quiz details save as one form, long enough to scroll: the check stays in sight at the bottom. */
.quiz-details .actions {
    position: sticky;
    bottom: 1rem;
    min-height: 1.5rem;
}

.row-form:has(.row-error[data-field="Name"]) [name="Name"],
.row-form:has(.row-error[data-field="Code"]) [name="Code"],
.row-form:has(.row-error[data-field="MinScore"]) [name="MinScore"],
.row-form:has(.row-error[data-field="MaxScore"]) [name="MaxScore"],
.row-form:has(.row-error[data-field="Questions"]) [name="Questions"] {
    border-color: var(--danger);
}

.row-actions {
    display: flex;
    gap: 0.25rem;
}

/* Same width as an arrow button, where the arrow doesn't apply: keeps every row's buttons aligned. */
.icon-slot {
    display: inline-block;
    width: var(--control-height);
}

/* Drag and drop (reorder.js). The markers use inset shadows, so the rows don't shift while dragging. */
.drag-handle {
    display: inline-flex;
    color: var(--muted);
    cursor: grab;
    user-select: none;
}

.drag-handle:active {
    cursor: grabbing;
}

.setup-list li.dragging {
    opacity: 0.4;
}

.setup-list li.drop-before {
    box-shadow: inset 0 3px 0 var(--accent-text);
}

.setup-list li.drop-after {
    box-shadow: inset 0 -3px 0 var(--accent-text);
}

/* HTML5 drag and drop doesn't work with touch; phones use the arrows. */
@media (pointer: coarse) {
    .drag-handle {
        display: none;
    }
}

/* Add-a-set/team bar on top of the list, set apart like the score-entry panel. */
.add-bar {
    margin-bottom: 1.25rem;
    padding: 0.75rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
}

/* Teams: a pasted list, folded away under the add bar until wanted. */
.add-many {
    margin: -0.75rem 0 1.25rem;
}

.add-many summary {
    width: fit-content;
    color: var(--accent-text);
    font-size: 0.875rem;
    cursor: pointer;
}

.add-many form {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
    margin-top: 0.5rem;
}

.add-many textarea {
    width: 100%;
    padding: 0.5rem 0.6rem;
    resize: vertical;
}

.invite {
    margin-bottom: 1rem;
}

.invite-link {
    width: 100%;
    font-size: 0.875rem;
}

/* ---------- Score entry ---------- */

.score-entry {
    padding: 1rem;
    margin-bottom: 1rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
}

.score-entry label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 600;
}

.score-entry input {
    width: 5rem;
    font-size: 1.125rem;
    font-variant-numeric: tabular-nums;
}

#team-name {
    min-width: 8rem;
}

.score-panels {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.5rem 2.5rem;
    margin-top: 1.5rem;
}

@media (min-width: 48rem) {
    .score-panels {
        grid-template-columns: 1fr 1fr;
    }
}

/* The publish controls span both panel columns. */
.panels-publish {
    grid-column: 1 / -1;
}

.score-panels h2 {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    margin-top: 0;
    font-size: 1.125rem;
}

.score-panels h2 .muted {
    font-family: var(--sans);
    font-size: 0.9375rem;
    font-weight: 400;
    font-variant-numeric: tabular-nums;
}

/* ---------- Tables ---------- */

.table-scroll {
    overflow-x: auto;
    margin-bottom: 1.5rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

.score-table,
table.overview,
table.ranking {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}

table.overview,
table.ranking {
    white-space: nowrap;
}

table.ranking {
    max-width: 36rem;
}

.score-table td,
table.overview td,
table.overview th,
table.ranking td,
table.ranking th {
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--line);
    text-align: right;
}

.score-table td {
    padding: 0.4rem 0.5rem;
}

table.overview th,
table.ranking th {
    background: var(--surface);
    color: var(--muted);
    font-size: 0.875rem;
    font-weight: 600;
}

table.overview tbody tr:last-child td {
    border-bottom: 0;
}

/* Set scores are 1-3 digits: compact columns, so 15 sets need ~41rem. */
table.overview th.set,
table.overview .set-points {
    min-width: 2.75rem;
    padding-left: 0.4rem;
    padding-right: 0.4rem;
}

/* Long team names wrap instead of being cut off (or pushing the table past a phone screen). */
table.ranking .name {
    white-space: normal;
    overflow-wrap: anywhere;
}

/* Long team names wrap instead of being cut off; the full name is also the tooltip. */
table.overview .name {
    min-width: 8rem;
    max-width: 12rem;
    white-space: normal;
    overflow-wrap: anywhere;
}

/* A rule between every column; the outer edge comes from .table-scroll. */
table.overview td + td,
table.overview th + th {
    border-left: 1px solid var(--line);
}

.score-table .position,
table.overview .position,
table.ranking .position {
    width: 2.5rem;
    color: var(--muted);
}

table.overview .name,
table.overview th.sticky,
table.ranking .name,
table.ranking th:nth-child(2) {
    text-align: left;
}

/* The team column stays in view while S1..Sn scroll; it needs its own background to cover them. */
table.overview th.sticky,
table.overview td.sticky {
    position: sticky;
    left: 0;
    background: var(--paper);
    box-shadow: inset -1px 0 0 var(--line);
}

table.overview th.sticky {
    background: var(--surface);
}

/* The team of a team link (?team=N): tinted and bold, with a bar on the left so it also shows without colour. */
table.overview tr.highlight td,
table.ranking tr.highlight td {
    background: var(--accent-soft);
    font-weight: 700;
}

table.overview tr.highlight td:first-child,
table.ranking tr.highlight td:first-child {
    box-shadow: inset 4px 0 0 var(--accent-text);
}

/* On a phone: tighter cells, smaller set scores and a narrower team column, so more sets fit beside the team. */
@media (max-width: 40rem) {
    table.overview td,
    table.overview th,
    table.ranking td,
    table.ranking th {
        padding: 0.35rem 0.4rem;
    }

    table.overview th.set,
    table.overview .set-points {
        min-width: 2.25rem;
        padding-left: 0.25rem;
        padding-right: 0.25rem;
        font-size: 0.875rem;
    }

    /* Break between words only: with "anywhere" the column shrinks until names break mid-word. */
    table.overview .name {
        min-width: 6rem;
        max-width: 9.5rem;
        overflow-wrap: break-word;
    }

    table.overview .rank,
    table.ranking .rank {
        font-size: 1.0625rem;
    }
}

.team-score {
    font-weight: 600;
}

table.overview .rank,
table.ranking .rank {
    font-family: var(--display);
    font-size: 1.25rem;
}

table.overview .total,
table.ranking .points {
    font-weight: 600;
}

/* Next to the total, quieter, so the total stays the figure that counts. */
table.overview .percentage {
    color: var(--muted);
}

.bar-cell {
    width: 40%;
}

.bar {
    display: block;
    height: 0.5rem;
    min-width: 3rem;
    background: var(--line);
    border-radius: 999px;
    overflow: hidden;
}

.bar-fill {
    display: block;
    height: 100%;
    background: var(--accent-text);
    border-radius: 999px;
}

/* ---------- Landing page ---------- */

/* Start page and About: Rodin's Thinker (GDJ, Pixabay) faintly in the sheet's top corner, looking at the text. The
   picture is a mask (dark bronze opaque, highlights see-through), so it takes the site's colour in both modes; a
   pseudo-element behind the content of an isolated sheet, so it never covers text or takes a click. */
.backdrop main {
    position: relative;
    isolation: isolate;
}

.backdrop main::before {
    content: "";
    position: absolute;
    top: 1.5rem;
    right: 1.5rem;
    z-index: -1;
    width: min(40%, 17rem);
    aspect-ratio: 726 / 900;
    background-color: light-dark(
        color-mix(in srgb, var(--accent-text) 20%, transparent),
        color-mix(in srgb, var(--accent-text) 16%, transparent));
    mask: url("/images/thinker.webp") no-repeat top right / contain;
    pointer-events: none;
}

/* The maker's logo on About: a picture on white, so a white tile in dark mode too. */
.maker-logo {
    display: block;
    width: 11rem;
    height: auto;
    padding: 0.5rem 0.75rem;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

/* On a phone he stands behind the text: smaller and fainter. */
@media (max-width: 40rem) {
    .backdrop main::before {
        top: 1rem;
        right: 0.75rem;
        width: 45%;
        background-color: color-mix(in srgb, var(--accent-text) 10%, transparent);
    }
}

.landing-intro .lead {
    max-width: 38rem;
    font-size: 1.1875rem;
}

/* The five steps of a quiz night, numbered like a scoreboard. */
.landing-steps {
    display: grid;
    gap: 1.5rem 2.5rem;
    margin: 2.5rem 0;
    padding: 0;
    list-style: none;
    counter-reset: step;
}

@media (min-width: 48rem) {
    .landing-steps {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.landing-steps li {
    position: relative;
    padding: 1rem 0 0 3.25rem;
    border-top: 2px solid var(--text);
    counter-increment: step;
}

.landing-steps li::before {
    content: counter(step);
    position: absolute;
    top: 0.75rem;
    left: 0;
    color: var(--accent-text);
    font-family: var(--display);
    font-size: 2.5rem;
    font-weight: 600;
    line-height: 1;
}

/* Heading and the step's icon on one row, the text below them at full width. */
.step-heading {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.4rem;
}

.step-icon {
    display: grid;
    flex: none;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: var(--radius);
    background: var(--accent-soft);
    color: var(--accent-text);
}

.step-icon svg.icon {
    width: 1.5rem;
    height: 1.5rem;
}

.landing-steps h2 {
    margin: 0;
    font-size: 1.25rem;
}

/* Microsoft and Google side by side, or wrapped on a phone. */
a.sign-in {
    gap: 0.6rem;
    margin: 0 0.5rem 0.5rem 0;
    padding-left: 0.4rem;
}

/* The provider's logo on a small white tile: Google's guidelines want its logo on white, Microsoft's matches. */
.provider-logo {
    display: inline-flex;
    padding: 0.3rem;
    background: #fff;
    border-radius: 4px;
}

.provider-logo svg.icon {
    width: 1.1rem;
    height: 1.1rem;
}

.landing-steps p {
    margin: 0;
    color: var(--muted);
}

.landing-end {
    padding-top: 1.5rem;
    border-top: 1px solid var(--line);
}

.landing-end h2 {
    margin-top: 0;
}

/* ---------- Proclamation (projector) ---------- */

/* The team just revealed on the scoreboard band, big enough to read at the back of the room. */
.proclamation-current {
    display: grid;
    justify-items: center;
    gap: 0.25rem;
    margin: 1rem 0 1.5rem;
    padding: 2rem 1rem;
    border-radius: 12px;
    background: var(--band);
    color: #fff;
    text-align: center;
}

.proclamation-current p {
    margin: 0;
}

.proclaimed-rank {
    font-family: var(--display);
    font-size: clamp(4rem, 12vw, 8rem);
    line-height: 1;
}

.proclaimed-name {
    font-family: var(--display);
    font-size: clamp(2rem, 6vw, 4rem);
    line-height: 1.1;
    overflow-wrap: anywhere;
}

.proclaimed-points {
    color: var(--band-muted);
    font-size: clamp(1.25rem, 3vw, 2rem);
}

/* Gold, silver and bronze for ranks 1 to 3: a disc with a ring, no image needed. */
.medal {
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    box-shadow: inset 0 0 0 0.4rem rgba(255, 255, 255, 0.35);
}

.medal.gold {
    background: #d4a017;
}

.medal.silver {
    background: #aeb6bf;
}

.medal.bronze {
    background: #b0703a;
}

.proclamation-ready {
    margin: 3rem 0;
    font-size: 1.5rem;
    text-align: center;
}

.proclamation-controls {
    justify-content: center;
    margin-bottom: 1.5rem;
}

.proclamation-controls .icon,
.proclamation-controls button {
    gap: 0.4rem;
}

table.proclamation-list {
    width: 100%;
    max-width: 40rem;
    margin: 0 auto;
    border-collapse: collapse;
    font-size: 1.25rem;
    font-variant-numeric: tabular-nums;
}

table.proclamation-list td {
    padding: 0.4rem 0.75rem;
    border-bottom: 1px solid var(--line);
}

table.proclamation-list .rank {
    width: 3rem;
    font-family: var(--display);
}

table.proclamation-list .points {
    text-align: right;
    font-weight: 600;
}

table.proclamation-list tr.current td {
    background: var(--accent-soft);
    font-weight: 700;
}

/* ---------- Analysis ---------- */

.statistics {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.25rem 2rem;
    margin: 0 0 2rem;
}

@media (min-width: 40rem) {
    .statistics {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

.statistic {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding-top: 0.75rem;
    border-top: 2px solid var(--text);
}

.statistic dt {
    order: 2;
    color: var(--muted);
    font-size: 0.875rem;
}

.statistic .value {
    order: 1;
    margin: 0;
    font-size: 1.75rem;
    font-weight: 600;
    line-height: 1.1;
}

.statistic .bar {
    order: 3;
}

/* The chart fills its box (charts.js: maintainAspectRatio off), so its shape comes from here: wide on a screen, about
   square on a phone held upright, where 2:1 left a chart under 200px high, half of it legend. */
.chart-box {
    position: relative;
    aspect-ratio: 2 / 1;
    margin-bottom: 1.5rem;
}

@media (max-width: 40rem) and (orientation: portrait) {
    .chart-box {
        aspect-ratio: 1 / 1.15;
    }
}

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