:root {
    --color-white: #fff;
    --color-black: #000;

    --box-padding: 20px 24px;
    --max-w-sm: 400px;
    --max-w-lg: 800px;
    --max-w-bubble: 92%;

    --color-primary-50: #f6f6fe;
    --color-primary-100: #eceafd;
    --color-primary-200: #dcdafc;
    --color-primary-300: #c5c1fb;
    --color-primary-400: #a7a2fa;
    --color-primary-500: #8880fb;
    --color-primary-600: #6d5dfa;
    --color-primary-700: #571efa;
    --color-primary-800: #441bc5;
    --color-primary-900: #301a8d;
    --color-primary-1000: #1f135c;

    --color-accent-50: #f0f9f7;
    --color-accent-100: #d1f6ee;
    --color-accent-200: #75f8e2;
    --color-accent-300: #00e6cc;
    --color-accent-400: #00c9b2;
    --color-accent-500: #00ab97;
    --color-accent-600: #008f81;
    --color-accent-700: #087369;
    --color-accent-800: #0b5952;
    --color-accent-900: #0a413c;
    --color-accent-1000: #072a27;

    --color-warm-50: #fff5ea;
    --color-warm-100: #ffe9d2;
    --color-warm-200: #ffd6ad;
    --color-warm-300: #f2b880;
    --color-warm-400: #e39c5f;
    --color-warm-500: #cb7f45;
    --color-warm-600: #af6737;
    --color-warm-700: #8f502c;
    --color-warm-800: #713e23;
    --color-warm-900: #532c1a;
    --color-warm-1000: #371c0f;

    --color-secondary-50: #f9fafb;
    --color-secondary-100: #eeeff2;
    --color-secondary-200: #d3d7de;
    --color-secondary-300: #b6bcc8;
    --color-secondary-400: #99a1b2;
    --color-secondary-500: #7c879c;
    --color-secondary-600: #637089;
    --color-secondary-700: #4d5b79;
    --color-secondary-800: #364768;
    --color-secondary-900: #203257;
    --color-secondary-1000: #121f3c;

    --color-red-50: #ffecec;
    --color-red-100: #ffc7c7;
    --color-red-200: #ffa2a2;
    --color-red-300: #ff7d7d;
    --color-red-400: #ff5858;
    --color-red-500: #e63e3e;
    --color-red-600: #b33030;
    --color-red-700: #802323;
    --color-red-800: #4c1515;
    --color-red-900: #190707;

    --color-yellow-50: #fffbe4;
    --color-yellow-100: #faf0c0;
    --color-yellow-200: #f8e799;
    --color-yellow-300: #f5de73;
    --color-yellow-400: #f0d449;
    --color-yellow-500: #e8ca27;
    --color-yellow-600: #b69d00;
    --color-yellow-700: #837000;
    --color-yellow-800: #4f4300;
    --color-yellow-900: #1b1600;
    --color-warning-100: #fffbe6;
    --color-warning-400: #f0c040;

    --color-green-50: #ecfbf8;
    --color-green-100: #c6f4e9;
    --color-green-200: #a0ecdb;
    --color-green-300: #79e4cd;
    --color-green-400: #53ddbe;
    --color-green-500: #3ac3a5;
    --color-green-600: #2d9880;
    --color-green-700: #206d5c;
    --color-green-800: #134137;
    --color-green-900: #061612;

    --color-blue-50: #f4f7fe;
    --color-blue-100: #dde6fb;
    --color-blue-200: #c6d5f8;
    --color-blue-300: #afc4f5;
    --color-blue-400: #98b3f2;
    --color-blue-500: #7e99d8;
    --color-blue-600: #6277a8;
    --color-blue-700: #465578;
    --color-blue-800: #2a3348;
    --color-blue-900: #0e1118;

    --color-neutral-50: #f9fafb;
    --color-neutral-100: #f0f1f3;
    --color-neutral-200: #d9dbdf;
    --color-neutral-300: #b7bbc2;
    --color-neutral-400: #8f959f;
    --color-neutral-500: #6e7582;
    --color-neutral-600: #555e6e;
    --color-neutral-700: #3e4859;
    --color-neutral-800: #283242;
    --color-neutral-900: #131f30;
    --color-neutral-1000: #0a121e;

    /* Semantic tokens: components use these, never the --color-* scales directly where a
       token fits. Naming: neutrals are category-first (--surface-*, --text-*, --border-*),
       colour roles are role-first (--brand, --brand-soft, --brand-surface, …). The dark
       theme below redefines the same tokens in the same order. */

    /* Surfaces */
    --surface-page: var(--color-white);
    --surface-card: var(--color-neutral-50);
    --surface-subtle: var(--color-neutral-100);

    /* Text */
    --text: var(--color-neutral-1000);
    --text-muted: var(--color-neutral-700);
    --text-inverse: var(--color-white);

    /* Borders */
    --border: var(--color-neutral-200);
    --border-subtle: var(--color-neutral-100);

    /* Roles */
    --brand: var(--color-primary-700);
    --brand-soft: var(--color-primary-400);
    --brand-surface: var(--color-primary-100);
    --accent: var(--color-accent-700);
    --action: var(--color-secondary-900);
    --success: var(--color-green-700);
    --success-hover: var(--color-green-600);

    /* States */
    --danger: var(--color-red-600);
    --danger-surface: #fff4f4;
    --danger-border: #e2b4b4;
    --draft-surface: #fff8e8;
    --draft-border: #e0c98a;

    --radial-gradient:
        radial-gradient(
            70% 100% at 100% 0%,
            rgba(0, 230, 204, 0.2) 0%,
            rgba(87, 30, 250, 0.01) 100%
        ),
        radial-gradient(
            40% 30% at 10% 110%,
            rgba(242, 184, 128, 0.2) 0%,
            rgba(87, 30, 250, 0.01) 100%
        ),
        linear-gradient(287deg, rgba(112, 81, 250, 0.2) 0%, rgba(220, 210, 254, 0.2) 50%);
}

/* Dark theme; theme.js sets data-theme from the stored choice or the system setting. */
:root[data-theme="dark"] {
    color-scheme: dark;

    /* Surfaces */
    --surface-page: var(--color-black);

    /* Text */
    --text: var(--color-white);
    --text-inverse: var(--color-black);

    --danger-surface: #2a1d1d;
    --danger-border: #5c3a3a;
    --draft-surface: #2a2418;
    --draft-border: #5c4f2c;

    --color-primary-50: #1f135c;
    --color-primary-100: #301a8d;
    --color-primary-200: #441bc5;
    --color-primary-300: #571efa;
    --color-primary-400: #6d5dfa;
    --color-primary-500: #8880fb;
    --color-primary-600: #a7a2fa;
    --color-primary-700: #c5c1fb;
    --color-primary-800: #dcdafc;
    --color-primary-900: #eceafd;
    --color-primary-1000: #f6f6fe;

    --color-accent-50: #072a27;
    --color-accent-100: #0a413c;
    --color-accent-200: #0b5952;
    --color-accent-300: #087369;
    --color-accent-400: #008f81;
    --color-accent-500: #00ab97;
    --color-accent-600: #00c9b2;
    --color-accent-700: #00e6cc;
    --color-accent-800: #75f8e2;
    --color-accent-900: #d1f6ee;
    --color-accent-1000: #f0f9f7;

    --color-warm-50: #371c0f;
    --color-warm-100: #532c1a;
    --color-warm-200: #713e23;
    --color-warm-300: #8f502c;
    --color-warm-400: #af6737;
    --color-warm-500: #cb7f45;
    --color-warm-600: #e39c5f;
    --color-warm-700: #f2b880;
    --color-warm-800: #ffd6ad;
    --color-warm-900: #ffe9d2;
    --color-warm-1000: #fff5ea;

    --color-secondary-50: #121f3c;
    --color-secondary-100: #203257;
    --color-secondary-200: #364768;
    --color-secondary-300: #4d5b79;
    --color-secondary-400: #637089;
    --color-secondary-500: #7c879c;
    --color-secondary-600: #99a1b2;
    --color-secondary-700: #b6bcc8;
    --color-secondary-800: #d3d7de;
    --color-secondary-900: #eeeff2;
    --color-secondary-1000: #f9fafb;

    --color-red-50: #190707;
    --color-red-100: #4c1515;
    --color-red-200: #802323;
    --color-red-300: #b33030;
    --color-red-400: #e63e3e;
    --color-red-500: #ff5858;
    --color-red-600: #ff7d7d;
    --color-red-700: #ffa2a2;
    --color-red-800: #ffc7c7;
    --color-red-900: #ffecec;

    --color-yellow-50: #1b1600;
    --color-yellow-100: #4f4300;
    --color-yellow-200: #837000;
    --color-yellow-300: #b69d00;
    --color-yellow-400: #e8ca27;
    --color-yellow-500: #f0d449;
    --color-yellow-600: #f5de73;
    --color-yellow-700: #f8e799;
    --color-yellow-800: #faf0c0;
    --color-yellow-900: #fffbe4;
    --color-warning-100: #1b1600;
    --color-warning-400: #f0c040;

    --color-green-50: #061612;
    --color-green-100: #134137;
    --color-green-200: #206d5c;
    --color-green-300: #2d9880;
    --color-green-400: #3ac3a5;
    --color-green-500: #53ddbe;
    --color-green-600: #79e4cd;
    --color-green-700: #a0ecdb;
    --color-green-800: #c6f4e9;
    --color-green-900: #ecfbf8;

    --color-blue-50: #0e1118;
    --color-blue-100: #2a3348;
    --color-blue-200: #465578;
    --color-blue-300: #6277a8;
    --color-blue-400: #7e99d8;
    --color-blue-500: #98b3f2;
    --color-blue-600: #afc4f5;
    --color-blue-700: #c6d5f8;
    --color-blue-800: #dde6fb;
    --color-blue-900: #f4f7fe;

    --color-neutral-50: #0a121e;
    --color-neutral-100: #131f30;
    --color-neutral-200: #283242;
    --color-neutral-300: #3e4859;
    --color-neutral-400: #555e6e;
    --color-neutral-500: #6e7582;
    --color-neutral-600: #8f959f;
    --color-neutral-700: #b7bbc2;
    --color-neutral-800: #d9dbdf;
    --color-neutral-900: #f0f1f3;
    --color-neutral-1000: #f9fafb;
}

* {
    box-sizing: border-box;
}

/* Base text size lives on html so rem follows it; percentages respect the browser setting. */
html {
    font-size: 95%;
}

body {
    margin: 0;
    background: var(--surface-page);
    color: var(--text);
    font-family:
        system-ui,
        -apple-system,
        "Segoe UI",
        sans-serif;
    line-height: 1.6;
    padding: env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left);
}

/* Login view only: branded gradient; min-height keeps it filling the viewport. */
body:has(#view-login:not([hidden])) {
    box-sizing: border-box;
    min-height: 100dvh;
    background: var(--radial-gradient);
}

/* Login view: header leaves the flow so the card centers in the viewport, not below the bar. */
body:has(#view-login:not([hidden])) .app-bar {
    position: fixed;
    top: env(safe-area-inset-top);
    left: env(safe-area-inset-left);
    right: env(safe-area-inset-right);
}

body:has(#view-login:not([hidden])) main {
    box-sizing: border-box;
    min-height: calc(100dvh - env(safe-area-inset-top));
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* Symmetric padding keeps the center true while clearing the fixed header. */
    padding-block: 88px;
}

@media (min-width: 640px) {
    html {
        font-size: 100%;
    }
}

/* Header and activity strip stick to the viewport top as one unit. */
.app-bar {
    position: sticky;
    top: 0;
    z-index: 900;
    background: var(--surface-page);
}

header {
    background: transparent;
    padding: 14px 16px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--border-subtle);
}

h1 {
    font-size: 19px;
    margin: 0;
}

h1,
h2,
h3 {
    font-weight: 600;
}

h4,
h5,
h6 {
    font-weight: 700;
}

.header-actions {
    display: flex;
    align-items: center;
    gap: 4px;
}

main {
    padding: 14px 16px calc(24px + env(safe-area-inset-bottom));
    max-width: var(--max-w-lg);
    /* --chat-inline-start: set on desktop next to the thread aside (see .chat-thread-aside). */
    margin: 0 auto 0 var(--chat-inline-start, auto);
}

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

.label.spaced {
    margin-top: 2em;
}

.card {
    background: var(--surface-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 14px;
}

#view-login.card {
    box-sizing: border-box;
    width: 100%;
    max-width: var(--max-w-sm);
    margin-inline: auto;
    box-shadow: 0 20px 100px rgba(112, 81, 250, 0.25);
}

.from {
    font-weight: 600;
    margin: 1em 0 0.25em;
    font-size: 1.5em;
    word-break: break-word;
}

.subject {
    font-weight: 500;
    margin: 0 0 1em;
    font-size: 1.2em;
    color: var(--text-muted);
}

