/* PandaPoll — mobile-first design system.
 *
 * The page is used one-handed, in a group chat, usually while doing something
 * else. So: one question at a time, thumb-sized targets, and never a control
 * whose meaning depends on colour alone.
 *
 * Two rules hold the system together:
 *
 * 1. Every fill carries its own ink. A colour is never used as a background
 *    without the matching `-on` token on top of it. The previous palette used
 *    one token for "tint a bar" and "fill a button" and then put white on it,
 *    which measured 4.7:1 in light mode, 2.5:1 in dark, and 1.8:1 for the
 *    selected middle tier. Pairing fill with ink makes that unspellable.
 * 2. Sizes come from the scale below. The previous sheet rendered sixteen
 *    distinct font sizes on a single screen, because every rule invented its
 *    own rem fraction (.72, .75, .78, .82, .85, .88, .92, .95…).
 */

/* ------------------------------------------------------------------ tokens */

:root {
    color-scheme: light dark;

    /* Warm paper and soft ink: the surface a friendly thing is printed on. */
    --bg: #fbf7f0;
    --surface: #ffffff;
    --surface-2: #f4efe6;
    --fg: #241f1a;
    --muted: #645c53;
    --faint: #6e655b;
    --line: #e8e1d5;
    --line-strong: #d6ccbc;

    /* Pale fill + dark ink, verified as a pair in both schemes. `-solid` is
     * for bars and hairlines and must never sit under text. */
    --great-fill: #c9e9d5;
    --great-on: #12492e;
    --great-solid: #2e7d51;

    --okay-fill: #fbe6c4;
    --okay-on: #6b4508;
    --okay-solid: #b57a1e;

    --cant-fill: #f9d9d2;
    --cant-on: #7a2b20;
    --cant-solid: #b0483c;

    --accent-fill: #d3e4f7;
    --accent-on: #0f3a66;
    --accent-solid: #2c608f;

    /* Actions get their own pair. The wash above is right for a pill or a
     * notice and wrong for a button: measured against the card it sits on,
     * the pale green read at 1.30:1 and the pale blue at 1.36:1, so the most
     * important control on the page had almost no presence. These carry
     * enough colour to read as a button — and still take dark ink, because
     * white-on-light was the original mistake, not the colour itself. */
    --great-action: #4fae7c;
    --great-action-on: #062a17;
    --accent-action: #7cb2df;
    --accent-action-on: #08243d;

    /* Aliases, so a rule written against the old names cannot silently lose
     * its colour. */
    --great: var(--great-solid);
    --great-ink: var(--great-on);
    --okay: var(--okay-solid);
    --okay-ink: var(--okay-on);
    --cant: var(--cant-solid);
    --accent: var(--accent-solid);
    --accent-ink: var(--accent-on);
    --on-accent: var(--accent-on);

    /* Type scale. Seven steps, floor 13px, nothing in between them. */
    --t-1: .8125rem;   /* 13px — micro, the smallest thing we will print */
    --t-2: .9375rem;   /* 15px — hints, secondary */
    --t-3: 1.0625rem;  /* 17px — body */
    --t-4: 1.25rem;    /* 20px — subheads, the primary button */
    --t-5: 1.625rem;   /* 26px — headline */
    --t-6: 2.125rem;   /* 34px — the day being asked about */
    --t-7: 2.75rem;    /* 44px — the confirmed moment */

    /* Four weights. 300 is display-only: it is generous at 34px and mush at
     * 13px, which is the one thing not worth copying from anybody. */
    --w-light: 300;
    --w-normal: 400;
    --w-medium: 500;
    --w-semi: 600;

    /* Spacing, 4px based. */
    --s-1: .25rem;
    --s-2: .5rem;
    --s-3: .75rem;
    --s-4: 1rem;
    --s-5: 1.5rem;
    --s-6: 2rem;
    --s-7: 3rem;

    /* Softer geometry than before: friendlier, and it suits the pale fills. */
    --r-sm: .625rem;
    --r-md: 1rem;
    --r-lg: 1.5rem;
    --r-full: 999px;

    --tap: 3rem;         /* 48px: the smallest thing worth aiming at */
    --tap-lg: 3.5rem;    /* 56px: the primary action */

    /* Warm-tinted and quiet. Air does the separating; shadow only lifts the
     * one thing the page is asking about. */
    --shadow-1: 0 1px 2px rgba(60, 46, 28, .05);
    --shadow-2: 0 6px 20px rgba(60, 46, 28, .09), 0 1px 3px rgba(60, 46, 28, .05);
    --shadow-up: 0 -8px 24px rgba(60, 46, 28, .07);

    --ease: cubic-bezier(.2, .7, .3, 1);
}

