/* ==========================================================================
   KRT-Orbit  |  "Kartell look" design system
   --------------------------------------------------------------------------
   ONE source of truth for colours, font, type scale, spacing and components.
   Every dashboard page (and every future plugin page) must use ONLY the
   tokens and component classes defined here. Do not add hard-coded colours,
   font sizes or pixel spacings in page templates - extend this file instead.

   Rules of the look (since 13.10.2026: "Optik 2026", design guide rule 151 -
   the structure of the dashboard with the visual style of the approved
   mock-up "D Mischung")
   - Very dark base. Cards are one clear step lighter AND carry a hairline
     border (--card-border), so card and page never melt together.
   - Rounded corners: 6 / 8 / 12 px (--r-sm / --r-md / --r-lg), pills for
     chips, checks and status tags (--r-pill).
   - Orange is reserved for actions and active states. Buttons keep the
     brown "Kartell website" fill, now with a thin orange outline.
   - Notices (banners, status line) show their symbol inside a tinted circle.
   - One font (Lato, self-hosted, weights 400 and 700 only).
   - Readable small print: captions and help texts are at least 13px and use
     --text-muted, never --text-dim.
   ========================================================================== */


/* ---------- 1. Font (self-hosted, no external request) ---------- */
@font-face {
    font-family: "Lato";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("/assets/fonts/lato-400.woff") format("woff");
}
@font-face {
    font-family: "Lato";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("/assets/fonts/lato-700.woff") format("woff");
}


/* ---------- 2. Design tokens ---------- */
:root {
    /* Surfaces, darkest to lightest */
    --bg-nav:      #0e0f11;   /* top bar (separate panels next to the content) */
    /* Sidebar since 06.10.2026 (decision of the user): the blue grey of the space on the sign-in page, darkened, so the
       frame is less hard and links up with the sign-in page. Surfaces inside the sidebar (active entry, hover, search
       field) are light translucent layers on top of it instead of the grey --surface, which would look like a hole. */
    --sidebar-bg:      #16181d;   /* 13.10.2026 (rule 151): neutral dark grey, one step above the page */   /* NOTE: not "--bg-sidebar", that is an old alias further down */
    --sidebar-raise:   rgba(255, 255, 255, 0.06);   /* active / hovered entry, current search hit */
    --sidebar-field:   rgba(255, 255, 255, 0.04);   /* search field */
    --bg-page:     #111214;   /* page background */
    --surface:     #1d2025;   /* cards (one clear step lighter than the page; 13.10.2026, rule 151) */
    --surface-2:   #262a30;   /* hover state, tiles inside cards, popups, chips */
    --surface-3:   #2d3036;   /* pressed state, track of switches */
    --well:        rgba(0, 0, 0, 0.30);   /* inset areas INSIDE a card (inputs, role boxes, lists) */
    --line:        rgba(255, 255, 255, 0.07); /* divider lines */
    --card-border: rgba(255, 255, 255, 0.07); /* hairline around every card (rule 151) */
    --card-border-hover: rgba(231, 126, 35, 0.40); /* clickable card on hover */
    --field-border: rgba(255, 255, 255, 0.12); /* inputs and selects */

    /* Text */
    --text:        #eceef1;
    --text-muted:  #b4bac1;   /* descriptions, help texts (lighter since 13.10.2026, rule 151) */
    --text-dim:    #737980;   /* disabled entries, time stamps; never for running text */

    /* Accent: actions and active states only */
    --orange:       #e77e23;
    --orange-hover: #f19a4f;
    --orange-soft:  rgba(231, 126, 35, 0.14);
    --on-orange:    #17110a;   /* text/icons on an orange fill */
    /* Brand button (fill of the Kartell website buttons) with its outline and text colour (rule 151) */
    --brand-fill:    rgba(231, 126, 35, 0.22);
    --brand-outline: rgba(231, 126, 35, 0.55);
    --brand-text:    #ffb066;

    /* Semantic colours (status lights, banners, destructive actions). "OK" is GREEN again since 06.10.2026 (decision of the
       user: green is the colour everybody reads as "success / running", like a green LED). It is the former green #2ecc71
       in the same hue, only calmed down, so it sits next to the Kartell orange. Earlier trials the same night: ice blue
       #5ccfff, mint #4fd1a5, dusty blue #7fa6c8, warmer green #6cbe62. Change it ONLY here (--ok, --ok-soft). */
    --ok:      #4fc076;
    --ok-soft: rgba(79, 192, 118, 0.14);
    --warn:   #f1c40f;
    --warn-soft: rgba(241, 196, 15, 0.10);
    --danger: #ff5a5a;
    --danger-soft: rgba(255, 90, 90, 0.10);

    /* Type scale: exactly five sizes */
    --fs-tag: 0.5625rem; /* 9px  micro tags only (e.g. "SOON") - not for running text */
    --fs-xs: 0.8125rem;  /* 13px  captions, tags, small labels, help texts (12px until 13.10.2026) */
    --fs-sm: 0.875rem;   /* 14px  body text, descriptions */
    --fs-md: 1rem;       /* 16px  card titles, emphasis */
    --fs-menu: 0.9375rem;      /* 15px  sidebar entries ONLY (balanced against the large capital headings; 05.10.2026) */
    --fs-menu-cat: 0.78rem;    /* ~12.5px  sidebar category labels ONLY */
    --fs-lg: 1.25rem;    /* 20px  section headings */
    --fs-xl: 1.75rem;    /* 28px  page title */

    /* Spacing grid (multiples of 8, plus half steps) */
    --sp-1: 4px;
    --sp-2: 8px;
    --sp-3: 12px;
    --sp-4: 16px;
    --sp-5: 24px;   /* standard card padding */
    --sp-6: 32px;
    --sp-7: 48px;

    /* Corner radii (13.10.2026, design guide rule 151; square from 05.10. to 13.10.2026): small parts 6px, buttons,
       fields and menu entries 8px, cards, popups and notices 12px, chips and status tags fully round. Do NOT hard-code
       radii in new code - use these tokens. Avatars, status dots, flags and switches stay circles. */
    --r-sm: 6px;
    --r-md: 8px;
    --r-lg: 12px;
    --r-pill: 999px;

    --frame-gap: 3px;   /* thin break (page colour) between sidebar, top bar and content */
    --font-mono: "Cascadia Mono", Consolas, "DejaVu Sans Mono", "Liberation Mono", monospace;   /* ONLY for the log window */
    --nav-width: 288px;
    --topbar-height: 64px;

    /* Legacy names: older page templates still reference these. Do NOT use
       them in new code - use the tokens above. */
    --bg-darkest: var(--bg-nav);
    --bg-sidebar: var(--surface);
    --bg-main: var(--bg-page);
    --bg-hover: var(--surface-2);
    --bg-inset: var(--well);
    --kartell-orange: var(--orange);
    --kartell-orange-light: var(--orange-hover);
    --text-main: var(--text);
    --text-disabled: var(--text-dim);
    --border-color: var(--line);
}


/* ---------- 3. Base ---------- */
* { box-sizing: border-box; margin: 0; padding: 0; }

html { font-size: 16px; }

body {
    font-family: "Lato", "Segoe UI", system-ui, -apple-system, sans-serif;
    font-size: var(--fs-sm);
    line-height: 1.5;
    font-weight: 400;
    background-color: var(--bg-page);
    color: var(--text);
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh;   /* dynamic viewport: follows the collapsing address bar of mobile browsers */
    overflow: hidden;
    -webkit-font-smoothing: antialiased;
    -webkit-text-size-adjust: 100%;   /* iOS: no automatic text enlargement after rotating the device */
}

/* Native dropdown lists, scrollbars and form controls follow the dark theme */
:root { color-scheme: dark; }
option, optgroup { background-color: var(--surface-2); color: var(--text); }
optgroup { color: var(--text-muted); }

/* Checkboxes, radio buttons and range sliders in the Kartell orange instead of the blue of the browser (rule 151) */
:root { accent-color: var(--orange); }
input[type="checkbox"], input[type="radio"] { width: 16px; height: 16px; }

/* Form controls do not inherit the font by default */
button, input, select, textarea { font-family: inherit; font-size: inherit; color: inherit; }
strong, b { font-weight: 700; }
a { color: inherit; }

/* Quiet dark scrollbars */
* { scrollbar-width: thin; scrollbar-color: var(--surface-3) transparent; }


/* ---------- 4. Icons (self-hosted outline SVGs, coloured by text colour) ----------
   Usage: <i class="icon icon-gear"></i>   - size follows font-size (1.25em). */
.icon {
    display: inline-block;
    width: 1.25em;
    height: 1.25em;
    flex-shrink: 0;
    vertical-align: -0.25em;
    background-color: currentColor;
    -webkit-mask: var(--icon) center / contain no-repeat;
            mask: var(--icon) center / contain no-repeat;
}
.icon-chart-simple{--icon:url('/assets/icons/view-dashboard-outline.svg')}
.icon-heart-pulse{--icon:url('/assets/icons/heart-pulse.svg')}
.icon-sliders{--icon:url('/assets/icons/tune.svg')}
.icon-gear{--icon:url('/assets/icons/cog-outline.svg')}
.icon-chevron-down{--icon:url('/assets/icons/chevron-down.svg')}
.icon-angle-down{--icon:url('/assets/icons/chevron-down.svg')}
.icon-gavel{--icon:url('/assets/icons/gavel.svg')}
.icon-comments{--icon:url('/assets/icons/message-text-outline.svg')}
.icon-ticket{--icon:url('/assets/icons/ticket-outline.svg')}
.icon-volume-high{--icon:url('/assets/icons/volume-high.svg')}
/* 09.10.2026: icons of the announced plugins (Community, Server-Verwaltung, Integrationen), Material Design Icons. */
.icon-hand-wave{--icon:url('/assets/icons/hand-wave-outline.svg')}
.icon-tap-button{--icon:url('/assets/icons/gesture-tap-button.svg')}
.icon-poll{--icon:url('/assets/icons/poll.svg')}
.icon-slash-command{--icon:url('/assets/icons/slash-forward-box.svg')}
.icon-account-sync{--icon:url('/assets/icons/account-sync-outline.svg')}
.icon-paperclip{--icon:url('/assets/icons/paperclip.svg')}
.icon-file-lines{--icon:url('/assets/icons/file-document-outline.svg')}
.icon-file-code{--icon:url('/assets/icons/file-code-outline.svg')}
.icon-language{--icon:url('/assets/icons/translate.svg')}
.icon-circle-question{--icon:url('/assets/icons/help-circle-outline.svg')}
.icon-bell{--icon:url('/assets/icons/bell-outline.svg')}
.icon-right-from-bracket{--icon:url('/assets/icons/logout.svg')}
.icon-xmark{--icon:url('/assets/icons/close.svg')}
.icon-magnify{--icon:url('/assets/icons/magnify.svg')}   /* sidebar search (06.10.2026) */
.icon-power-off{--icon:url('/assets/icons/power.svg')}
/* Logos of the community's own pages, taken from das-kartell.org (files as published there), used on the sign-in page. */
.icon-discord{--icon:url('/assets/icons/discord_small.svg')}
.icon-teamspeak{--icon:url('/assets/icons/teamspeak_small.svg')}
.icon-clock-rotate-left{--icon:url('/assets/icons/history.svg')}
.icon-robot{--icon:url('/assets/icons/robot-outline.svg')}
.icon-server{--icon:url('/assets/icons/server.svg')}
.icon-users{--icon:url('/assets/icons/account-group-outline.svg')}
.icon-tower-broadcast{--icon:url('/assets/icons/broadcast.svg')}
.icon-bullhorn{--icon:url('/assets/icons/bullhorn.svg')}   /* 14.10.2026: Community > Ankündigungen (MDI bullhorn) */
.icon-clock{--icon:url('/assets/icons/clock-outline.svg')}
.icon-circle-info{--icon:url('/assets/icons/information-outline.svg')}
.icon-triangle-exclamation{--icon:url('/assets/icons/alert-circle-outline.svg')}   /* 12.10.2026 (owner): round warning sign instead of the triangle everywhere; class name kept so no template changes */
.icon-list-check{--icon:url('/assets/icons/format-list-checks.svg')}
.icon-arrow-left{--icon:url('/assets/icons/arrow-left.svg')}
.icon-arrow-right{--icon:url('/assets/icons/arrow-right.svg')}
/* Optical fix (04.10.2026): the arrow sits in the middle of its box, but text looks centred on the x-height, so the arrow appeared
   about 1.5px too low. Lifted slightly; used with a small gap (see .ov-status-link, .module-status-btn). */