.body {
    margin: 0;
    color: var(--text-muted);
    font-size: 1em;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.proposal {
    background: var(--draft-surface);
    border: 1px solid var(--draft-border);
    border-radius: 12px;
    padding: 14px;
    white-space: pre-wrap;
    margin-top: 8px;
}

.error {
    background: var(--danger-surface);
    border: 1px solid var(--danger-border);
    border-radius: 12px;
    padding: 12px 14px;
    margin-bottom: 12px;
    white-space: pre-wrap;
}

/* Persistent notice inside the app bar when the instance has no configuration. */
.config-banner {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 16px 12px;
    padding: 10px 12px;
    background: var(--draft-surface);
    border: 1px solid var(--draft-border);
    border-radius: 12px;
    font-size: 0.9em;
}

.config-banner-icon {
    flex: none;
}

.config-banner-text {
    flex: 1;
}

/* Offline notice when network connectivity is lost. */
.offline-banner {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 16px 12px;
    padding: 10px 12px;
    background: var(--draft-bg);
    border: 1px solid var(--draft-border);
    border-radius: 12px;
    font-size: 0.9em;
}

.offline-banner-icon {
    flex: none;
    color: var(--color-warm-600);
}

.offline-banner-text {
    flex: 1;
}

textarea,
input,
select {
    width: 100%;
    font: inherit;
    color: inherit;
    background: var(--surface-card);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 8px 12px;
    margin-top: 10px;
    transition: border-color 0.15s ease;
    font-size: 0.9rem;
}

/* iOS zooms into any focused field whose text is below 16px and does not zoom back out
   afterwards. Only iOS Safari knows -webkit-touch-callout, so desktop and Android keep
   their sizes. !important, since several fields set their own smaller size (13-15px). */
@supports (-webkit-touch-callout: none) {
    textarea,
    input:not([type="checkbox"], [type="radio"]),
    select {
        font-size: max(16px, 1rem) !important;
    }
}

/* Touch: quick repeated taps on controls (cycling the template bar, rating) must not
   trigger the double-tap zoom; pinch zoom stays available. */
button,
a,
[role="button"] {
    touch-action: manipulation;
}

/* Elements with a long-press menu (bindLongPress in ui.js): a long press must not select
   text or open the iOS callout (magnifier, copy menu) instead of the menu. */
.has-long-press {
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}

/* Checkboxes and radios keep their natural size instead of the full-width input rule. */
input[type="checkbox"],
input[type="radio"] {
    flex: none;
    width: auto;
    padding: 0;
    margin: 0;
}

/* Control and its text on one line. */
.checkbox-label {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
}

.login-keycloak-option {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 4px 0 12px;
    color: var(--text);
    cursor: pointer;
}

.login-keycloak-option[hidden] {
    display: none;
}

.login-keycloak-option input[type="checkbox"] {
    width: 18px;
    height: 18px;
    margin: 0;
    padding: 0;
}

@media (hover: hover) {
    textarea:hover,
    input:hover,
    select:hover {
        border: 1px solid var(--text-muted);
    }
}

@media (hover: hover) {
    textarea:hover:disabled,
    input:hover:disabled,
    select:hover:disabled {
        border: 1px solid var(--border);
    }
}

select {
    -webkit-appearance: none;
    appearance: none;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%2364748b' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 16px center;
    padding-right: 40px;
}

#skills-installed,
#repo-list {
    margin-top: 12px;
}

textarea {
    min-height: 14em;
}

button {
    font: inherit;
    border: 1px solid var(--border);
    background: var(--surface-card);
    color: var(--text);
    width: 100%;
    margin-top: 1em;
    font-weight: 500;
    min-height: 40px;
    align-self: flex-start;
    border-radius: 6px;
    padding: 0.2em 0.6em;
    line-height: 1;
    font-size: 0.8rem;
    letter-spacing: 0.01em;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

button.menu-btn {
    display: flex;
    justify-content: space-between;
    align-items: center;
    text-align: left;
    padding-left: 1em;
    font-size: 1em;
    padding: 1em;
    margin-top: 0.75em;

    /* margin: 0; */
}

@media (hover: hover) {
    button:hover {
        background: var(--surface-subtle);
        color: var(--text);
    }
}

button:disabled {
    opacity: 0.55;
    background-color: transparent;
}

/* Same dimming as disabled buttons; the label of a disabled field dims along. */
.skills-field :disabled,
.skills-field:has(:disabled) label {
    opacity: 0.55;
}

.skills-field :disabled {
    cursor: not-allowed;
}

button.primary {
    background: var(--action);
    color: var(--text-inverse);
}

@media (hover: hover) {
    button.primary:hover {
        background: var(--brand);
        color: var(--text-inverse);
    }
}

#chat-send {
    background: var(--color-primary-700);
    color: var(--text-inverse);
}

#chat-stop {
    background: var(--color-red-500);
    color: var(--color-white);
}

@media (hover: hover) {
    #chat-stop:hover {
        background: var(--color-red-600);
        color: var(--color-white);
    }
}

@media (hover: hover) {
    #chat-send:hover:not(:disabled) {
        background: var(--action);
        color: var(--text-inverse);
    }
}

button.send {
    background: var(--success);
    color: var(--text-inverse);
}

.row {
    display: flex;
    gap: 10px;
}

.row button {
    flex: 1;
}

.row.wrap {
    flex-wrap: wrap;
}

.status {
    color: var(--text-muted);
    font-size: 15px;
    margin-top: 12px;
}

.hint {
    color: var(--text-muted);
    font-size: 13px;
    line-height: 1.45;
    margin: 8px 0 4px;
}

.empty {
    text-align: center;
    color: var(--text-muted);
    padding: 48px 8px;
}

.current-toolbar {
    margin-bottom: 18px;
    background: var(--radial-gradient);
    padding: var(--box-padding);
    display: grid;
    border-radius: 12px;
    margin-bottom: 3rem;
    gap: 1em;
}

@media (min-width: 640px) {
    .current-toolbar {
        gap: 3em;
        grid-template-columns: 1fr 200px;
    }
}

.toolbar-cta {
    justify-self: end;
    align-self: end;
    max-width: 200px;
}

.current-page-title {
    margin: 3rem 0 1rem;
    font-size: 2rem;
    line-height: 1.25;
    font-weight: 500;
}

.current-toolbar p {
    margin: 0;
    max-width: 400px;
}

@media (min-width: 640px) {
    .current-toolbar p {
        max-width: unset;
    }
}

.current-group {
    margin: 18px 0 24px;
}

.current-group h3 {
    color: var(--text-muted);
    font-size: 13px;
    margin: 14px 0 8px;
}

.current-source-status {
    color: var(--text-muted);
    font-size: 14px;
    margin: 0 0 10px;
}

.current-source-empty {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 52px;
    padding: 10px 14px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface-subtle);
}

.current-empty-icon {
    display: inline-flex;
    flex: 0 0 auto;
    color: var(--text-muted);
}

.current-source-error {
    padding: 10px 12px;
    border-left: 3px solid var(--danger-border);
    border-radius: 8px;
    background: var(--danger-surface);
}

.current-item {
    cursor: pointer;
    touch-action: pan-y;
}

.current-item:active {
    border-color: var(--action);
}

.current-preview {
    margin-bottom: 0;
}

.mail-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: var(--text-muted);
    padding: 48px 8px;
}

/* Same pulsing dot as .progress::before (keyframes defined there). */
.spinner {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--color-primary-500);
    animation: progress-pulse 1.2s ease-in-out infinite;
    margin-bottom: 12px;
}

.spinner-small {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--color-primary-500);
    animation: progress-pulse 1.2s ease-in-out infinite;
    display: inline-block;
    vertical-align: middle;
    margin-right: 8px;
}

/* Pull-to-Refresh: der Indikator hängt unter der Kopfzeile und folgt dem Zug.
   --pull (Weg in px) und --pull-ratio (0..1) setzt pullToRefresh.js. */
.pull-indicator {
    position: fixed;
    top: calc(env(safe-area-inset-top) + var(--app-bar-height, 60px));
    left: 50%;
    z-index: 950;
    box-sizing: border-box;
    width: 32px;
    height: 32px;
    margin-left: -16px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--surface-page);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.22);
    transform: translateY(calc(var(--pull, 0px) - 40px));
    opacity: var(--pull-ratio, 0);
    pointer-events: none;
    transition:
        transform 0.18s ease-out,
        opacity 0.18s ease-out;
}

.pull-indicator[hidden] {
    display: none;
}

.pull-indicator-arrow {
    width: 9px;
    height: 9px;
    border-right: 2px solid var(--color-primary-700);
    border-bottom: 2px solid var(--color-primary-700);
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform 0.18s ease-out;
}

.pull-indicator.is-ready .pull-indicator-arrow {
    transform: rotate(-135deg) translate(-2px, -2px);
}

.pull-indicator .spinner-small {
    display: none;
    margin: 0;
}

.pull-indicator.is-busy .pull-indicator-arrow {
    display: none;
}

.pull-indicator.is-busy .spinner-small {
    display: inline-block;
}

.chat-log {
    display: flex;
    flex-direction: column;
    gap: 2.5rem;
    padding-bottom: 20px;
}

/* Thread switcher: toggle with the active chat, "+" fixed at the right. It sticks below
   the app bar (height from exposeHeight in app.js) so switching never needs scrolling. */
.chat-threads {
    position: sticky;
    top: calc(var(--app-bar-height, 60px) + 12px);
    z-index: 30;
    display: flex;
    align-items: center;
    width: 100%;
    gap: 8px;
    padding: 0 0 8px 0;
}

/* While the progress shows, it takes the place right below the header; its real height
   (it grows with a wrapping text) comes from app.js (exposeHeight). */
body:has(#progress:not([hidden])) .chat-threads {
    top: calc(var(--app-bar-height, 60px) + var(--progress-height, 58px) + 12px);
}

.chat-threads::before {
    content: "";
    height: 60px;
    width: 100%;
    top: -12px;
    left: 0;
    position: absolute;
    pointer-events: none;
    background: linear-gradient(180deg, var(--surface-page), transparent);
}

/* Menu button that opens the thread aside; the aside is permanent on desktop, so the
   button disappears there (see the 1024px media query below). */
.chat-thread-toggle {
    position: relative;
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    min-height: auto;
    margin: 0;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 50%;
    color: inherit;
    background-color: color-mix(in srgb, var(--surface-subtle) 70%, transparent);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
}

@media (hover: hover) {
    .chat-thread-toggle:hover {
        background-color: var(--border);
    }
}

.chat-thread-toggle [data-icon],
.chat-thread-toggle svg {
    width: 1.3rem;
    height: 1.3rem;
}

/* Small marker on the menu button when another chat runs or waits for an answer. */
.chat-thread-others {
    position: absolute;
    top: 2px;
    right: 2px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    border: 2px solid var(--success);
    background: var(--surface-page);
}

/* Thread aside. Below the desktop breakpoint it is collapsible: hidden left of the
   viewport, and when open (.open, set by chat.js) it covers --thread-aside-w of the width
   while main and the fixed composer move right by the same amount ("pushed aside").
   It spans from below the app bar (height from exposeHeight) to the bottom edge; on
   mobile it covers the tab bar while open. */
:root {
    --icon-button-width: 40px;
    --padding-x: 36px;
    --thread-aside-w: calc(100vw - var(--icon-button-width) - var(--padding-x));
    --thread-aside-shift: calc(var(--thread-aside-w) + 12px);
    /* There is no bottom tab bar any more; what stays reserved at the bottom (composer,
       aside, menu page) is just the safe area. */
    --tabs-height: env(safe-area-inset-bottom, 0px);
    /* Gap between the pinned chat input and the bottom edge (on top of the safe area). */
    --composer-lift: 12px;
}

/* Small screens: the input sits closer to the bottom edge. After the rule above, which
   would otherwise win by source order. */
@media (min-width: 640px) {
    :root {
        --composer-lift: 24px;
    }
}

/* The aside belongs to the three areas and to the detail pages opened from them (an Odot,
   a mail); login, help and the menu pages go without it. */