/* Dark lives in two places on purpose. The media query is the default and is
 * suppressed when the reader has explicitly chosen light; the attribute rule
 * is the explicit choice and has to win in both directions. Custom properties
 * cannot be shared between the two selectors, so the block is written twice —
 * change one, change the other. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --bg: #16130f;
        --surface: #201c17;
        --surface-2: #2a251e;
        --fg: #f3eee5;
        --muted: #b3a899;
        --faint: #a2988a;
        --line: #352f26;
        --line-strong: #453d31;

        /* The pairs invert — deep fill, light ink — so every component keeps
         * working without knowing which scheme it is in. */
        --great-fill: #1b3a2a;
        --great-on: #a6e3be;
        --great-solid: #56b782;

        --okay-fill: #3a2e17;
        --okay-on: #f0ce86;
        --okay-solid: #dda94f;

        --cant-fill: #3b221c;
        --cant-on: #f3b3a6;
        --cant-solid: #d97b6d;

        --accent-fill: #17293d;
        --accent-on: #a9cdf2;
        --accent-solid: #7fb0e6;

        /* Saturated here, because on a dark card a deep fill is a card. */
        --great-action: #56b782;
        --great-action-on: #0b2c1b;
        --accent-action: #7fb0e6;
        --accent-action-on: #0b2036;

        --shadow-1: 0 1px 2px rgba(0, 0, 0, .35);
        --shadow-2: 0 6px 20px rgba(0, 0, 0, .45), 0 1px 3px rgba(0, 0, 0, .3);
        --shadow-up: 0 -8px 24px rgba(0, 0, 0, .4);
    }
}

/* An explicit choice also pins color-scheme, or the browser keeps drawing its
 * own form controls, scrollbars and autofill in the other scheme. */
:root[data-theme="light"] { color-scheme: light; }

:root[data-theme="dark"] {
    color-scheme: dark;
    --bg: #16130f;
    --surface: #201c17;
    --surface-2: #2a251e;
    --fg: #f3eee5;
    --muted: #b3a899;
    --faint: #a2988a;
    --line: #352f26;
    --line-strong: #453d31;

    --great-fill: #1b3a2a;
    --great-on: #a6e3be;
    --great-solid: #56b782;

    --okay-fill: #3a2e17;
    --okay-on: #f0ce86;
    --okay-solid: #dda94f;

    --cant-fill: #3b221c;
    --cant-on: #f3b3a6;
    --cant-solid: #d97b6d;

    --accent-fill: #17293d;
    --accent-on: #a9cdf2;
    --accent-solid: #7fb0e6;

    --great-action: #56b782;
    --great-action-on: #0b2c1b;
    --accent-action: #7fb0e6;
    --accent-action-on: #0b2036;

    --shadow-1: 0 1px 2px rgba(0, 0, 0, .35);
    --shadow-2: 0 6px 20px rgba(0, 0, 0, .45), 0 1px 3px rgba(0, 0, 0, .3);
    --shadow-up: 0 -8px 24px rgba(0, 0, 0, .4);
}

* { box-sizing: border-box; }

/* [hidden] is a UA stylesheet rule, so any author rule that gives an element a
 * display of its own beats it. .roster-row is a grid and every button is an
 * inline-flex, which quietly cost the roster its collapse, the "Person
 * hinzufügen" button its ability to disappear once the list is full, and each
 * row its × control — the create form opened with all eight name fields on
 * screen. One global rule rather than three patched selectors: the next
 * element that gets both a display and a hidden toggle should not have to
 * rediscover this. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    min-height: 100dvh;
    background: var(--bg);
    color: var(--fg);
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    font-size: var(--t-3);
    font-weight: var(--w-normal);
    line-height: 1.55;
    /* A pasted link or a name without spaces must not widen the page: on a
     * phone that turns into a sideways scroll the whole layout inherits. */
    overflow-wrap: break-word;
    /* No 300ms delay, no grey flash box on tap: the two things that make a
     * web page feel unlike an app. */
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    display: flex;
    flex-direction: column;
}

/* ------------------------------------------------------------------ layout */