.icon-arrow-right { transform: translateY(-0.1em); }
.icon-plus{--icon:url('/assets/icons/plus.svg')}
.icon-eye{--icon:url('/assets/icons/eye-outline.svg')}
/* Ticket plugin (08.10.2026): edit, single person, move up. */
.icon-pen{--icon:url('/assets/icons/pencil.svg')}
.icon-user{--icon:url('/assets/icons/account.svg')}
.icon-chevron-up{--icon:url('/assets/icons/chevron-up.svg')}
.icon-circle-check{--icon:url('/assets/icons/check-circle-outline.svg')}
.icon-lock{--icon:url('/assets/icons/lock-outline.svg')}
.icon-lock-open{--icon:url('/assets/icons/lock-open-variant-outline.svg')}
.icon-check{--icon:url('/assets/icons/check.svg')}
.icon-earth-europe{--icon:url('/assets/icons/earth.svg')}
.icon-rotate{--icon:url('/assets/icons/refresh.svg')}
.icon-play{--icon:url('/assets/icons/play-circle-outline.svg')}
.icon-stop{--icon:url('/assets/icons/stop-circle-outline.svg')}
.icon-restart{--icon:url('/assets/icons/restart.svg')}
.icon-puzzle{--icon:url('/assets/icons/puzzle-outline.svg')}
.icon-shield-lock{--icon:url('/assets/icons/shield-lock-outline.svg')}
.icon-console{--icon:url('/assets/icons/console.svg')}
.icon-pause{--icon:url('/assets/icons/pause.svg')}
.icon-system{--icon:url('/assets/icons/server-network-outline.svg')}
.icon-broom{--icon:url('/assets/icons/broom.svg')}
.icon-menu{--icon:url('/assets/icons/menu.svg')}
.icon-download{--icon:url('/assets/icons/download.svg')}
.icon-upload{--icon:url('/assets/icons/upload.svg')}
.icon-trash{--icon:url('/assets/icons/trash.svg')}
.icon-restore{--icon:url('/assets/icons/restore.svg')}
.icon-copy{--icon:url('/assets/icons/copy.svg')}
.icon-circle-exclamation{--icon:url('/assets/icons/alert-circle-outline.svg')}
.icon-star{--icon:url('/assets/icons/star.svg')}
.icon-star-outline{--icon:url('/assets/icons/star-outline.svg')}
.icon-image{--icon:url('/assets/icons/image-outline.svg')}
.icon-video{--icon:url('/assets/icons/video-outline.svg')}
.icon-music{--icon:url('/assets/icons/music-note.svg')}
.icon-file{--icon:url('/assets/icons/file-outline.svg')}
.icon-folder{--icon:url('/assets/icons/folder-outline.svg')}   /* plugin "Akten" (06.10.2026) */
/* Devices of the page Einstellungen > Sitzungen (08.10.2026). */
.icon-device-phone{--icon:url('/assets/icons/cellphone.svg')}
.icon-device-tablet{--icon:url('/assets/icons/tablet.svg')}
.icon-device-desktop{--icon:url('/assets/icons/monitor.svg')}
.status-dot.placeholder { visibility: hidden; }   /* menu entry without switch next to entries with a dot (Akten) */


/* ---------- 5. App shell: sidebar, top bar, content ---------- */
.nav-sidebar {
    background-color: var(--sidebar-bg);
    width: var(--nav-width);
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    padding-bottom: var(--sp-5);
    scrollbar-width: none;
}
.nav-sidebar::-webkit-scrollbar { display: none; }

/* Shell: top bar (full width) on top, below it sidebar + content */
.app-body { flex: 1; display: flex; gap: var(--frame-gap); min-height: 0; }

.brand-text {
    font-size: var(--fs-sm);
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--text);
    white-space: nowrap;
}
/* Mascot head (KRT-Orbit robot, 06.10.2026) in front of the wordmark, on every page with the top bar (base.html and the
   sign-in page). Decorative only (empty alt). The image carries its own light rim so the dark helmet stays visible on the
   dark top bar. Design guide rule 50. */
/* ---------- Mascot poses (06.10.2026, design guide rule 50, macro templates/_mascot.html) ----------
   The dark robot gets the same thin light rim as on the sign-in page, so it stays visible on dark cards. */
.mascot { display: block; height: auto; margin: 0 auto; filter: drop-shadow(0 0 1px rgba(255, 255, 255, 0.35)) drop-shadow(0 6px 16px rgba(0, 0, 0, 0.45)); }
.mascot-sm { width: 72px; }
.mascot-md { width: 120px; }
.mascot-lg { width: 180px; }
.mascot-state { max-width: 560px; margin: var(--sp-6) auto; padding: var(--sp-6) var(--sp-5); text-align: center; }
.mascot-state .mascot { margin-bottom: var(--sp-5); }
.mascot-state-title { font-size: var(--fs-lg); font-weight: 400; letter-spacing: 0.04em; text-transform: uppercase; line-height: 1.3; margin-bottom: var(--sp-3); }
.mascot-state-text { font-size: var(--fs-sm); color: var(--text-muted); margin-bottom: var(--sp-3); }
.mascot-state-actions { margin-top: var(--sp-4); display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); }
.att-empty .mascot { margin-bottom: var(--sp-3); }
@media (max-width: 599px) { .mascot-lg { width: 140px; } .mascot-state { margin: var(--sp-4) auto; padding: var(--sp-5) var(--sp-3); } }
/* Error pages (templates/error.html): same frame as the sign-in page, plain page colour, card centred. */
.error-page { min-height: 100vh; display: flex; flex-direction: column; background-color: var(--bg-page); }
.error-stage { flex: 1; display: flex; align-items: center; justify-content: center; padding: var(--sp-5) var(--sp-4); }
.error-code { font-size: var(--fs-xs); color: var(--text-dim); letter-spacing: 0.06em; }
/* Bot tile of the start page: the sleeping robot sits in the lower right corner while the bot is stopped or offline. */
/* Sidebar search without results: a small robot with the magnifying glass above the text. */
.nav-search-empty .mascot { width: 64px; margin: 0 0 var(--sp-3); }

.brand-mascot-wrap { position: relative; display: inline-block; vertical-align: middle; margin: -4px var(--sp-2) 0 0; }
.brand-mascot { display: block; width: 34px; height: 34px; }
/* Sleeping (script in base.html): after a few idle minutes the head shows closed eyes and three small "z" letters rise
   from its top right corner, one after the other, and fade out. */
.brand-zzz { position: absolute; left: 28px; top: -8px; width: 26px; height: 30px; pointer-events: none; display: none; }
.brand-mascot-wrap.is-sleeping .brand-zzz { display: block; }
.brand-zzz span {
    position: absolute;
    left: 0;
    bottom: 0;
    color: var(--orange);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0;
    text-shadow: 0 0 6px rgba(231, 126, 35, 0.6);
    line-height: 1;
    opacity: 0;
    animation: mascot-zzz 3s ease-out infinite;
}
.brand-zzz span:nth-child(2) { animation-delay: 1s; font-size: 13px; }
.brand-zzz span:nth-child(3) { animation-delay: 2s; font-size: 16px; }
@keyframes mascot-zzz {
    0%   { transform: translate(0, 0); opacity: 0; }
    15%  { opacity: 1; }
    100% { transform: translate(14px, -22px); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .brand-zzz span { animation: none; opacity: 1; }
    .brand-zzz span:nth-child(2) { transform: translate(6px, -9px); }
    .brand-zzz span:nth-child(3) { transform: translate(12px, -19px); }
}
/* Brand exception to the 'orange only for actions' rule: the org name part of the wordmark is orange. */
.brand-text span { color: var(--orange); font-weight: 400; }
/* The wordmark is a link to the start page (08.10.2026): looks unchanged, no underline; on hover or keyboard focus it
   brightens slightly, like the logo of a website. */
.brand-link { text-decoration: none; display: inline-block; transition: opacity 0.15s ease; }
.brand-link:hover { opacity: 0.8; }
.brand-link:focus-visible { outline: 1px solid var(--orange); outline-offset: 4px; }

/* ---------- Sidebar search (06.10.2026, design guide rule 51) ----------
   Replaces the Kartell logo at the top of the sidebar. Generous space above and below so the field does not look
   squeezed against the top bar or the first menu category. Field on --surface (like a menu entry on hover), magnifier
   left, the shortcut hint right; orange ring on focus (same as all inputs). Results replace the menu while a query is
   typed and reuse the look of the menu entries. */
.nav-search { padding: var(--sp-5) var(--sp-3) var(--sp-2); flex-shrink: 0; }
.nav-search-field {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    height: 40px;
    padding: 0 var(--sp-3);
    background-color: var(--sidebar-field);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
}
.nav-search-field:hover { background-color: var(--sidebar-raise); }
.nav-search-field:focus-within { border-color: var(--orange); box-shadow: 0 0 0 3px var(--orange-soft); background-color: var(--sidebar-field); }
.nav-search-field > .icon { width: 18px; height: 18px; color: var(--text-dim); }
.nav-search-field:focus-within > .icon { color: var(--orange); }
.nav-search-field input {
    flex: 1;
    min-width: 0;
    height: 100%;
    padding: 0;
    border: 0;
    outline: 0;
    background: transparent;
    color: var(--text);
    font: inherit;
    font-size: var(--fs-sm);
}
.nav-search-field input::placeholder { color: var(--text-dim); }
.nav-search-key {                 /* shortcut hint: plain dim text, no box (feedback of the user 06.10.2026) */
    flex-shrink: 0;
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-dim);
    font: inherit;
    font-size: var(--fs-xs);
    font-weight: 400;
    letter-spacing: 0.02em;
    white-space: nowrap;
}
.nav-search-field:focus-within .nav-search-key { display: none; }
/* No hardware keyboard shortcut hint on compact (touch) screens. */
@media (max-width: 1023px) { .nav-search-key { display: none; } }
.nav-search-clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    margin-right: -4px;
    padding: 0;
    border: 0;
    border-radius: var(--r-sm);
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
}
.nav-search-clear:hover { background-color: var(--surface-3); color: var(--text); }
.nav-search-clear .icon { width: 16px; height: 16px; }
.nav-search-clear[hidden], .nav-search-results[hidden], .nav-menu[hidden] { display: none; }

.nav-search-results { padding: var(--sp-2) 0 var(--sp-3); }
.nav-search-group {
    padding: var(--sp-3) var(--sp-5) var(--sp-2);
    font-size: var(--fs-menu-cat);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-dim);
    font-weight: 700;
}
.menu-item.nav-search-hit { align-items: center; justify-content: flex-start; gap: 10px; }
.menu-item.nav-search-hit .nav-search-text { display: flex; flex-direction: column; min-width: 0; }
.nav-search-hit .nav-search-label { color: inherit; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nav-search-hit .nav-search-path { font-size: var(--fs-xs); color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nav-search-hit mark { background: none; color: var(--orange); }
.nav-search-hit.is-current { background-color: var(--sidebar-raise); color: var(--text); }
.nav-search-hit.is-current .icon { color: var(--orange); }
.nav-search-empty { padding: var(--sp-4) var(--sp-5); font-size: var(--fs-sm); color: var(--text-muted); }
/* Stage 2 (08.10.2026): short line while members and incidents are being looked up on the server. */
.nav-search-loading { padding: var(--sp-3) var(--sp-5); font-size: var(--fs-xs); color: var(--text-dim); }
.nav-search-empty span { display: block; margin-top: var(--sp-1); font-size: var(--fs-xs); color: var(--text-dim); }

/* Menu section headings */
.menu-category {
    padding: var(--sp-5) var(--sp-5) var(--sp-2);
    font-size: var(--fs-menu-cat);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-dim);
    font-weight: 700;
}
.menu-category.collapsible {
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;
    user-select: none;
}
.menu-category.collapsible:hover { color: var(--text-muted); }
.menu-category-caret { transition: transform 0.15s ease; }
.menu-section.collapsed .menu-category-caret { transform: rotate(-90deg); }
.menu-section.collapsed .menu-section-items { display: none; }

/* Menu items */
.menu-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin: 2px var(--sp-3);
    padding: 9px var(--sp-3);
    border-radius: var(--r-md);
    color: var(--text-muted);
    text-decoration: none;
    font-size: var(--fs-menu);
    transition: background-color 0.15s ease, color 0.15s ease;
    cursor: pointer;
}
.menu-item-inner {
    display: flex;
    align-items: center;
    gap: 10px;
    white-space: nowrap;
}
.menu-item .icon { width: 22px; height: 22px; color: var(--text-dim); transition: color 0.15s ease; }
.menu-item:hover:not(.disabled) { background-color: var(--sidebar-raise); color: var(--text); }
.menu-item:hover:not(.disabled) .icon { color: var(--text-muted); }

/* Active page: orange tint + white text + orange icon, no side border (rule 151) */
.menu-item.active { background-color: var(--orange-soft); color: var(--text); }
.menu-item.active .icon { color: var(--orange); }