body:not(:has(:is(#tab-chat, #tab-mail, #tab-dots, #page-dot, #page-mail):not([hidden])))
    .chat-thread-aside {
    display: none;
}

/* The current chat is only highlighted while the chat itself is shown. */
body:not(:has(#tab-chat:not([hidden]))) .chat-thread-row.active {
    background: none;
    color: inherit;
}

.chat-thread-aside {
    position: fixed;
    top: var(--app-bar-height, 60px);
    bottom: 0;
    left: 0;
    /* Above the fixed tab bar (1000), below nothing else that is fixed in the chat. */
    z-index: 1001;
    box-sizing: border-box;
    width: var(--thread-aside-w);
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    overscroll-behavior: contain;
    margin: 12px;
    padding: 12px;
    background: var(--surface-subtle);
    transform: translateX(-100%);
    visibility: hidden;
    /* visibility flips only after the slide-out, so the aside stays visible while moving. */
    transition:
        transform 0.25s ease,
        visibility 0s linear 0.25s;
    border-radius: 12px;
}

.chat-thread-aside.open {
    transform: none;
    visibility: visible;
    transition: transform 0.25s ease;
}

/* Pushing aside: main moves via left (a transform would make it the containing block of
   the fixed composer), the composer via translate, which composes with its own transform. */
main {
    /* Always relative with an explicit left: left only applies to positioned elements and
       cannot interpolate from auto, so toggling either on open would jump instead of slide. */
    position: relative;
    left: 0;
    transition: left 0.25s ease;
}

#tab-chat .composer,
#tab-chat .chat-credit {
    transition: translate 0.25s ease;
}

/* The pushed main must not widen the page: mobile Chrome grows the layout viewport to fit
   overflow that only reaches the viewport via body propagation. With html set, body keeps
   its own overflow, and clip (unlike hidden) is no scroll container, so sticky still works.
   Both stay on while the aside is closed as well: main's left is still animating back during
   the slide-out, so gating them on .open would let the viewport grow after every area switch. */
body {
    overflow-x: clip;
}

html {
    overflow-x: hidden;
}

/* Main and the composer are centred with at most --max-w-lg; from that width on their auto
   margin already offsets them, so only the rest is added. Otherwise they would slide past
   the right edge on wider (tablet) viewports. */
body:has(.chat-thread-aside.open) {
    --thread-aside-push: calc(var(--thread-aside-shift) - max(0px, (100vw - var(--max-w-lg)) / 2));
}

body:has(.chat-thread-aside.open) main {
    left: var(--thread-aside-push);
    /* iOS Safari only sends click for taps on "clickable" elements; the pointer cursor
       makes the whole chat one, so a tap beside the aside reaches the document handler
       in chat.js that closes it. */
    cursor: pointer;
}

body:has(.chat-thread-aside.open) #tab-chat .composer,
body:has(.chat-thread-aside.open) #tab-chat .chat-credit {
    translate: var(--thread-aside-push) 0;
}

@media (prefers-reduced-motion: reduce) {
    .chat-thread-aside,
    .chat-thread-aside.open,
    main,
    #tab-chat .composer,
    #tab-chat .chat-credit {
        transition: none;
    }
}

/* Desktop: the aside is a permanent column and the chat is centred in the space right of
   it. --chat-inline-start is that left offset: the aside plus half of the leftover width.
   Keep 1024px in sync with chat.js. */
@media (min-width: 1024px) {
    :root {
        --thread-aside-w: 280px;
    }

    /* Inherited by main and the fixed composer, so the content of all three areas and
       their detail pages is centred in the column right of the aside. */
    body:has(:is(#tab-chat, #tab-mail, #tab-dots, #page-dot, #page-mail):not([hidden])) {
        --chat-inline-start: calc(
            (var(--thread-aside-w) + 24px) +
                max(0px, (100vw - var(--thread-aside-w) - 24px - var(--max-w-lg)) / 2)
        );
    }

    .chat-thread-aside {
        transform: none;
        visibility: visible;
        transition: none;
    }

    .chat-thread-toggle {
        display: none;
    }

    /* Aktuell and Odots only carry the menu button in their top bar; the aside replaces
       it on desktop. The chat's top bar keeps the template bar (menu and "+" are hidden)
       and goes only while there is no template to show. */
    #tab-mail > .chat-threads,
    #tab-dots > .chat-threads,
    #tab-chat > .chat-threads:not(:has(.chat-pinned-bar:not([hidden]))) {
        display: none;
    }

    #tab-chat .chat-thread-actions {
        display: none;
    }
}

/* Heading above the list; the list's right margin is mirrored so both edges align. The
   bar carries the rule, so it runs below the heading and the pin button alike. */
.chat-thread-heading-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.chat-thread-heading {
    flex: none;
    margin: 0;
    font-size: 0.8rem;
    color: var(--muted);
}

/* Shows each chat's pinned messages below it; filled icon while on. */
.chat-thread-pins-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 40px;
    height: 40px;
    min-height: 40px;
    margin: 0;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--text-muted);
}

.chat-thread-pins-toggle[aria-pressed="true"] {
    color: var(--brand);
}

@media (hover: hover) {
    .chat-thread-pins-toggle:hover {
        background: var(--color-neutral-200);
    }
}

/* A pinned message below its chat: a row like the chat's (main button + "more"),
   indented and a bit smaller. The main button shares the chip's layout. */
.chat-thread-row.chat-thread-pin-row {
    /* margin-left: 24px; */
    font-size: 0.85rem;
    color: var(--text-muted);
    background-color: var(--color-neutral-50);
}

/* Only the pins below the active chat are tinted; the others stay transparent. */
.chat-thread-row.chat-thread-pin-row.in-active-chat {
    background-color: color-mix(in srgb, var(--color-warm-300) 30%, transparent);
}

:root[data-theme="dark"] .chat-thread-row.chat-thread-pin-row.in-active-chat {
    background-color: color-mix(in srgb, var(--color-warm-300) 50%, transparent);
}

.chat-thread-pin-row .chat-thread-pin {
    padding: 6px 0 6px 10px;
}

.chat-thread-pin .icon {
    flex: none;
    width: 1rem;
    height: 1rem;
    color: var(--brand);
}

.chat-thread-heading-wrapper {
    margin: 2em 0 0.25em 0;
    padding: 0 0 0 14px;
}

/* The list takes its full height; once nav, heading and list outgrow the aside, the
   aside as a whole scrolls (see .chat-thread-aside). */
.chat-thread-list {
    box-sizing: border-box;
    flex: none;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* Still scrollable by touch, wheel and keyboard; only the scrollbar is hidden. */
.chat-thread-aside {
    scrollbar-width: none;
}

.chat-thread-aside::-webkit-scrollbar {
    display: none;
}

/* Fades at the top and bottom edge, as high as the aside's padding: they stick to the
   scrollport and the content scrolls out underneath. The negative margins put them into
   the padding, so they take no room in the column. Keep 12px in sync with the padding. */
.chat-thread-aside::before,
.chat-thread-aside::after {
    content: "";
    position: sticky;
    z-index: 1;
    flex: none;
    height: 12px;
    pointer-events: none;
}

.chat-thread-aside::before {
    top: -12px;
    margin: -12px -12px 0;
    background: linear-gradient(to bottom, var(--surface-subtle), transparent);
}

.chat-thread-aside::after {
    bottom: -12px;
    margin: 0 -12px -12px;
    background: linear-gradient(to top, var(--surface-subtle), transparent);
}

/* One chat in the list: the chip switches to it, the "more" button opens its actions.
   The row carries hover and the active highlight; the chip stays transparent. Hovering
   the "more" button highlights only that button, not the row. */
.chat-thread-row {
    display: flex;
    align-items: center;
    gap: 2px;
    border-radius: 6px;
    color: var(--text);
}

@media (hover: hover) {
    .chat-thread-row:not(.active):hover:not(:has(.chat-thread-more:hover)) {
        background: var(--color-neutral-200);
        color: var(--color-neutral-1000);
    }
}

.chat-thread-row.active {
    background: var(--action);
    color: var(--text-inverse);
}

.chat-thread-chip,
.chat-thread-pin {
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
    align-items: center;
    gap: 8px;
    padding: 10px 0 10px 14px;
    margin-top: 0;
    text-align: left;
    border: none;
}

.chat-thread-pin .icon {
    color: var(--text);
}
/* Text colour comes from the row, also over the global button:hover. */
.chat-thread-row .chat-thread-chip,
.chat-thread-row .chat-thread-chip:hover,
.chat-thread-row .chat-thread-pin,
.chat-thread-row .chat-thread-pin:hover,
.chat-thread-row .chat-thread-more {
    color: inherit;
}

/* Transparent tap target over the row's full height; the hover shows on the inner
   .chat-thread-more-icon only. */
.chat-thread-more {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    align-self: stretch;
    width: 40px;
    min-height: auto;
    margin: 0;
    padding: 0;
    border: none;
}

.chat-thread-more-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    color: var(--text-muted);
}

.chat-thread-row.active .chat-thread-more-icon {
    color: var(--color-neutral-200);
}

@media (hover: hover) {
    .chat-thread-more:hover .chat-thread-more-icon {
        background: var(--color-neutral-200);
        color: var(--color-neutral-800);
        border-radius: 4px;
    }
}

@media (hover: hover) {
    .chat-thread-row.active .chat-thread-more:hover .chat-thread-more-icon {
        background: var(--color-secondary-800);
        color: var(--color-neutral-50);
    }
}

.chat-thread-more svg {
    width: 1rem;
    height: 1rem;
    color: currentColor;
}

.chat-thread-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    /* Buttons use line-height: 1, which makes overflow: hidden clip descenders. */
    line-height: 1.3;
}

/* inline-block, so the dot keeps its size also in rows that are not flex containers.
   The aside's Odots and Aktuell buttons show the same dot while their area works: Odots
   toggles .is-running, Aktuell follows #current-loading as long as it is visible. */
.aside-nav-btn.is-running::after,
body:has(#current-loading:not([hidden])) #tab-btn-mail::after {
    content: "";
}

.chat-thread-dot,
.aside-nav-btn.is-running::after,
body:has(#current-loading:not([hidden])) #tab-btn-mail::after {
    display: inline-block;
    vertical-align: middle;
    flex: none;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--success);
    animation: progress-pulse 1.2s ease-in-out infinite;
}

/* Inside an active (highlighted) row or button the dot takes a lighter green. */
.chat-thread-row.active .chat-thread-dot,
.aside-nav-btn.active.is-running::after,
body:has(#current-loading:not([hidden])) #tab-btn-mail.active::after {
    background: var(--color-green-300);
}

.chat-thread-pending {
    flex: none;
    font-weight: 600;
}

/* Round buttons of the chat's action group: menu and "+" (mobile only).
   36px plus the group's 2px padding keeps the bar at the 40px of a single button. */
.chat-thread-action {
    flex: 0 0 36px;
    width: 36px;
    height: 36px;
    margin: 0;
    padding: 0;
    /* border: 1px solid var(--border); */
    border: 0;
    border-radius: 50%;
    color: inherit;
    min-height: auto;
    align-self: center;
    background-color: transparent;
}

@media (hover: hover) {
    .chat-thread-action:hover,
    .chat-thread-actions .chat-thread-toggle:hover {
        background-color: var(--border);
    }
}

.chat-thread-action:disabled {
    opacity: 0.4;
}

.chat-thread-action[aria-pressed="true"] {
    color: var(--text-inverse);
    background-color: var(--action);
}

/* A new, empty chat shows no "+" until the conversation starts; the menu button before
   it stays. */
#tab-chat.is-empty .chat-thread-add-inline {
    display: none;
}

/* In the chat the menu button sits in the action group, shaped like the "+" beside it. */
.chat-thread-actions .chat-thread-toggle {
    width: 36px;
    height: 36px;
    border: 0;
    background-color: transparent;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

.chat-thread-actions {
    display: flex;
    flex: none;
    padding: 2px;
    gap: 2px;
    border-radius: 100px;
    z-index: 10;
    border: 1px solid var(--border);
    background-color: color-mix(in srgb, var(--border) 30%, transparent);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
}

.bubble {
    padding: 12px 14px;
    white-space: pre-wrap;
    /* Long words and links wrap at the edge instead of widening the bubble; anywhere
       (unlike break-word) also lowers the min-content width the flex layout sizes by. */
    overflow-wrap: anywhere;
    max-width: var(--max-w-bubble);
    border-radius: 0.75em;
}

.bubble.user {
    background: var(--brand-surface);
    align-self: flex-end;
    border-bottom-right-radius: 0px;
}

.bubble.assistant {
    background: none;
    padding: 0 0 14px;
    align-self: flex-start;
    border-bottom-left-radius: 0px;
}

.bubble.clarification {
    background: var(--color-warning-100, #fffbe6);
    border-left: 3px solid var(--color-warning-400, #f0c040);
    border-radius: 0.5em;
    padding: 10px 14px;
    align-self: flex-start;
    color: #3a2e00;
}

:root[data-theme="dark"] .bubble.clarification {
    background: #3a2e00;
    border-left-color: #c9960a;
    color: #fde68a;
}

.bubble.clarification .clarification-icon {
    margin-right: 6px;
}

/* Wraps a chat bubble and its action buttons, which sit below the bubble. */
.message-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-width: var(--max-w-bubble);
}

.message-row.user {
    align-self: flex-end;
    align-items: flex-end;
}

.message-row.assistant {
    align-self: flex-start;
    align-items: flex-start;
}

.message-row .bubble {
    max-width: 100%;
}

/* Charts use the full chat width (main's max-width) instead of shrinking to their content. */
.message-row.assistant:has(.chart),
.message-row.assistant:has(.chart) > .bubble {
    align-self: stretch;
    max-width: none;
}

.message-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    letter-spacing: 0.02em;
}

.message-actions > button {
    position: static;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    min-height: 36px;
    margin: 0;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--text-muted);
    /* Dimmed by default, never hidden: touch has no hover to reveal them. */
    opacity: 0.6;
}