.appbar {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: var(--s-2);
    padding: var(--s-3) var(--s-4);
    padding-top: max(var(--s-3), env(safe-area-inset-top));
    background: color-mix(in srgb, var(--bg) 86%, transparent);
    backdrop-filter: saturate(160%) blur(12px);
    -webkit-backdrop-filter: saturate(160%) blur(12px);
    border-bottom: 1px solid var(--line);
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: var(--s-2);
    /* A real 44px target, stated rather than hoped for: padding alone landed
     * it on 42. */
    min-height: 2.75rem;
    padding: var(--s-2) var(--s-2) var(--s-2) 0;
    font-size: var(--t-3);
    font-weight: var(--w-medium);
    letter-spacing: -.015em;
    text-decoration: none;
    color: var(--fg);
}
.brand .mark { font-size: 1.25rem; line-height: 1; }

.appbar .spacer { flex: 1; }

main {
    flex: 1;
    width: 100%;
    max-width: 32rem;
    margin: 0 auto;
    padding: var(--s-4) var(--s-4) var(--s-6);
}

/* Room for the sticky action bar so the last card is never trapped under it. */
main.has-thumb { padding-bottom: var(--s-4); }

footer {
    border-top: 1px solid var(--line);
    padding: var(--s-4) var(--s-4) calc(var(--s-4) + env(safe-area-inset-bottom));
    color: var(--faint);
    font-size: var(--t-1);
    text-align: center;
}
footer p { margin: 0; }

/* Quiet by design: a preference, not an action. It still gets a full 44px. */
.theme-toggle {
    margin: var(--s-3) auto 0;
    min-height: 2.75rem;
    padding: var(--s-2) var(--s-3);
    background: transparent;
    border: 1px solid var(--line);
    border-radius: var(--r-full);
    color: var(--muted);
    font-size: var(--t-1);
    font-weight: var(--w-medium);
}
.theme-toggle [data-theme-icon] { font-size: var(--t-2); line-height: 1; }

/* The install hint: one paragraph and two small buttons, shown once. */
.install {
    margin: 0 auto var(--s-4);
    max-width: 28rem;
    padding: var(--s-3);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    color: var(--muted);
    text-align: left;
}
.install-actions { display: flex; gap: var(--s-2); margin-top: var(--s-2) !important; }

/* ---------------------------------------------------------------- typography */

h1 {
    font-size: var(--t-5);
    line-height: 1.15;
    letter-spacing: -.02em;
    margin: var(--s-2) 0 var(--s-1);
    font-weight: var(--w-semi);
}
h2 {
    font-size: var(--t-4);
    line-height: 1.25;
    margin: 0 0 var(--s-2);
    letter-spacing: -.01em;
    font-weight: var(--w-medium);
}

.section-label {
    font-size: var(--t-1);
    text-transform: uppercase;
    letter-spacing: .08em;
    font-weight: var(--w-semi);
    color: var(--faint);
    margin: var(--s-6) 0 var(--s-3);
}

.lede {
    color: var(--muted);
    font-size: var(--t-3);
    margin: var(--s-2) 0 var(--s-5);
}
.hint {
    color: var(--muted);
    font-size: var(--t-2);
    font-weight: var(--w-normal);
    line-height: 1.5;
}
.micro { font-size: var(--t-1); color: var(--faint); line-height: 1.5; }
/* The gate explaining why this browser is a stranger again: set apart from
 * the ordinary hint below it, in the body colour because it is news. */
.hint.lost { color: var(--fg); margin-bottom: var(--s-3); }

/* The UA draws <strong> at 700, which is a fifth weight the scale does not
 * have. Emphasis is one step up from its surroundings, not a jump. */
strong, b { font-weight: var(--w-semi); }

/* Links inside running text. Without this they fall back to the UA's blue —
 * #0000EE in light, a pale periwinkle in dark — neither of which belongs
 * anywhere near this palette. Underlined, because in a sentence colour alone
 * is not allowed to be the only signal. */
main a:not(.button):not(.brand):not(.person-pick):not(.recent-link) {
    color: var(--accent-on);
    text-decoration: underline;
    text-underline-offset: .18em;
    text-decoration-thickness: .07em;
    text-decoration-color: color-mix(in srgb, var(--accent-on) 45%, transparent);
}
main a:not(.button):not(.brand):not(.person-pick):not(.recent-link):hover {
    text-decoration-color: currentColor;
}

.kicker {
    margin: 0 0 var(--s-2);
    font-size: var(--t-1);
    font-weight: var(--w-semi);
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--accent-on);
}