/* Not built yet: dimmed; the small framed "Soon" tag marks it */
.menu-item.disabled { color: var(--text-dim); cursor: default; }
.menu-item.disabled .icon { color: var(--text-dim); opacity: 0.7; }
/* Health dot next to a menu entry (the "System" entry): yellow = warning, red = error; hidden while all is well. */
.menu-health-dot {
    width: 8px;
    height: 8px;
    margin-left: var(--sp-2);
    border-radius: 50%;
    flex-shrink: 0;
    background-color: var(--warn);
}
.menu-health-dot.danger { background-color: var(--danger); box-shadow: 0 0 8px var(--danger); }
.menu-health-dot[hidden] { display: none; }
.coming-soon-tag {
    font-size: var(--fs-tag);
    line-height: 1.5;
    color: var(--text-dim);
    padding: 0 6px;
    border: 1px solid var(--surface-3);
    border-radius: var(--r-sm);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    white-space: nowrap;
    flex-shrink: 0;
    margin-left: var(--sp-2);
}
.menu-item.module-inactive { color: var(--text-dim); }
/* Locked entry (09.10.2026, design guide rule 93): the person sees the entry but may not open it (moderators: System,
   Einstellungen, Mitglieder, ...). base.html adds the class and the small lock on the right; a click opens the popup
   "Kein Zugriff". Dimmed like a "Soon" entry, but still clickable so the popup can explain why. */
.menu-item.menu-locked { color: var(--text-dim); }
.menu-item.menu-locked .menu-item-inner .icon { color: var(--text-dim); }
.menu-item .menu-lock { width: 16px; height: 16px; margin-left: var(--sp-2); flex-shrink: 0; color: var(--text-dim); }
/* 13.10.2026 (design guide rule 142): hidden closed entries and the note at the end of the menu. */
.menu-item.menu-hidden, .menu-section[hidden], .module-card[hidden], .module-section[hidden], .module-tab[hidden] { display: none !important; }
.menu-closed-note { margin: var(--sp-4) var(--sp-3) var(--sp-2); padding-top: var(--sp-3); border-top: 1px solid rgba(255, 255, 255, 0.06); font-size: var(--fs-xs); line-height: 1.45; color: var(--text-dim); }
/* Start page (09.10.2026): "Öffnen" of a tile the person may not open - lock instead of the arrow, dimmed like the menu. */
.module-status-btn.module-btn-locked { color: var(--text-dim); }
/* Locked controls inside the pages (09.10.2026, design guide rule 99, macros in templates/_locked.html): buttons, tabs and
   small links that the person may not use stay visible in grey with a lock in front; a click opens "Kein Zugriff".
   No orange hover and no glow - they are not actions for this person. */
.btn.btn-locked, .btn.btn-locked:hover, .btn.btn-locked:focus-visible { background-color: rgba(255, 255, 255, 0.04); color: var(--text-dim); box-shadow: none; animation: none; cursor: not-allowed; }
.btn.btn-locked .icon, .module-tab.tab-locked .icon, .subtab.subtab-locked .icon, .link-locked .icon { width: 13px; height: 13px; }
.module-tab.tab-locked, .module-tab.tab-locked:hover, .subtab.subtab-locked, .subtab.subtab-locked:hover { color: var(--text-dim); cursor: not-allowed; }
.module-tab.tab-locked, .subtab.subtab-locked { display: inline-flex; align-items: center; gap: 6px; }
.link-locked, .link-locked:hover { color: var(--text-dim) !important; cursor: not-allowed; text-decoration: none !important; background: none; border: 0; padding: 0; font: inherit; display: inline-flex; align-items: center; gap: 4px; }
.btn-push-right { margin-left: auto; }

/* Status dot in front of every switchable plugin: grey = inactive, orange = active.
   The 'Allgemein' items (Dashboard, Bot-Status, ...) have no dot on purpose. */
.status-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.status-dot.on { background-color: var(--orange); box-shadow: 0 0 6px rgba(231, 126, 35, 0.7); }   /* small lamp: glows while on (rule 151) */
.status-dot.off { background-color: #4a4f57; }

/* The content window (page colour). Sidebar, top bar and content are three independent panels separated by a thin break. */
.main-wrapper { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; background-color: var(--bg-page); }

.top-bar {
    height: var(--topbar-height);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 var(--sp-6) 0 var(--sp-5);
    background-color: var(--bg-nav);
    margin-bottom: var(--frame-gap);
    flex-shrink: 0;
}
.top-bar-left { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
/* Menu button and backdrop belong to the compact layout (section 18); on desktop they do not exist. */
.nav-toggle { display: none; }
.nav-backdrop { display: none; }
.right-control-box { display: flex; align-items: center; gap: var(--sp-4); margin-left: auto; }

.notification-bell {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    border-radius: var(--r-md);
    background: transparent;
    color: var(--text-muted);
    font-size: var(--fs-md);
    font-family: inherit;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.notification-bell:hover, .notification-bell[aria-expanded="true"] { background-color: var(--surface); color: var(--text); }

/* User menu */
.dropdown-wrapper { position: relative; display: inline-block; }
.user-profile {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-1);
    border-radius: var(--r-md);
    color: var(--text-muted);
    cursor: pointer;
    transition: background-color 0.15s ease;
}
.user-profile:hover { background-color: var(--surface); }
.user-profile .icon { transition: transform 0.15s ease; }
.dropdown-wrapper.open .user-profile .icon { transform: rotate(180deg); }

.user-avatar,
.dropdown-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background-color: var(--surface-2);
    background-size: cover;
    background-position: center;
    flex-shrink: 0;
    /* mask clip avoids a thin uneven sliver at the edge of circular background images */
    -webkit-mask-image: -webkit-radial-gradient(circle, #fff 100%, #000 100%);
            mask-image: radial-gradient(circle, #fff 100%, #000 100%);
}
.dropdown-avatar { width: 40px; height: 40px; }

.dropdown-content {
    display: none;
    position: absolute;
    right: 0;
    top: 48px;
    min-width: 232px;
    padding: var(--sp-2);
    background-color: var(--surface-2);
    border: 1px solid var(--card-border);
    border-radius: var(--r-lg);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
    z-index: 1000;
}
.dropdown-wrapper.open .dropdown-content { display: block; }
.dropdown-header {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-3);
    margin-bottom: var(--sp-1);
}
.dropdown-header-label { font-size: var(--fs-xs); color: var(--text-muted); }
.dropdown-header-name { font-size: var(--fs-md); font-weight: 700; color: var(--text); }
.dropdown-item {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    white-space: nowrap;   /* 13.10.2026: "Persönliche Einstellungen" stays on one line; the menu grows instead */
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--r-md);
    color: var(--text-muted);
    text-decoration: none;
    font-size: var(--fs-sm);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.dropdown-item:hover { background-color: var(--surface-3); color: var(--text); }
.dropdown-item.logout-btn:hover { color: var(--danger); }
.dropdown-item.is-disabled { color: var(--text-dim); cursor: default; }
.dropdown-item.is-disabled:hover { background-color: transparent; color: var(--text-dim); }
.dropdown-item .coming-soon-tag { margin-left: auto; }

.content-area {
    flex: 1;
    padding: var(--sp-6) var(--sp-6) var(--sp-7);
    overflow-y: auto;
    position: relative;
}
/* Content column: uses the full available width (long descriptions wrap on their own via
   max-width on the text). The high cap only matters on ultra-wide monitors. */
.page { max-width: 1680px; margin: 0; }


/* ---------- 6. Page header ---------- */
.feature-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--sp-5);
}
/* Page title: capitals in normal weight, like the headings of the Kartell website. */
.feature-header-text h1 { font-size: var(--fs-xl); font-weight: 400; letter-spacing: 0.03em; text-transform: uppercase; color: var(--text); line-height: 1.2; }
.feature-header-text p { font-size: var(--fs-sm); color: var(--text-muted); margin-top: var(--sp-1); max-width: 980px; line-height: 1.55; }

.back-link {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    color: var(--text-muted);
    font-size: var(--fs-sm);
    text-decoration: none;
    margin-bottom: var(--sp-4);
    transition: color 0.15s ease;
}
.back-link:hover { color: var(--text); }


/* ---------- 7. Cards ("feature-box") ----------
   The one container for page content. Card = surface colour, no border.
   Header (title + description + optional switch/link), body below.        */
.feature-box {
    width: 100%;
    background-color: var(--surface);
    border: 1px solid var(--card-border);
    border-radius: var(--r-lg);
    margin-bottom: var(--sp-4);
    overflow: hidden;   /* NOTE: clips absolutely positioned popups - use position:fixed for those */
}
.feature-box.disabled { opacity: 0.6; }

.feature-box-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-5);
}
.feature-box-header-text { flex: 1; min-width: 0; }   /* takes the free space so a switch / caret after it sits at the right edge */
.feature-box-header-text h3 { font-size: var(--fs-md); font-weight: 700; color: var(--text); }
.feature-box-header-text p {
    font-size: var(--fs-sm);
    color: var(--text-muted);
    margin-top: var(--sp-1);
    max-width: 760px;     /* long descriptions wrap instead of running across the screen */
}
.feature-box-body { padding: 0 var(--sp-5) var(--sp-5); }
/* Short summary in the header of a collapsible card (e.g. "2 von 3 aktiv"); only shown while the card is collapsed
   so the card still tells the most important fact without being opened. Goes between header text and caret. */
.feature-box-summary { display: none; flex-shrink: 1; min-width: 0; max-width: 45%; font-size: var(--fs-sm); color: var(--text-muted); text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.feature-box.collapsible.collapsed .feature-box-summary { display: block; }

/* Collapsible card */
.feature-box.collapsible .feature-box-header { cursor: pointer; }
.feature-box-collapse-caret { color: var(--text-dim); transition: transform 0.15s ease; flex-shrink: 0; }
.feature-box.collapsible:hover .feature-box-collapse-caret { color: var(--text-muted); }
.feature-box.collapsible.collapsed .feature-box-collapse-caret { transform: rotate(-90deg); }
.feature-box.collapsible.collapsed .feature-box-body { display: none; }

/* Action link in a card header (leads to a detail page) */
.feature-box-header-link {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    color: var(--orange);
    font-size: var(--fs-sm);
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
    flex-shrink: 0;
    transition: color 0.15s ease;
}
.feature-box-header-link:hover { color: var(--orange-hover); }


/* ---------- 8. Switch (on/off) ---------- */
.toggle-switch { display: inline-flex; align-items: center; gap: var(--sp-3); flex-shrink: 0; }
.toggle-switch-label { font-size: var(--fs-xs); font-weight: 700; color: var(--text-muted); }
.toggle-track {
    position: relative;
    width: 40px;
    height: 24px;
    border-radius: 12px;
    background-color: var(--surface-3);
    cursor: pointer;
    transition: background-color 0.2s ease;
    flex-shrink: 0;
}
.toggle-track.on { background-color: var(--orange); }
.toggle-track.locked { cursor: default; }
.toggle-knob {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background-color: #fff;
    transition: left 0.2s ease;
}
.toggle-track.on .toggle-knob { left: 19px; }


/* ---------- 9. Buttons ---------- */
/* One button shape for the whole dashboard: rounded (--r-md), capitals, the brown fill of the Kartell website with a thin
   outline, and on hover a solid fill with a short glow (same behaviour as the brand button of the sign-in page). The
   colour variants only set the custom properties below: orange (primary, default), grey (.btn-secondary, .btn-cancel)
   and red (.btn-deactivate). --btn-glow-k scales the glow. Outline and lighter text since 13.10.2026 (rule 151), so the
   main action no longer looks disabled. */
.btn, .button, .module-status-btn {
    --btn-bg: var(--brand-fill);
    --btn-fg: var(--brand-text);
    --btn-border: var(--brand-outline);
    --btn-bg-hover: var(--orange);
    --btn-fg-hover: #fff;
    --btn-glow: 231, 126, 35;
    --btn-glow-k: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    min-height: 36px;
    /* Optical centring (13.10.2026, design guide rule 154): labels are upper case, and Lato reserves room for descenders
       below the baseline, so a mathematically centred label sat about 1.5 px too high (measured). The content box is
       moved down by 0.115em (1.5 px at 13 px) and the icons are lifted by twice that, so label and icon both sit in the
       optical middle. em-based, so larger buttons (.btn-brand-lg) scale along. */
    padding: calc(6px + 0.115em) var(--sp-4) calc(6px - 0.115em);
    border: 1px solid var(--btn-border);
    border-radius: var(--r-md);
    background-color: var(--btn-bg);
    color: var(--btn-fg);
    font-family: inherit;
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}
.btn:hover:not(:disabled), .btn:focus-visible:not(:disabled), .button:hover, .button:focus-visible,
.module-status-btn:hover, .module-status-btn:focus-visible {
    border-color: var(--btn-bg-hover);
    background-color: var(--btn-bg-hover);
    color: var(--btn-fg-hover);
    box-shadow: 0 0 12px rgba(var(--btn-glow), calc(0.5 * var(--btn-glow-k)));
    animation: btn-surge 0.6s ease-out;
}
@keyframes btn-surge {
    0%   { box-shadow: 0 0 0 0 rgba(var(--btn-glow), 0); }
    30%  { box-shadow: 0 0 20px 2px rgba(var(--btn-glow), calc(0.6 * var(--btn-glow-k))); }
    100% { box-shadow: 0 0 12px 0 rgba(var(--btn-glow), calc(0.5 * var(--btn-glow-k))); }
}
@media (prefers-reduced-motion: reduce) {
    .btn:hover, .btn:focus-visible, .button:hover, .module-status-btn:hover { animation: none; }
}
.btn > .icon, .button > .icon, .module-status-btn > .icon { margin-top: -0.23em; }   /* rule 154, see the padding above */
/* Primary action = orange (the default above); .btn-activate / .btn-primary / .button need no extra rules. */
/* Secondary = grey */
.btn-secondary, .btn-cancel {
    --btn-bg: var(--surface-2);
    --btn-fg: #dfe2e6;
    --btn-border: rgba(255, 255, 255, 0.10);
    --btn-bg-hover: rgba(255, 255, 255, 0.18);
    --btn-fg-hover: #fff;
    --btn-glow: 200, 205, 215;
    --btn-glow-k: 0.45;
}
/* Cancel: same grey, but only an outline until hovered */
.btn-cancel { --btn-bg: transparent; --btn-border: rgba(255, 255, 255, 0.16); }
/* Secondary button for a destructive action (delete a single item): grey until hovered, then red */
.btn-danger-hover {
    --btn-bg-hover: rgba(255, 90, 90, 0.22);
    --btn-fg-hover: var(--danger);
    --btn-glow: 255, 90, 90;
    --btn-glow-k: 0.7;
}

/* Brand button (style of the Kartell website): dark orange-tinted fill, orange capitals, square corners; on hover the
   fill turns solid orange and the button glows. Used on the sign-in page; the dashboard buttons (.btn) share the same look. */
.btn-brand {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: calc(var(--sp-3) + 0.115em) var(--sp-5) calc(var(--sp-3) - 0.115em);   /* optical centring, rule 154 */
    border: 1px solid var(--brand-outline);
    border-radius: var(--r-md);
    background-color: var(--brand-fill);
    color: var(--brand-text);
    font-size: var(--fs-sm);
    font-weight: 400;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.25s ease, color 0.25s ease;
}
.btn-brand:hover, .btn-brand:focus-visible {
    background-color: var(--orange);
    color: #fff;
    box-shadow: 0 0 12px rgba(231, 126, 35, 0.5);
    animation: btn-brand-surge 0.6s ease-out;
}
/* "Too much energy": at the moment of the hover the glow shoots out beyond the edges for a short time, then settles. */
@keyframes btn-brand-surge {
    0%   { box-shadow: 0 0 0 0 rgba(231, 126, 35, 0); }
    30%  { box-shadow: 0 0 20px 2px rgba(240, 150, 70, 0.6); }
    100% { box-shadow: 0 0 12px 0 rgba(231, 126, 35, 0.5); }
}
@media (prefers-reduced-motion: reduce) {
    .btn-brand:hover, .btn-brand:focus-visible { animation: none; }
}
.btn-brand-lg { padding: calc(var(--sp-4) + 0.05em) var(--sp-6) calc(var(--sp-4) - 0.05em); font-size: var(--fs-md); }   /* optical centring, rule 154 */
/* Destructive = red */
.btn-deactivate {
    --btn-bg: rgba(255, 90, 90, 0.16);
    --btn-fg: #ff8a8a;
    --btn-border: rgba(255, 90, 90, 0.50);
    --btn-bg-hover: var(--danger);
    --btn-fg-hover: #fff;
    --btn-glow: 255, 90, 90;
}
.btn:disabled, .btn[disabled], .btn-primary:disabled { opacity: 0.45; cursor: not-allowed; }


/* ---------- 10. Form elements and inset areas ---------- */
.field-label { display: block; font-size: var(--fs-xs); font-weight: 700; color: var(--text-muted); margin-bottom: var(--sp-2); }
.hint { display: flex; align-items: flex-start; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--text-muted); line-height: 1.55; max-width: 980px; }
.hint .icon { margin-top: 1px; }
.feature-header-text .hint { margin-top: var(--sp-2); max-width: 72ch; }