/* The highlight sits on the icon, not on the 40px button (the touch target). */
.message-actions > button svg {
    box-sizing: content-box;
    padding: 4px;
    margin: 2px;
    border-radius: 4px;
    transition: background-color 0.15s ease;
}

/* Full strength while the actions are in use or show a state (pinned, copied, rated). */
.message-actions:focus-within > button,
.message-actions .pin-button.is-pinned,
.message-actions .copy-button.copied,
.message-actions .rating-button.active {
    opacity: 1;
}

@media (hover: hover) {
    .message-row:hover .message-actions > button {
        opacity: 1;
    }

    .message-actions > button:hover {
        background: transparent;
    }

    .message-actions > button:hover svg {
        background: var(--brand-surface);
    }
}

.has-copy {
    position: relative;
}

.bubble.has-copy,
.body.has-copy,
.proposal.has-copy {
    padding-right: 42px;
}

.copy-button,
.edit-button,
.retry-button,
.pin-button,
.template-button {
    position: absolute;
    top: -12px;
    right: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 25px;
    height: 25px;
    padding: 0;
    border: none;
    border-radius: 4px;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    z-index: 2;
    -webkit-tap-highlight-color: transparent;
    transition:
        background-color 0.15s ease,
        color 0.15s ease,
        opacity 0.15s ease;
}

/* Keep the copy button inside the mail body, level with its first line. */
.body.has-copy .copy-button {
    top: 4px;
}

.copy-button svg,
.edit-button svg,
.retry-button svg,
.pin-button svg,
.template-button svg {
    display: block;
}

.bubble.is-pinned {
    background-color: var(--color-warm-100);
    padding: 12px 14px;
}

.copy-button.copied {
    color: var(--success);
    border-color: var(--success);
}

/* Only on real hover devices, so the state does not stick after a tap. */
@media (hover: hover) {
    .copy-button:hover,
    .edit-button:hover,
    .retry-button:hover,
    .pin-button:hover,
    .template-button:hover {
        background: var(--brand-surface);
        color: inherit;
    }
}

.copy-button:active,
.edit-button:active,
.retry-button:active,
.pin-button:active,
.template-button:active {
    transform: scale(0.94);
}

.mcp-ui-text {
    margin-top: 6px;
}

.mcp-form {
    display: flex;
    flex-direction: column;
    gap: 1em;
    margin-top: 3em;
    padding: var(--box-padding);
    background: var(--surface-subtle);
    border: 1px solid var(--border);
    border-radius: 8px;
}

.mcp-form + .mcp-form {
    margin-top: 1em;
}

.mcp-form-title {
    font-size: 16px;
    overflow-wrap: anywhere;
}

/* Beats `.markdown h4` when the form renders inside a chat bubble. */
.mcp-form .mcp-form-title {
    margin: 0;
}

.mcp-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 0.8rem;
}

.mcp-field-inline {
    flex-direction: row;
    align-items: center;
}

.mcp-field-label {
    font-weight: 600;
}

.mcp-field input,
.mcp-field select {
    margin-top: 0;
}

.mcp-field input[type="checkbox"] {
    width: auto;
    min-height: 0;
}

.mcp-form-submit,
.mcp-button {
    width: auto;
    min-height: 40px;
    margin-top: 4px;
    align-self: flex-start;
    border-radius: 6px;
    padding: 0.2em 1em;
    line-height: 1;
    min-width: 200px;
    font-size: 0.8rem;
    letter-spacing: 0.01em;
    font-weight: 500;
}

.mcp-button {
    text-align: left;
    min-width: 0;
}

.mcp-link {
    display: inline-block;
    width: auto;
    box-sizing: border-box;
    min-height: 40px;
    margin-top: 4px;
    align-self: flex-start;
    border-radius: 6px;
    padding: 0 1em;
    line-height: 40px;
    min-width: 200px;
    font-size: 0.8rem;
    letter-spacing: 0.01em;
    font-weight: 500;
    text-align: center;
    text-decoration: none;
    background: var(--action);
    color: var(--text-inverse);
    cursor: pointer;
    transition: background-color 0.15s ease;
}

@media (hover: hover) {
    .mcp-link:hover {
        background: var(--brand);
        color: var(--text-inverse);
    }
}

.mcp-form-done {
    margin: 0;
    color: var(--success);
    font-size: 14px;
}

.mcp-form textarea,
.mcp-form input,
.mcp-form select {
    padding: 0.5em 0.75em;
    border-radius: 6px;
    background-color: var(--surface-page);
}

.mcp-box {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 8px;
}

.mcp-box.is-horizontal {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
}

.activity {
    color: var(--text-muted);
    font-size: 14px;
    margin-top: 10px;
    min-height: 1.4em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.composer {
    display: flex;
    gap: 10px;
    align-items: center;
    margin-top: 14px;
    background: linear-gradient(0deg, var(--surface-page), transparent);
}

/* Empty chat: the composer waits a little below the middle of the viewport; the greeting
   above it moves along. */
#tab-chat.is-empty .composer {
    position: fixed;
    top: 56%;
    left: 0;
    right: 0;
    box-sizing: border-box;
    max-width: var(--max-w-lg);
    margin: 0 auto 0 var(--chat-inline-start, auto);
    padding: 0 16px;
    transform: translateY(-50%);
}

/* Greeting above the centred input of an empty chat; gone with the first message.
   Absolutely positioned, so the input itself stays centred. */
.chat-greeting {
    display: none;
    text-wrap: balance;
}

#tab-chat.is-empty .chat-greeting {
    display: block;
    position: absolute;
    bottom: calc(100% + 3rem);
    left: 16px;
    right: 16px;
    margin: 0;
    text-align: center;
    font-size: 2rem;
    font-weight: 300;
    line-height: 1.2;
    color: var(--color-primary-900);
}

/* Credit of an empty chat at the bottom edge. Same box as the composer (width, inline
   start), so it is centred below the input, also next to the desktop aside. Not inside the
   composer: its transform would make it the containing block of this fixed line. */
.chat-credit {
    display: none;
}

#tab-chat.is-empty .chat-credit {
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    box-sizing: border-box;
    max-width: var(--max-w-lg);
    margin: 0 auto 0 var(--chat-inline-start, auto);
    padding: 0 16px;
    text-align: center;
    font-size: 0.8rem;
    color: var(--color-primary-700);
    pointer-events: none;
}

/* Once the conversation starts, the composer is pinned above the tab bar. Heights come
   from app.js (exposeHeight); the fallbacks only matter before the first measurement. */
#tab-chat:not(.is-empty) .composer {
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(var(--tabs-height, 61px) + var(--composer-lift, 0px));
    z-index: 10;
    box-sizing: border-box;
    max-width: var(--max-w-lg);
    margin: 0 auto 0 var(--chat-inline-start, auto);
    padding: 10px 16px;
    /* background: var(--surface-page); */
}

/* Covers everything from the middle of the pinned input down to the bottom edge (the
   composer's own padding and the lifted gap), so messages do not show through below the
   input. Behind the input (z-index -1 inside the composer's stacking context) and
   absolutely positioned, so it does not count into the measured --composer-height. */
#tab-chat:not(.is-empty) .composer::after {
    content: "";
    position: absolute;
    z-index: -1;
    left: 0;
    right: 0;
    top: 50%;
    bottom: calc(-1 * (var(--composer-lift, 0px) + var(--tabs-height, 0px)));
    background: var(--surface-page);
    pointer-events: none;
}

/* The chat fills the space between app bar and composer, so the log can sit at the bottom
   and grow upwards; main reserves room for the fixed composer and tab bar. */
main:has(> #tab-chat:not(.is-empty):not([hidden])) {
    padding-bottom: calc(
        var(--tabs-height, 61px) + var(--composer-lift, 0px) + var(--composer-height, 74px)
    );
}

#tab-chat:not(.is-empty) {
    display: flex;
    flex-direction: column;
    min-height: calc(
        100dvh - env(safe-area-inset-top) - var(--app-bar-height, 60px) - 14px -
            var(--tabs-height, 61px) - var(--composer-lift, 0px) - var(--composer-height, 74px)
    );
}

#tab-chat:not(.is-empty) .chat-log {
    margin-top: auto;
}

/* Fade above the composer so messages scroll out softly instead of being cut off. */
/* #tab-chat:not(.is-empty) .composer::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 100%;
    height: 32px;
    background: linear-gradient(to top, var(--surface-page), transparent);
    pointer-events: none;
} */

.composer .optional-label {
    color: var(--text-muted);
    display: none;
}

/* Small screens show the plan button's icon only; the label appears from 600px. */
@media (min-width: 600px) {
    .composer .optional-label {
        display: inline-block;
    }
}

/* Pill that holds mic, input, plan and send; the input itself stays transparent inside it. */
.composer-field {
    display: flex;
    flex: 1;
    gap: 3px;
    align-items: center;
    min-width: 0;
    padding: 0.25rem;
    background-color: var(--surface-card);
    border: 1px solid var(--color-neutral-300);
    border-radius: 100px;
    box-shadow: 0 0 20px rgba(154, 144, 216, 0.15);
    overflow: hidden;
}

.composer-field:focus-within {
    border-color: var(--brand-soft);
}

.row .icon-button {
    flex: 0 0 52px;
    height: 52px;
    min-height: 52px;
    padding: 0;
    font-size: 20px;
}

.composer-field .icon-button {
    display: flex;
    flex: 0 0 auto;
    gap: 0.2rem;
    align-items: center;
    align-self: center;
    min-width: 52px;
    min-height: 52px;
    padding: 0 1rem;
    border: none;
    border-radius: 100px;
    font-size: 0.8rem;
    font-weight: 400;
    white-space: nowrap;
}

.composer-field input {
    flex: 1;
    min-width: 0;
    height: 100%;
    margin-top: 0;
    padding: 0 0.8rem;
    background: transparent;
    border: none;
    outline: none;
    box-shadow: none;
}

.composer-field input::placeholder {
    color: var(--text-muted);
    opacity: 1;
}

.composer-field input:focus,
.composer-field input:focus-visible {
    outline: none;
    box-shadow: none;
    background: transparent;
}

#tab-chat .row {
    margin-top: 12px;
}

#tab-chat .row button {
    margin-top: 0;
}

/* Section heading that names who a group of settings applies to; plain text, no card. */
.settings-scope {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 12px 0 16px;
    font-size: 14px;
}

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

.settings-scope span {
    color: var(--text-muted);
    font-size: 13px;
}

/* Model roles: shows both configured models, the button swaps their roles. */
.model-switch {
    display: flex;
    align-items: stretch;
    gap: 10px;
    margin: 4px 0 6px;
}

.model-option {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface-card);
    color: var(--text);
    text-align: left;
    cursor: default;
}

.model-option.active {
    border-color: var(--success);
    background: var(--success);
    color: var(--text-inverse);
}

.model-option-slot {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    opacity: 0.7;
}

.model-option-name {
    font-size: 13px;
    font-weight: 600;
    word-break: break-word;
}

.model-swap-button {
    margin-top: 0;
}

#chat-mic.is-listening {
    background: var(--color-red-600);
    border-color: var(--color-red-600);
    color: var(--text-inverse);

    box-shadow: 0 0 0 4px rgba(179, 48, 48, 0.18);
    animation: mic-listening-pulse 1.2s ease-in-out infinite;
}

.voice-listening {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-top: 10px;
    padding: 8px 12px;
    border: 1px solid var(--danger-border);
    border-radius: 10px;
    background: var(--danger-surface);
    color: var(--danger);
    font-size: 14px;
    font-weight: 600;
}

.voice-listening-dot {
    flex: 0 0 10px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--color-red-500);
    animation: mic-listening-dot 1s ease-in-out infinite;
}

@keyframes mic-listening-pulse {
    50% {
        box-shadow: 0 0 0 7px rgba(179, 48, 48, 0.08);
    }
}

@keyframes mic-listening-dot {
    50% {
        opacity: 0.35;
        transform: scale(0.8);
    }
}

@media (prefers-reduced-motion: reduce) {
    #chat-mic.is-listening,
    .voice-listening-dot {
        animation: none;
    }
}

/* Area buttons ("Aktuell", "Odots") at the top of the aside; navigation.js marks the
   shown area .active. Rows like the chat list, with badge and spinner after the label. */
.aside-nav {
    flex: none;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.aside-nav-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    margin: 0;
    padding: 10px 14px 10px 8px;
    text-align: left;
    border: none;
    border-radius: 6px;
}

/* Buttons and links in the aside sit transparent on its background; hover shows a light
   neutral. That shade stays light in the dark theme too, so the text turns dark on it.
   The current area/chat (.active) keeps its own highlight. */
.chat-thread-aside :is(button, a) {
    background: transparent;
}