.tag {
    display: inline-block;
    font-size: var(--t-1);
    background: var(--accent-fill);
    color: var(--accent-on);
    padding: var(--s-1) var(--s-2);
    border-radius: var(--r-full);
    vertical-align: middle;
    font-weight: var(--w-semi);
}

/* ------------------------------------------------------------------- meta */

.meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
    margin: var(--s-3) 0 var(--s-4);
}

.pill {
    display: inline-flex;
    align-items: center;
    gap: var(--s-1);
    padding: var(--s-1) var(--s-3);
    border-radius: var(--r-full);
    background: var(--surface-2);
    color: var(--muted);
    font-size: var(--t-2);
    white-space: nowrap;
}
.pill.warn { background: var(--okay-fill); color: var(--okay-on); font-weight: var(--w-medium); }
.pill.go { background: var(--great-fill); color: var(--great-on); font-weight: var(--w-medium); }

/* ------------------------------------------------------------------ cards */

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: var(--s-5);
    margin: var(--s-3) 0;
    box-shadow: var(--shadow-1);
}
.card > :first-child { margin-top: 0; }
.card > :last-child { margin-bottom: 0; }

.card.flat { box-shadow: none; background: transparent; border-color: transparent; }
.card.warn { border-color: color-mix(in srgb, var(--okay-solid) 40%, var(--line)); }
.card.confirmed { border-color: color-mix(in srgb, var(--great-solid) 40%, var(--line)); }
.card.off { border-color: color-mix(in srgb, var(--cant-solid) 35%, var(--line)); }

/* The one question the page is actually asking. It is the only card that
 * lifts off the page, which is how it is picked out at arm's length. */
.ask {
    border: 1px solid color-mix(in srgb, var(--accent-solid) 25%, var(--line));
    box-shadow: var(--shadow-2);
    padding: var(--s-5);
}
/* The day is the biggest thing on the screen and the lightest: at 34px the
 * light weight reads as generous rather than thin. */
.ask .when-day {
    font-size: var(--t-6);
    line-height: 1.08;
    font-weight: var(--w-light);
    letter-spacing: -.02em;
    margin: var(--s-2) 0 0;
}
.ask .when-clock {
    font-size: var(--t-5);
    font-weight: var(--w-light);
    color: var(--muted);
    margin: var(--s-1) 0 0;
    font-variant-numeric: tabular-nums;
}
.ask .when-rel {
    display: inline-flex;
    margin-top: var(--s-3);
}

.headline {
    margin: 0 0 var(--s-2);
    font-size: var(--t-5);
    font-weight: var(--w-light);
    letter-spacing: -.02em;
    line-height: 1.2;
}

/* ---------------------------------------------------------------- progress */

.progress {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    margin: 0 0 var(--s-2);
}
.dots { display: flex; gap: var(--s-1); }
.dot {
    width: .4375rem;
    height: .4375rem;
    border-radius: var(--r-full);
    background: var(--line-strong);
}
.dot.done { background: var(--accent-solid); }
.dot.now {
    background: var(--accent-solid);
    box-shadow: 0 0 0 3px var(--accent-fill);
}

/* All times on offer, in date order, so a run of same-day alternatives can
 * be scanned at a glance instead of only compared one question at a time. */
.mini-overview {
    display: flex;
    gap: var(--s-2);
    overflow-x: auto;
    margin: 0 0 var(--s-3);
    padding: 0 0 var(--s-1);
    -webkit-overflow-scrolling: touch;
}
.mini-slot {
    display: inline-flex;
    align-items: center;
    gap: var(--s-1);
    flex: none;
    padding: var(--s-1) var(--s-3);
    border-radius: var(--r-full);
    background: var(--surface-2);
    color: var(--muted);
    font-size: var(--t-1);
    white-space: nowrap;
}
.mini-slot.now {
    background: var(--accent-fill);
    color: var(--accent-on);
    font-weight: var(--w-medium);
    box-shadow: 0 0 0 1px var(--accent-solid);
}
.mini-slot.great { background: var(--great-fill); color: var(--great-on); }
.mini-slot.okay { background: var(--okay-fill); color: var(--okay-on); }
.mini-slot.cant { background: var(--cant-fill); color: var(--cant-on); }
.mini-icon { font-weight: var(--w-semi); }

/* ----------------------------------------------------------------- buttons */