/* Permission status line in a page header (e.g. System): shows at a glance whether the signed-in person may run
   actions. Blue (OK colour) = granted, red = not granted. */
.access-status { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); font-size: var(--fs-sm); color: var(--text-muted); }
.access-status strong { font-weight: 700; }
.access-status.granted .icon, .access-status.granted strong { color: var(--ok); }
.access-status.denied .icon, .access-status.denied strong { color: var(--danger); }

/* Small note line at the bottom of a card body (info icon + text), kept apart from the content above it. */
.feature-box-footnote { display: flex; align-items: flex-start; gap: var(--sp-2); margin-top: var(--sp-3); font-size: var(--fs-xs); color: var(--text-muted); line-height: 1.5; }
.feature-box-footnote .icon { margin-top: 1px; }
/* Plain small muted paragraph (no icon layout) */
.note { font-size: var(--fs-xs); color: var(--text-muted); line-height: 1.55; }
/* Help text directly below a form, an input or a button row gets air (13.10.2026, rule 151 addendum: "Buchstaben ohne
   Umlaute ..." under "Neue Gruppe" in Staffeln > Rollen & Gruppen sat glued to the field). */
form + .note, form + .hint, .input + .note, .select + .note, .textarea + .note, .input + .hint, .select + .hint { margin-top: var(--sp-3); }

.input, .select, .textarea {
    width: 100%;
    padding: 10px var(--sp-3);
    background-color: var(--well);
    border: 1px solid var(--field-border);
    border-radius: var(--r-md);
    color: var(--text);
    font-size: var(--fs-sm);
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.input:focus, .select:focus, .textarea:focus { border-color: var(--orange); box-shadow: 0 0 0 3px var(--orange-soft); }

/* Inset area inside a card (role boxes, previews) */
.well { background-color: var(--well); border-radius: var(--r-md); padding: var(--sp-4); }

/* Chip (roles, tags): a pill (rule 151) */
.chip {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-1) var(--sp-3);
    border-radius: var(--r-pill);
    background-color: var(--surface-2);
    color: var(--text);
    font-size: var(--fs-xs);
}

/* Status banner (success / error / warning message above a page or inside a card). Since 13.10.2026 (rule 151): a tinted
   box with a thin border in the level colour; the FIRST icon of the banner sits in a tinted circle (drawn with ::before,
   because an icon is a mask and cannot carry its own background). --banner-tint / --banner-line / --banner-icon per level. */
.banner {
    --banner-tint: var(--surface);
    --banner-line: var(--card-border);
    --banner-icon: var(--text-muted);
    --banner-circle: rgba(255, 255, 255, 0.07);
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    margin-bottom: var(--sp-4);
    border: 1px solid var(--banner-line);
    border-radius: var(--r-lg);
    background-color: var(--banner-tint);
    font-size: var(--fs-sm);
    line-height: 1.55;
}
.banner > .icon { color: var(--banner-icon); }
.banner:has(> .icon:first-child) { padding-left: 56px; min-height: 52px; }
.banner:has(> .icon:first-child)::before { content: ""; position: absolute; left: var(--sp-4); top: 50%; width: 28px; height: 28px; margin-top: -14px; border-radius: 50%; background-color: var(--banner-circle); }
.banner > .icon:first-child { position: absolute; left: calc(var(--sp-4) + 6px); top: 50%; width: 16px; height: 16px; margin-top: -8px; }
.banner.ok    { --banner-tint: rgba(79, 192, 118, 0.08); --banner-line: rgba(79, 192, 118, 0.28); --banner-icon: var(--ok);     --banner-circle: rgba(79, 192, 118, 0.16); }
.banner.error { --banner-tint: var(--danger-soft);       --banner-line: rgba(255, 90, 90, 0.28);  --banner-icon: #ff7a7a;       --banner-circle: rgba(255, 90, 90, 0.16); }
.banner.warn  { --banner-tint: var(--warn-soft);         --banner-line: rgba(241, 196, 15, 0.26); --banner-icon: var(--warn);   --banner-circle: rgba(241, 196, 15, 0.16); }
/* Banner on a card (permanent warnings): darker well background so it reads as its own row, tighter stacking. */
.banner.in-card { margin-bottom: var(--sp-3); }
.banner.in-card:not(.ok):not(.error):not(.warn) { --banner-tint: var(--well); }


/* ---------- 11. Plugin overview (dashboard) ---------- */
.module-tabs {
    display: flex;
    gap: var(--sp-5);
    margin-bottom: var(--sp-6);
    border-bottom: 1px solid var(--line);   /* baseline under the tabs (rule 151) */
    overflow-x: auto;
    scrollbar-width: none;
}
.module-tabs::-webkit-scrollbar { display: none; }
/* Fade at the edge(s) where more tabs are hidden (set by the script in base.html, only when the row overflows). */
.module-tabs {
    --tabs-fade-start: 0px;
    --tabs-fade-end: 0px;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--tabs-fade-start), #000 calc(100% - var(--tabs-fade-end)), transparent);
    mask-image: linear-gradient(to right, transparent, #000 var(--tabs-fade-start), #000 calc(100% - var(--tabs-fade-end)), transparent);
}
.module-tabs.fade-start { --tabs-fade-start: 32px; }
.module-tabs.fade-end { --tabs-fade-end: 32px; }
.module-tab {
    padding: var(--sp-2) 0;
    font-size: var(--fs-sm);
    font-weight: 700;
    color: var(--text-muted);
    cursor: pointer;
    white-space: nowrap;
    border-bottom: 2px solid transparent;
    transition: color 0.15s ease;
}
.module-tab:hover { color: var(--text); }
.module-tab.active { color: var(--text); border-bottom-color: var(--orange); }

.module-section { margin-bottom: var(--sp-6); }
.module-section-title { font-size: var(--fs-lg); font-weight: 400; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text); margin-bottom: var(--sp-4); }
.module-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--sp-4); }
.module-card {
    background-color: var(--surface);
    border: 1px solid var(--card-border);
    border-radius: var(--r-lg);
    padding: var(--sp-5);
    transition: border-color 0.15s ease;
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}
.module-card:hover { border-color: var(--card-border-hover); }
.module-card-icon {
    width: 40px;
    height: 40px;
    border-radius: 10px;
    background-color: var(--surface-2);
    color: var(--orange);   /* orange symbol in the grey field (rule 151); grey while the plugin is off, see below */
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-md);
    flex-shrink: 0;
}
.module-card-title { font-size: var(--fs-md); font-weight: 700; color: var(--text); }
.module-card-desc { font-size: var(--fs-sm); color: var(--text-muted); flex: 1; }
.module-status-btn {
    align-self: flex-start;   /* same brown button as every primary action (rule 151) */
}
.module-card:has(.toggle-track:not(.on)) .module-card-icon { color: var(--text-muted); }
.module-status-btn .btn-icon-arrow { display: none; }
/* The icons have blank space inside their box; pull them closer to the label (plus on the left, arrow on the right) */
.module-status-btn .btn-icon-plus { margin-right: calc(var(--sp-1) * -1); }
.module-status-btn .btn-icon-arrow { margin-left: calc(var(--sp-1) * -1); }
.module-status-btn:hover .btn-icon-plus { display: none; }
.module-status-btn:hover .btn-icon-arrow { display: inline-block; }
.module-status-btn.active { --btn-bg: var(--brand-fill); --btn-fg: var(--brand-text); }
/* NEW (05.10.2026): plugin card with a real switch (button "Öffnen" left, switch right) and the state line of
   plugins that run in the bot but have no dashboard page yet (dot from dashboard/plugin_registry.py). */
.module-card-actions { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.module-card-state { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--text-muted); }
/* NEW (05.10.2026): typed confirmation in the popups of critical deletions (_confirm_word.html). */
.confirm-word-label { display: block; margin-top: var(--sp-4); color: var(--text); }
.confirm-word-label code { color: var(--orange); font-weight: 700; }
.confirm-word-input { display: block; width: 100%; margin-top: var(--sp-2); }


/* ---------- 11b. Dashboard overview ("Tagesuebersicht", band above the plugin list) ----------
   Status line + four tiles + collapsible activity card. Tiles are cards (surface colour) like the plugin cards; the
   traffic-light colour only appears as a small dot (.ov-dot) and in the status icon, never as a coloured card.
   The strip of 30 day segments (.ov-strip) uses the same traffic-light colours.                              */
.ov { margin-bottom: var(--sp-7); }   /* clear break before the large "Plugins" heading */

.ov-status { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--sp-4); background-color: var(--surface); border: 1px solid var(--card-border); border-radius: var(--r-lg); padding: var(--sp-5); margin-bottom: var(--sp-4); }
.ov-status-body { flex: 1 1 260px; min-width: 0; align-self: center; }
/* Signal colour of the status line: a 4 px stripe on the left edge (--status-stripe per level, none while loading).
   Since 09.10.2026 (design guide rule 97) the line has no robot and no symbol any more: title, a muted summary line
   ("4 von 4 Prüfungen in Ordnung · Stand 18:42 Uhr") and the checks (.ov-check) to the right of it. */
/* Since 13.10.2026 (rule 151): no stripe any more - the level is shown by a symbol in a tinted circle (.ov-status-icon:
   tick / exclamation mark / cross), like the notices. --status-stripe stays as the level colour of the circle. */