@media (hover: hover) {
    .chat-thread-aside
        :is(button, a):not(
            .active,
            :disabled,
            .chat-thread-chip,
            .chat-thread-pin,
            .chat-thread-more
        ):hover {
        background: var(--color-neutral-200);
        color: var(--color-neutral-1000);
    }
}

/* "Neuer Chat" is always in the aside; below the desktop breakpoint additionally as the
   round "+" next to the pin toggle. Keep 1024px in sync with chat.js. */
@media (min-width: 1024px) {
    .chat-thread-add-inline {
        display: none;
    }
}

.aside-nav-btn:disabled {
    opacity: 0.4;
}

.aside-nav-btn.active {
    background: var(--action);
    color: var(--text-inverse);
}

.aside-nav-icon {
    flex: none;
    padding: 3px;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    transition: color 0.3s ease;
}

/* The "+" of "Neuer Chat" sits on a round --line background. */
.chat-thread-add .aside-nav-icon {
    background: var(--border);
}

/* On the dark active background the circle follows the inverted text colour. */
.chat-thread-add.active .aside-nav-icon {
    background: var(--action);
    color: var(--text-inverse);
}

.aside-nav-label {
    flex: 1 1 auto;
    min-width: 0;
}

/* Header help button while the help tab is shown (switchTab toggles .active), and the
   settings button while a menu page is open (showPage/closePage toggle it). */
.header-actions .icon-button.active {
    background: var(--surface-subtle);
    border-color: var(--surface-subtle);
}

@media (hover: hover) {
    .header-actions .icon-button:hover {
        background: var(--surface-subtle);
        border-color: var(--surface-subtle);
    }
}

.tab-badge {
    flex: 0 0 auto;
    background: var(--color-green-700);
    color: var(--text-inverse);
    border-radius: 999px;
    padding: 0 6px;
    font-size: 11px;
    line-height: 18px;
    font-variant-numeric: tabular-nums;
}

.aside-nav-btn.active .tab-badge {
    background: var(--color-green-200);
    color: var(--text);
}
/* A running Odot pulses in its row: a green circle behind the task icon. The icon has no
   padding of its own, so the circle gets some, cancelled by a negative margin to avoid a
   layout shift. */
.dot-row.is-running .task-icon {
    padding: 4px;
    margin: -4px;
    border-radius: 50%;
    animation: nav-icon-pulse 1.4s ease-in-out infinite;
}

@keyframes nav-icon-pulse {
    from,
    to {
        background: var(--color-green-300);
    }

    50% {
        background: var(--color-green-600);
    }
}

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

@media (prefers-reduced-motion: reduce) {
    .dot-row.is-running .task-icon,
    .dot-running::before {
        animation-duration: 2.4s;
    }
}

.toast {
    position: fixed;
    left: 16px;
    right: 16px;
    bottom: calc(24px + env(safe-area-inset-bottom));
    border-radius: 8px;
    padding: 6px 16px;
    font-size: 0.9em;
    font-weight: 400;
    text-align: center;
    z-index: 1100;
    max-width: var(--max-w-sm);
    margin: 0 auto;
    border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
    background-color: color-mix(in srgb, var(--surface-subtle) 60%, transparent);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
}

.toast.toast-error {
    color: var(--danger);
    border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent);

    background-color: color-mix(in srgb, var(--danger-surface) 60%, transparent);
}

/* The toast drops in at the top, below the sticky chrome of the visible area — below
   the progress (or the app bar) in Aktuell/Odots and the pages, below the top bar in the
   chat. It never takes clicks, so it cannot block the controls it overlaps. */
.toast {
    top: calc(var(--app-bar-height, 60px) + var(--progress-height, 0px) + 14px);
    bottom: auto;
    pointer-events: none;
}

body:has(#tab-chat:not([hidden])) .toast {
    top: calc(var(--app-bar-height, 60px) + 20px + var(--chat-threads-height, 52px));
}

/* Desktop: centred over the content column right of the aside, like the chat itself;
   pages without that column keep the full width. */
@media (min-width: 1024px) {
    .toast {
        left: var(--chat-inline-start, 16px);
        right: max(16px, calc(100vw - var(--chat-inline-start, 100vw) - var(--max-w-lg)));
    }
}

[hidden] {
    display: none !important;
}

/* At the top of main, which already has the side padding. It sticks right below the header
   while the page scrolls; the top bar of Aktuell/Odots then sticks below it (see
   .chat-threads), so header, progress and that bar stack in the order they have unscrolled. */
.progress {
    position: sticky;
    top: var(--app-bar-height, 60px);
    z-index: 31;
    gap: 12px;
    display: flex;
    align-items: center;
    min-height: 58px;
    padding: var(--box-padding);
    border-radius: 12px;
    margin-bottom: 6px;
    background-color: color-mix(in srgb, var(--color-primary-100) 70%, transparent);

    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
}

/* Desktop: no solid strip; the page colour holds for the top 30% and then fades out
   downwards (no top bar sticks below). */
/* @media (min-width: 1024px) {
    .progress {
        background: linear-gradient(to bottom, var(--surface-page) 60%, transparent);
    }
} */

/* Activity indicator: a filled dot that pulses in size while work is in progress. */
.progress::before {
    content: "";
    flex: 0 0 14px;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--color-primary-500);
    animation: progress-pulse 1.2s ease-in-out infinite;
}

/* Uniform scale keeps the dot round and does not shift the layout. */
@keyframes progress-pulse {
    0%,
    100% {
        scale: 1;
    }
    50% {
        scale: 0.6;
    }
}

@media (prefers-reduced-motion: reduce) {
    .progress::before,
    .spinner,
    .spinner-small,
    .chat-thread-dot,
    .aside-nav-btn.is-running::after,
    body:has(#current-loading:not([hidden])) #tab-btn-mail::after,
    #sd-activity:not([hidden])::before {
        animation: none;
    }
}

.progress-bar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background-size: 200% 100%;
    animation: progress-slide 1.4s linear infinite;
}

@keyframes progress-slide {
    from {
        background-position: 200% 0;
    }
    to {
        background-position: 0 0;
    }
}

.progress span {
    flex: 1;
    min-width: 0;
    color: var(--text-muted);
    font-size: 0.9em;
    font-weight: 400;
    line-height: 1.3;
}

.chat-progress {
    overflow: hidden;
    min-height: 52px;
    margin: 12px 0 6px;
}

.mcp-form > *:first-child,
.markdown > *:first-child,
.markdown blockquote > *:first-child {
    margin-top: 0;
}

.mcp-form > *:last-child,
.markdown > *:last-child,
.markdown blockquote > *:last-child {
    margin-bottom: 0;
}

.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
    font-size: 1rem;
    margin: 2rem 0 1.4rem;
    line-height: 1.4;
}

.markdown h2 + h2,
.markdown h3 + h3,
.markdown h4 + h4,
.markdown h5 + h5,
.markdown h6 + h6 {
    margin-top: 1rem;
}

/* Markdown "# " renders as h2 (levels are shifted down by one). */
.markdown h2 {
    font-size: 1.6rem;
}

.markdown h3 {
    font-size: 1.4rem;
}

.markdown h4 {
    font-size: 1.2rem;
}

.markdown h6 {
    font-size: 0.8rem;
    text-transform: uppercase;
    color: var(--text-muted);
}

@media (min-width: 640px) {
    .markdown h2 {
        font-size: 1.8rem;
    }

    .markdown h3 {
        font-size: 1.5rem;
    }

    .markdown h4 {
        font-size: 1.2rem;
    }

    .markdown h6 {
        font-size: 0.8rem;
    }
}

.markdown p {
    margin: 0 0 1.4rem;
}

.markdown ul,
.markdown ol {
    margin: 0 0 8px;
    padding-left: 20px;
}

.markdown li {
    margin-bottom: 10px;
    margin-top: 10px;
}

.markdown hr {
    margin: 40px 0;
    border: none;
    border-top: 1px solid var(--border);
}

.markdown code {
    background: var(--surface-card);
    border-radius: 4px;
    padding: 2px 6px;
    font-size: 0.9em;
    color: var(--danger);
    border: 1px solid var(--border-subtle);
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}

.markdown pre {
    background: var(--surface-card);
    border-radius: 8px;
    padding: var(--box-padding);
    overflow-x: auto;
    border: 1px solid var(--border-subtle);
    white-space: pre;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 0.8rem;
    margin: 8px 0;
}

.markdown pre code {
    background: none;
    padding: 0;
    border: none;
    color: var(--accent);
    font-size: inherit;
    font-family: inherit;
    white-space: inherit;
}

/* mcp-ui links render as filled buttons (`.mcp-link`), not as prose links. Chat
   mounts them inside the `markdown` bubble, so without the `:not()` they would
   inherit `--brand` as their label colour and become unreadable on `--action`. */
.markdown a:not(.mcp-link) {
    color: var(--brand);
    text-underline-offset: 2px;
}

.markdown blockquote {
    margin: 1em 0;
    padding: 1em;
    border-left: 3px solid var(--brand);
    background-color: var(--surface-card);
}

.markdown img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}

.md-table {
    margin: 10px 0;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.md-table table {
    border-collapse: collapse;
    width: 100%;
    font-size: 15px;
}

.md-table th,
.md-table td {
    border: 1px solid var(--border);
    padding: 6px 10px;
    text-align: left;
    vertical-align: top;
    white-space: nowrap;
}

.is-pinned.markdown hr,
.is-pinned.markdown code,
.is-pinned.markdown pre,
.is-pinned .md-table th,
.is-pinned .md-table td {
    border-color: color-mix(in srgb, var(--color-warm-500) 50%, transparent);
}

.is-pinned.markdown blockquote {
    background-color: var(--color-warm-200);
}

.md-table thead th {
    background: var(--surface-subtle);
    font-weight: 600;
}

.is-pinned .md-table thead th {
    background: var(--color-warm-200);
}

/* Checkbox and text sit side by side; long text wraps within its own column. */
.markdown li.task {
    list-style: none;
    margin-left: -18px;
    display: flex;
    align-items: baseline;
    gap: 12px;
}

/* Reset the global input sizing so the checkbox does not claim the full row. */
.markdown li.task input {
    flex: none;
    width: auto;
    padding: 0;
    margin: 0;
}

.markdown li.task .task-body {
    flex: 1;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Strike through only the item's own text, not its nested sub-items. */
.markdown li.task.done > .task-body > .task-text {
    text-decoration: line-through;
}

.chart {
    margin-top: 10px;
    padding: var(--box-padding);
    background: var(--surface-card);
    border-radius: 8px;
    width: 100%;
    border: 1px solid var(--border-subtle);
}

.chart-title {
    font-weight: 600;
    margin-bottom: 1em;
}

.chart-row {
    display: flex;
    align-items: center;
    font-size: 0.8rem;
}

/* Label and value stretch to the row height so their borders form continuous
   lines; equal vertical padding keeps the text centred on the bar. */
.chart-label {
    flex: 0 0 40%;
    align-self: stretch;
    padding: 0.5em 0.75em 0.5em 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    border-right: 1px solid var(--border);
}

.chart-track {
    flex: 1;
    background: var(--surface-subtle);
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    height: 1.4em;
    overflow: hidden;
    margin-bottom: 0.5em;
    margin-top: 0.5em;
}

.chart-bar {
    display: block;
    height: 100%;
    border-top-right-radius: 4px;
    border-bottom-right-radius: 4px;
    background: var(--brand);
}

.chart-value {
    flex: 0 0 auto;
    min-width: 52px;
    align-self: stretch;
    padding: 0.5em 0 0.5em 0.75em;
    text-align: right;
    color: var(--text-muted);
    border-left: 1px solid var(--border);
}

.chart-pie-wrapper {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.25rem;
    margin-top: 0.5rem;
}

@media (min-width: 480px) {
    .chart-pie-wrapper {
        flex-direction: row;
        justify-content: space-around;
        align-items: center;
    }
}

.chart-pie {
    width: 140px;
    height: 140px;
    border-radius: 50%;
    position: relative;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
    flex-shrink: 0;
}

.chart-pie.is-donut::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 70px;
    height: 70px;
    background: var(--surface-card);
    border-radius: 50%;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
}

.chart-legend {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    width: 100%;
    font-size: 0.85rem;
}

.chart-legend-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.2rem 0;
}

.chart-legend-swatch {
    width: 12px;
    height: 12px;
    border-radius: 3px;
    flex-shrink: 0;
}

.chart-legend-label {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text);
}

.chart-legend-pct {
    font-weight: 600;
    color: var(--text);
}

.chart-legend-value {
    color: var(--text-muted);
    font-size: 0.75rem;
}

.icon-button {
    width: auto;
    min-height: 40px;
    margin: 0;
    padding: 6px 12px;
    font-size: 20px;
    line-height: 1;
    border-radius: 10px;
}

.header-actions .icon-button {
    border: none;
    width: 40px;
    padding: 0;
    background-color: var(--surface-page);
}

/* Material Symbols from icons.js; sized in em, so they follow the surrounding text. */
.icon {
    flex: none;
    vertical-align: -0.25em;
}