button, .button {
    font: inherit;
    font-size: var(--t-2);
    font-weight: var(--w-medium);
    color: var(--fg);
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    padding: var(--s-3) var(--s-4);
    min-height: var(--tap);
    cursor: pointer;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--s-2);
    transition: transform .12s var(--ease), background-color .15s var(--ease),
                border-color .15s var(--ease);
}
button:active, .button:active { transform: scale(.98); }
button:focus-visible, .button:focus-visible, a:focus-visible,
input:focus-visible, select:focus-visible, summary:focus-visible {
    outline: 3px solid var(--accent-solid);
    outline-offset: 2px;
}

/* The action pair, not the wash: this has to look like the thing you press. */
.button.primary, button.primary {
    background: var(--accent-action);
    border: 1px solid color-mix(in srgb, var(--accent-action) 70%, #000);
    color: var(--accent-action-on);
    font-weight: var(--w-semi);
}
.button.block, button.block { width: 100%; }
button.big { min-height: var(--tap-lg); font-size: var(--t-4); }
button.small, .button.small {
    min-height: 2.5rem;
    padding: var(--s-1) var(--s-3);
    font-size: var(--t-1);
}
button.ghost { background: transparent; border-color: var(--line); color: var(--muted); }
button.danger {
    border-color: color-mix(in srgb, var(--cant-solid) 45%, var(--line));
    color: var(--cant-on);
    background: transparent;
}

/* The quiet secondary: additive, never in competition with the primary. */
button.soft, .button.soft {
    width: 100%;
    margin-top: var(--s-3);
    background: var(--surface-2);
    border-color: transparent;
    color: var(--muted);
    font-size: var(--t-2);
}

/* ------------------------------------------------------- the answer buttons */

/* The primary answer is deliberately far larger than the other two: most
 * answers are "yes", and the middle tier must be available without competing
 * for the same glance. */
.answers { display: grid; gap: var(--s-2); margin-top: var(--s-4); }

.answer {
    width: 100%;
    min-height: var(--tap-lg);
    font-size: var(--t-4);
    font-weight: var(--w-semi);
    border-radius: var(--r-md);
}
.answer .ic { font-size: 1em; line-height: 1; }

.answer.yes {
    background: var(--great-action);
    border: 1px solid color-mix(in srgb, var(--great-action) 70%, #000);
    color: var(--great-action-on);
}
.answer-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2); }
.answer-row .answer {
    min-height: var(--tap);
    font-size: var(--t-2);
    font-weight: var(--w-medium);
    background: var(--surface);
}
.answer.maybe {
    color: var(--okay-on);
    border-color: color-mix(in srgb, var(--okay-solid) 40%, var(--line));
}
.answer.no {
    color: var(--cant-on);
    border-color: color-mix(in srgb, var(--cant-solid) 35%, var(--line));
}

/* The sticky thumb zone: on a phone the answer is always reachable, whatever
 * the page above it is doing. */
.thumb {
    position: sticky;
    bottom: 0;
    z-index: 15;
    margin: var(--s-4) calc(var(--s-4) * -1) 0;
    padding: var(--s-3) var(--s-4) calc(var(--s-3) + env(safe-area-inset-bottom));
    background: color-mix(in srgb, var(--bg) 92%, transparent);
    backdrop-filter: saturate(160%) blur(12px);
    -webkit-backdrop-filter: saturate(160%) blur(12px);
    border-top: 1px solid var(--line);
    box-shadow: var(--shadow-up);
}
.thumb .answers { margin-top: 0; }

/* --------------------------------------------------------------- slot list */

.slots { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--s-2); }

.slot {
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    background: var(--surface);
    padding: var(--s-3) var(--s-4);
    box-shadow: var(--shadow-1);
}
.slot.winner { border-color: var(--great-solid); }
.slot.leading { border-color: color-mix(in srgb, var(--accent-solid) 45%, var(--line)); }

.slot-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--s-2);
}
.slot .when { font-weight: var(--w-medium); letter-spacing: -.01em; }
.slot .tally { color: var(--muted); font-size: var(--t-1); white-space: nowrap; }
.slot .by { color: var(--faint); font-size: var(--t-1); margin-top: var(--s-1); }

/* Two segments, because "zur Not" is a different promise than "passt". */
.bar {
    display: flex;
    height: .375rem;
    background: var(--surface-2);
    border-radius: var(--r-full);
    overflow: hidden;
    margin: var(--s-2) 0 0;
}
.bar span { display: block; height: 100%; transition: width .3s var(--ease); }
.bar .g { background: var(--great-solid); }
.bar .o { background: var(--okay-solid); }