.ov-status { --status-stripe: var(--text-dim); --status-soft: rgba(255, 255, 255, 0.06); align-items: center; }
.ov-status-icon { width: 44px; height: 44px; flex-shrink: 0; align-self: center; border-radius: 50%; background-color: var(--status-soft); display: flex; align-items: center; justify-content: center; }
.ov-status-icon .icon { width: 22px; height: 22px; color: var(--status-stripe); --icon: url('/assets/icons/clock-outline.svg'); }
.ov-status[data-level="ok"] .ov-status-icon .icon { --icon: url('/assets/icons/check.svg'); }
.ov-status[data-level="warning"] .ov-status-icon .icon { --icon: url('/assets/icons/alert-circle-outline.svg'); }
.ov-status[data-level="error"] .ov-status-icon .icon { --icon: url('/assets/icons/close.svg'); }
.ov-status[data-level="unknown"] .ov-status-icon .icon { --icon: url('/assets/icons/help-circle-outline.svg'); }
.ov-status:has(.ov-issues:not([hidden])) { padding-bottom: var(--sp-5); }   /* hints listed below: keep the normal bottom space */
.ov-status[data-level="ok"] { --status-stripe: var(--ok); --status-soft: var(--ok-soft); }
.ov-status[data-level="warning"] { --status-stripe: var(--warn); --status-soft: rgba(241, 196, 15, 0.14); }
.ov-status[data-level="error"] { --status-stripe: var(--danger); --status-soft: rgba(255, 90, 90, 0.14); }
.ov-status-title { font-size: 1.125rem; font-weight: 700; color: var(--text); line-height: 1.4; }
.ov-status-text { font-size: var(--fs-sm); color: var(--text-muted); margin-top: var(--sp-1); }
.ov-status-text[hidden], .ov-issues[hidden], .ov-checks[hidden] { display: none; }
/* Checks of the status line (09.10.2026, design guide rule 97): flat entries in the grey of the "Öffnen" buttons
   (rgba(255, 255, 255, 0.08), square corners, orange with white text on hover like those buttons; chosen by the user
   after trying the blue grey of the sidebar and --surface-2), dot in the state
   colour, name in text colour, value muted (never in the signal colour). Each one is a link to its place and sits above
   the link of the whole card (z-index). Below 1200 px they move into their own row under the title. */
.ov-checks { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-2); position: relative; z-index: 1; }
.ov-check { display: inline-flex; align-items: center; gap: var(--sp-2); padding: 7px 14px; border-radius: var(--r-pill); background-color: var(--surface-2); font-size: var(--fs-xs); line-height: 1.3; color: var(--text); text-decoration: none; white-space: nowrap; }
a.ov-check { transition: background-color 0.25s ease, color 0.25s ease; }
a.ov-check:hover, a.ov-check:focus-visible { background-color: var(--orange); color: #fff; outline: none; box-shadow: 0 0 12px rgba(231, 126, 35, 0.5); }
a.ov-check:hover .ov-check-value, a.ov-check:focus-visible .ov-check-value { color: #fff; }
a.ov-check:hover .ov-dot, a.ov-check:focus-visible .ov-dot { background-color: #fff; }   /* the status colour would clash with the orange */
.ov-check-label { font-weight: 700; }
.ov-check-value { color: var(--text-muted); }
@media (max-width: 1199px) { .ov-checks { flex-basis: 100%; justify-content: flex-start; order: 2; } }
/* The whole status line is one link to the System area: the link itself has no visible content and is stretched over the
   card (position: absolute; inset: 0). Links INSIDE the card (the listed hints, .ov-issue) sit above it (z-index) and keep
   their own target. On hover/keyboard focus the card gets the same thin half-orange frame as the clickable tiles. */
.ov-status { position: relative; transition: background-color 0.15s ease; }
.ov-status-link { position: absolute; inset: 0; z-index: 0; font-size: 0; }
.ov-status:has(.ov-status-link:hover), .ov-status:has(.ov-status-link:focus-visible) { border-color: var(--card-border-hover); }
.ov-status-link:focus-visible { outline: none; }
.ov-issue { position: relative; z-index: 1; }

.ov-issues { flex-basis: 100%; order: 3; display: flex; flex-direction: column; gap: var(--sp-1); }   /* own row below icon, title and link */
.ov-issue { display: flex; align-items: flex-start; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md); background-color: var(--well); color: var(--text); text-decoration: none; }
a.ov-issue { transition: background-color 0.15s ease; }
a.ov-issue:hover { background-color: var(--surface-2); }
.ov-issue .ov-dot { margin-top: 6px; }
.ov-issue-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.ov-issue-title { font-size: var(--fs-sm); font-weight: 700; }
.ov-issue-desc { font-size: var(--fs-xs); color: var(--text-muted); }
.ov-issue-arrow { color: var(--text-dim); margin-top: 3px; flex-shrink: 0; }
.ov-issue-more { font-size: var(--fs-xs); color: var(--text-muted); padding: var(--sp-1) var(--sp-3) 0; }

.ov-tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); margin-bottom: var(--sp-4); }
@media (min-width: 1360px) { .ov-tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.ov-tile { position: relative; min-width: 0; display: flex; flex-direction: column; background-color: var(--surface); border: 1px solid var(--card-border); border-radius: var(--r-lg); padding: var(--sp-5); color: var(--text); text-decoration: none; }
.ov-tile-link { font: inherit; text-align: left; width: 100%; cursor: pointer; transition: border-color 0.15s ease; }
.ov-tile-link:hover { border-color: var(--card-border-hover); }   /* thin half-orange frame, as used on the Kartell website */
.ov-tile-label { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--text-muted); min-width: 0; }
.ov-tile-label > span:not(.ov-dot) { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ov-tile-value { margin-top: var(--sp-3); font-size: var(--fs-lg); font-weight: 700; color: var(--text); line-height: 1.25; overflow-wrap: anywhere; }
.ov-tile-lines { margin-top: var(--sp-2); font-size: var(--fs-xs); color: var(--text-muted); }
.ov-tile-lines > div + div { margin-top: var(--sp-1); }
.ov-tile-lines.ov-clamp > div:first-child { color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.ov-only-compact { display: none; }   /* shown only where the top bar hides ping and member count (max 900px, like .bot-pill-detail) */
@media (max-width: 900px) { .ov-only-compact { display: block; } .ov-only-compact:empty { display: none; } .ov-hide-compact { display: none; } }   /* .ov-hide-compact: the opposite - detail lines without room on small tiles */
.ov-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background-color: var(--text-dim); }
.ov-dot.ok { background-color: var(--ok); }
.ov-dot.warn { background-color: var(--warn); }
.ov-dot.danger { background-color: var(--danger); }
.ov-dot.accent { background-color: var(--orange); }
.ov-tile-label .ov-dot:empty { margin-left: auto; }

.ov-strip { display: flex; gap: 2px; height: 20px; margin-top: var(--sp-3); }
.ov-seg { flex: 1; min-width: 0; border-radius: 2px; background-color: var(--surface-3); }
.ov-seg.ok { background-color: var(--ok); }
.ov-seg.warn { background-color: var(--warn); }
.ov-seg.error { background-color: var(--danger); }
.ov-seg.stopped { background-color: var(--text-dim); }
.ov-seg.none { background-color: var(--surface-3); }
.ov-seg:hover { opacity: 0.75; }
.ov-strip + .ov-tile-lines { min-height: 1.5em; }

.ov-activity { padding-top: var(--sp-2); padding-bottom: var(--sp-2); }
.ov-activity-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; }
.ov-activity-row + .ov-activity-row { border-top: 1px solid var(--line); }
.ov-activity-text { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; gap: 0 var(--sp-3); color: var(--text); }
.ov-activity-who { color: var(--text-muted); }
.ov-activity-time { color: var(--text-muted); font-size: var(--fs-xs); white-space: nowrap; }


/* ---------- 11c. Change log rows (card "Aenderungsprotokoll" on the settings page) ----------
   One row per changed setting: title (+ affected item), "old -> new" values, person; time at the right.
   Inside a .well, hairline between rows (Regel 4).                                                       */
.change-list { padding-top: var(--sp-2); padding-bottom: var(--sp-2); }
.change-row { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); padding: var(--sp-3) 0; }
.change-row + .change-row { border-top: 1px solid var(--line); }
.change-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.change-title { color: var(--text); font-weight: 700; overflow-wrap: anywhere; }
.change-subject { margin-left: var(--sp-2); font-weight: 400; color: var(--text-muted); }
.change-values { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) calc(var(--sp-1) / 2); color: var(--text-muted); font-size: var(--fs-xs); }
.change-old { color: var(--text-dim); overflow-wrap: anywhere; }
.change-new { color: var(--text); overflow-wrap: anywhere; }
.change-meta { flex-shrink: 0; display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-1); text-align: right; }
.change-who { color: var(--text); font-size: var(--fs-xs); }
.change-time { color: var(--text-muted); font-size: var(--fs-xs); white-space: nowrap; }


/* ---------- 12. Modals ---------- */
.modal-overlay {
    display: none;
    position: fixed;   /* relative to the window: stays in view however far the page is scrolled */
    inset: 0;
    background-color: rgba(0, 0, 0, 0.7);
    z-index: 2000;
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(3px);
}
.modal-box {
    background-color: var(--surface-2);
    width: 420px;
    max-width: calc(100% - 32px);
    max-height: calc(100% - 32px);
    overflow-y: auto;
    border: 1px solid var(--card-border);
    border-radius: var(--r-lg);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.55);
    animation: modalFadeIn 0.2s ease-out;
}
@keyframes modalFadeIn { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: translateY(0); } }
.modal-header { padding: var(--sp-5) var(--sp-5) var(--sp-3); display: flex; justify-content: space-between; align-items: center; gap: var(--sp-4); }
.modal-header h3 { font-size: var(--fs-md); font-weight: 700; color: var(--text); }
.modal-close { color: var(--text-muted); cursor: pointer; font-size: var(--fs-md); transition: color 0.15s ease; }
.modal-close:hover { color: var(--text); }
.modal-body { padding: var(--sp-3) var(--sp-5) var(--sp-5); color: var(--text-muted); font-size: var(--fs-sm); text-align: center; }
.modal-body.left-align { text-align: left; }
.modal-icon { font-size: var(--fs-xl); color: var(--text-muted); margin-bottom: var(--sp-3); }
.modal-footer { padding: var(--sp-4) var(--sp-5); background-color: rgba(0, 0, 0, 0.18); display: flex; justify-content: flex-end; gap: var(--sp-2); }
/* Robot in hint and confirmation popups (06.10.2026, design guide rule 54; macro modal_mascot in templates/_mascot.html).
   The box becomes a two-column grid: the robot left of title and text, the footer over the full width. On phones the
   robot sits above the title (see the responsive section). Decorative only (empty alt). */
.modal-box.has-mascot { display: grid; grid-template-columns: auto minmax(0, 1fr); }
.modal-box.has-mascot > .modal-mascot { grid-column: 1; grid-row: 1 / span 2; align-self: start; width: 64px; height: auto; margin: var(--sp-5) 0 var(--sp-3) var(--sp-5);
    filter: drop-shadow(0 0 1px rgba(255, 255, 255, 0.35)) drop-shadow(0 4px 10px rgba(0, 0, 0, 0.45)); }
.modal-box.has-mascot > .modal-header { grid-column: 2; grid-row: 1; }
.modal-box.has-mascot > .modal-body { grid-column: 2; grid-row: 2; }
.modal-box.has-mascot > .modal-footer { grid-column: 1 / -1; grid-row: 3; }
/* Greyed plugin switch for people of the moderation lists ("Nur Administration"); a click opens "Kein Zugriff". */
.toggle-track.is-locked { opacity: 0.45; filter: grayscale(1); cursor: not-allowed; }
/* Area label of "Letzte Aktivitaeten" (Administration only): small, quiet, same width for both words. */
.ov-activity-area { margin-left: auto; align-self: center; flex-shrink: 0; min-width: 86px; text-align: center; padding: 1px var(--sp-2); border: 1px solid var(--line); border-radius: var(--r-pill);
    color: var(--text-muted); font-size: var(--fs-xs); letter-spacing: 0.02em; }


/* ---------- 13. Simple centred panel (e.g. "no access" page) ---------- */
.panel { max-width: 480px; margin: var(--sp-7) auto; padding: var(--sp-6); background-color: var(--surface); border: 1px solid var(--card-border); border-radius: var(--r-lg); text-align: center; }
.panel .user-avatar { width: 72px; height: 72px; margin: 0 auto var(--sp-4); }
.panel h1 { font-size: var(--fs-lg); font-weight: 700; margin-bottom: var(--sp-3); }
.panel p { color: var(--text-muted); margin-bottom: var(--sp-4); }


/* ---------- 13b. Sign-in page (public, before the login) ----------
   Standalone page: top bar on top (brand left; community icons, language switch and a login button right), the centred
   card in the middle, a small footer at the bottom. The stage scrolls on its own, because the body is locked to the
   viewport height. */
