/*
 * Die Bausteine der App. Farben, Abstände und Schriften kommen ausschließlich aus tokens.css –
 * hier steht kein Hex-Wert. Wer das Design anpasst, ändert die Tokens; wer einen Baustein
 * anpasst, findet ihn im Layer `components` unter seinem Klassennamen.
 *
 * Vier Layer, feste Reihenfolge: reset < base < layout < components. Ein Baustein gewinnt damit
 * immer gegen die Basis, ohne !important und ohne Selektor-Rennen.
 */
@layer reset, base, layout, components;

/* Manrope, die Schrift des Design-Exports. Lokal mitgeliefert (SIL OFL, fonts/OFL.txt), damit kein
   fremder Server den privaten Link sieht und die App ohne Netz startet. Variabler Schnitt 200–800. */
@font-face {
    font-family: Manrope;
    font-style: normal;
    font-weight: 200 800;
    font-display: swap;
    src: url("/shared/fonts/manrope-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: Manrope;
    font-style: normal;
    font-weight: 200 800;
    font-display: swap;
    src: url("/shared/fonts/manrope-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;
}

@layer reset {
    *, *::before, *::after { box-sizing: border-box; }
    body { margin: 0; }
    h1, h2, h3, p, ol, ul, dl, dd, fieldset, menu, figure { margin: 0; }
    ol, ul, menu { padding: 0; list-style: none; }
    fieldset { padding: 0; border: 0; min-inline-size: 0; }
    button, input, textarea, select { font: inherit; color: inherit; }
    table { border-collapse: collapse; }
    img, svg { display: block; max-inline-size: 100%; }
}

@layer base {
    html {
        font-family: var(--font-body);
        font-size: var(--font-size-md);
        line-height: 1.45;
        background: var(--color-bg);
        color: var(--color-text);
        font-variant-numeric: tabular-nums;
        -webkit-text-size-adjust: 100%;
    }

    body {
        min-block-size: 100dvh;
        container-type: inline-size;
        display: grid;
        grid-template-rows: auto 1fr auto;
        grid-template-areas: "header" "main" "tabbar";
        background: var(--color-bg);
    }

    h1, h2, h3, .display {
        font-family: var(--font-display);
        font-weight: var(--weight-display);
        letter-spacing: -0.02em;
        line-height: 1.1;
        text-wrap: balance;
    }
    h1 { font-size: var(--font-size-lg); }
    h2 { font-size: var(--font-size-md); }
    h3 { font-size: var(--font-size-sm); }

    :focus-visible {
        outline: 2px solid var(--color-focus);
        outline-offset: 3px;
    }

    a { color: inherit; }

    .label, legend, th {
        font-family: var(--font-body);
        font-size: var(--font-size-xs);
        font-weight: 800;
        text-transform: uppercase;
        letter-spacing: var(--tracking-label);
        color: var(--color-label);
    }

    /* Knöpfe wie im Export: normale Schreibweise, fett, Rahmen 1.5px mit 3:1 zur Fläche. */
    button, .button {
        cursor: pointer;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: var(--spacing-sm);
        border: 1.5px solid var(--color-hairline-strong);
        border-radius: var(--radius-sm);
        background: transparent;
        color: var(--color-text);
        text-decoration: none;
        font-size: var(--font-size-sm);
        font-weight: 700;
        padding-block: 0.6em;
        padding-inline: 1.2em;
        min-block-size: 3rem;       /* Touch-Ziel 48 px wie bei Android (N.8) */
        transition: background var(--duration-fast), color var(--duration-fast), border-color var(--duration-fast);

        &:hover:not(:disabled) { border-color: var(--color-accent); }
        &:disabled { cursor: default; opacity: 0.55; }
        &.primary { background: var(--color-button-bg); color: var(--color-button-text); border-color: transparent; }
        &.primary:hover:not(:disabled) { background: var(--color-button-bg-hover); border-color: transparent; }
        &.ghost { border-color: transparent; color: var(--color-text-muted); }
        &.ghost:hover:not(:disabled) { color: var(--color-text); border-color: transparent; }
        &.danger { border-color: var(--color-danger-line); color: var(--color-danger); }
        &.danger:hover:not(:disabled) { background: var(--color-danger); color: var(--color-danger-ink); border-color: var(--color-danger); }
        /* Klein nur, wo eine Maus zielt – am Handy bleibt das Touch-Ziel 48 px (N.8). */
        &.small { padding-inline: 0.8em; }
        @container (min-width: 48rem) {
            &.small { min-block-size: 2.25rem; padding-block: 0.35em; font-size: var(--font-size-xs); }
        }
        & svg { inline-size: 1.1em; block-size: 1.1em; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
    }

    input, textarea, select {
        inline-size: 100%;
        border: 1.5px solid var(--color-hairline-strong);
        border-radius: var(--radius-sm);
        background: var(--color-bg-deep);
        font-weight: 600;
        color: var(--color-text);
        padding-block: 0.55em;
        padding-inline: 0.8em;
        min-block-size: 3rem;
        font-size: max(16px, 1em);  /* iOS zoomt bei kleinerer Schrift ins Feld */

        &:user-invalid { border-color: var(--color-danger); }
    }
    input[type="radio"], input[type="checkbox"] { inline-size: 1.15em; block-size: 1.15em; min-block-size: 0; margin: 0; accent-color: var(--color-accent); }

    .skip {
        position: absolute;
        inset-block-start: -100%;
        inset-inline-start: var(--spacing-md);
        padding: var(--spacing-sm);
        background: var(--color-surface);
        &:focus { inset-block-start: var(--spacing-md); z-index: 1; }
    }

    .muted, .hint { color: var(--color-text-muted); font-size: var(--font-size-sm); }

    .visually-hidden {
        position: absolute;
        inline-size: 1px;
        block-size: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
}

@layer layout {
    .app-header {
        grid-area: header;
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        justify-content: space-between;
        gap: var(--spacing-sm) var(--spacing-lg);
        padding-block: var(--spacing-sm);
        padding-inline: var(--spacing-md);
        background: var(--color-header-bg);      /* Kopfband in Slate wie im Export */
        color: var(--color-header-text);

        .brand { display: flex; align-items: center; gap: var(--spacing-sm); text-decoration: none; }
        .mark { inline-size: 1.75rem; block-size: 1.75rem; }
        .wordmark { display: flex; flex-direction: column; line-height: 1.1; }
        .title { font-family: var(--font-display); font-weight: var(--weight-display); font-size: var(--font-size-md); }
        .sub { font-size: var(--font-size-xs); text-transform: uppercase; letter-spacing: var(--tracking-label); color: var(--color-header-muted); margin-block-start: 0.2em; }

        nav { display: flex; align-items: center; gap: var(--spacing-xs) var(--spacing-md); }
        nav a {
            text-decoration: none;
            font-size: var(--font-size-xs);
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: var(--tracking-label);
            color: var(--color-header-muted);
            padding-block: 0.4em;
            border-block-end: 2px solid transparent;
        }
        nav a:hover, nav a.is-active { color: var(--color-header-text); border-color: var(--color-ball); }
        .main-nav { display: none; }   /* am Handy übernimmt die Tabbar */

        /* Knöpfe im Band („Abmelden“, F1.31.5/6): Die Grundregel für Knöpfe denkt an helle Flächen –
           Slate-Schrift, Slate-Hover, Slate-Fokus verschwänden auf dem Slate-Band. */
        button {
            color: var(--color-header-text);
            border-color: var(--color-header-line);
            &:hover:not(:disabled) { border-color: var(--color-header-focus); }
        }
        :focus-visible { outline-color: var(--color-header-focus); }

        /* Kopfband der Trainer-Ansicht (F1.31): Seitentitel nur am Handy */
        .band-title {
            display: none;
            margin: 0;
            font-family: var(--font-display);
            font-weight: var(--weight-display);
            font-size: var(--font-size-lg);
            letter-spacing: -0.02em;
            line-height: 1.1;
        }
    }

    main {
        grid-area: main;
        inline-size: 100%;
        min-inline-size: 0;     /* sonst weitet ein langer, ungebrochener Name (Trainee-Zeile) die Spalte – und am Handy die ganze Seite */
        max-inline-size: 64rem;
        margin-inline: auto;
        padding-block: var(--spacing-md) var(--spacing-xl);
        padding-inline: var(--spacing-md);
    }

    .tabbar {
        grid-area: tabbar;
        position: sticky;
        inset-block-end: 0;
        z-index: 10;            /* über der Liste, unter Sheets (20) und Toast (30) */
        display: grid;
        grid-auto-flow: column;
        grid-auto-columns: 1fr;
        background: var(--color-surface);
        border-block-start: 1px solid var(--color-hairline);
        padding-block-end: env(safe-area-inset-bottom);
        block-size: calc(var(--tabbar-block-size) + env(safe-area-inset-bottom));   /* fest: die Eingabe im Verlauf klebt darüber (messages R6.15) */

        a {
            display: grid;
            justify-items: center;
            align-content: center;
            gap: 0.2em;
            padding-block: var(--spacing-sm);
            text-decoration: none;
            font-size: var(--font-size-xs);
            font-weight: 700;
            letter-spacing: 0.04em;
            color: var(--color-text-muted);
        }
        svg { inline-size: 1.4rem; block-size: 1.4rem; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
        a.is-active { color: var(--color-accent); }
    }

    /*
     * Startbildschirm (F1.32): bis die erste Seite fertig ist. Darunter ist alles verborgen –
     * `visibility` statt `display`, damit Kopf, Router und Views schon rendern, aber weder zu sehen
     * noch für Screenreader und Zeiger da sind. Ohne `is-booting` gibt es ihn nicht mehr.
     */
    .splash {
        position: fixed;
        inset: 0;
        z-index: 50;            /* über allem: Tabbar (10), Sheets (20), Toast (30) */
        display: grid;
        place-content: center;
        justify-items: center;
        gap: var(--spacing-lg);
        background: var(--color-splash);
    }
    .splash-mark { inline-size: 7rem; block-size: 7rem; border-radius: 22%; }
    .splash-dots { display: flex; gap: var(--spacing-sm); }
    .splash-dots i {
        inline-size: 0.55rem;
        block-size: 0.55rem;
        border-radius: 50%;
        background: var(--color-ball);
        animation: splash-dot 1.2s ease-in-out infinite;
    }
    .splash-dots i:nth-child(2) { animation-delay: 0.2s; }
    .splash-dots i:nth-child(3) { animation-delay: 0.4s; }
    @media (prefers-reduced-motion: reduce) {
        .splash-dots i { animation: none; }
    }
    body:not(.is-booting) .splash { display: none; }
    body.is-booting > :not(.splash) { visibility: hidden; }

    /* Trainee-Seite und Apex: kein Trainer-Chrome – es gäbe dort nichts zu verwalten. */
    body.is-trainee .main-nav, body.is-trainee .tabbar, body.is-trainee .legal-nav,
    body.is-anonymous .main-nav, body.is-anonymous .tabbar { display: none; }
    /* Rechtsseite mit Rückweg des Trainees (legal R5.2): gar kein Kopfband – oben steht „Zurück“. */
    body.is-legal-return .app-header { display: none; }

    /* Am Handy weicht die Marke dem Titel der Seite (F1.31.1) – nur auf Seiten mit Navigationseintrag. */
    @container not (min-width: 48rem) {
        body.has-band-title:not(.is-trainee):not(.is-anonymous) .app-header {
            padding-block: var(--spacing-md);
            .brand { display: none; }
            .band-title { display: block; }
        }
    }

    /* Angemeldet gehört der Kopf der Navigation; Datenschutz und Impressum stehen unter „Einstellungen".
       Nur die Anmeldemaske zeigt sie im Kopf – dort gibt es sonst keinen Weg dorthin. */
    body:not(.is-anonymous) .legal-nav { display: none; }

    /* Briefsymbol (messages R6.1) ganz rechts: Am Handy schiebt `space-between` es nach außen, am
       Desktop nimmt der Rand vor der Navigation den freien Platz – Navigation und Symbol rücken zusammen. */
    .mailbox { display: contents; }

    @container (min-width: 48rem) {
        .app-header { padding-inline: var(--spacing-lg); }
        /* Kopf in einer Zeile: Wird es eng, bricht die Navigation in sich um, nicht das Briefsymbol weg. */
        .app-header { flex-wrap: nowrap; column-gap: var(--spacing-sm); }
        .app-header .main-nav { display: flex; flex-wrap: wrap; justify-content: flex-end; min-inline-size: 0; margin-inline-start: auto; }
        body:not(.is-trainee):not(.is-anonymous) .tabbar { display: none; }
    }
}

@layer components {
    .page-title { margin-block-end: var(--spacing-md); }
    /* Am Handy zeigt das Kopfband den Titel (F1.31); die h1 bleibt für Screenreader – genau eine je Seite. */
    @container not (min-width: 48rem) {
        body.has-band-title:not(.is-trainee):not(.is-anonymous) .view .page-title {
            position: absolute;
            inline-size: 1px;
            block-size: 1px;
            margin: 0;
            overflow: hidden;
            clip-path: inset(50%);
            white-space: nowrap;
        }
    }

    /* Fläche: Formulare und Gruppen – Karte mit weichem Schatten (im Dunkeln nur eine feine Kontur) */
    .surface {
        background: var(--color-surface);
        border: 1px solid var(--color-hairline);
        box-shadow: var(--shadow-card);
        border-radius: var(--radius-md);
        padding: var(--spacing-md);
        display: grid;
        gap: var(--spacing-md);
    }

    .field { display: grid; gap: var(--spacing-xs); }
    /* Feld-Labels klein und grau in normaler Schreibweise; Abschnitts-Labels bleiben Großbuchstaben. */
    .field > .label { margin-block-end: 0.1em; text-transform: none; letter-spacing: 0; font-weight: 700; color: var(--color-text-muted); }

    .actions { display: flex; flex-wrap: wrap; gap: var(--spacing-sm); }

    /* Hinweis / Fehler – role=status bzw. role=alert */
    .notice {
        display: flex;
        align-items: flex-start;
        gap: var(--spacing-sm);
        padding-block: var(--spacing-sm);
        padding-inline: var(--spacing-md);
        border-radius: var(--radius-sm);
        border: 1px solid var(--color-hairline);
        background: var(--color-surface-raised);
        font-size: var(--font-size-sm);

        &.is-error { border-color: var(--color-danger); color: var(--color-danger); }
    }

    /* Toast: Rückmeldung oben über der Seite, blendet sich selbst aus (Toast.js). Über Sheets (z 20),
       unter der Statusleiste (safe-area). Erscheint mit kurzem Gleiten – ohne, wer weniger Bewegung will. */
    .toast {
        position: fixed;
        z-index: 30;
        inset-block-start: calc(env(safe-area-inset-top) + var(--spacing-sm));
        inset-inline: var(--spacing-md);
        margin-inline: auto;
        max-inline-size: 32rem;
        align-items: center;
        justify-content: space-between;
        background: var(--color-surface);
        border-color: var(--color-hairline-strong);
        box-shadow: 0 0.5rem 1.5rem oklch(from var(--color-ink) l c h / 0.18);
        animation: toast-in var(--duration-fast) ease-out;

        &.is-error { background: var(--color-surface); }
        & button { min-inline-size: 3rem; flex-shrink: 0; font-size: var(--font-size-md); }
    }
    @keyframes toast-in { from { opacity: 0; translate: 0 -0.75rem; } }
    @media (prefers-reduced-motion: reduce) { .toast { animation: none; } }

    .empty { color: var(--color-text-muted); padding-block: var(--spacing-lg); text-align: center; }

    .login { max-inline-size: 26rem; margin-inline: auto; display: grid; gap: var(--spacing-md); }

    /* Abmelden am Handy: Die Hauptnavigation mit dem Knopf ist dort ausgeblendet – ohne diesen gäbe es
       keinen Weg hinaus. Am Desktop steht er im Kopf, hier also nicht ein zweites Mal. */
    .account-logout { margin-block-start: var(--spacing-md); }
    @container (min-width: 48rem) { .account-logout { display: none; } }

    /* Lade-Zustand statt weißer Seite, solange die Lambda hochfährt */
    .loading { color: var(--color-text-muted); padding-block: var(--spacing-lg); text-align: center; }
}

@layer components {
    /* --- Verfügbarkeit --------------------------------------------------- */
    .availability { display: grid; gap: var(--spacing-md); }

    /* Verfügbarkeit am Handy (R7): erst die Termine, das Formular als Sheet hinter „+ Termine anlegen“.
       Ab 48rem steht es wie bisher direkt über der Liste, ohne Knopf (R7.4). */
    .form-sheet:not(.is-open) { display: none; }
    .form-sheet.is-open {
        position: fixed;
        inset: 0;
        z-index: 20;
        display: flex;
        align-items: flex-end;
        justify-content: center;
        background: var(--color-backdrop);
    }
    .form-sheet-body {
        inline-size: min(100%, 28rem);
        max-block-size: 92dvh;
        overflow-y: auto;
        overscroll-behavior: contain;
        padding: var(--spacing-md) var(--spacing-md) var(--spacing-lg);
        border-radius: calc(var(--radius-md) + 8px) calc(var(--radius-md) + 8px) 0 0;
        background: var(--color-surface);
        display: grid;
        gap: var(--spacing-sm);
    }
    /* Im Sheet ist das Sheet die Fläche – die Karte darin wäre ein Rahmen im Rahmen. */
    @container not (min-width: 48rem) {
        .form-sheet-body .slot-form { border: 0; padding: 0; background: none; }
    }
    .form-sheet-title { text-align: center; }
    .add-slots { inline-size: 100%; }
    .slot-form .actions button { flex: 1; }     /* R7.5: volle Breite wie „+ Neuer Trainee“ */
    @container (min-width: 48rem) {
        .add-slots, .form-sheet .sheet-grip, .form-sheet-title, .form-sheet-close { display: none; }
        .form-sheet:not(.is-open), .form-sheet.is-open { display: block; position: static; background: none; }
        .form-sheet-body {
            display: block; inline-size: auto; max-block-size: none; overflow: visible;
            padding: 0; border-radius: 0; background: none;
        }
    }

    .week-nav { display: flex; align-items: center; justify-content: space-between; }
    .week-days {
        display: grid;
        grid-template-columns: repeat(7, minmax(0, 1fr));    /* sonst weitet das breitere Manrope die Seite am Handy */
        gap: var(--spacing-xs);
    }
    .day {
        display: grid;
        justify-items: center;
        gap: 0.1em;
        padding-block: var(--spacing-sm);
        padding-inline: 0.1em;
        min-block-size: 0;
        text-transform: none;
        letter-spacing: 0;
        font-weight: 500;
        background: var(--color-surface);
        border-color: var(--color-hairline);

        .day-name { font-size: var(--font-size-xs); font-weight: 700; color: var(--color-text-muted); }
        .day-date { font-size: var(--font-size-sm); font-weight: 700; }
        .day-count { font-size: var(--font-size-xs); color: var(--color-text-muted); }
        &.is-today { border-color: var(--color-label); }
        &.is-selected { border-color: var(--color-accent); background: var(--color-surface-raised); }
        &.is-selected .day-count { color: var(--color-accent); font-weight: 600; }
    }

    /* Umschalter: weiße Pille im Graufeld */
    .segments {
        display: grid;
        grid-auto-flow: column;
        grid-auto-columns: 1fr;
        gap: var(--spacing-xs);
        padding: var(--spacing-xs);
        border-radius: calc(var(--radius-sm) + 2px);
        background: var(--color-surface-raised);

        button { border: 0; border-radius: calc(var(--radius-sm) - 1px); min-block-size: 3rem; color: var(--color-text-muted); }
        button.is-active { background: var(--color-surface); color: var(--color-accent); box-shadow: var(--shadow-segment); }
    }

    .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-sm); }

    .choices { display: flex; flex-wrap: wrap; gap: var(--spacing-xs); }
    .choice {
        flex: 1 1 5rem;
        text-transform: none;
        letter-spacing: 0;
        font-weight: 700;
        color: var(--color-text-muted);
        background: var(--color-surface);
        &.is-active { border-color: var(--color-accent); background: var(--color-surface-raised); color: var(--color-accent); }
    }

    .preview { font-size: var(--font-size-sm); color: var(--color-text-muted); strong { color: var(--color-text); } }
    .section-label { margin-block: var(--spacing-md) var(--spacing-sm); }

    /* Termine und Listen als einzelne Karten, nicht als Tabelle mit Linien */
    .slot-list, .item-list {
        display: grid;
        grid-template-columns: minmax(0, 1fr);    /* Zeilen nie breiter als die Liste – lange Namen kürzen */
        gap: calc(var(--spacing-sm) + 1px);
    }
    .slot, .item {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: var(--spacing-sm);
        padding-block: var(--spacing-sm);
        padding-inline: var(--spacing-md);
        background: var(--color-surface);
        border: 1px solid var(--color-hairline);
        border-radius: var(--radius-sm);
        box-shadow: var(--shadow-row);
    }
    .item { border-radius: var(--radius-md); box-shadow: var(--shadow-card); padding: var(--spacing-md); }

    /* Trainer-Liste: Zeile + „Löschen“. Am Handy ist die Zeile ein waagrechter Scroll-Container mit
       Snap – Wischen legt den Knopf frei, Tippen löscht (availability R5.6, D2). Kein Gesten-JS. */
    .slot-list .slot:has(.slot-row) { flex-wrap: nowrap; padding: 0; gap: 0; }
    .slot:has(.slot-row):not(.is-swipeable) { overflow: hidden; }     /* Ecken der Karte; Wischen braucht overflow-x */
    .slot-row {
        flex: 0 0 100%;
        display: flex;
        align-items: center;
        gap: var(--spacing-sm);
        padding-block: var(--spacing-sm);
        padding-inline: var(--spacing-md);
        scroll-snap-align: start;
    }
    .slot.is-swipeable {
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scroll-snap-type: x mandatory;
        scrollbar-width: none;
        &::-webkit-scrollbar { display: none; }
    }
    .slot-delete {
        flex: 0 0 auto;
        scroll-snap-align: end;
        border: 0;
        border-radius: 0;
        min-block-size: auto;
        align-self: stretch;
        background: var(--color-danger);
        color: var(--color-danger-ink);
        font-size: var(--font-size-xs);
        &:hover:not(:disabled) { background: var(--color-danger); color: var(--color-danger-ink); border-color: transparent; }
    }
    @container (min-width: 48rem) {
        .slot.is-swipeable { overflow-x: visible; }
        .slot-row { flex: 1 1 auto; }
        .slot-delete {
            align-self: center;
            margin-inline-end: var(--spacing-sm);
            border: 1.5px solid var(--color-danger-line);
            border-radius: var(--radius-sm);
            background: transparent;
            color: var(--color-danger);
            min-block-size: 2.25rem;
            &:hover:not(:disabled) { background: var(--color-danger); color: var(--color-danger-ink); border-color: var(--color-danger); }
        }
    }
    .slot-time { font-weight: 700; min-inline-size: 3.2em; }
    .slot-meta { flex: 1; font-size: var(--font-size-xs); color: var(--color-text-muted); }

    /* Pillen: „frei“ grau, „gebucht“ auf der Neon-Tönung in Oliv */
    .pill {
        padding-block: 0.25em;
        padding-inline: 0.7em;
        border-radius: var(--radius-xs);
        font-size: var(--font-size-xs);
        font-weight: 700;
        white-space: nowrap;
        &.is-free { background: var(--color-surface-raised); color: var(--color-accent); }
        &.is-booked { background: var(--color-highlight-bg); color: var(--color-highlight); }
        &.is-late { background: var(--color-surface-raised); color: var(--color-text-muted); }
    }


    .item-icon { color: var(--color-label); display: flex; }
    /* 10rem Mindestbreite: Reicht der Platz daneben nicht, rutschen die Aktionen in eine eigene Zeile,
       statt den Text in eine schmale Spalte zu quetschen (am Handy: sechs Zeilen für einen Termin). */
    .item-title { flex: 1 1 10rem; min-inline-size: 0; display: flex; flex-direction: column; line-height: 1.2; }
    .item-status { font-size: var(--font-size-xs); color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.08em; }
    .item.is-inactive .item-title { color: var(--color-text-muted); }
    .item-actions { display: flex; flex-wrap: wrap; gap: var(--spacing-xs); justify-content: flex-end; margin-inline-start: auto; }
    .rename-field { flex: 1; }

    /* Stundenlängen (settings R3.6–R3.13): Zeitregeln und Liste als zwei Karten untereinander; die
       Liste schlicht in Zeilen, Feld und „+ Hinzufügen“ nebeneinander, der Knopf auf Höhe des Felds. */
    b-timing { display: grid; gap: var(--spacing-md); }
    .lessons .item { padding-block: var(--spacing-xs); box-shadow: none; }
    .lessons .item-title { flex-basis: 4rem; }     /* „45 Min“ ist kurz – die Knöpfe bleiben am Handy in der Zeile */
    .lessons .item.is-default { border-color: var(--color-accent); }
    .lesson-add { display: flex; align-items: end; gap: var(--spacing-sm); .field { flex: 1; } }
}

@layer components {
    /* --- Listen mit Avatar (Trainees, Buchungen) ------------------------- */
    .avatar {
        display: flex;
        align-items: center;
        justify-content: center;
        inline-size: 2.25rem;
        block-size: 2.25rem;
        flex-shrink: 0;
        border-radius: var(--radius-sm);
        background: var(--color-surface-raised);
        color: var(--color-accent);
        font-weight: 700;
    }
    .booking-when { font-size: var(--font-size-xs); color: var(--color-text-muted); }
    /* Buchung am Handy: die Aktion über die ganze Karte unter dem Text – der Daumen trifft sie ohne Zielen. */
    .booking .item-actions { flex-basis: 100%; display: grid; grid-template-columns: 1fr; }   /* nur Absagen (F1.24, bookings R5.2) */
    .booking .item-actions button { padding-inline: 0.4em; }
    @container (min-width: 48rem) {
        .booking .item-actions { flex-basis: auto; display: flex; }
    }

    /* Trainee: Aktionen in der Zeile des Namens, der Name kürzt notfalls mit „…“. Jede Aktion hat ihre
       eigene Optik – vier gleiche Icons ließen raten. Widerrufen steht abgesetzt, gegen Fehltipps. */
    .trainee { flex-wrap: nowrap; }
    .trainee .item-title { flex: 1 1 0; }
    .trainee .item-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .trainee .item-actions { flex-wrap: nowrap; flex-shrink: 0; }
    .trainee .item-actions button { min-inline-size: 3rem; padding-inline: 0.7em; }
    .trainee .action-link { border-color: var(--color-hairline-strong); color: var(--color-text); }
    .trainee .action-share { background: var(--color-highlight-bg); color: var(--color-highlight); border-color: var(--color-highlight-line); }
    .trainee .action-qr { background: var(--color-surface-raised); color: var(--color-text); }
    .trainee .action-revoke { margin-inline-start: var(--spacing-sm); }
    /* Ziel eines Links (Änderungswunsch, Vermerk – messages R8.5, R8.6): Rahmen in der Akzentfarbe wie alles Gewählte */
    .item.is-target, .slot.is-target { border-color: var(--color-accent); border-inline-start: 3px solid var(--color-accent); }
    .btn-label { display: none; }
    @container (min-width: 48rem) { .btn-label { display: inline; } }

    /* --- Sheets: Rückfragen (buchen, löschen, Änderungswunsch) ----------- */
    .sheet-backdrop {
        position: fixed;
        inset: 0;
        z-index: 20;
        display: flex;
        align-items: flex-end;
        justify-content: center;
        background: var(--color-backdrop);
    }
    .sheet {
        inline-size: min(100%, 28rem);
        padding: var(--spacing-md) var(--spacing-md) var(--spacing-lg);
        border-radius: calc(var(--radius-md) + 8px) calc(var(--radius-md) + 8px) 0 0;
        background: var(--color-surface);
        display: grid;
        gap: var(--spacing-sm);
        text-align: center;
    }
    .sheet-grip { inline-size: 2.25rem; block-size: 4px; margin-inline: auto; border-radius: 999px; background: var(--color-hairline-strong); }
    .sheet-title { font-size: var(--font-size-lg); }
    .sheet-sub { color: var(--color-text-muted); font-size: var(--font-size-sm); }
    .sheet-link {
        padding: var(--spacing-sm);
        border: 1px solid var(--color-hairline);
        border-radius: var(--radius-sm);
        background: var(--color-surface-raised);
        font-size: var(--font-size-xs);
        overflow-wrap: anywhere;
    }
    .sheet-feedback { font-size: var(--font-size-sm); color: var(--color-accent); }
    @container (min-width: 48rem) {
        .sheet-backdrop { align-items: center; }
        .sheet { border-radius: var(--radius-md); }
        .sheet-grip { display: none; }
    }

    /* QR-Code: fest hell, auch im Dunkelmodus – Kamera und Papier lesen keine Themen. */
    .qr { inline-size: min(70vw, 14rem); block-size: auto; margin-inline: auto; padding: var(--spacing-sm); border-radius: var(--radius-sm); background: #ffffff; }

    /* --- Trainee-Seite (privater Link, kein App-Chrome) ------------------- */
    /* Begrüßung im Kopfband: schließt an .app-header an, über die volle Breite */
    .trainee-head {
        margin-inline: calc(-1 * var(--spacing-md));
        margin-block: calc(-1 * var(--spacing-md)) var(--spacing-md);
        padding: var(--spacing-xs) var(--spacing-md) var(--spacing-md);
        background: var(--color-header-bg);
        color: var(--color-header-text);
    }
    .trainee-greeting { font-size: var(--font-size-lg); }
    .trainee-sub { margin-block-start: var(--spacing-xs); color: var(--color-header-muted); }
    .trainee-body { display: grid; gap: var(--spacing-md); }
    /* Installieren (booking R4.4): unten, über dem Fuß – abgesetzt, aber ohne zu drängeln. */
    .install { margin-block-start: var(--spacing-xl); padding-block-start: var(--spacing-md); border-block-start: 1px solid var(--color-hairline); display: grid; gap: var(--spacing-xs); justify-items: start; }
    /* Benachrichtigungen (push R3): auf der Trainee-Seite unter dem Installieren, beim Trainer im Block „Auf diesem Gerät“. */
    .notifications { display: grid; gap: var(--spacing-xs); justify-items: start; }
    .trainee-notifications { display: block; margin-block-start: var(--spacing-md); }
    .device { display: grid; gap: var(--spacing-md); }
    .device .install { margin-block-start: 0; padding-block-start: 0; border-block-start: 0; }
    /* Zahnrad „Einstellungen“ (push R3.10) – nur auf der Trainee-Seite, rechts neben dem Briefsymbol.
       Der Rand schiebt das Briefsymbol nach rechts statt in die Mitte; ohne Spaltenlücke stehen beide
       dicht beieinander – die 48-px-Touch-Ziele (N.8) halten sie auseinander. */
    .trainee-settings { display: contents; }
    body.is-trainee:has(.settings-link) .app-header { column-gap: 0; }
    body.is-trainee:has(.settings-link) .mailbox-link { margin-inline-start: auto; }
    .settings-link {
        display: grid;
        place-items: center;
        min-inline-size: 3rem;
        min-block-size: 3rem;
        padding: 0;
        border: 0;
        background: none;
        color: var(--color-header-text);    /* steht im dunklen Kopfband */
        cursor: pointer;
    }
    .settings-sheet { text-align: start; }
    .settings-sheet .sheet-title, .settings-sheet .sheet-sub { text-align: center; }
    .settings-sheet .install { margin-block-start: 0; padding-block-start: var(--spacing-sm); }
    .page-foot { margin-block-start: var(--spacing-xl); font-size: var(--font-size-xs); color: var(--color-text-muted); }
    /* Die Links stehen im Fließtext – erst die Polsterung macht sie mit dem Daumen treffbar. */
    .page-foot a { display: inline-block; padding-block: 0.9em; }
    .page-foot .version { display: block; margin-block-start: var(--spacing-xs); }

    /*
     * Fuß der Trainee-Seite (legal R4): klebt unten wie die Eingabe im Verlauf (messages R6.15) – sticky
     * statt fixed, damit er am Seitenende im Fluss steht und nie etwas verdeckt. Die Seite füllt die
     * Höhe (main → .view → b-booking als Spalte), `.trainee-page` nimmt den freien Platz; so steht der
     * Fuß auch auf einer kurzen Seite am unteren Rand. Den Rand unter der Home-Leiste hält er selbst
     * frei; die Fläche reicht über die ganze Breite (50cqi: die Breite von body, ohne Scrollleiste).
     */
    main:has(> .view > b-booking), main:has(> .view > .trainee-screen) { display: flex; flex-direction: column; padding-block-end: 0; }
    main > .view:has(> b-booking), main > .view:has(> .trainee-screen) { flex: 1; display: flex; flex-direction: column; }
    b-booking, .trainee-screen { flex: 1; display: flex; flex-direction: column; }
    .trainee-page { flex: 1; padding-block-end: var(--spacing-lg); }
    .page-foot.is-pinned {
        position: sticky;
        inset-block-end: 0;
        z-index: 10;            /* über dem Inhalt, unter Sheets (20) und Toast (30) – wie die Tabbar */
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        align-items: center;
        column-gap: var(--spacing-sm);
        margin-block-start: 0;
        margin-inline: calc(50% - 50cqi);
        padding-inline: var(--spacing-md);
        padding-block-end: env(safe-area-inset-bottom);
        background: var(--color-surface);
        border-block-start: 1px solid var(--color-hairline);
        a { display: inline-flex; align-items: center; min-block-size: 2.75rem; padding-block: 0; }   /* ≥ 44 px (R4.4) */
        b-deployed-tasks { display: inline-flex; align-items: center; min-block-size: 2.75rem; }
        b-deployed-tasks::before { content: "·"; margin-inline-end: var(--spacing-sm); }
        .version { margin-block-start: 0; }
    }
    .deployed-list { display: grid; gap: var(--spacing-sm); text-align: start; max-block-size: 60vh; overflow-y: auto; padding: 0; }
    .deployed-list li { display: grid; gap: 0.1em; list-style: none; }
    .day-heading { margin-block: var(--spacing-md) var(--spacing-xs); }
    .day-group .slot-list { gap: calc(var(--spacing-sm) + 2px); }
    .day-group .slot { border-radius: var(--radius-md); }
    /* Freier Termin: Karte mit Neon-Balken – Neon ist Fläche, nie Schrift */
    .free-slot {
        inline-size: 100%;
        display: flex;
        align-items: center;
        gap: var(--spacing-md);
        font-weight: 500;
        min-block-size: 4.5rem;     /* die Fläche, auf die der Trainee tippt – größer als ein Knopf */
        padding-block: var(--spacing-sm);
        padding-inline: var(--spacing-md);
        background: var(--color-surface);
        border: 1px solid var(--color-hairline);
        border-radius: var(--radius-md);
        box-shadow: var(--shadow-card);
        justify-content: flex-start;
        &::before { content: ""; flex: 0 0 auto; inline-size: 0.5rem; block-size: 2.75rem; border-radius: 5px; background: var(--color-ball); }
        &:hover:not(:disabled) { border-color: var(--color-accent); background: var(--color-surface); }
    }
    .free-slot-time { font-size: var(--font-size-lg); font-weight: var(--weight-display); }
    .free-slot-duration { flex: 1; text-align: start; font-size: var(--font-size-xs); color: var(--color-text-muted); }
    /* Bestätigung: weiße Karte, Haken Neon auf Slate */
    .confirmation {
        display: flex;
        align-items: center;
        gap: var(--spacing-sm);
        padding: var(--spacing-md);
        border: 1px solid var(--color-hairline);
        border-radius: var(--radius-md);
        background: var(--color-surface);
        box-shadow: var(--shadow-card);
    }
    .confirmation-mark {
        display: grid; place-items: center; flex: 0 0 auto;
        inline-size: 2.5rem; block-size: 2.5rem; border-radius: 50%;
        background: var(--color-header-bg); color: var(--color-ball); font-weight: 700;
    }
    .confirmation-text { display: grid; }

    /* --- Trainee-App (T58, trainee-app R3–R5; Mockup A) ---------------------- */
    /* „Alle Coaches in einer App“ auf der Trainee-Seite (booking R6.4) – abgesetzt wie „Installieren“. */
    .app-offer { margin-block-start: var(--spacing-xl); padding-block-start: var(--spacing-md); border-block-start: 1px solid var(--color-hairline); display: grid; gap: var(--spacing-xs); justify-items: start; }
    .app-offer .section-label { margin-block-end: 0; }
    /* Coach am eigenen Termin: Vorname vor Tag und Ort („Anna · Sa, 24. Oktober …“) */
    .slot-coach { font-weight: 700; color: var(--color-text); }
    /* Coach-Chips über den freien Terminen – die vorhandenen .choices/.choice, nur nicht gestreckt; viele scrollen waagrecht. */
    .coach-chips { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding-block-end: 2px; }
    .coach-chips .choice { flex: 0 0 auto; padding-inline: 1em; }
    .coach-rules { font-size: var(--font-size-xs); color: var(--color-text-muted); }
    /* Unterseiten (Nachrichten, Einstellungen): Spalte mit „Zurück“ oben, so breit wie sein Text. */
    .sub-page { display: grid; gap: var(--spacing-md); align-content: start; }
    .sub-page .page-title { margin-block-end: 0; }
    .sub-page .surface .section-label { margin-block-end: 0; }
    .personal-link { text-align: start; }
    /* Bestätigung beim ersten Übernehmen (trainee-app R2.2): Wahl und Häkchen mit Text daneben, groß genug zum Tippen. */
    .consent-points { display: grid; gap: var(--spacing-xs); padding-inline-start: 1.2em; }
    .consent-choices { display: grid; gap: var(--spacing-xs); border: 0; padding: 0; margin: 0; }
    .consent-choices legend { margin-block-end: var(--spacing-xs); }
    .check { display: flex; align-items: flex-start; gap: var(--spacing-sm); min-block-size: 2.75rem; padding-block: var(--spacing-xs); cursor: pointer; }
    .check input { margin-block-start: 0.2em; flex-shrink: 0; }
    .legal .draft-notice { line-height: 1.4; }
    .legal ul { display: grid; gap: var(--spacing-xs); padding-inline-start: 1.2em; }

    /* --- Rechtstexte ------------------------------------------------------- */
    .legal { max-inline-size: 65ch; margin-inline: auto; line-height: 1.6; display: grid; gap: var(--spacing-md); }
    .legal .section-label { margin-block-end: 0; }
    /* Zurück-Knopf (BackButton.js) oben vor der Überschrift – so breit wie sein Text, nicht wie die Spalte. */
    .back-button { justify-self: start; padding-inline-start: 0.8em; }
    .legal .back-button { color: var(--color-text); }      /* ein Knopf, kein Verweis im Text (.legal a) */
    .legal a { color: var(--color-accent); }
    .legal code { font-size: var(--font-size-xs); background: var(--color-surface-raised); padding-inline: 0.3em; border-radius: var(--radius-sm); }
}

@layer components {
    /* --- Nachrichten (messages R6) ----------------------------------------- */
    .mailbox-link {
        position: relative;
        display: grid;
        place-items: center;
        min-inline-size: 3rem;          /* Touch-Ziel 48 px (N.8) */
        min-block-size: 3rem;
        color: var(--color-header-text);    /* steht im dunklen Kopfband */
        text-decoration: none;
    }
    .mailbox-badge {
        display: inline-grid;
        place-items: center;
        min-inline-size: 1.25rem;
        block-size: 1.25rem;
        padding-inline: 0.3em;
        border-radius: 999px;
        background: var(--color-button-bg);     /* Neon – sichtbar im Band wie in der Liste */
        color: var(--color-button-text);
        font-size: var(--font-size-xs);
        font-weight: 700;
        line-height: 1;
    }
    .mailbox-link .mailbox-badge { position: absolute; inset-block-start: 0.35rem; inset-inline-end: 0.2rem; }
    /* Am PC beim Trainer (F1.31.7): Symbol 1.5rem (24 px beim Grundmaß), so groß wie Navigation und „Abmelden“ wirken; die
       Fläche bleibt 48 px; der Zähler sitzt weiter an der oberen rechten Ecke des Umschlags. Hover als heller Chip,
       der Fokus kommt aus dem Band (F1.31.6). Handy und Trainee-Seite bleiben unverändert. */
    @container (min-width: 48rem) {
        body:not(.is-trainee) .mailbox-link {
            border-radius: var(--radius-sm);
            transition: background var(--duration-fast);
            & svg { inline-size: 1.5rem; block-size: 1.5rem; }
            &:hover { background: var(--color-header-chip); }
        }
    }

    .broadcast { margin-block-end: var(--spacing-md); }
    .broadcast textarea, .composer textarea { resize: vertical; }

    .conversation { padding: 0; }
    .conversation-link {
        display: flex;
        align-items: center;
        gap: var(--spacing-sm);
        inline-size: 100%;
        min-inline-size: 0;
        padding-block: var(--spacing-sm);
        padding-inline: var(--spacing-md);
        color: inherit;
        text-decoration: none;
    }
    .conversation .item-title { flex: 1 1 0; }
    .conversation .item-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }   /* wie in der Trainee-Liste */
    .conversation-preview {
        font-size: var(--font-size-sm);
        color: var(--color-text-muted);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .conversation.is-unread .item-name, .conversation.is-unread .conversation-preview { font-weight: 700; color: var(--color-text); }
    .conversation-meta { display: grid; justify-items: end; gap: 0.25em; font-size: var(--font-size-xs); color: var(--color-text-muted); flex-shrink: 0; }

    /* Kopfzeile des Verlaufs (messages R6.22, R6.23): klebt oben am Fensterrand wie bei WhatsApp; das
       Kopfband der Shell darüber scrollt weg. Eigene Fläche, damit die Blasen darunter verschwinden statt
       durchzuscheinen; sie steht im Fluss vor der ersten Blase und verdeckt am Anfang also nichts. */
    .thread-head {
        position: sticky;
        inset-block-start: 0;
        z-index: 5;                         /* über den Blasen, unter Leiste (15), Tabbar (10), Sheets und Toast */
        display: flex;
        align-items: center;
        gap: var(--spacing-xs);
        padding-block-start: env(safe-area-inset-top);
        background: var(--color-bg);
    }
    .thread-head .page-title { margin-block-end: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .back-link { display: grid; place-items: center; min-inline-size: 3rem; min-block-size: 3rem; color: var(--color-text); }

    .bubbles {
        list-style: none;
        padding: 0;
        margin-block: var(--spacing-md);
        display: flex;
        flex-direction: column;
        gap: var(--spacing-sm);
        overflow-x: clip;                   /* das Knöpfchen eines sehr breiten Vermerks schöbe die Seite sonst breit (S5) */
        -webkit-tap-highlight-color: transparent;   /* langes Drücken (R6.7) ohne grauen Schleier über dem Verlauf */
    }
    .bubble {
        position: relative;                 /* Bezug für Reaktion, Knöpfchen und Leiste (R6.5, R6.7, R6.13) */
        max-inline-size: min(85%, 32rem);
        display: grid;
        gap: 0.2em;
        padding-block: var(--spacing-xs);
        padding-inline: var(--spacing-sm);
        border-radius: var(--radius-md);
        border: 1px solid var(--color-hairline);
        background: var(--color-surface);
        overflow-wrap: anywhere;            /* lange Links brechen, statt die Seite zu weiten (S5) */
    }
    .bubble.is-own { align-self: flex-end; background: oklch(from var(--color-accent) l c h / 0.14); border-color: transparent; }
    .bubble.is-other { align-self: flex-start; }
    /* Vermerk (R8.1–R8.3): Pille mittig in der Farbe seiner Art, darunter klein die Uhrzeit. Gewählt
       (R6.7) wird die Pille umrandet, nicht die Zeile getönt – sie hat schon ihre Farbe. */
    .bubble.is-note {
        align-self: center;
        max-inline-size: 100%;
        display: grid;
        justify-items: center;
        gap: 0.2em;
        padding: 0;
        border-color: transparent;
        background: none;
        text-align: center;
    }
    .bubble.is-note.is-selected { background: none; border-color: transparent; }
    .note-pill {
        display: flex;                      /* Satz und Reaktion in einer Zeile (R6.5); der Termin im Satz ist der Link (R8.9) */
        flex-wrap: wrap;
        align-items: center;
        justify-content: center;
        gap: 0.15em var(--spacing-xs);
        max-inline-size: min(100%, 32rem);
        padding-block: var(--spacing-xs);
        padding-inline: var(--spacing-md);
        border: 1.5px solid transparent;    /* erst gewählt sichtbar – ohne dass die Pille springt */
        border-radius: var(--radius-md);
        background: var(--note-bg);
        color: var(--note-ink);
        &.is-booked { --note-bg: var(--color-note-booked-bg); --note-ink: var(--color-note-booked); }
        &.is-cancelled { --note-bg: var(--color-note-cancelled-bg); --note-ink: var(--color-note-cancelled); }
        &.is-moved { --note-bg: var(--color-note-moved-bg); --note-ink: var(--color-note-moved); }
    }
    .bubble.is-note.is-selected > .note-pill { border-color: var(--color-accent); }
    .note-link { color: inherit; font-weight: 700; text-decoration: underline; text-underline-offset: 0.15em; }
    .bubble.is-note > .bubble-time { justify-self: center; }
    .bubble-text { white-space: pre-wrap; }
    .bubble-time { font-size: var(--font-size-xs); color: var(--color-text-muted); justify-self: end; }
    .bubble-tag { font-size: var(--font-size-xs); color: var(--color-label); text-transform: uppercase; letter-spacing: var(--tracking-label); }

    /* --- Reaktion, Leiste und Knöpfchen an der Sprechblase (messages R6.5–R6.14) --------- */
    /* Gewählt (R6.7): hervorgehoben mit der Neon-Tönung, umrandet in der Akzentfarbe wie alles Gewählte –
       die Tönung allein trüge im Dunkeln nicht: Eigene Blasen sind dort schon neon getönt. */
    .bubble.is-selected { background: var(--color-highlight-bg); border-color: var(--color-accent); }

    /* Am Handy keine Textauswahl und kein Callout beim langen Drücken – dafür gibt es Kopieren.
       Mit der Maus bleibt Markieren möglich; Stillhalten markiert dort nichts. */
    @media (pointer: coarse) {
        .bubble, .bubble a { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
    }

    /* Die Reaktion (R6.5): kleiner, gefüllter Daumen am unteren Rand, unten links – rechts steht die
       Uhrzeit. Beim Vermerk ohne Blase steht er hinter dem Satz. */
    .bubble-reaction {
        display: inline-grid;
        place-items: center;
        inline-size: 1.6rem;
        block-size: 1.6rem;
        border: 1px solid var(--color-hairline);
        border-radius: 999px;
        background: var(--color-surface);
        color: var(--color-accent);
        & svg { inline-size: 0.95rem; block-size: 0.95rem; fill: currentColor; }
    }
    .bubble:not(.is-note) > .bubble-reaction { position: absolute; inset-block-end: -0.9rem; inset-inline-start: var(--spacing-sm); }
    .bubble.has-reaction:not(.is-note) { margin-block-end: 0.75rem; }

    /* Die Leiste (R6.7): schwebt direkt über der Blase, an deren Seite ausgerichtet, beim Vermerk mittig.
       Passt sie dort nicht hin, setzt die Ansicht is-below oder is-pinned (Conversation.js). */
    .message-bar {
        position: absolute;
        z-index: 15;                        /* über Eingabe und Tabbar (10), unter Sheets (20) und Toast (30) */
        inset-block-end: calc(100% + var(--spacing-xs));
        inset-inline-start: 0;
        display: flex;
        align-items: center;
        gap: 0.1rem;
        padding: var(--spacing-xs);
        border: 1px solid var(--color-hairline-strong);
        border-radius: 999px;
        background: var(--color-surface);
        box-shadow: 0 0.5rem 1.5rem oklch(from var(--color-ink) l c h / 0.18);
        inline-size: max-content;           /* so breit wie ihr Inhalt, auch über einer schmalen Blase */
        white-space: nowrap;

        & button {
            min-inline-size: 3rem;          /* Touch-Ziel 48 px (N.8) */
            padding-block: 0;
            padding-inline: 0.75em;
            border-color: transparent;
            border-radius: 999px;
            color: var(--color-text);
        }
        & button:hover:not(:disabled) { border-color: transparent; background: var(--color-surface-raised); }
        & svg { inline-size: 1.35rem; block-size: 1.35rem; flex-shrink: 0; }
        & [aria-pressed="true"] { color: var(--color-accent); background: oklch(from var(--color-accent) l c h / 0.14); }
        & [aria-pressed="true"] svg { fill: currentColor; }      /* gewählt = gefüllt */
        &.is-below { inset-block: calc(100% + var(--spacing-xs)) auto; }
    }
    .bubble.is-own > .message-bar { inset-inline: auto 0; }
    .bubble.is-note > .message-bar { inset-inline-start: 50%; translate: -50% 0; }
    .bubble > .message-bar.is-pinned {
        position: fixed;
        inset-block: calc(env(safe-area-inset-top) + var(--spacing-sm)) auto;
        inset-inline: 0;
        margin-inline: auto;
        translate: none;
    }

    /* Das Knöpfchen (R6.13, R6.14): neben der Blase zur Mitte hin, wie bei WhatsApp Web – es verdeckt
       keinen Text. Sichtbar beim Überfahren mit der Maus und bei Tastaturfokus; sonst unsichtbar, aber per
       Tab erreichbar – und am Handy fängt es keinen Tipp ab. Bei offener Leiste weg: Sie steht dort. */
    .bubble-more {
        position: absolute;
        inset-block-start: 50%;
        inset-inline-start: calc(100% + var(--spacing-xs));
        translate: 0 -50%;
        inline-size: 1.75rem;
        block-size: 1.75rem;
        min-block-size: 0;
        padding: 0;
        border: 1px solid var(--color-hairline-strong);
        border-radius: 999px;
        background: var(--color-surface);
        color: var(--color-text-muted);
        opacity: 0;
        pointer-events: none;
        & svg { inline-size: 1rem; block-size: 1rem; flex-shrink: 0; }
        &:hover:not(:disabled) { border-color: var(--color-accent); color: var(--color-text); }
        /* Brücke über den Spalt zur Blase: Auf dem Weg dorthin bleibt die Blase überfahren. */
        &::before { content: ""; position: absolute; inset: calc(-1 * var(--spacing-xs) - 1px); }
    }
    .bubble.is-own > .bubble-more { inset-inline: auto calc(100% + var(--spacing-xs)); }
    /* Schmal füllt ein Vermerk die Zeile – daneben wäre kein Platz (die Liste schneidet ab): in seine Ecke. */
    @container not (min-width: 48rem) {
        .bubble.is-note > .bubble-more { inset-block-start: calc(-1 * var(--spacing-sm)); inset-inline: auto 0; translate: none; }
    }
    .bubble > .bubble-more:focus-visible { opacity: 1; pointer-events: auto; }
    @media (hover: hover) and (pointer: fine) {
        .bubble:hover > .bubble-more { opacity: 1; pointer-events: auto; }
    }
    .bubble.is-selected > .bubble-more { opacity: 0; pointer-events: none; }

    /* Text an den Trainee beim Absagen und Verschieben (bookings R4.1) */
    .change-sheet .field { text-align: start; }
    .change-sheet textarea { resize: vertical; }

    /*
     * Verlauf wie bei WhatsApp (messages R6.15–R6.17): Der Verlauf füllt die Höhe zwischen Kopf und
     * Tabbar bzw. Fensterrand; die Eingabe steht unten – in einem kurzen Verlauf liegt der freie Platz
     * zwischen Nachrichten und Eingabe – und klebt beim Scrollen am unteren Rand. Beim Trainer am
     * Handy klebt sie direkt über der Tabbar (feste Höhe, Token), sonst am Fensterrand.
     */
    main:has(> .view > b-conversation), main:has(> .view > b-trainee-thread) { display: flex; flex-direction: column; padding-block-end: 0; }
    main > .view:has(> b-conversation), main > .view:has(> b-trainee-thread) { flex: 1; display: flex; flex-direction: column; }
    b-conversation, b-trainee-thread { flex: 1; display: flex; flex-direction: column; }
    .composer {
        position: sticky;
        inset-block-end: 0;
        z-index: 5;                         /* über den Blasen und ihren Reaktionen, unter der Tabbar (10) */
        margin-block-start: auto;
        display: flex;
        align-items: flex-end;
        gap: var(--spacing-xs);
        padding-block: var(--spacing-sm) calc(var(--spacing-sm) + env(safe-area-inset-bottom));
        background: var(--color-bg);
    }
    @container not (min-width: 48rem) {
        body:not(.is-trainee):not(.is-anonymous) .composer {
            inset-block-end: calc(var(--tabbar-block-size) + env(safe-area-inset-bottom));
            padding-block-end: var(--spacing-sm);   /* den Rand unten hält die Tabbar frei */
        }
    }
    .composer textarea { flex: 1; min-inline-size: 0; }
    .composer-send { flex-shrink: 0; min-inline-size: 3rem; padding-inline: 0.6em; }
}

/* Ladepunkte des Startbildschirms (F1.32): nacheinander aufleuchten, ohne Sprung in der Größe zu stören. */
@keyframes splash-dot {
    0%, 100% { opacity: 0.3; transform: scale(0.8); }
    50% { opacity: 1; transform: scale(1); }
}