/* Your own answer, and the control to change it. */
.tiers {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--s-1);
    margin-top: var(--s-3);
}
.tiers .tier {
    min-height: var(--tap);
    font-size: var(--t-1);
    font-weight: var(--w-medium);
    padding: var(--s-1);
    border-radius: var(--r-sm);
    flex-direction: column;
    gap: 0;
    line-height: 1.2;
}
.tier.on.great { background: var(--great-fill); border-color: var(--great-solid); color: var(--great-on); }
.tier.on.okay { background: var(--okay-fill); border-color: var(--okay-solid); color: var(--okay-on); }
.tier.on.cant { background: var(--cant-fill); border-color: var(--cant-solid); color: var(--cant-on); }

.mine-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--s-1);
    font-size: var(--t-1);
    font-weight: var(--w-semi);
    padding: var(--s-1) var(--s-2);
    border-radius: var(--r-full);
    background: var(--surface-2);
    color: var(--muted);
}
.mine-chip.great { background: var(--great-fill); color: var(--great-on); }
.mine-chip.okay { background: var(--okay-fill); color: var(--okay-on); }
.mine-chip.cant { background: var(--cant-fill); color: var(--cant-on); }

/* ------------------------------------------------------------------ people */

.people {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
    margin: var(--s-3) 0 0;
    padding: 0;
    list-style: none;
}
.person {
    display: inline-flex;
    align-items: center;
    gap: var(--s-2);
    padding: var(--s-1) var(--s-3) var(--s-1) var(--s-1);
    border-radius: var(--r-full);
    background: var(--surface-2);
    font-size: var(--t-2);
}
.avatar {
    width: 1.75rem;
    height: 1.75rem;
    border-radius: var(--r-full);
    display: grid;
    place-items: center;
    background: var(--accent-fill);
    color: var(--accent-on);
    font-size: var(--t-1);
    font-weight: var(--w-semi);
}
.person.done .avatar { background: var(--great-fill); color: var(--great-on); }
.person.me { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent-solid) 45%, transparent); }

/* Named at create time, still silent. Dimmed rather than coloured: waiting for
 * somebody is a status, not a fault, and the roll-call must not read as a list
 * of offenders. */
.person.waiting {
    background: transparent;
    box-shadow: inset 0 0 0 1px var(--line-strong);
    color: var(--muted);
}
.person.waiting .avatar { background: var(--surface-2); color: var(--faint); }

/* Who said what, under each time's bar. Same tints as the answer buttons, so
 * a name reads as the answer it gave without a legend. */
.who-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-1);
    margin: var(--s-2) 0 0;
    padding: 0;
    list-style: none;
}
.who-chip {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: .1rem var(--s-2);
    border-radius: var(--r-full);
    font-size: var(--t-1);
    font-weight: var(--w-semi);
}
.who-chip.great { background: var(--great-fill); color: var(--great-on); }
.who-chip.okay { background: var(--okay-fill); color: var(--okay-on); }
.who-chip.cant { background: var(--cant-fill); color: var(--cant-on); }

/* --------------------------------------------------------------- form bits */

label { display: block; margin: var(--s-4) 0 0; font-weight: var(--w-medium); font-size: var(--t-2); }
/* A caption for a group of controls (the chip rows), which is not a <label>
 * because it labels no single field. */
.field-label { margin: var(--s-4) 0 0; font-weight: var(--w-medium); font-size: var(--t-2); }
label .hint { font-weight: var(--w-normal); display: block; margin-top: var(--s-1); }

input[type=text], input[type=date], input[type=time], input:not([type]), select, textarea {
    display: block;
    width: 100%;
    margin-top: var(--s-2);
    padding: var(--s-3) var(--s-4);
    /* Longhands, not the `font` shorthand: `inherit` is not a valid family
     * inside it, so the whole declaration was dropped and fields fell back to
     * the UA default — 13.3px Arial, which is exactly the iOS zoom-on-focus
     * this rule exists to prevent.
     * 16px minimum, or iOS zooms the whole page on focus. */
    font-family: inherit;
    font-size: 1rem;
    font-weight: var(--w-normal);
    line-height: 1.35;
    background: var(--bg);
    color: var(--fg);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    min-height: var(--tap);
}
input:focus, select:focus { border-color: var(--accent-solid); }
::placeholder { color: var(--faint); opacity: 1; }