/* Background (since 06.10.2026, design guide rule 50): drawn space scene in the style of the mascot (stars, asteroids at the
   edges, the arc of a planet with an orange glow at the bottom), anchored at the bottom so the planet stays visible on every
   screen; the calm middle keeps heading and button readable. Until 06.10.2026: a still frame of the community video
   (login-background.jpg, no longer used). The colour underneath matches the picture, so nothing flashes while it loads. */
.login-page {
    background-color: #1e222d;
    background-image: linear-gradient(180deg, rgba(14, 15, 17, 0.10) 0%, rgba(14, 15, 17, 0.30) 100%), url('/assets/branding/mascot/login-space.jpg');
    background-size: cover;
    background-position: center bottom;
    background-repeat: no-repeat;
}
.public-nav { display: flex; align-items: center; gap: var(--sp-3); margin-left: auto; }
.public-link { color: var(--text-muted); text-decoration: none; font-size: var(--fs-sm); font-weight: 700; white-space: nowrap; transition: color 0.15s ease; }
.public-link:hover { color: var(--text); }
.public-divider { width: 1px; height: 24px; background-color: var(--text-muted); opacity: 0.6; }
.public-icons { display: flex; align-items: center; gap: var(--sp-1); }
.icon-link { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: var(--r-md); color: var(--orange); font-size: 1.5rem; transition: background-color 0.15s ease, color 0.15s ease; }
.icon-link:hover { background-color: var(--surface-3); color: var(--orange-hover); }
.icon-link .icon { width: 1em; height: 1em; vertical-align: 0; }

/* Language switch (opens on click; reuses the dropdown of the user menu) */
.lang-trigger { display: inline-flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); border: 0; border-radius: var(--r-md); background: transparent; color: var(--text-muted); font: inherit; font-size: var(--fs-sm); font-weight: 700; cursor: pointer; transition: background-color 0.15s ease, color 0.15s ease; }
.lang-trigger:hover, .lang-switch.open .lang-trigger { background-color: var(--surface); color: var(--text); }
.lang-trigger .icon { transition: transform 0.15s ease; }
/* Optical centring: capital letters sit slightly above the middle of the line box, so flag and arrow are nudged up. */
.lang-trigger .flag { transform: translateY(-1px); }
.lang-trigger .icon-angle-down { margin-top: -2px; }
.lang-switch.open .lang-trigger .icon-angle-down { transform: rotate(180deg); }
.lang-menu { min-width: 180px; top: 44px; }
.dropdown-item.is-current { color: var(--text); cursor: default; }
.flag { width: 20px; height: 20px; flex-shrink: 0; border-radius: 50%; }
.dropdown-item.is-disabled .flag { opacity: 0.5; }
.lang-menu .dropdown-item .icon-check { margin-left: auto; color: var(--text-muted); }

.login-stage { flex: 1; min-height: 0; overflow-y: auto; display: flex; align-items: center; justify-content: center; padding: var(--sp-5) max(var(--sp-4), env(safe-area-inset-right)) var(--sp-6) max(var(--sp-4), env(safe-area-inset-left)); }
.login-card { width: 100%; max-width: 560px; margin: auto; text-align: center; }
/* Since 06.10.2026 (space background): the card is centred in the space ABOVE the planet. The bottom padding keeps the
   lower part of the window (where the glowing arc of the planet sits) free, so the robot "flies" above the planet and
   the button never lands on the arc, also on low laptop screens; on large screens the group no longer sticks to the
   top edge (feedback of the user on a 1700 x 1300 window). */
/* 13.10.2026: auto margins centre the card while there is room and keep it fully visible (scrollable) when the window is
   too low - with align-items: center the floating robot was cut at the top bar on 900 px high screens with the
   maintenance notice. The extra top padding leaves room for the float animation. */
.login-page .login-stage { align-items: flex-start; padding-top: var(--sp-6); padding-bottom: clamp(var(--sp-6), 16vh, 220px); }
.login-page .login-card { margin: auto; }
.login-card .btn-brand { background-color: #3b2717; }   /* solid brown so the planet arc never shows through the button (13.10.2026) */
.login-logo { display: block; width: min(380px, 75vw); height: auto; margin: 0 auto var(--sp-7); }
/* Mascot on the sign-in page (06.10.2026, design guide rule 50): the robot with jetpack. The group floats slowly up and
   down (mascot-float); the flame flickers quickly (mascot-flame, grows and shrinks around the nozzle, orange glow
   pulses) and a small spark keeps drifting away from it (mascot-spark). The flame layers sit behind the robot; their
   positions are percentages of the robot picture. A thin light rim and a soft orange glow lift the dark robot off the
   dark background. */
/* Width also follows the window height (30vh), so the button stays above the planet on low laptop screens. */
.login-mascot { width: min(330px, 62vw, 30vh); min-width: 200px; margin: 0 auto var(--sp-5); }
.login-mascot-float {
    position: relative;
    filter: drop-shadow(0 0 1px rgba(255, 255, 255, 0.45)) drop-shadow(0 0 22px rgba(255, 140, 40, 0.22));
    animation: mascot-float 5s ease-in-out infinite;
    will-change: transform;
}
.login-mascot-robot { position: relative; display: block; width: 100%; height: auto; }
.login-mascot-flame, .login-mascot-spark { position: absolute; display: block; height: auto; pointer-events: none; }
.login-mascot-flame {
    left: 5.838%;
    top: 63.919%;
    width: 14.257%;
    transform-origin: 78% 4%;
    animation: mascot-flame 0.14s ease-in-out infinite alternate, mascot-flame-glow 1.1s ease-in-out infinite;
}
.login-mascot-spark {
    left: 0;
    top: 73.687%;
    width: 6.042%;
    animation: mascot-spark 1.3s linear infinite;
}
/* Reflection on the visor (09.10.2026, design guide rule 50): a band of light that sweeps diagonally across the visor
   about every 7 seconds and stays invisible in between. It lies exactly over the robot picture and is cut to the visor by
   a mask of the same size (jetpack-visor-mask.png); "screen" only brightens, so eyes and the painted stripes stay visible. */
.login-mascot-glint {
    position: absolute; left: 0; top: 0; width: 100%; aspect-ratio: 760 / 845; pointer-events: none;
    background: linear-gradient(115deg, transparent 0%, transparent 38%, rgba(255, 255, 255, 0.05) 43%, rgba(255, 255, 255, 0.42) 49%, rgba(255, 255, 255, 0.55) 50%, rgba(255, 255, 255, 0.42) 51%, rgba(255, 255, 255, 0.05) 57%, transparent 62%, transparent 100%) no-repeat;
    background-size: 300% 100%;
    background-position: 100% 0;
    mix-blend-mode: screen;
    -webkit-mask: url("/assets/branding/mascot/jetpack-visor-mask.png") center / 100% 100% no-repeat;
            mask: url("/assets/branding/mascot/jetpack-visor-mask.png") center / 100% 100% no-repeat;
    animation: mascot-glint 7s ease-in-out 1.5s infinite;
}
@keyframes mascot-glint {
    0%        { background-position: 100% 0; }
    22%, 100% { background-position: 0% 0; }
}
@keyframes mascot-float {
    0%, 100% { transform: translateY(0) rotate(-1deg); }
    50%      { transform: translateY(-12px) rotate(1.2deg); }
}
@keyframes mascot-flame {
    from { transform: scale(0.86, 0.84) rotate(-3deg); opacity: 0.88; }
    to   { transform: scale(1.06, 1.12) rotate(2deg); opacity: 1; }
}
@keyframes mascot-flame-glow {
    0%, 100% { filter: drop-shadow(0 0 6px rgba(255, 150, 40, 0.55)) brightness(1); }
    50%      { filter: drop-shadow(0 0 14px rgba(255, 170, 60, 0.9)) brightness(1.12); }
}
@keyframes mascot-spark {
    0%   { transform: translate(55%, -55%) scale(0.5); opacity: 0; }
    15%  { opacity: 1; }
    100% { transform: translate(-90%, 90%) scale(1.05); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .login-mascot-float, .login-mascot-flame, .login-mascot-spark, .login-mascot-glint { animation: none; }
    .login-mascot-spark { opacity: 0.8; }
}
/* Heading in the style of the Kartell website (capitals, normal weight); same size as before so the logo stays the largest element. */
.login-card h1 { font-size: var(--fs-lg); font-weight: 400; letter-spacing: 0.04em; text-transform: uppercase; line-height: 1.3; margin-bottom: var(--sp-3); }
.login-card p { font-size: var(--fs-md); color: var(--text-muted); margin-bottom: var(--sp-6); }
/* Two-factor hint below the sentence (12.10.2026 evening, the whole dashboard needs the Discord two-factor). */
.login-card p:has(+ .login-mfa-note) { margin-bottom: var(--sp-2); }
.login-card p.login-mfa-note { display: flex; align-items: center; justify-content: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--text-dim); }
.login-mfa-note .icon { color: var(--orange); }
.login-card .banner { justify-content: center; text-align: left; }
/* Maintenance notice of the sign-in page (09.10.2026, design guide rule 98): only type, no box - the heading in orange
   capitals with wide letter spacing between two thin orange lines that fade out towards the edges, the sentence below in
   muted text. Same distance to the button as the text above it. */
.login-maint { margin: 0 auto var(--sp-5); }
.login-maint-title { display: flex; align-items: center; gap: 14px; margin-bottom: var(--sp-2); color: var(--orange); font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; }
.login-maint-title::before, .login-maint-title::after { content: ""; flex: 1; height: 1px; background: linear-gradient(90deg, transparent, rgba(231, 126, 35, 0.6)); }
.login-maint-title::after { background: linear-gradient(270deg, transparent, rgba(231, 126, 35, 0.6)); }
.login-maint-text { font-size: var(--fs-sm); color: var(--text-muted); white-space: pre-line; }
/* 12.10.2026: hint text of System > Wartungsmodus above the fixed sentence; "kein Wartungszugang" in the warning colour. */
.login-maint-text + .login-maint-text { margin-top: var(--sp-1); }
.login-maint-text.login-maint-denied { color: var(--warn); }

.public-footer { flex-shrink: 0; display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); padding: var(--sp-4) max(var(--sp-4), env(safe-area-inset-right)) max(var(--sp-5), env(safe-area-inset-bottom)) max(var(--sp-4), env(safe-area-inset-left)); }
.public-footer-links { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; row-gap: var(--sp-2); }
.public-footer-links .public-link { padding: 0 var(--sp-4); font-weight: 400; letter-spacing: 0.08em; text-transform: uppercase; }
.public-footer-links .public-link + .public-link { border-left: 1px solid var(--text-dim); }
.public-footer-note { font-size: var(--fs-xs); color: var(--text-dim); }

/* Short confirmation (e.g. after the logout): floats below the top bar, disappears on its own, can be closed. */
.toast { position: fixed; top: calc(var(--topbar-height) + var(--sp-3)); left: 50%; transform: translateX(-50%); z-index: 50; display: flex; align-items: center; gap: var(--sp-3); max-width: calc(100vw - 2 * var(--sp-4)); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md); background-color: var(--surface-2); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45); font-size: var(--fs-sm); transition: opacity 0.4s ease; }
.toast.ok .icon { color: var(--ok); }
.toast.is-hiding { opacity: 0; }
.toast-close { display: inline-flex; align-items: center; justify-content: center; margin-left: var(--sp-2); padding: 0; border: 0; background: transparent; color: var(--text-muted); cursor: pointer; }
.toast-close:hover { color: var(--text); }


/* ---------- 14. Tabs as links, toolbar, segmented control (System area) ---------- */
a.module-tab { text-decoration: none; display: block; }

.toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.toolbar-spacer { flex: 1; }

.segmented { display: inline-flex; gap: 2px; padding: 2px; background-color: var(--surface-2); border-radius: var(--r-md); }
.segmented button {
    border: 0;
    background: transparent;
    color: var(--text-muted);
    font-weight: 700;
    padding: var(--sp-1) var(--sp-3);
    border-radius: var(--r-sm);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.segmented button:hover { color: var(--text); }
.segmented button.active { background-color: var(--surface-3); color: var(--text); }

/* ---------- 15. Meters (server health tiles) ----------
   Fill colour = traffic light: .ok / .warn / .danger */
.meter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--sp-3); }
.meter { background-color: var(--well); border-radius: var(--r-md); padding: var(--sp-4); }
.meter-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); color: var(--text-muted); margin-bottom: var(--sp-2); }
.meter-value { font-size: var(--fs-lg); font-weight: 700; color: var(--text); }
.meter-bar { height: 6px; border-radius: 3px; background-color: var(--surface-3); overflow: hidden; }
.meter-fill { height: 100%; border-radius: 3px; background-color: var(--ok); transition: width 0.4s ease; }
.meter-fill.warn { background-color: var(--warn); }
.meter-fill.danger { background-color: var(--danger); }
.meter-sub { margin-top: var(--sp-2); font-size: var(--fs-xs); color: var(--text-muted); }
.meter-sub + .meter-sub { margin-top: var(--sp-1); }
.meter-sub.warn { color: var(--warn); }
.meter-foot { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 0 var(--sp-3); }
.meter-foot-lines { white-space: nowrap; }
.meter-note { margin-top: var(--sp-2); font-size: var(--fs-xs); font-weight: 700; text-align: right; white-space: nowrap; }
.meter-note.warn { color: var(--warn); }
.meter-note.danger { color: var(--danger); }
.meter-sub.danger { color: var(--danger); }