.icon-button .icon,
.help-clear-btn .icon,
.task-icon .icon,
.plan-icon .icon,
.help-btn-icon .icon,
.help-card-icon .icon,
.drop-overlay-icon .icon {
    display: block;
    margin: 0 auto;
    width: 1.4rem;
    height: 1.4rem;
}

.header-actions .icon {
    width: 1.2rem;
    height: 1.2rem;
}

/* The theme button carries both icons and shows the one for the other theme. */
:root[data-theme="dark"] .theme-icon-dark,
:root:not([data-theme="dark"]) .theme-icon-light {
    display: none;
}

.back {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    width: auto;
    min-height: auto;
    padding: 0;
    border: none;
    background-color: unset;
    align-self: center;
    margin: 0;
    transition: color 0.15s;
}

@media (hover: hover) {
    .back:hover {
        background-color: unset;
        color: var(--text-muted);
    }
}

.back .icon {
    width: 1rem;
    height: 1rem;
}

.page-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    /* The height of .page-close, so a nav with only "Zurück" (Odot detail) keeps the
       same spacing as one with the close button. */
    min-height: 44px;
}

/* Round icon button; right-aligned, also on the menu's first level where there is
   no back button. 44px keeps the minimum touch target size. */
.page-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 44px;
    height: 44px;
    min-height: 44px;
    /* auto pushes it to the right edge even when it is the only child. */
    margin: 0 0 0 auto;
    padding: 0;
    border-radius: 50%;
    border: none;
    background-color: var(--surface-page);
}

.page-close .icon {
    width: 1.4rem;
    height: 1.4rem;
}

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

#page-mail > .page-nav {
    margin-bottom: 12px;
}

.menu-meta {
    color: var(--text-muted);
    font-size: 13px;
    font-weight: 400;
    margin: 4px 0 12px;
    word-break: break-word;
}

/* The menu page fills the viewport between app bar and main's bottom padding, so the
   version line (margin-top: auto) sits at the bottom even when the menu is short. */
main:has(> #page-menu:not([hidden])) {
    /* Just the safe area below; the generic padding leaves a gap below the version. */
    --menu-bottom-pad: calc(var(--tabs-height, 0px) + 8px);
    padding-bottom: var(--menu-bottom-pad);
}

#page-menu:not([hidden]) {
    display: flex;
    flex-direction: column;
    min-height: calc(
        100dvh - env(safe-area-inset-top) - var(--app-bar-height, 60px) - 14px -
            var(--menu-bottom-pad)
    );
}

/* Tap target for the hidden demo panel (five quick taps). Kept tappable even
   while the version text is still empty, and without selection/callout. */
#menu-version {
    margin-top: auto;
    min-height: 22px;
    touch-action: manipulation;
    -webkit-user-select: none;
    user-select: none;
}

h2 {
    font-size: 17px;
    margin: 16px 0 8px;
}

/* Shared search and tag filter above the installed and repository sections. */
.skills-filter {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 8px;
    margin: 1em 0;
}

/* Grid items default to min-width: auto; 0 keeps long options inside their 1fr column. */
.skills-filter > * {
    min-width: 0;
}

/* Search spans the full row (Tailwind col-span-full). */
.skills-filter > :first-child {
    grid-column: 1 / -1;
}

.skills-field {
    margin-top: 10px;
}

.skills-field label {
    display: block;
    color: var(--text-muted);
    font-size: 13px;
    font-weight: 600;
}

.skills-field input,
.skills-field select {
    margin-top: 4px;
}

.skill-row {
    background: var(--surface-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px;
    margin-bottom: 10px;
}

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

.skill-meta {
    color: var(--text-muted);
    font-size: 14px;
    margin: 2px 0 8px;
    word-break: break-word;
}

.skill-actions {
    display: flex;
    gap: 8px;
}

.skill-actions button {
    flex: 1;
    margin-top: 0;
}

.update-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    /* Wrap instead of overflowing: the global `button { width: 100% }` made
       the action button demand the full row width next to the label. */
    flex-wrap: wrap;
    gap: 12px;
    padding: 10px 14px;
    margin: 0 0 12px;
    border-radius: 0.5em;
    /* Theme tokens, not the static primary palette: --color-primary-100 stays
       light lavender in dark mode and reads as a white-on-pink block. */
    background: var(--surface-subtle);
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    color: var(--text);
    font-size: 0.9em;
}

.update-banner button {
    margin-top: 0;
    /* Undo the global width: 100%, otherwise the row grows past its container. */
    width: auto;
    flex-shrink: 0;
}

.update-banner-action {
    background: var(--surface-card);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.2em 0.6em;
    min-height: 0;
    font-size: 0.8rem;
    font-weight: 500;
    cursor: pointer;
}

@media (hover: hover) {
    .update-banner-action:hover:not(:disabled) {
        border-color: var(--accent);
        color: var(--accent);
    }
}

.update-banner-action:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

button.secondary {
    background: var(--surface-subtle);
    color: var(--text-muted);
    border-style: dashed;
}

button.logout {
    /* background: var(--danger-surface); */
    /* color: var(--text); */
    /* border-color: var(--danger-border); */
    background-color: unset;
    border: unset;
    justify-content: center;
}

#btn-home {
    cursor: pointer;
    user-select: none;
}

.app-logo {
    display: block;
    height: 32px;
    width: 32px;
}

.app-logo-main {
    fill: var(--color-primary-700);
}

.app-logo-accent {
    fill: var(--color-primary-900);
}

#settings-prompt {
    width: 100%;
    min-height: 140px;
    margin-top: 8px;
    font-size: 15px;
    line-height: 1.4;
}

.help-search-row {
    display: flex;
    align-items: center;
    gap: 8px;
    position: relative;
}

.help-search-row input {
    margin-top: 0;
    padding-right: 42px;
}

.help-clear-btn {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    width: 32px;
    height: 32px;
    min-height: 32px;
    border-radius: 50%;
    border: none;
    background: var(--border);
    color: var(--text);
    padding: 0;
    margin: 0;
    font-size: 14px;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.help-topics {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
    margin-top: 8px;
}

.help-topic-btn {
    margin: 0;
    min-height: 52px;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    padding: 10px 14px;
    font-size: 15px;
    font-weight: 600;
    text-align: left;
    border-radius: 12px;
    border: 1px solid var(--border);
    background: var(--surface-card);
    color: var(--text);
    cursor: pointer;
    transition:
        background 0.15s,
        border-color 0.15s,
        color 0.15s;
}

@media (hover: hover) {
    .help-topic-btn:hover {
        background: var(--surface-subtle);
    }
}

.help-topic-btn.active {
    background: var(--action);
    border-color: var(--action);
    color: var(--text-inverse);
}

.help-btn-icon {
    font-size: 18px;
    flex-shrink: 0;
}

.help-content {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin-top: 16px;
}

.help-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.help-card-header {
    display: flex;
    align-items: center;
    gap: 10px;
    border-bottom: 1px solid var(--border);
    padding-bottom: 8px;
}

.help-card-icon {
    font-size: 24px;
}

.help-card-title {
    margin: 0;
    font-size: 18px;
    font-weight: 600;
    color: var(--text);
}

.help-card-body {
    color: var(--text);
    font-size: 15px;
    line-height: 1.5;
}

.help-card-body h3 {
    margin: 14px 0 6px;
    font-size: 16px;
    color: var(--text);
}

.help-card-body p {
    margin: 6px 0;
}

.help-card-body ul,
.help-card-body ol {
    margin: 6px 0;
    padding-left: 20px;
}

.help-card-body li {
    margin-bottom: 4px;
}

.help-card-body code {
    background: var(--surface-card);
    padding: 2px 6px;
    border-radius: 8px;
    font-size: 0.9em;
}

.help-card-body pre {
    background: var(--surface-card);
    border-radius: 8px;
    padding: var(--box-padding);
    overflow-x: auto;
}

hr {
    border: none;
    border-top: 1px solid var(--border);
    margin: 14px 0;
}

.help-nav-row {
    margin-top: 8px;
    border-top: 1px solid var(--border);
    padding-top: 12px;
}

.help-nav-row button {
    margin-top: 0;
    font-size: 14px;
    min-height: 40px;
}

/* Plan card: vertical flow chart */

.plan-card {
    background: var(--surface-card);
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    padding: var(--box-padding);
    display: flex;
    flex-direction: column;
    gap: 12px;
}

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

.plan-icon {
    font-size: 22px;
    line-height: 1;
}

.plan-titles {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.plan-title {
    font-size: 15px;
}

.plan-badge {
    align-self: flex-start;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--action);
    background: color-mix(in srgb, var(--action) 12%, transparent);
    border-radius: 999px;
    padding: 2px 8px;
}

.plan-badge.is-done {
    color: var(--success);
    background: color-mix(in srgb, var(--success) 15%, transparent);
}

.plan-body {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.plan-intro,
.plan-outro,
.plan-text {
    font-size: 14px;
    line-height: 1.45;
    color: var(--text);
}

.plan-intro > *:first-child,
.plan-outro > *:first-child,
.plan-text > *:first-child {
    margin-top: 0;
}

.plan-intro > *:last-child,
.plan-outro > *:last-child,
.plan-text > *:last-child {
    margin-bottom: 0;
}

.plan-stepper {
    list-style: none;
    margin: 0;
    padding: 4px 0;
    display: flex;
    flex-direction: column;
}

.plan-step {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 10px 12px;
}

.plan-step + .plan-step {
    margin-top: 24px;
}

.plan-step + .plan-step::before {
    content: "";
    position: absolute;
    left: 23px;
    top: -24px;
    width: 2px;
    height: 24px;
    background: var(--action);
    opacity: 0.45;
}

.plan-step + .plan-step::after {
    content: "";
    position: absolute;
    left: 19px;
    top: -9px;
    width: 0;
    height: 0;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 7px solid var(--action);
    opacity: 0.8;
}

.plan-step-no {
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--action);
    color: var(--text-inverse);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 600;
}

.plan-step-text {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    line-height: 1.45;
}

.plan-step-text > *:first-child {
    margin-top: 0;
}

.plan-step-text > *:last-child {
    margin-bottom: 0;
}

.plan-note {
    margin: 0;
    font-size: 12px;
    color: var(--text-muted);
}

.plan-actions {
    display: flex;
    gap: 10px;
}

.plan-actions button {
    flex: 1;
    margin-top: 0;
    min-height: 40px;
    font-size: 15px;
}

.plan-execute {
    background: var(--action);
    border-color: var(--action);
    color: var(--text-inverse);
}

.plan-discard {
    background: var(--surface-card);
}

/* Skill pill, built by ui.js skillPill() and used by the mail detail. */

.task-skill {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: 48px;
    margin-top: 0;
    padding: 10px 16px;
    border-radius: 12px;
    background: var(--surface-card);
    border: 1px solid var(--border);
    color: var(--text);
    text-align: left;
    font-weight: 600;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    touch-action: manipulation;
}

.task-skill:active {
    background: var(--surface-card);
}

.task-icon {
    flex: 0 0 auto;
    font-size: 16px;
    line-height: 1;
}

.task-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Skill-usage chips on an assistant chat bubble, built by chat.js render(). */
.skill-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 8px;
}

.skill-chips-label {
    color: var(--text-muted);
    font-size: 11px;
    font-weight: 600;
}

.skill-chip {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-card);
    color: var(--text-muted);
    font-size: 11px;
    font-style: normal;
    line-height: 1.6;
}

/* The chip opens a detail sheet; a pointer plus a slightly darker outline on
   hover signals that without making the background info prominent. */
.skill-chip[role="button"] {
    cursor: pointer;
}

.skill-chip[role="button"]:focus-visible {
    border-color: var(--text-muted);
    color: var(--text);
}

@media (hover: hover) {
    .skill-chip[role="button"]:hover {
        border-color: var(--text-muted);
        color: var(--text);
    }
}

.skill-tag {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-card);
    color: var(--text-muted);
    font-size: 11px;
    line-height: 1.6;
}

/* Detail sheet for a used skill (chip tap), see chat.js openSkillInfo(). */
.skill-info-card {
    display: flex;
    flex-direction: column;
}

.skill-info-header {
    display: flex;
    align-items: flex-start;
    gap: 8px;
}

.skill-info-title {
    flex: 1;
    min-width: 0;
    font-size: 16px;
    font-weight: 600;
}

.skill-info-close {
    flex: 0 0 auto;
}

.skill-info-description {
    margin: 10px 0 0;
    white-space: pre-wrap;
}

.skill-info-meta {
    margin-top: 8px;
    color: var(--text-muted);
    font-size: 12px;
}

.skill-info-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}

.skill-info-hint {
    margin-top: 12px;
    color: var(--text-muted);
    font-size: 12px;
}

.skill-info-body .skill-info-open {
    width: 100%;
    margin-top: 14px;
}

#mail-actions,
#mail-skill-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 8px;
}