.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2); }
.field-row input { margin-top: 0; }

/* ----------------------------------------------------------------- roster */

/* Who is coming, as a list of people rather than a stack of anonymous fields.
 * The first row is "Du", so the form opens with the person filling it in and
 * the shape of the outcome is visible before anything is typed. */
.roster { list-style: none; margin: var(--s-3) 0 0; padding: 0; display: grid; gap: var(--s-3); }

.roster-row {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: var(--s-1) var(--s-2);
}
/* Placed explicitly. Left to auto-placement the full-width input collapsed
 * column 2 to zero and pushed the remove button onto its own row, where it
 * became a 410px-wide invisible target directly under the field — the exact
 * mis-tap this layout exists to prevent. */
.roster-num { grid-column: 1; grid-row: 1; font-size: var(--t-1); font-weight: var(--w-medium); color: var(--faint); }
.roster-row input { grid-column: 1 / -1; grid-row: 2; margin-top: 0; }
/* Removing an optional row is available but never prominent: it sits up on the
 * caption line, not beside the field, so a thumb aiming for the input cannot
 * hit it. The glyph is small; the target is a full 44px. */
.roster-drop {
    grid-column: 2;
    grid-row: 1;
    min-height: 2.75rem;
    min-width: 2.75rem;
    padding: 0 var(--s-2);
    font-size: var(--t-4);
    line-height: 1;
    font-weight: var(--w-normal);
    color: var(--faint);
    background: transparent;
    border: 0;
    border-radius: var(--r-sm);
}

/* Chips: the cheap way to say "Friday at 8". Typing a date into a phone is the
 * most expensive interaction in the whole app. */