/* ---------- 16. Read-only log window ---------- */
.log-window {
    background-color: var(--well);
    border-radius: var(--r-md);
    padding: var(--sp-3) var(--sp-4);
    height: 420px;
    overflow-y: auto;
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    line-height: 1.6;
    color: var(--text-muted);
}
.log-line { white-space: pre-wrap; word-break: break-word; }
.log-line.error { color: var(--danger); }
.log-line.warn { color: var(--warn); }
.log-note { color: var(--text-dim); }

/* ---------- 17. Bot indicator in the top bar ----------
   Small read-only text indicator (dot + "Bot online" + ping/members). Quiet on purpose: muted text, only
   the dot carries the traffic-light colour. On narrow screens only dot and state remain. */
.bot-pill { display: flex; align-items: center; gap: var(--sp-2); color: var(--text-muted); white-space: nowrap; }
.bot-pill[hidden] { display: none; }
.bot-pill-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background-color: var(--text-dim); }
.bot-pill-dot.ok { background-color: var(--ok); box-shadow: 0 0 6px var(--ok); }
.bot-pill-dot.danger { background-color: var(--danger); box-shadow: 0 0 6px var(--danger); }
.bot-pill-state { font-weight: 700; color: var(--text); }
.bot-pill-detail { font-size: var(--fs-xs); }
@media (max-width: 900px) { .bot-pill-detail { display: none; } }

/* Maintenance label (08.10.2026, rule 61): orange chip left of the bot indicator while the maintenance mode is on.
   Phone: only the lock icon remains (like the bot indicator, which keeps only its dot). */
.maint-pill { display: flex; text-decoration: none; align-items: center; gap: var(--sp-2); padding: 6px var(--sp-3); white-space: nowrap; border-radius: var(--r-sm);
    background-color: var(--brand-fill); color: var(--brand-text); font-size: var(--fs-xs); font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.06em; }
.maint-pill .icon { width: 14px; height: 14px; }
@media (max-width: 640px) { .maint-pill-text { display: none; } .maint-pill { padding: var(--sp-1) var(--sp-2); } }
.maint-pill:hover { background-color: rgba(231, 126, 35, 0.24); }
/* Deleting entries of the Medienspeicher and the Textspeicher (08.10.2026, rule 62): reason choice in the popup
   (_entry_delete_dialog.html); the delete button of the bulk bar is hidden until something is selected. */
.btn[hidden] { display: none; }
.del-reasons { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5); margin-top: var(--sp-2); }
.del-reason-text { margin-top: var(--sp-3); }
.del-reason-text[hidden] { display: none; }
.del-reason-text .input { width: 100%; }
/* System > Wartungsmodus (hint text form) and the cross links between that tab and Einstellungen > Wartungszugang. */
.maint-system-link { color: var(--orange); text-decoration: underline; }
.maint-system-link:hover { color: var(--orange-hover); }
.maint-text-form { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-4); }
.maint-text-label { font-weight: 700; color: var(--text); font-size: var(--fs-sm); }
.maint-text-form .textarea { width: 100%; min-height: 76px; resize: vertical; }
.maint-text-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
@media (max-width: 640px) { .maint-text-foot .btn { width: 100%; justify-content: center; } }


/* ---------- 17b. Notifications (the bell in the top bar) ----------
   Bell button with an unread badge and a compact panel with one slim card per notification (title row with
   tags and time, then one short text). Four levels, each with a colour for icon and title: information
   (neutral), success (blue, the OK colour), warning (yellow), error (red). Unread cards carry a thin bar in the level
   colour; read cards are dimmed. Sizes are deliberately small (fs-sm titles, fs-xs texts, 8px/12px padding)
   so that the panel matches the fine-grained look of the rest of the interface. Desktop: the panel hangs
   under the bell. Compact/phone: the panel spans the full width below the top bar over a dimmed backdrop.
   All texts are written with textContent in base.html, never as markup. */
.notify-wrapper { display: flex; align-items: center; }
.notify-wrapper[hidden] { display: none; }
.notify-badge {
    position: absolute;
    top: -2px;
    right: -2px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    background-color: var(--orange);
    color: var(--on-orange);
    font-size: var(--fs-xs);
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    box-shadow: 0 0 0 2px var(--bg-nav);
    pointer-events: none;
}
.notify-badge[hidden] { display: none; }

.notify-backdrop { display: none; }
.notify-panel {
    position: fixed;
    top: calc(var(--topbar-height) + var(--sp-1));
    right: var(--sp-6);
    z-index: 1600;
    display: flex;
    flex-direction: column;
    width: 380px;
    max-width: calc(100vw - var(--sp-5));
    max-height: min(540px, calc(100vh - var(--topbar-height) - var(--sp-5)));
    max-height: min(540px, calc(100dvh - var(--topbar-height) - var(--sp-5)));
    background-color: var(--surface-2);
    border: 1px solid var(--card-border);
    border-radius: var(--r-lg);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
    overflow: hidden;
}
.notify-panel[hidden] { display: none; }
.notify-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-1) var(--sp-3);
    padding: var(--sp-4) var(--sp-3) var(--sp-3) var(--sp-4);
}
.notify-header h3 { margin: 0; font-size: var(--fs-sm); font-weight: 700; color: var(--text); }
.notify-readall {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    padding: 2px var(--sp-2);
    border: 0;
    border-radius: var(--r-sm);
    background: transparent;
    color: var(--orange);
    font-family: inherit;
    font-size: var(--fs-xs);
    cursor: pointer;
    transition: color 0.15s ease, background-color 0.15s ease;
}
.notify-readall:hover { color: var(--orange-hover); background-color: var(--surface-3); }
.notify-readall:disabled { color: var(--text-dim); cursor: default; background: transparent; }

.notify-list {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding: 0 var(--sp-3) var(--sp-3);
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
}
.notify-item {
    --notify-color: var(--text);
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--r-md);
    background-color: var(--surface);
    color: inherit;
    text-decoration: none;
    cursor: default;
    transition: background-color 0.15s ease;
}
a.notify-item, .notify-item.is-clickable { cursor: pointer; }
a.notify-item:hover, .notify-item.is-clickable:hover { background-color: var(--surface-3); }
.notify-item.level-info    { --notify-color: var(--text); }
.notify-item.level-success { --notify-color: var(--ok); }
.notify-item.level-warning { --notify-color: var(--warn); }
.notify-item.level-error   { --notify-color: var(--danger); }
.notify-item .icon { flex-shrink: 0; margin-top: 1px; font-size: var(--fs-md); color: var(--notify-color); }
.notify-item.level-info .icon { color: var(--text-muted); }
.notify-body { min-width: 0; flex: 1; }
.notify-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0 var(--sp-3); }
.notify-title { min-width: 0; font-size: var(--fs-sm); font-weight: 700; line-height: 1.35; color: var(--notify-color); overflow-wrap: anywhere; }
.notify-time { font-size: var(--fs-xs); color: var(--text-dim); white-space: nowrap; }
.notify-foot { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-1); font-size: var(--fs-xs); line-height: 1.4; color: var(--text-dim); }
.notify-readmark { display: inline-flex; align-items: center; gap: var(--sp-1); white-space: nowrap; }
.notify-readmark::before { content: "\00b7"; margin-right: var(--sp-1); }
.notify-item .notify-readmark .icon { margin-top: 0; font-size: var(--fs-xs); color: inherit; opacity: 1; }
.notify-text { margin-top: var(--sp-1); font-size: var(--fs-xs); line-height: 1.55; color: var(--text-muted); overflow-wrap: anywhere; }
.notify-item.is-unread .notify-text { color: var(--text); }
.notify-tag { flex-shrink: 0; margin-left: auto; padding: 0 var(--sp-2); border-radius: var(--r-pill); background-color: var(--surface-3); color: var(--text-muted); font-size: var(--fs-xs); font-weight: 700; line-height: 1.5; }
.notify-tag.is-new { background-color: var(--orange-soft); color: var(--orange); }
.notify-item:not(.is-unread) .notify-title { opacity: 0.7; }
.notify-item:not(.is-unread) .icon { opacity: 0.7; }
.notify-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-5) var(--sp-4) var(--sp-6);
    color: var(--text-muted);
    font-size: var(--fs-xs);
    text-align: center;
}
.notify-empty[hidden] { display: none; }
.notify-empty .icon { font-size: var(--fs-lg); color: var(--text-dim); }
.notify-footer { position: relative; padding: var(--sp-1) var(--sp-4) var(--sp-4); background-color: var(--surface-2); box-shadow: 0 -8px 8px var(--surface-2); font-size: var(--fs-xs); line-height: 1.4; color: var(--text-muted); text-align: center; }
.notify-footer[hidden] { display: none; }

@media (max-width: 1023px) {
    .notify-panel { right: var(--sp-4); }
    .notify-backdrop {
        display: block;
        position: fixed;
        inset: calc(var(--topbar-height) + var(--frame-gap)) 0 0 0;
        z-index: 1550;
        background-color: rgba(0, 0, 0, 0.6);
    }
    .notify-backdrop[hidden] { display: none; }
}
@media (max-width: 640px) {
    /* Phone: full-width sheet hanging from the top bar */
    .notify-panel {
        top: calc(var(--topbar-height) + var(--frame-gap));
        left: 0;
        right: 0;
        width: auto;
        max-width: none;
        max-height: calc(100vh - var(--topbar-height) - var(--frame-gap) - var(--sp-6));
        max-height: calc(100dvh - var(--topbar-height) - var(--frame-gap) - var(--sp-6));
        border-radius: 0 0 var(--r-lg) var(--r-lg);
    }
    .notify-footer { padding-bottom: calc(var(--sp-4) + env(safe-area-inset-bottom)); }
    .notify-header { padding-left: max(var(--sp-4), env(safe-area-inset-left)); padding-right: max(var(--sp-3), env(safe-area-inset-right)); }
    .notify-list { padding-left: max(var(--sp-3), env(safe-area-inset-left)); padding-right: max(var(--sp-3), env(safe-area-inset-right)); }
}
@media (pointer: coarse) {
    .notify-readall { min-height: 36px; padding: var(--sp-1) var(--sp-3); }
}
body.notify-open-compact { overflow: hidden; }

/* ---------- 18. Responsive layout ----------
   Mobile-first rules are NOT used; the desktop layout above is the base and these blocks adapt it.
   Breakpoints (the only ones allowed; media queries cannot read tokens, so the values are written out):
     >= 1024px   desktop and tablet landscape: fixed sidebar (unchanged)
     <= 1023px   compact (tablet portrait, phone): sidebar becomes a drawer, opened with the menu button
     <=  640px   phone: tighter spacing, stacked headers and button rows, one-column grids
   Touch devices (pointer: coarse) get 44px tap targets and 16px form text (prevents the iOS zoom on focus).
   Every new page and component must work at 390px width without horizontal scrolling. */

/* --- Compact: the sidebar turns into a drawer ------------------------------------------------------ */
@media (max-width: 1023px) {
    /* max() keeps the bar out of the notch / rounded corners (safe-area insets are 0 on devices without one) */
    .top-bar { padding: 0 max(var(--sp-5), env(safe-area-inset-right)) 0 max(var(--sp-3), env(safe-area-inset-left)); }
    .nav-toggle {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 40px;
        height: 40px;
        border: 0;
        border-radius: var(--r-md);
        background: transparent;
        color: var(--text-muted);
        font-size: var(--fs-lg);
        cursor: pointer;
        flex-shrink: 0;
        transition: background-color 0.15s ease, color 0.15s ease;
    }
    .nav-toggle:hover, body.nav-open .nav-toggle { background-color: var(--surface); color: var(--text); }

    /* The drawer slides in below the top bar. visibility keeps the closed menu out of the tab order. */
    .nav-sidebar {
        position: fixed;
        top: calc(var(--topbar-height) + var(--frame-gap));
        bottom: 0;
        left: 0;
        width: min(320px, 86vw);
        z-index: 1500;
        transform: translateX(-100%);
        visibility: hidden;
        transition: transform 0.2s ease, visibility 0s linear 0.2s;
        box-shadow: 0 0 40px rgba(0, 0, 0, 0.6);
        padding-bottom: calc(var(--sp-5) + env(safe-area-inset-bottom));
    }
    body.nav-open .nav-sidebar { transform: none; visibility: visible; transition: transform 0.2s ease; }
    .nav-backdrop {
        position: fixed;
        inset: calc(var(--topbar-height) + var(--frame-gap)) 0 0 0;
        z-index: 1400;
        background-color: rgba(0, 0, 0, 0.6);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.2s ease;
    }
    body.nav-open .nav-backdrop { display: block; opacity: 1; pointer-events: auto; }
    .nav-backdrop { display: block; }

    .content-area { padding: var(--sp-5) var(--sp-5) var(--sp-7); }
    .module-tabs { gap: var(--sp-4); }
}