.overlay {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(0, 0, 0, 0.45);
}

.overlay[hidden] {
    display: none;
}

.overlay-card {
    width: 100%;
    max-width: var(--max-w-sm);
    max-height: 85vh;
    overflow-y: auto;
    background: var(--surface-card);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 16px;
}

.overlay-card input,
.overlay-card textarea {
    margin-top: 10px;
}

.overlay-card .row {
    margin-top: 12px;
}

#current-action-body > button,
#dot-run-overlay-body > button {
    width: 100%;
    margin: 6px 0;
    text-align: left;
}

#current-action-body > button.current-skill-action {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
}

#current-action-body > button.current-skill-not_relevant,
#current-action-body > button.current-skill-unavailable {
    opacity: 0.5;
    border-color: var(--text-muted);
    color: var(--text-muted);
}

.current-skill-relevance-status {
    flex-basis: 100%;
    font-size: 12px;
    font-weight: 400;
}

#current-action-title,
#dot-run-overlay-title {
    font-size: 16px;
    margin-bottom: 10px;
}

.sheet-preview {
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 30vh;
    overflow-y: auto;
    color: var(--text-muted);
    font-size: 14px;
}

.mail-classification {
    margin-bottom: 12px;
}

.classification-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
}

.mail-list-tags {
    margin: 6px 0;
    gap: 4px;
}

.mail-list-tags .classification-badge {
    font-size: 11px;
}

.classification-badge {
    display: inline-flex;
    align-items: center;
    border-radius: 6px;
    font-weight: 500;
    font-size: 0.8rem;
    line-height: 1.4;
    padding: 0.2em 0.5em;
}

/* Middle band: keeps the filled colour, marked with a leading question mark. */
.classification-badge.confidence-uncertain::before {
    content: "?";
    font-weight: 600;
    margin-right: 3px;
}

/* Upper band: outlined pill in the field's own colour. */
.classification-badge.confidence-confident {
    border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
}

.classification-badge.confidence-inconclusive {
    border: 1px dotted color-mix(in srgb, currentColor 30%, transparent);
    background: var(--color-blue-50);
    color: var(--color-blue-800);
}

.badge-category {
    color: var(--color-primary-900);
    background: var(--color-primary-100);
}

.badge-urgent-hoch {
    background: var(--color-red-50);
    color: var(--color-red-600);
}

.badge-urgent-normal {
    background: var(--color-green-50);
    color: var(--color-green-800);
    border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
}

.badge-urgent-niedrig {
    background: var(--color-blue-50);
    color: var(--color-blue-800);
}

.badge-action {
    background: var(--color-yellow-50);
    color: var(--color-yellow-800);
}

.badge-action-needed {
    background: var(--color-yellow-50);
    color: var(--color-yellow-800);
}

.badge-action-none {
    background: var(--color-blue-50);
    color: var(--color-blue-800);
}

.badge-tonality-sachlich {
    background: var(--color-blue-50);
    color: var(--color-blue-800);
}

.badge-tonality-freundlich {
    background: var(--color-green-50);
    color: var(--color-green-800);
}

.badge-tonality-draengend,
.badge-tonality-drängend {
    background: var(--color-yellow-50);
    color: var(--color-yellow-800);
}

.badge-tonality-kritisch {
    background: var(--color-red-50);
    color: var(--color-red-600);
}

.mcp-server-group {
    background: var(--surface-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    margin-bottom: 12px;
    overflow: hidden;
}

.mcp-server-summary {
    padding: 12px 16px;
    cursor: pointer;
    font-size: 15px;
    user-select: none;
}

.mcp-tools-list {
    padding: 8px 12px 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.mcp-tool-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 10px 14px;
    margin-bottom: 0;
    box-sizing: border-box;
    width: 100%;
}

.mcp-tool-info {
    flex: 1 1 auto;
    min-width: 0;
}

.mcp-tool-info .skill-name {
    font-weight: 600;
    font-size: 15px;
    word-break: break-word;
    color: var(--text);
}

.mcp-tool-info .skill-meta {
    font-size: 13px;
    color: var(--text-muted);
    margin: 2px 0 0;
    word-break: break-word;
}

.mcp-toggle-switch {
    position: relative;
    display: inline-block;
    width: 48px;
    height: 28px;
    flex: 0 0 48px;
    margin: 0;
    cursor: pointer;
}

.mcp-toggle-switch input {
    opacity: 0;
    width: 0;
    height: 0;
    position: absolute;
    margin: 0;
}

.mcp-toggle-slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: var(--border);
    transition: 0.2s ease;
    border-radius: 28px;
}

.mcp-toggle-slider:before {
    position: absolute;
    content: "";
    height: 20px;
    width: 20px;
    left: 4px;
    bottom: 4px;
    background-color: #fff;
    transition: 0.2s ease;
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
}

.mcp-toggle-switch input:checked + .mcp-toggle-slider {
    background-color: var(--success);
}

.mcp-toggle-switch input:checked + .mcp-toggle-slider:before {
    transform: translateX(20px);
}

.mcp-toggle-switch input:disabled + .mcp-toggle-slider {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Drag & Drop Overlays */
.drop-overlay {
    z-index: 3000;
    background: rgba(0, 0, 0, 0.7);
    backdrop-filter: blur(4px);
    pointer-events: none;
}

.drop-overlay-box {
    border: 3px dashed var(--brand);
    border-radius: 18px;
    padding: 36px 48px;
    background: var(--surface-card);
    text-align: center;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
    max-width: var(--max-w-bubble);
    pointer-events: auto;
}

.drop-overlay-icon {
    font-size: 52px;
    margin-bottom: 12px;
    line-height: 1;
}

.drop-overlay-title {
    font-size: 20px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 6px;
}

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

.drop-result-card {
    max-width: 600px;
}

.drop-result-card .proposal {
    max-height: 60vh;
    overflow-y: auto;
}

.drop-result-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
}

.drop-choice-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

.drop-choice-btn {
    text-align: left;
    padding: 12px 14px;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--surface-card);
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 4px;
    transition:
        background-color 0.15s,
        border-color 0.15s;
}

@media (hover: hover) {
    .drop-choice-btn:hover {
        border-color: var(--brand);
        background: var(--brand-surface);
    }
}

.drop-choice-btn-title {
    font-weight: 600;
    font-size: 15px;
    color: var(--text);
}

.drop-choice-btn-desc {
    font-size: 13px;
    color: var(--text-muted);
}

#sd-input {
    min-height: 6em;
}

#sd-activity:not([hidden]) {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 40px;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface-card);
    color: var(--text);
}

#sd-activity:not([hidden])::before {
    content: "";
    flex: 0 0 16px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--color-primary-500);
    animation: progress-pulse 1.2s ease-in-out infinite;
}

#sd-proposal {
    margin-top: 16px;
}

.sd-preview {
    white-space: pre-wrap;
    word-break: break-word;
    overflow-x: auto;
    max-height: 24em;
    background: var(--surface-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px;
    margin-top: 8px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.85rem;
}

/* ===== Systemcheck / Health-Check page ===== */

#health-result-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

.health-row {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    background: var(--surface-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px 14px;
    border-left-width: 4px;
}

.health-row--ok {
    border-left-color: #22c55e;
}

.health-row--warning {
    border-left-color: #f59e0b;
}

.health-row--error {
    border-left-color: #ef4444;
}

.health-row--disabled {
    border-left-color: var(--border);
    opacity: 0.65;
}

.health-row--loading {
    border-left-color: var(--color-primary-400, #aa98fb);
    opacity: 0.85;
}

.health-icon {
    flex: 0 0 auto;
    font-size: 18px;
    line-height: 1.3;
}

.health-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.health-label {
    font-size: 14px;
    font-weight: 600;
    line-height: 1.3;
}

.health-response {
    font-size: 13px;
    color: var(--text-muted);
    line-height: 1.4;
    word-break: break-word;
}

.menu-list {
    list-style: none;
    padding: 0;
    margin: 0;
    margin: 2em 0;
}

/* A hidden entry (e.g. "Abmelden" before login) takes its list item along. */
.menu-list li:has(> [hidden]) {
    display: none;
}

.menu-btn-icon {
    flex: none;
    width: 1.4rem;
    height: 1.4rem;
    color: var(--text-muted);
}

.menu-title {
    border-bottom: 1px solid var(--border);
    padding: 1em 0;
    margin: 0 0 1em;
}

/* ===== Intelligent rating ===== */

/* Rating shortcut: only shown while rating is on, so its icon always carries the bar
   colour as the "on" mark; it has no pressed state. */
.header-actions .rating-toggle {
    color: var(--brand);
}

:root[data-theme="dark"] .header-actions .rating-toggle {
    color: var(--color-primary-600);
}

/* Rating row below an assistant answer: the guess plus correction controls. */
.rating-control {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    /* Some room after the last button of the action row. */
    margin-left: 6px;
    font-size: 12px;
    color: var(--text-muted);
}

.rating-guess {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 2px 6px 3px;
    background-color: var(--color-primary-50);
    border-radius: 4px;
}

.rating-guess .icon {
    flex: none;
}

/* Thumbs and flag sit in .message-actions and take its button style; a chosen one is
   marked in the accent colour. */
.message-actions .rating-button.active .icon {
    background-color: var(--color-primary-600);
    color: var(--text-inverse);
}

.rating-button:active {
    transform: scale(0.94);
}

.rating-note {
    color: var(--color-primary-700);
}

/* Operator statistics block in the gear menu (instance-wide). */
.rating-stats {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 8px;
}

.rating-stat {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 0;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
}

.rating-stat-label {
    color: var(--text-muted);
}

.rating-stat-value {
    font-weight: 600;
    text-align: right;
}

/* Template bar, in the chat's top bar after menu and "+"; that bar is sticky, so this
   one moves with it. It takes the remaining width. */
.chat-pinned-bar {
    position: relative;
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
    align-items: center;
    gap: 6px;
    margin: 0;
    padding: 0 4px 0 2px;
    background-color: var(--surface-subtle);
    border-radius: 8px;
    font-size: 13px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.chat-pinned-bar[hidden] {
    display: none !important;
}

/* Switched off, the bar shrinks to its toggle, so it can be switched on again. */
.chat-pinned-bar.is-collapsed {
    flex: none;
    padding: 2px;
}

.chat-pinned-bar.is-collapsed > :not(.chat-pinned-toggle) {
    display: none;
}

.chat-pinned-bar-main {
    display: flex;
    flex: 1;
    align-items: center;
    gap: 8px;
    min-width: 0;
    margin: 0;
    padding: 6px 4px;
    border: none;
    background: transparent;
    color: inherit;
    font-size: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

@media (hover: hover) {
    .chat-pinned-bar-main:hover {
        background: transparent;
        opacity: 0.9;
    }
}

.chat-pinned-bar-text {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--text);
}

.chat-pinned-bar-count {
    color: var(--text-muted);
    flex-shrink: 0;
    border-right: 1px solid var(--color-neutral-400);
    padding-right: 0.5em;
}

.chat-pinned-toggle,
.chat-pinned-bar-all {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    /* The global button rule sets min-height: 44px, which would win over height. */
    min-height: auto;
    align-self: center;
    padding: 0;
    margin: 0;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    flex-shrink: 0;
    -webkit-tap-highlight-color: transparent;
}

/* Small ⋮ like .chat-thread-more-icon: a 1rem icon in a 28px shape that takes the hover. */
.chat-pinned-bar-all .icon {
    box-sizing: content-box;
    width: 1rem;
    height: 1rem;
    padding: 6px;
    border-radius: 4px;
}

@media (hover: hover) {
    .chat-pinned-bar-all:hover .icon {
        background: var(--color-neutral-200);
        color: var(--color-neutral-800);
    }
}

/* History & Pinned Drawer / Modal */
.chat-history-card {
    width: 100%;
    max-width: var(--max-w-sm);
    max-height: 85vh;
    display: flex;
    flex-direction: column;
    padding: 0;
    overflow: hidden;
    box-sizing: border-box;
}

/* Templates window: styled like the chat (dark --action for what is selected or primary,
   neutral hover, rounded cards like the bubbles); no green accent. */
.chat-history-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
    background: var(--surface-page);
    box-sizing: border-box;
    width: 100%;
}

.chat-history-tabs {
    display: flex;
    gap: 6px;
    min-width: 0;
}

.chat-history-tab {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin: 0;
    padding: 6px 12px;
    border: 1px solid transparent;
    border-radius: 20px;
    background: transparent;
    color: var(--text-muted);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: all 0.15s ease;
    white-space: nowrap;
}

@media (hover: hover) {
    .chat-history-tab:hover {
        background: var(--color-neutral-200);
        color: var(--color-neutral-1000);
    }
}

.chat-history-tab.active {
    background: var(--action);
    color: var(--text-inverse);
}

.chat-history-close {
    margin: 0;
    min-width: 36px;
    min-height: 36px;
    width: 36px;
    height: 36px;
    padding: 0;
    flex-shrink: 0;
}

.chat-badge {
    font-size: 11px;
    padding: 1px 6px;
    border-radius: 10px;
    background: var(--border);
    color: inherit;
}

.chat-history-tab.active .chat-badge {
    background: var(--text-inverse);
    color: var(--action);
}

.chat-history-content {
    flex: 1;
    overflow-y: auto;
    padding: 12px 14px;
    background: var(--surface-page);
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-height: 160px;
    box-sizing: border-box;
    width: 100%;
}

/* "Neue Vorlage" above the list; while editing it takes the item's look. */
.chat-history-new {
    margin-bottom: 12px;
}

.chat-history-search-wrap {
    margin-bottom: 12px;
}

.chat-history-search-input {
    width: 100%;
    box-sizing: border-box;
    padding: 8px 12px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-size: 14px;
}

.chat-history-empty {
    text-align: center;
    color: var(--text-muted);
    padding: 32px 16px;
    font-size: 14px;
}

.chat-history-item {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 0.75em;
    background: var(--surface-card);
    cursor: pointer;
    box-sizing: border-box;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    flex-shrink: 0;
    overflow: hidden;
    transition:
        border-color 0.15s ease,
        background 0.15s ease;
}

@media (hover: hover) {
    .chat-history-item:hover {
        background: var(--surface-subtle);
    }
}

.chat-history-item-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    font-size: 12px;
    color: var(--text-muted);
    min-width: 0;
}

.chat-history-item-role {
    font-weight: 600;
    color: var(--text);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chat-history-item-text {
    font-size: 14px;
    line-height: 1.4;
    color: var(--text);
    white-space: pre-wrap;
    word-break: break-word;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.chat-history-item-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    margin-top: 4px;
    width: 100%;
    box-sizing: border-box;
}

.chat-history-action-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    width: auto;
    min-height: 32px;
    margin: 0;
    padding: 4px 10px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface-page);
    color: var(--text);
    font-size: 12px;
    cursor: pointer;
    white-space: nowrap;
    -webkit-tap-highlight-color: transparent;
}

@media (hover: hover) {
    .chat-history-action-btn:hover {
        background: var(--color-neutral-200);
        color: var(--color-neutral-1000);
    }
}

.chat-history-section-header {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-muted);
    margin: 10px 0 2px 2px;
    word-break: break-word;
    overflow-wrap: anywhere;
}