.chips {
    display: flex;
    gap: var(--s-2);
    overflow-x: auto;
    scroll-snap-type: x proximity;
    padding: var(--s-1) var(--s-1) var(--s-2);
    margin: var(--s-2) calc(var(--s-1) * -1) 0;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.chips::-webkit-scrollbar { display: none; }

.chip {
    flex: 0 0 auto;
    scroll-snap-align: start;
    min-width: 4rem;
    min-height: var(--tap);
    padding: var(--s-2) var(--s-3);
    border-radius: var(--r-md);
    border: 1px solid var(--line-strong);
    background: var(--surface);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0;
    font-size: var(--t-2);
    font-weight: var(--w-medium);
    line-height: 1.2;
}
.chip .sub { font-size: var(--t-1); font-weight: var(--w-normal); color: var(--faint); }
.chip[aria-pressed="true"] {
    background: var(--accent-fill);
    border-color: var(--accent-solid);
    color: var(--accent-on);
}
.chip[aria-pressed="true"] .sub { color: var(--accent-on); opacity: .8; }

.chips.times .chip { min-width: 4.5rem; font-variant-numeric: tabular-nums; }

details.more { margin: var(--s-4) 0 0; }
details.more > summary {
    cursor: pointer;
    color: var(--accent-on);
    font-weight: var(--w-medium);
    font-size: var(--t-2);
    /* 44px, so a disclosure is as aimable as the controls it hides. */
    min-height: 2.75rem;
    display: flex;
    align-items: center;
    list-style: none;
}
details.more > summary::-webkit-details-marker { display: none; }
details.more > summary::before { content: "＋"; margin-right: var(--s-2); font-weight: var(--w-normal); }
details.more[open] > summary::before { content: "－"; }

/* ------------------------------------------------------------------- links */

.linkbox {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: var(--s-3);
    margin: var(--s-3) 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: var(--t-1);
    color: var(--muted);
    overflow: hidden;
}
.linkbox code {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.share-row { display: grid; grid-template-columns: 1fr auto; gap: var(--s-2); margin-top: var(--s-4); }
.share-row .button { min-height: var(--tap-lg); }
details.qr img { display: block; margin: var(--s-3) auto 0; width: 220px; max-width: 100%; height: auto; background: #fff; border-radius: var(--r-sm); }

/* ------------------------------------------------------------------ notices */

/* A confirmation has to be seen without scrolling — the action that triggers
 * it can be anywhere on the page, including below the fold. Fixed-position
 * and self-dismissing, so it overlays instead of pushing the page down (the
 * old in-flow banner did that and bounced the layout on every redraw). Pure
 * CSS: it still works on the plain-HTML degrade with no JS at all. */
.notice, .error {
    display: flex;
    align-items: flex-start;
    gap: var(--s-2);
    border-radius: var(--r-md);
    padding: var(--s-3) var(--s-4);
    font-size: var(--t-2);
    font-weight: var(--w-medium);
    position: fixed;
    left: 50%;
    top: calc(env(safe-area-inset-top) + var(--s-3));
    z-index: 50;
    max-width: calc(100% - var(--s-4) * 2);
    box-shadow: var(--shadow-1);
    pointer-events: none;
    animation: toast 3.5s ease forwards;
}
.notice { background: var(--great-fill); color: var(--great-on); }
.error { background: var(--cant-fill); color: var(--cant-on); }

@keyframes toast {
    0%   { opacity: 0; transform: translate(-50%, -0.5rem); }
    8%   { opacity: 1; transform: translate(-50%, 0); }
    85%  { opacity: 1; transform: translate(-50%, 0); }
    100% { opacity: 0; transform: translate(-50%, -0.5rem); }
}

/* The confirmed hero: the moment the whole thing exists for. */
.hero {
    text-align: center;
    padding: var(--s-6) var(--s-5);
    border-radius: var(--r-lg);
    background: var(--great-fill);
    border: 1px solid color-mix(in srgb, var(--great-solid) 35%, transparent);
    box-shadow: var(--shadow-2);
    color: var(--great-on);
}
.hero .check {
    width: 3rem;
    height: 3rem;
    margin: 0 auto var(--s-3);
    border-radius: var(--r-full);
    background: var(--great-on);
    color: var(--great-fill);
    display: grid;
    place-items: center;
    font-size: var(--t-4);
}
.hero .day {
    font-size: var(--t-7);
    font-weight: var(--w-light);
    letter-spacing: -.025em;
    line-height: 1.05;
}
.hero .clock {
    font-size: var(--t-5);
    font-weight: var(--w-light);
    font-variant-numeric: tabular-nums;
    opacity: .85;
}

/* --------------------------------------------------------------- transitions */

/* Patched fragments announce themselves quietly, so an answer arriving from
 * someone else is noticed without stealing the page. */
@keyframes settle {
    from { opacity: .6; transform: translateY(3px); }
    to { opacity: 1; transform: none; }
}
#poll { animation: settle .22s var(--ease); }

.copied { position: relative; }
.copied::after {
    content: "Kopiert";
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    border-radius: inherit;
    background: var(--great-fill);
    color: var(--great-on);
    font-weight: var(--w-semi);
    animation: settle .15s var(--ease);
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        transition-duration: .001ms !important;
    }
}

/* ------------------------------------------------------------------ desktop */

@media (min-width: 40rem) {
    main { padding-top: var(--s-5); }
    .thumb {
        position: static;
        margin: var(--s-4) 0 0;
        padding: 0;
        background: none;
        border: 0;
        box-shadow: none;
        backdrop-filter: none;
    }
}

/* ----------------------------------------------------- your polls, locally */

/* Built by pandapoll.js from localStorage, so these classes appear in no
 * template — which is exactly how they got missed once already. */
.slot.recent { display: flex; align-items: center; gap: var(--s-3); }
.recent-link {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--s-1);
    text-decoration: none;
    color: inherit;
    /* The whole row is the target: a two-line link 20px tall was the smallest
     * thing on the page. */
    min-height: var(--tap);
    justify-content: center;
    padding: var(--s-2) 0;
}
.recent-link .when { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.slot.recent .forget { flex: 0 0 auto; min-height: 2.75rem; }

/* ------------------------------------------------------- the identity gate */

/* Picking who you are is the first thing that happens, so the names are
 * targets in their own right rather than a dropdown. */
.people.picker {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
    gap: var(--s-2);
    margin: var(--s-3) 0 0;
}
.people.picker li { display: block; }
.people.picker form { margin: 0; }

.person-pick {
    width: 100%;
    justify-content: flex-start;
    gap: var(--s-2);
    padding: var(--s-2) var(--s-3);
    min-height: var(--tap);
    border-radius: var(--r-md);
    background: var(--surface-2);
    border: 1px solid var(--line);
    font-weight: var(--w-medium);
    font-size: var(--t-2);
}
.person-pick .who { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* A rule with a word in it: "oder" separates picking from typing. */
.or {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    margin: var(--s-5) 0 var(--s-1);
    color: var(--faint);
    font-size: var(--t-1);
}
.or::before, .or::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--line);
}