/* --- Phone ------------------------------------------------------------------------------------------ */
@media (max-width: 640px) {
    .top-bar { padding-right: max(var(--sp-3), env(safe-area-inset-right)); }
    .brand-text > span:not(.brand-mascot-wrap) { display: none; }   /* keep the short wordmark (and the robot head) only */
    .right-control-box { gap: var(--sp-2); }
    .bot-pill-state { font-size: var(--fs-xs); }

    .content-area { padding: var(--sp-4) var(--sp-4) var(--sp-6); }

    .feature-header { flex-direction: column; align-items: flex-start; gap: var(--sp-3); margin-bottom: var(--sp-4); }
    .feature-header-text h1 { font-size: var(--fs-lg); }
    .feature-box-header { padding: var(--sp-4); gap: var(--sp-3); }
    .feature-box-body { padding: 0 var(--sp-4) var(--sp-4); }
    .feature-box-summary { display: none !important; }   /* no room next to title and caret */

    .module-grid { grid-template-columns: 1fr; }
    .module-card { padding: var(--sp-4); }
    .module-section-title { font-size: var(--fs-md); }
    .meter-grid { grid-template-columns: 1fr 1fr; }
    .well { padding: var(--sp-3); }

    /* Overview band: status line wraps its link below, tiles stay 2 x 2 with tighter padding */
    .ov { margin-bottom: var(--sp-6); }
    .ov-status { padding: var(--sp-4); gap: var(--sp-3); margin-bottom: var(--sp-3); }
    .ov-checks { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }   /* phone: two columns, same width */
    .ov-check { display: grid; grid-template-columns: 8px minmax(0, 1fr); align-content: start; column-gap: var(--sp-2); row-gap: 2px; white-space: normal; }   /* dot and name, the value always in a second line below the name */
    .ov-check-value { grid-column: 2; }
    .ov-status:not([data-level="ok"]) .ov-status-link { display: none; }   /* phone: every listed hint links to its place itself; no accidental taps on the card */
    .ov-tiles { gap: var(--sp-3); margin-bottom: var(--sp-3); }
    .ov-tile { padding: var(--sp-4); }
    .ov-tile-value { font-size: var(--fs-md); margin-top: var(--sp-2); }
    .ov-strip { margin-top: var(--sp-2); }
    .ov-activity-row { align-items: flex-start; }
    .ov-activity-row .ov-dot { margin-top: 6px; }
    .ov-activity-text { flex-direction: column; }
    .ov-activity-area { margin: var(--sp-1) 0 0; align-self: flex-start; min-width: 0; }
    .ov-activity-time { align-self: flex-start; padding-top: 2px; }

    /* Change log: the time moves below the entry */
    .change-row { flex-direction: column; gap: var(--sp-2); }
    .change-meta { flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: 0; text-align: left; }
    .change-time::before { content: "\00b7"; margin: 0 var(--sp-2); }   /* middle dot between person and time */
    .change-time { white-space: normal; }
    .log-window { height: 320px; }

    /* Popups become bottom-aligned sheets with full-width buttons */
    .modal-overlay { align-items: flex-end; }
    .modal-box { width: 100%; max-width: 100%; border-radius: var(--r-lg) var(--r-lg) 0 0; max-height: 90%; padding-bottom: env(safe-area-inset-bottom); }
    .modal-header { padding: var(--sp-4) var(--sp-4) var(--sp-2); }
    .modal-body { padding: var(--sp-2) var(--sp-4) var(--sp-4); }
    .modal-footer { padding: var(--sp-3) var(--sp-4); flex-direction: column-reverse; }   /* main action on top, cancel below */
    .modal-footer .btn { width: 100%; }
    .modal-box.has-mascot { grid-template-columns: minmax(0, 1fr); }
    .modal-box.has-mascot > .modal-mascot { grid-column: 1; grid-row: 1; width: 56px; margin: var(--sp-4) var(--sp-4) 0; }
    .modal-box.has-mascot > .modal-header { grid-column: 1; grid-row: 2; }
    .modal-box.has-mascot > .modal-body { grid-column: 1; grid-row: 3; }
    .modal-box.has-mascot > .modal-footer { grid-column: 1; grid-row: 4; }

    .panel { margin: var(--sp-5) auto; padding: var(--sp-5); }
    /* Sign-in page: the login button of the top bar is dropped (the main one is right there); smaller heading. */
    .public-login { display: none; }
    .public-footer-links .public-link { padding: 0 6px; font-size: var(--fs-xs); letter-spacing: 0.02em; }
    .login-logo { margin-bottom: var(--sp-6); }
    .login-mascot { margin-bottom: var(--sp-4); }
    .toolbar .btn, .action-row .btn { flex: 1 1 auto; }
}

/* --- Very narrow phones (iPhone SE / mini, small Android) ------------------------------------------- */
@media (max-width: 400px) {
    .bot-pill-state { display: none; }               /* the dot alone still shows the state */
    .meter-grid { grid-template-columns: 1fr; }
}
@media (max-width: 340px) { .ov-tiles { grid-template-columns: 1fr; } }

/* --- Touch devices: tap targets and form text ---------------------------------------------------- */
@media (pointer: coarse) {
    .menu-item { padding-top: var(--sp-3); padding-bottom: var(--sp-3); }
    .menu-category.collapsible { padding-top: var(--sp-4); padding-bottom: var(--sp-3); }
    .btn, .button, .module-status-btn { min-height: 44px; }
    .module-tab { padding: var(--sp-3) 0; }
    .dropdown-item { min-height: 44px; }
    .notification-bell, .user-profile { min-width: 40px; min-height: 40px; }
    .input, .select, .textarea, input, select, textarea { font-size: var(--fs-md); }   /* >= 16px: iOS does not zoom */
    .toggle-track { min-height: 24px; }
}

/* ------------------------------------------------------------------------------
   Sub tabs (08.10.2026, Design Guide rule 59): the ONE look for every second row of tabs below the main tabs
   (.module-tabs): Akten (Aktuell / Archiv / Papierkorb), Regelwerke and Einbettung of Mod & Verwarnungen, Einbettung
   of the Chatprotokoll. Small boxes WITHOUT a running line, so they read as one level below the main tabs (text on the
   grey line); the active box gets the orange underline. Optional count or note in .subtab-count.
   Markup: <nav class="subtabs"><a class="subtab active" href="...">Name <span class="subtab-count">3</span></a></nav>
   ------------------------------------------------------------------------------ */
.subtabs { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-5); }
.subtab {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    font-size: var(--fs-xs);
    color: var(--text-muted);
    background-color: var(--surface-2);   /* one step lighter than the cards, so the boxes stand out from the page */
    border-radius: var(--r-md) var(--r-md) 0 0;   /* rounded top, the bottom keeps the orange underline straight (rule 151) */
    border-bottom: 2px solid transparent;
    text-decoration: none;
}
.subtab:hover { color: var(--text); background-color: var(--surface-3); }
.subtab.active { color: var(--text); border-bottom-color: var(--orange); }
.subtab-count { color: var(--text-dim); }
.subtab.active .subtab-count { color: var(--text-muted); }

/* Help section at the bottom of a page (08.10.2026, design guide rule 69, chosen by the project owner from four
   drafts: "Entwurf C"). The guide cards stay exactly as they are (flat, collapsed); only a thin grey line and the muted
   title "Hilfe zu dieser Seite" separate them from the content above. Introduced in the Akten first; every other page
   with guides takes over the same markup:
     <section class="help-section"><h2 class="help-section-title">Hilfe zu dieser Seite</h2> ...cards... </section> */
.help-section { margin-top: var(--sp-7); padding-top: var(--sp-5); border-top: 1px solid var(--line); }
.help-section-title { margin: 0 0 var(--sp-4); font-size: var(--fs-md); font-weight: 700; color: var(--text-muted); letter-spacing: normal; text-transform: none; }
/* Text of the guide cards on every page (same look as .att-explain of the plugin pages, so System etc. match). */
.help-section .att-explain p { font-size: var(--fs-sm); color: var(--text-muted); max-width: 90ch; line-height: 1.55; }
.help-section .att-explain p + p { margin-top: var(--sp-3); }
.help-section .att-explain strong { color: var(--text); }


/* Two-factor page (12.10.2026, design guide rule 130, wish of the project owner: "etwas hübscher, mit Roboter"):
   one card in two halves - left the robot in front of the closed hatch ("no-access") on the space of the sign-in page,
   right the explanation with three numbered steps, the state of the account and the two buttons. Stacks on phones. */
.tf-card { display: grid; grid-template-columns: minmax(260px, 2fr) 3fr; max-width: 980px; margin: var(--sp-6) auto; background-color: var(--surface); border: 1px solid var(--card-border); border-radius: var(--r-lg); overflow: hidden; }
.tf-visual { position: relative; display: flex; align-items: center; justify-content: center; padding: var(--sp-7) var(--sp-5);
    background: linear-gradient(180deg, rgba(14, 15, 17, 0.25) 0%, rgba(14, 15, 17, 0.75) 100%), url("/assets/branding/mascot/login-space.jpg") center / cover no-repeat; }
.tf-visual .mascot { width: 230px; }
.tf-visual-tag { position: absolute; left: var(--sp-4); bottom: var(--sp-4); display: inline-flex; align-items: center; gap: var(--sp-2); padding: var(--sp-1) var(--sp-3); font-size: var(--fs-xs); letter-spacing: 0.08em; text-transform: uppercase; color: var(--text); background-color: rgba(14, 15, 17, 0.7); border-radius: var(--r-pill); }
.tf-body { padding: var(--sp-6); display: flex; flex-direction: column; gap: var(--sp-4); }
.tf-eyebrow { font-size: var(--fs-xs); letter-spacing: 0.12em; text-transform: uppercase; color: var(--orange); }
.tf-title { font-size: var(--fs-lg); font-weight: 400; letter-spacing: 0.04em; text-transform: uppercase; line-height: 1.3; margin: 0; }
.tf-lead { font-size: var(--fs-sm); color: var(--text-muted); line-height: 1.55; margin: 0; }
.tf-account { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); padding: var(--sp-3) var(--sp-4); background-color: var(--well); border-radius: var(--r-md); font-size: var(--fs-sm); color: var(--text-muted); }
.tf-account strong { color: var(--text); font-weight: 700; }
.tf-state { display: inline-flex; align-items: center; gap: var(--sp-2); margin-left: auto; padding: 2px var(--sp-2); font-size: var(--fs-xs); color: var(--warn); background-color: rgba(241, 196, 15, 0.12); border-radius: var(--r-pill); }
.tf-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); counter-reset: tf-step; }
.tf-steps li { display: grid; grid-template-columns: 32px 1fr; gap: var(--sp-3); align-items: start; padding: var(--sp-3); background-color: var(--surface-2); border-radius: var(--r-md); font-size: var(--fs-sm); color: var(--text-muted); line-height: 1.5; counter-increment: tf-step; }
.tf-steps li::before { content: counter(tf-step); display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; font-weight: 700; color: var(--orange); background-color: var(--orange-soft); border-radius: 50%; }
.tf-steps li strong { color: var(--text); }
.tf-actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-2); }
.tf-note { display: flex; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--text-muted); line-height: 1.5; margin: 0; }
.tf-note .icon { flex: none; margin-top: 2px; }
/* Since 12.10.2026 evening the page stands alone (whole dashboard needs the two-factor): no menu, the card centred on the
   sign-in stage, the signed-in name and "Abmelden" in the top bar. */
.tf-page .login-stage { align-items: flex-start; padding-bottom: var(--sp-6); }
.tf-page .tf-card { width: 100%; margin: auto; }   /* auto margins centre it without cutting the top when it is taller than the stage */
.tf-top-user { font-size: var(--fs-sm); color: var(--text-muted); max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tf-top-logout { padding: calc(var(--sp-2) + 0.115em) var(--sp-3) calc(var(--sp-2) - 0.115em); }   /* optical centring, rule 154 */
@media (max-width: 899px) {
    .tf-card { grid-template-columns: 1fr; margin: var(--sp-4) auto; }
    .tf-visual { padding: var(--sp-6) var(--sp-4); }
    .tf-visual .mascot { width: 170px; }
    .tf-body { padding: var(--sp-5) var(--sp-4); }
    .tf-state { margin-left: 0; }
    .tf-top-user { display: none; }
}

/* Confidential ticket (12.10.2026 evening, design guide rule 137): a ticket whose topic is restricted (e.g. a complaint
   about the moderation) carries this tag next to its topic in the ticket list, the queue, the ticket page and the archive. */
.conf-tag { display: inline-flex; align-items: center; gap: 4px; margin-left: var(--sp-2); padding: 1px var(--sp-2); font-size: var(--fs-tag); letter-spacing: 0.06em; text-transform: uppercase; font-weight: 700; vertical-align: middle; background-color: var(--orange-soft); color: var(--orange); border-radius: var(--r-pill); white-space: nowrap; }
.conf-tag .icon { width: 1.1em; height: 1.1em; }