.chat-history-item-desc {
    font-size: 11px;
    color: var(--text-muted);
    word-break: break-word;
    overflow-wrap: anywhere;
}

.chat-history-action-btn.primary {
    background: var(--action);
    color: var(--text-inverse);
    border-color: var(--action);
}

@media (hover: hover) {
    .chat-history-action-btn.primary:hover {
        opacity: 0.9;
        background: var(--action);
        color: var(--text-inverse);
    }
}

.chat-history-action-btn.danger {
    color: var(--danger);
}

@media (hover: hover) {
    .chat-history-action-btn.danger:hover {
        background: var(--danger-surface);
        color: var(--danger);
    }
}

/* Same look as the other inputs (see textarea, input, select). */
.chat-edit-input,
.chat-edit-textarea {
    width: 100%;
    box-sizing: border-box;
    margin: 0 0 8px;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface-page);
    color: var(--text);
    font-size: 0.9rem;
    font-family: inherit;
}

.chat-edit-textarea {
    resize: vertical;
}

@media (max-width: 480px) {
    #chat-history-overlay {
        padding: 8px;
    }

    .chat-history-card {
        max-height: 90vh;
        border-radius: 12px;
    }

    .chat-history-header {
        padding: 10px 12px;
    }

    .chat-history-content {
        padding: 10px 10px;
        gap: 6px;
    }

    .chat-history-item {
        padding: 8px 10px;
    }

    .chat-history-tab {
        padding: 5px 8px;
        font-size: 12px;
        gap: 4px;
    }

    .chat-history-action-btn {
        padding: 3px 6px;
        font-size: 11px;
    }
}

/* REQ-MOB-11: Odots — Tab und Detailseite und Detailseite */

.dot-group {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 18px 2px 8px;
    color: var(--text-muted);
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.dot-group-icon .icon {
    width: 16px;
    height: 16px;
    fill: currentColor;
}

.dot-group-label {
    flex: 1;
}

.dot-group-count {
    font-weight: 400;
    font-variant-numeric: tabular-nums;
}

.dot-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 56px;
    margin-bottom: 8px;
    padding: 10px 12px;
    border-radius: 12px;
    background: var(--surface-card);
    border: 1px solid var(--border);
    color: var(--text);
    text-align: left;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    touch-action: manipulation;
}

.dot-row:active {
    background: var(--surface-card);
}

.dot-body {
    flex: 1;
    min-width: 0;
}

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

.dot-sub {
    color: var(--text-muted);
    font-size: 13px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dot-halted {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-top: 3px;
    color: var(--danger);
    font-size: 12px;
    font-weight: 600;
}

.dot-halted .icon {
    width: 14px;
    height: 14px;
    fill: currentColor;
}

.dot-off {
    flex: 0 0 auto;
    color: var(--text-muted);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.dot-unread {
    flex: 0 0 auto;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--accent);
    color: var(--text-inverse);
    font-size: 12px;
    font-weight: 600;
    line-height: 22px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* Ein laufender oder wartender Odot, direkt in seiner Zeile. */
.dot-running {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 3px;
    color: var(--accent);
    font-size: 12px;
    font-weight: 600;
}

.dot-running::before {
    content: "";
    width: 10px;
    height: 10px;
    border-radius: 50%;
    border: 2px solid color-mix(in srgb, currentColor 30%, transparent);
    border-top-color: currentColor;
    animation: tab-spin 0.8s linear infinite;
}

/* Umbenennen, Löschen; "Neuer Odot" sits in the toolbar tile like "Neu laden". */
.dot-actions {
    display: flex;
    gap: 8px;
    margin: 4px 0 12px;
}

.dot-actions button {
    flex: 1;
}

.dot-delete {
    background: none;
    border: 1px solid var(--danger-border);
    color: var(--danger);
}

.dot-alert {
    margin: 12px 0;
    padding: 12px;
    border-radius: 12px;
    background: var(--surface-card);
    border: 1px solid var(--danger-border);
}

.dot-alert .body {
    margin: 4px 0 10px;
}

.dot-alert button {
    width: 100%;
}

.dot-notify {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 12px;
    padding: 12px;
    border-radius: 12px;
    background: var(--surface-card);
    border: 1px solid var(--border);
    font-size: 15px;
    cursor: pointer;
}

.dot-notify input {
    width: 20px;
    height: 20px;
    accent-color: var(--accent);
}

.run {
    margin-bottom: 8px;
    border-radius: 12px;
    background: var(--surface-card);
    border: 1px solid var(--border);
    overflow: hidden;
}

.run-head {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    margin: 0;
    padding: 12px;
    background: none;
    border: none;
    border-radius: 0;
    color: var(--text);
    text-align: left;
    cursor: pointer;
    touch-action: manipulation;
}

.run-status {
    flex: 0 0 auto;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--text-muted);
}

.run-success .run-status {
    background: var(--color-green-500);
}

.run-error .run-status {
    background: var(--danger);
}

.run-running .run-status,
.run-queued .run-status {
    background: var(--accent);
}

.run-waiting .run-status {
    background: #f59e0b;
}

.run-waiting .run-label {
    color: #d97706;
}

.dot-waiting {
    padding: 2px 8px;
    background: rgba(245, 158, 11, 0.15);
    border: 1px solid rgba(245, 158, 11, 0.4);
    border-radius: 12px;
    color: #d97706;
    font-size: 11px;
    font-weight: 600;
}

.run-interactive {
    margin-top: 12px;
    padding: 12px;
    background: var(--surface, rgba(255, 255, 255, 0.05));
    border: 1px solid rgba(245, 158, 11, 0.3);
    border-radius: 8px;
}

.run-interactive-prompt {
    font-weight: 600;
    margin-bottom: 10px;
    color: var(--text, #fff);
}

.run-interactive-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 6px;
}

.run-choice-btn {
    flex: 0 0 auto;
    width: auto !important;
    margin-top: 0 !important;
    min-height: 38px;
    padding: 8px 18px;
    background: var(--accent, #3b82f6);
    color: #fff;
    border: none;
    border-radius: 6px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}

@media (hover: hover) {
    .run-choice-btn:hover {
        opacity: 0.9;
    }
}

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

.run-interactive-input-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    width: 100%;
}

.run-choice-input {
    flex: 1 1 auto;
    min-width: 0;
    width: 100%;
    height: 42px;
    box-sizing: border-box;
    padding: 8px 12px;
    background: var(--card, #1e293b);
    border: 1px solid var(--line, #334155);
    border-radius: 6px;
    color: var(--text, #fff);
    font-size: 14px;
}

.run-choice-input:focus {
    outline: none;
    border-color: var(--accent, #3b82f6);
}

.run-choice-submit {
    flex: 0 0 auto;
    width: auto !important;
    margin-top: 0 !important;
    height: 42px;
    min-height: 42px;
    padding: 0 20px;
    background: var(--accent, #3b82f6);
    color: #fff;
    border: none;
    border-radius: 6px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
}

@media (hover: hover) {
    .run-choice-submit:hover {
        opacity: 0.9;
    }
}

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

.run-label {
    font-weight: 600;
    font-size: 14px;
}

.run-source {
    flex: 1;
    min-width: 0;
    color: var(--text-muted);
    font-size: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.run-when {
    flex: 0 0 auto;
    color: var(--text-muted);
    font-size: 12px;
    white-space: nowrap;
}

.run-body {
    padding: 0 12px 12px 30px;
    border-top: 1px solid var(--border);
}

.run-body > * {
    margin: 10px 0 0;
    font-size: 14px;
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
}

.run-error {
    color: var(--danger);
}

/* Ergebnisse löschen: eine einzelne Zeile oder die ganze Liste. */
.run-delete,
.run-cancel-btn {
    display: block;
    margin-top: 10px;
    padding: 6px 12px;
    background: none;
    border: 1px solid var(--danger-border);
    border-radius: 8px;
    color: var(--danger);
    font-size: 14px;
    cursor: pointer;
}

.runs-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
}

.runs-clear {
    margin: 0;
    padding: 4px 0;
    background: none;
    border: none;
    color: var(--action);
    font-size: 14px;
    cursor: pointer;
}

/* REQ-MOB-11: Formular zum Einstellen des Odot-Auslösers */

.trigger-form {
    margin-top: 12px;
    padding: 14px;
    border-radius: 12px;
    background: var(--surface-card);
    border: 1px solid var(--border);
}

.trigger-panel {
    margin-top: 10px;
}

.trigger-field {
    display: block;
    margin-bottom: 10px;
    color: var(--text-muted);
    font-size: 13px;
}

.trigger-field input,
.trigger-field select,
.trigger-raw,
.trigger-time {
    width: 100%;
    margin-top: 4px;
    padding: 10px;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--surface-page);
    color: var(--text);
    font-size: 15px;
}

.trigger-time {
    max-width: 220px;
}

/* Ein Odot besteht aus zwei gleichwertigen Teilen: „Wenn" (Bedingung) und
   „Dann" (Skill). Beide sind antippbar, deshalb sehen sie wie Karten aus und
   nicht wie Schaltflaechen — ein Button-Framework wuerde hier die falsche
   Erwartung wecken. */
.dot-part {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
    padding: 14px;
    border-radius: 12px;
    background: var(--surface-card);
    border: 1px solid var(--border);
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    touch-action: manipulation;
}

.dot-part:active {
    background: var(--surface-card);
}

.dot-part-label {
    flex: 0 0 auto;
    color: var(--text-muted);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.dot-part-value {
    flex: 1;
    min-width: 0;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dot-part-hint {
    flex: 0 0 auto;
    color: var(--text-muted);
    font-size: 16px;
    line-height: 1;
}

.dot-part-hint .icon {
    width: 18px;
    height: 18px;
    fill: currentColor;
}

.trigger-raw {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.trigger-check {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 10px 0;
    font-size: 14px;
}

.trigger-check input {
    width: 20px;
    height: 20px;
    accent-color: var(--accent);
}

.trigger-days {
    display: flex;
    gap: 4px;
    margin: 8px 0 12px;
}

.trigger-day {
    flex: 1;
    min-width: 0;
    margin-top: 0;
    padding: 8px 0;
    font-size: 13px;
}

.trigger-day[aria-pressed="true"] {
    background: var(--accent);
    color: var(--text-inverse);

    border-color: var(--accent);
}

.trigger-form > button {
    width: 100%;
}

.trigger-caption {
    display: block;
    margin-bottom: 4px;
}

.trigger-preview {
    margin: 12px 0;
    padding: 10px 12px;
    border-radius: 10px;
    background: var(--surface-card);
    color: var(--text);
    font-size: 14px;
}

.chat-history-list {
    display: grid;
    gap: 8px;
}
