/* Bundled board fonts. SIL OFL 1.1 -- licences ship beside the files in wwwroot/fonts/.
   Served from the app itself, never a CDN: a store runs offline, and a font that fails to load is a
   board that silently renders in the wrong typeface.
   Paths are relative to this stylesheet's own URL (this file ships from the RCL's static web assets
   at _content/BetterPickUp.WebUI/webui.css), matching the precedent set by Geist-Regular.woff2 in
   betterpickup-shadcn.css -- NOT prefixed with _content/BetterPickUp.WebUI/, which would double up. */
@font-face {
    font-family: 'Geist';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('fonts/Geist[wght].woff2') format('woff2');
}
@font-face {
    font-family: 'Geist';
    font-style: italic;
    font-weight: 100 900;
    font-display: swap;
    src: url('fonts/Geist-Italic[wght].woff2') format('woff2');
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/inter-400.woff2') format('woff2');
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('fonts/inter-700.woff2') format('woff2');
}
@font-face {
    font-family: 'Roboto';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/roboto-400.woff2') format('woff2');
}
@font-face {
    font-family: 'Roboto';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('fonts/roboto-700.woff2') format('woff2');
}
@font-face {
    font-family: 'Open Sans';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/open-sans-400.woff2') format('woff2');
}
@font-face {
    font-family: 'Open Sans';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('fonts/open-sans-700.woff2') format('woff2');
}
@font-face {
    font-family: 'Source Sans 3';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/source-sans-400.woff2') format('woff2');
}
@font-face {
    font-family: 'Source Sans 3';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('fonts/source-sans-700.woff2') format('woff2');
}

.fw-bold {
    font-weight: bold !important;
}

.text-muted {
    color: var(--mud-palette-action-default) !important;
}
.center {
    text-align: center;
}

.logo-avatar {
    object-fit: contain;
    background-color: var(--mud-palette-surface);
    padding: 0.25rem;
}

.logo-avatar--lg {
    width: 120px;
    height: 120px;
    border-radius: 0.5rem;
}

.logo-avatar--sm {
    width: 40px;
    height: 40px;
    border-radius: 4px;
}

.app-nav-drawer {
    background-color: color-mix(in srgb, var(--mud-palette-surface) 94%, var(--mud-palette-text-primary));
    border-right: 1px solid var(--mud-palette-lines-default);
}



.home-card {
    cursor: pointer;
    transition: box-shadow 120ms ease, transform 120ms ease;
}

.home-card:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
}

.app-theme-dark .home-card:hover {
    box-shadow: 0 6px 18px rgba(255, 255, 255, 0.10);
}

.home-card:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   Order card chrome.

   The card's colours (fill, text, border, corner radius, and the per-status
   accent stripe) are no longer literals here — they used to be, first as
   hard-coded Material rgba() values duplicated between here and
   ControlPanelPageContent.razor.css, then as a set of theme-derived per-status
   card classes. Both were replaced by BPU-17: the effective design comes from
   the control panel's settings document and is turned into an inline style by
   ControlPanelDesignCss.Card. This file only owns the border geometry that is
   NOT part of that design (width/style of the accent stripe) and layout, not
   colour.

   Colour is never the only cue: the status is always rendered with its label.
   --------------------------------------------------------------------------- */

.order-card {
    border-left-width: 4px;
    border-left-style: solid;
}

/* Controls on the card take the CARD's colour, not the theme's (BPU-127).

   The card's fill and text are the operator's choice; the buttons and chips on it came from the
   MudBlazor palette. In the light theme the two happened to agree. In the dark theme the palette's
   primary is near-white, the card's default fill is white, and the day's work — "In Bearbeitung" —
   measured 1.00 : 1 against the surface it sits on. Invisible, on the one screen that is touched all
   day.

   `inherit` rather than a named colour: the card already carries `color: {cardFontColor}` inline, so
   this follows whatever the operator chose, including a fill nobody has thought of yet.

   The error button is deliberately NOT in this list. Red is the one colour on the card that means
   something, and it must not become the card's text colour. */
.order-card .mud-button-text-primary,
.order-card .mud-button-text-default,
.order-card .mud-icon-button:not(.mud-error-text),
.order-card .mud-chip-color-default {
    color: inherit;
}

.order-card .mud-chip-outlined.mud-chip-color-default {
    border-color: currentColor;
}

/* The name is the card's subject — what staff read from arm's length and call out. */
.order-card-name {
    overflow-wrap: anywhere;
}

.order-card-on-the-way {
    color: var(--mud-palette-info);
}

.order-column-content {
    max-height: 60vh;
    overflow-y: auto;
}

/* ControlPanel Tab view: a flex column filling the viewport below the app bar. The card area
   scrolls; the status tab bar stays pinned to the bottom of the screen. `dvh` tracks the mobile
   browser chrome so the bar isn't hidden behind a bottom URL bar, and `env(safe-area-inset-bottom)`
   clears the home indicator. The subtracted `2rem` is MudMainContent's `pa-4` (top + bottom). */
.cp-tabview-root {
    /* Anchored to the viewport from just under the app bar to the bottom, so the pinned tab bar sits
       at the true bottom regardless of the layout's content-offset hacks. Sidesteps computing that
       offset (auto appbar padding + per-layout margin-top + page padding), which was pushing the bar
       below the fold. */
    position: fixed;
    top: 3rem;
    left: 0;
    right: 0;
    bottom: 0;
    box-sizing: border-box;
    /* No horizontal padding: the tab bar must reach both viewport edges. Horizontal breathing room
       is applied to the inner content (toolbar, cards) instead. */
    padding: 0.5rem 0 0 0;
    display: flex;
    flex-direction: column;
    min-height: 0;

    /* The panel's own page colour, which otherwise never paints (BPU-127). MudMainContent carries it
       inline — but this root is `position: fixed`, so main content has no in-flow child left, its box
       collapses to nothing, and it paints a background nobody can see. The TEXT colour still arrives,
       because inheritance follows the DOM and not the box: that is how the lane title ended up as the
       panel's dark ink on the app theme's dark page, at 1.02 : 1.

       `inherit` keeps one source of truth. No design configured means main content is transparent,
       this is transparent, and the board looks exactly as it did. */
    background-color: inherit;
}

.control-panel-tab-title {
    flex: 0 0 auto;
    font-weight: 600;
    font-size: 2rem;
    line-height: 1.2;
    margin-bottom: 0.5rem;
}

@media (min-width: 1280px) {
    .control-panel-tab-title {
        font-size: 2.375rem;
    }
}

@media (min-width: 1920px) {
    .control-panel-tab-title {
        font-size: 2.75rem;
    }
}

.cp-tabview-toolbar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
    padding-left: 1rem;
    padding-right: 1rem;
}

.cp-tabview-search {
    flex: 1 1 auto;
}

.cp-loading-bar {
    flex: 0 0 auto;
    height: 4px;
    margin-bottom: 0.5rem;
}

/* MudTabs fills the remaining height; its panels scroll and the tab bar is pinned at the bottom
   (Position.Bottom => .mud-tabs-reverse => panels above, tabbar below in the column). */
.control-panel-tab-view.mud-tabs {
    flex: 1 1 auto;
    min-height: 0;

    /* Die Seitenfarbe eine Ebene weiterreichen (BPU-138). `inherit` an der Leiste nimmt den Wert des
       ELTERNELEMENTS, und das ist diese Komponente — ohne die Zeile hier ist sie durchsichtig, die
       Leiste erbt Durchsichtigkeit, und die Karten scheinen hindurch. Beim Messen aufgefallen, nicht
       beim Ansehen: `rgba(0, 0, 0, 0)` gegen `rgb(255, 255, 255)` der Seite. */
    background-color: inherit;
}

.control-panel-tab-view .mud-tabs-panels {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding-left: 0.75rem;
    padding-right: 0.75rem;
}

/* MudBlazor sizes the tabs (MinimumTabWidth=min(20vw,120px)); the bar is capped at 600px and centred.
   align-self:center centers a shrink-to-content flex item in the column (margin:auto does not, since a
   stretched item has no free space to absorb). */
.control-panel-tab-view .mud-tabs-tabbar {
    flex: 0 0 auto;
    align-self: center;
    max-width: 100%;
    padding-bottom: env(safe-area-inset-bottom, 0px);

    /* Die Leiste ist eine Ebene ueber der Liste, nicht ihr Ende (BPU-138). Sie ist am unteren Rand
       verankert, die Karten scrollen unter ihr durch — ohne Abgrenzung klebte die letzte Karte an den
       Reitern.

       Der Hintergrund wird GEERBT und nicht gesetzt: die Seitenfarbe gehoert seit BPU-17 dem
       Betreiber, und eine Leiste in eigener Fuellung wuerde mit jeder gewaehlten Farbe streiten. Die
       Abgrenzung kommt deshalb aus Kante und Schatten. Beide aus currentColor beziehungsweise
       Schwarz mit geringer Deckung — das traegt in hellem wie dunklem Thema und ueber jeder
       Seitenfarbe, ohne einen zweiten Farbton einzufuehren. */
    background-color: inherit;
    border-top: 1px solid currentColor;
    box-shadow: 0 -0.5rem 1rem -0.5rem rgba(0, 0, 0, 0.35);
}

/* Die Haarlinie soll andeuten, nicht trennen. currentColor waere in voller Deckung ein Strich quer
   ueber den Bildschirm; als Rahmenfarbe mit Alpha bleibt sie eine Kante. */
.control-panel-tab-view .mud-tabs-tabbar {
    border-top-color: rgba(128, 128, 128, 0.25);
}

/* Der Zähler sitzt in der oberen rechten Ecke des REITERS (BPU-133).

   Diese Regel stammt aus BPU-113 und hängte ihn an die Ecke des SYMBOLS — richtig, solange ein Reiter
   nur aus einem Symbol bestand. Seit BPU-128 steht darunter ein Wort, und derselbe Bezugspunkt legte
   den Zähler zwischen beide: gemessen 63 px unter der Oberkante eines 84 px hohen Reiters, mitten im
   Wort.

   MudBlazor legt ZWEI Umschläge um das Symbol, und beide müssen aufhören, ein Bezugsrahmen zu sein:
   `.mud-badge-wrapper` und darüber `.mud-badge-root`. Nur den ersten still zu stellen genügt nicht —
   der Zähler zählt dann seine vier Pixel von der Kante des zweiten, also weiterhin vom Symbol.
   Gemessen, nachdem der erste Versuch ihn noch weiter nach unten geschoben hatte. `!important`,
   weil MudBlazors `.mud-badge.mud-badge-bottom.right` spezifischer ist als dieser Selektor. */
/* Der Zähler an die obere rechte Ecke des SYMBOLS (BPU-134).

   Zweimal danebengegriffen, bevor die Messung es zeigte: nicht der Zähler wird verschoben, sondern
   sein UMSCHLAG. `.mud-badge` sitzt vier Pixel über der Kante von `.mud-badge-wrapper` — das stimmte
   die ganze Zeit —, und der Umschlag selbst wird von MudBlazor unterhalb des Symbols platziert. Wer
   nur am Zähler zieht, verschiebt ihn relativ zu einem Rahmen, der schon am falschen Ort steht. */
/* Der Anker, nicht der Zähler. `.mud-badge-root` ist ein leeres Element ohne Höhe, und seit die
   Reiter eine Spalte sind (BPU-128), ist es das dritte Element der Spalte — unter Symbol UND Wort,
   gemessen bei y=766 in einem Reiter, der bei 695 beginnt. Alles, was daran hängt, landet dort.

   Deshalb wird der Anker aus dem Fluss genommen und über das Symbol gelegt: `left: 50%` trifft die
   Mitte des Reiters, an der das Symbol zentriert steht, und der halbe Symbolabstand schiebt ihn an
   dessen rechte obere Ecke — bei jeder Reiterbreite, ob 75 px am Telefon oder 200 am Schreibtisch. */
.cp-tabview-root .mud-tabs .mud-tab .mud-badge-root {
    position: absolute;
    top: 0.25rem;
    left: 50%;
    margin-left: 0.625rem;
    height: 0;
}

.cp-tabview-root .mud-tabs .mud-tab .mud-badge-wrapper {
    inset: 0 !important;
    transform: none !important;
}

.cp-tabview-root .mud-tabs .mud-tab .mud-badge {
    inset: 0 !important;
    transform: none !important;
}

/* Add-order FAB: bottom-left, floated above the pinned tab bar and the safe area. The app-wide
   scroll-to-top FAB lives bottom-right, so the two never collide. */
.cp-tabview-fab {
    position: fixed;
    left: 1rem;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 4.5rem);
    z-index: 1100;
}


/* ---------------------------------------------------------------------------
   Monitor board (guest-facing, full screen, no chrome).
   Sizes are in vw/vh so the same markup fills a 24" counter screen and a 65"
   wall panel without a breakpoint.
   --------------------------------------------------------------------------- */

.monitor-root {
    position: fixed;
    inset: 0;
    color: #fff;
    overflow: hidden;
    font-variant-numeric: tabular-nums;

    /* A hand's width off the bezel. Without it the headings and the outer tiles sit flush against
       the edge of the screen, which on a wall-mounted display reads as a cropped picture rather
       than a designed one. box-sizing so the inset:0 above still fills the screen exactly. */
    padding: 10px;
    box-sizing: border-box;
}

.monitor-columns {
    display: grid;
    height: 100%;
    box-sizing: border-box;
}

/* auto-fit + a zero minimum collapses empty tracks: two sections get two equal columns, but when a
   group is hidden (ShowPreparing/ShowReady false) and only one <section> renders, the grid quietly
   becomes one column instead of leaving an empty half. */
.monitor-columns.two-col { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); }

/* One column means the two lists STACK, not that the ready list disappears. Ready goes on top: it is
   the only thing the guest is actually waiting for. */
/* Halves, not auto: a section whose height comes from its content gives .monitor-tiles below nothing
   definite to fit its rows into, and the stacked board goes back to overflowing the screen. */
.monitor-columns.one-col {
    grid-template-columns: 1fr;
    grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
}

.monitor-columns.one-col .monitor-col-ready { order: 1; }
.monitor-columns.one-col .monitor-col-preparing { order: 2; }

/* 3vh base for the .monitor-box heading below: MonitorStyleCss writes an inline
   font-size:{FontScalePercent}% onto the <h2>, and a percentage resolves against the PARENT, not the
   element itself. This is that base - see the comment on .monitor-box before "fixing" it back there. */
.monitor-col {
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
    font-size: 3vh;
}

.monitor-box {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 0.5em;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 1vh 1.5vh;
    margin: 0 0 1.5vh 0;
    text-align: center;
    /* font-size deliberately NOT set here: MonitorStyleCss writes an inline font-size:{FontScalePercent}%
       on this element, and a percentage resolves against the PARENT. The responsive base therefore lives
       on .monitor-col above - putting a vh size here too would simply be overridden by the inline style
       and the scale would be dead (this is exactly the bug BPU-19 fixed: font-size:100% resolving
       against nothing but the browser's 16px default). */
}

.monitor-box-lines {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15em;
    min-width: 0;
}

.monitor-box-image {
    flex: 0 0 auto;
    height: 1.6em;
    width: auto;
    max-width: 30%;
    object-fit: contain;
}

.monitor-box-sup {
    font-size: 0.42em;
    font-weight: 500;
    letter-spacing: 0.04em;
    text-transform: none;
    opacity: 0.75;
    line-height: 1.2;
}

.monitor-box-text {
    line-height: 1.1;
}

/* The measuring container, and the reason it is a separate element from the grid it wraps: an element
   with container-type:size cannot answer its OWN cq queries, and a font-size in cqh on the container
   itself is a circular dependency that hangs the renderer outright (it did). flex-basis is 0, not auto,
   for the same family of reason - a basis taken from content would let the tiles size the box that is
   supposed to be sizing them. */
.monitor-tiles-fit {
    flex: 1 1 0;
    min-height: 0;
    container-type: size;
}

.monitor-tiles {
    display: grid;
    height: 100%;
    gap: 1.2vh;
    /* The configured rows ARE the layout, not just the cap on how many tiles get sent. Fixed 1fr tracks
       are what stop the list from growing past the bottom of its .monitor-col, and what stop one tile
       with a larger inline FontScalePercent (the just-ready highlight) from pushing its neighbours. */
    grid-template-rows: repeat(var(--monitor-rows, 1), minmax(0, 1fr));

    /* 8vh base for .monitor-tile below - same reasoning as .monitor-col/.monitor-box above. It is also
       the fallback: a browser without container query units keeps the old fixed size rather than none. */
    font-size: 8vh;
    /* ...but the base a row-built grid needs is the row's own height, so a 100% scale means "fills its
       row" instead of "8vh, whatever the row turned out to be". 1.35 leaves the 1.3 line-height its
       room; the gaps are taken off the top because they are not the rows' to spend. */
    font-size: calc((100cqh - (var(--monitor-rows, 1) - 1) * 1.2vh) / var(--monitor-rows, 1) / 1.35);
}

.monitor-tile {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1.5vw;
    font-weight: 700;
    line-height: 1.3;
    text-align: center;
    /* font-size deliberately NOT set here: MonitorStyleCss writes an inline
       font-size:{FontScalePercent}% on this element, and a percentage resolves against the
       PARENT. The responsive base therefore lives on .monitor-tiles - putting a vh size here
       too would simply be overridden by the inline style and the scale would be dead. */
}

.monitor-tile-ready { color: #4ade80; }

.monitor-columns.lanes .monitor-tile-ready {
    justify-content: space-between;
    padding-left: 1.5vw;
    padding-right: 1.5vw;
}

.monitor-destination {
    font-size: 0.7em;
    font-weight: 600;
    opacity: 0.85;
    white-space: nowrap;
}

.monitor-tile-ready.is-just-ready { animation: monitor-pulse 1.2s ease-in-out 3; }

.monitor-overflow {
    font-size: 2.5vh;
    opacity: 0.55;
    margin-top: 1.5vh;
}

.monitor-notice {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #0b0b0d;
    text-align: center;
    padding: 4vh 4vw;
}

.monitor-notice-text {
    font-size: 5vh;
    font-weight: 600;
}

/* Colour-blind mode drops the green/grey cue entirely. What carries the status is the column and the
   heading over it - the same thing that carries it in normal mode, which is why dropping the colour
   here costs the guest nothing. */
.monitor-root.cb-safe .monitor-tile-ready { color: #fff; }

@keyframes monitor-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
    .monitor-tile-ready.is-just-ready { animation: none; outline: 0.4vh solid currentColor; outline-offset: 0.6vh; }
}

/* ------------------------------------------------------------------------------------------------
   Banter loader (Uiverse.io by Nawsome). Drop-in loading animation used in place of the old spinner.
   The wrapper is what gives the absolutely-positioned loader its height and centres it, so the
   component can be dropped into any loading slot. Box colour tracks the MudBlazor theme primary
   (the original #fff was invisible on light backgrounds).
   ------------------------------------------------------------------------------------------------ */
.banter-loader-wrap {
  position: relative;
  width: 100%;
  min-height: 160px;
}

.banter-loader {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 72px;
  height: 72px;
  margin-left: -36px;
  margin-top: -36px;
}

.banter-loader__box {
  float: left;
  position: relative;
  width: 20px;
  height: 20px;
  margin-right: 6px;
}

.banter-loader__box:before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: var(--mud-palette-primary, #18181B);
}

.banter-loader__box:nth-child(3n) {
  margin-right: 0;
  margin-bottom: 6px;
}

.banter-loader__box:nth-child(1):before, .banter-loader__box:nth-child(4):before {
  margin-left: 26px;
}

.banter-loader__box:nth-child(3):before {
  margin-top: 52px;
}

.banter-loader__box:last-child {
  margin-bottom: 0;
}

@keyframes moveBox-1 {
  9.0909090909% { transform: translate(-26px, 0); }
  18.1818181818% { transform: translate(0px, 0); }
  27.2727272727% { transform: translate(0px, 0); }
  36.3636363636% { transform: translate(26px, 0); }
  45.4545454545% { transform: translate(26px, 26px); }
  54.5454545455% { transform: translate(26px, 26px); }
  63.6363636364% { transform: translate(26px, 26px); }
  72.7272727273% { transform: translate(26px, 0px); }
  81.8181818182% { transform: translate(0px, 0px); }
  90.9090909091% { transform: translate(-26px, 0px); }
  100% { transform: translate(0px, 0px); }
}

.banter-loader__box:nth-child(1) { animation: moveBox-1 4s infinite; }

@keyframes moveBox-2 {
  9.0909090909% { transform: translate(0, 0); }
  18.1818181818% { transform: translate(26px, 0); }
  27.2727272727% { transform: translate(0px, 0); }
  36.3636363636% { transform: translate(26px, 0); }
  45.4545454545% { transform: translate(26px, 26px); }
  54.5454545455% { transform: translate(26px, 26px); }
  63.6363636364% { transform: translate(26px, 26px); }
  72.7272727273% { transform: translate(26px, 26px); }
  81.8181818182% { transform: translate(0px, 26px); }
  90.9090909091% { transform: translate(0px, 26px); }
  100% { transform: translate(0px, 0px); }
}

.banter-loader__box:nth-child(2) { animation: moveBox-2 4s infinite; }

@keyframes moveBox-3 {
  9.0909090909% { transform: translate(-26px, 0); }
  18.1818181818% { transform: translate(-26px, 0); }
  27.2727272727% { transform: translate(0px, 0); }
  36.3636363636% { transform: translate(-26px, 0); }
  45.4545454545% { transform: translate(-26px, 0); }
  54.5454545455% { transform: translate(-26px, 0); }
  63.6363636364% { transform: translate(-26px, 0); }
  72.7272727273% { transform: translate(-26px, 0); }
  81.8181818182% { transform: translate(-26px, -26px); }
  90.9090909091% { transform: translate(0px, -26px); }
  100% { transform: translate(0px, 0px); }
}

.banter-loader__box:nth-child(3) { animation: moveBox-3 4s infinite; }

@keyframes moveBox-4 {
  9.0909090909% { transform: translate(-26px, 0); }
  18.1818181818% { transform: translate(-26px, 0); }
  27.2727272727% { transform: translate(-26px, -26px); }
  36.3636363636% { transform: translate(0px, -26px); }
  45.4545454545% { transform: translate(0px, 0px); }
  54.5454545455% { transform: translate(0px, -26px); }
  63.6363636364% { transform: translate(0px, -26px); }
  72.7272727273% { transform: translate(0px, -26px); }
  81.8181818182% { transform: translate(-26px, -26px); }
  90.9090909091% { transform: translate(-26px, 0px); }
  100% { transform: translate(0px, 0px); }
}

.banter-loader__box:nth-child(4) { animation: moveBox-4 4s infinite; }

@keyframes moveBox-5 {
  9.0909090909% { transform: translate(0, 0); }
  18.1818181818% { transform: translate(0, 0); }
  27.2727272727% { transform: translate(0, 0); }
  36.3636363636% { transform: translate(26px, 0); }
  45.4545454545% { transform: translate(26px, 0); }
  54.5454545455% { transform: translate(26px, 0); }
  63.6363636364% { transform: translate(26px, 0); }
  72.7272727273% { transform: translate(26px, 0); }
  81.8181818182% { transform: translate(26px, -26px); }
  90.9090909091% { transform: translate(0px, -26px); }
  100% { transform: translate(0px, 0px); }
}

.banter-loader__box:nth-child(5) { animation: moveBox-5 4s infinite; }

@keyframes moveBox-6 {
  9.0909090909% { transform: translate(0, 0); }
  18.1818181818% { transform: translate(-26px, 0); }
  27.2727272727% { transform: translate(-26px, 0); }
  36.3636363636% { transform: translate(0px, 0); }
  45.4545454545% { transform: translate(0px, 0); }
  54.5454545455% { transform: translate(0px, 0); }
  63.6363636364% { transform: translate(0px, 0); }
  72.7272727273% { transform: translate(0px, 26px); }
  81.8181818182% { transform: translate(-26px, 26px); }
  90.9090909091% { transform: translate(-26px, 0px); }
  100% { transform: translate(0px, 0px); }
}

.banter-loader__box:nth-child(6) { animation: moveBox-6 4s infinite; }

@keyframes moveBox-7 {
  9.0909090909% { transform: translate(26px, 0); }
  18.1818181818% { transform: translate(26px, 0); }
  27.2727272727% { transform: translate(26px, 0); }
  36.3636363636% { transform: translate(0px, 0); }
  45.4545454545% { transform: translate(0px, -26px); }
  54.5454545455% { transform: translate(26px, -26px); }
  63.6363636364% { transform: translate(0px, -26px); }
  72.7272727273% { transform: translate(0px, -26px); }
  81.8181818182% { transform: translate(0px, 0px); }
  90.9090909091% { transform: translate(26px, 0px); }
  100% { transform: translate(0px, 0px); }
}

.banter-loader__box:nth-child(7) { animation: moveBox-7 4s infinite; }

@keyframes moveBox-8 {
  9.0909090909% { transform: translate(0, 0); }
  18.1818181818% { transform: translate(-26px, 0); }
  27.2727272727% { transform: translate(-26px, -26px); }
  36.3636363636% { transform: translate(0px, -26px); }
  45.4545454545% { transform: translate(0px, -26px); }
  54.5454545455% { transform: translate(0px, -26px); }
  63.6363636364% { transform: translate(0px, -26px); }
  72.7272727273% { transform: translate(0px, -26px); }
  81.8181818182% { transform: translate(26px, -26px); }
  90.9090909091% { transform: translate(26px, 0px); }
  100% { transform: translate(0px, 0px); }
}

.banter-loader__box:nth-child(8) { animation: moveBox-8 4s infinite; }

@keyframes moveBox-9 {
  9.0909090909% { transform: translate(-26px, 0); }
  18.1818181818% { transform: translate(-26px, 0); }
  27.2727272727% { transform: translate(0px, 0); }
  36.3636363636% { transform: translate(-26px, 0); }
  45.4545454545% { transform: translate(0px, 0); }
  54.5454545455% { transform: translate(0px, 0); }
  63.6363636364% { transform: translate(-26px, 0); }
  72.7272727273% { transform: translate(-26px, 0); }
  81.8181818182% { transform: translate(-52px, 0); }
  90.9090909091% { transform: translate(-26px, 0); }
  100% { transform: translate(0px, 0); }
}

.banter-loader__box:nth-child(9) { animation: moveBox-9 4s infinite; }

.settings-section-header {
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--mud-palette-lines-default);
}

.panel-pin-screen {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 70vh;
    padding: 1rem;
}

.panel-pin-card {
    width: 100%;
    max-width: 24rem;
}

.panel-pin-dots {
    display: flex;
    gap: 0.75rem;
}

.panel-pin-dot {
    width: 1rem;
    height: 1rem;
    border-radius: 50%;
    border: 2px solid currentColor;
    opacity: 0.35;
}

.panel-pin-dot.is-filled {
    opacity: 1;
    background-color: currentColor;
}

.panel-pin-keypad {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.75rem;
    width: 100%;
}

.panel-pin-key {
    min-height: 3.5rem;
    font-size: 1.25rem;
}

.panel-pin-error {
    width: 100%;
}

.bpu-auth {
    display: grid;
    grid-template-columns: 1.05fr 1fr;
    min-height: 100vh;
}

.bpu-auth-brand {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 2rem;
    padding: 3rem;
    overflow: hidden;
    color: var(--mud-palette-text-primary);
    border-right: 1px solid var(--mud-palette-lines-default);
    background:
        radial-gradient(70% 70% at 82% 88%, color-mix(in srgb, var(--mud-palette-primary) 16%, transparent), transparent 60%),
        radial-gradient(60% 60% at 12% 8%, color-mix(in srgb, var(--mud-palette-primary) 9%, transparent), transparent 55%),
        radial-gradient(120% 120% at 15% 10%, var(--mud-palette-surface), transparent 60%),
        linear-gradient(160deg, var(--mud-palette-surface), var(--mud-palette-background));
}

.bpu-auth-brand::before {
    content: '';
    position: absolute;
    inset: 0;
    opacity: 0.5;
    pointer-events: none;
    background-image:
        linear-gradient(var(--mud-palette-lines-default) 1px, transparent 1px),
        linear-gradient(90deg, var(--mud-palette-lines-default) 1px, transparent 1px);
    background-size: 2.25rem 2.25rem;
    -webkit-mask-image: radial-gradient(80% 80% at 30% 20%, #000 30%, transparent 75%);
    mask-image: radial-gradient(80% 80% at 30% 20%, #000 30%, transparent 75%);
}

.bpu-auth-brand > * {
    position: relative;
    z-index: 1;
}

.bpu-auth-logo,
.bpu-auth-mobilelogo {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
    font-size: 1.0625rem;
}

.bpu-auth-logo {
    position: absolute;
    top: 3rem;
    left: 3rem;
}

.bpu-mark {
    flex: none;
    display: block;
    --bpu-mark-plate: var(--mud-palette-primary);
    --bpu-mark-ink: #FFFFFF;
}

.bpu-wordmark {
    letter-spacing: -0.021em;
    white-space: nowrap;
}

.bpu-appbar-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 1.0625rem;
    cursor: pointer;
}

.bpu-wordmark-light {
    font-weight: 400;
}

.bpu-wordmark-bold {
    font-weight: 700;
}

.bpu-auth-pitch {
    width: 100%;
    max-width: 27rem;
    margin-inline: auto;
}

.bpu-auth-claim {
    margin: 0 0 1rem;
    max-width: 22ch;
    font-size: 1.875rem;
    line-height: 1.25;
    font-weight: 600;
    letter-spacing: -0.02em;
}

.bpu-auth-lead {
    margin: 0;
    max-width: 38ch;
    color: var(--mud-palette-text-secondary);
}

.bpu-auth-points {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin: 1.75rem 0 0;
    padding: 0;
    list-style: none;
}

.bpu-auth-point {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    font-size: 0.875rem;
    line-height: 1.4;
    color: var(--mud-palette-text-secondary);
}

.bpu-auth-point .mud-icon-root {
    flex: none;
    margin-top: 0.0625rem;
    color: var(--mud-palette-success);
}

.bpu-auth-footnote {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--mud-palette-text-disabled);
}

.bpu-auth-form {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 2.5rem 1.5rem;
}

.bpu-auth-theme {
    position: absolute;
    top: 1.25rem;
    right: 1.25rem;
}

.bpu-auth-card {
    width: 100%;
    max-width: 23rem;
}

.bpu-auth-mobilelogo {
    display: none;
    margin-bottom: 1.75rem;
}

@media (max-width: 860px) {
    .bpu-auth {
        grid-template-columns: 1fr;
    }

    .bpu-auth-brand {
        display: none;
    }

    .bpu-auth-mobilelogo {
        display: inline-flex;
    }
}

/* The tenant switcher in the drawer (BPU-100). Shaped like a field rather than a toolbar button:
   it states the frame every entry below it is read in, so it has to look like something one reads
   as well as presses. */
.app-nav-tenant {
    padding: 0.75rem 0.75rem 0.25rem;
}

.app-nav-tenant .bpu-tenantsel {
    display: block;
    width: 100%;
}

.bpu-tenantsel-inline {
    width: min(22rem, 100%);
}

.bpu-tenantsel-inline .bpu-tenantsel {
    display: block;
    width: 100%;
}

.bpu-tenantsel-btn {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    width: 100%;
    text-align: left;
    padding: 0.5rem 0.625rem;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    cursor: pointer;
    transition: background-color 0.15s ease-out, border-color 0.15s ease-out;
}

.bpu-tenantsel-btn:hover {
    background: var(--mud-palette-action-default-hover);
}

.bpu-tenantsel-btn:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

/* One tenant: the same surface, without the affordance. */
.bpu-tenantsel-btn--static {
    cursor: default;
    background: transparent;
}

.bpu-tenantsel-btn--static:hover {
    background: transparent;
}

/* No tenant chosen is a state to notice, not an error to shout about. */
.bpu-tenantsel-btn.is-unset {
    border-color: var(--mud-palette-warning);
}

/* min-width on both levels — without it a flex child ignores its ellipsis. */
.bpu-tenantsel-text {
    display: flex;
    flex-direction: column;
    gap: 0.0625rem;
    min-width: 0;
    flex: 1;
}

.bpu-tenantsel-hint {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mud-palette-text-disabled);
    line-height: 1.2;
}

.bpu-tenantsel-name {
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bpu-tenantsel-icon,
.bpu-tenantsel-chevron {
    flex: none;
    color: var(--mud-palette-text-secondary);
}

.bpu-tenantsel-item-mark {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 4px;
    color: var(--mud-palette-text-secondary);
}

.bpu-tenantsel-chevron {
    font-size: 1.125rem;
}

.app-nav-heading {
    margin: 0;
    padding: 0.75rem 1rem 0.25rem;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--mud-palette-text-disabled);
}

.app-nav-divider {
    margin: 0.5rem 0 0;
    border-color: var(--mud-palette-lines-default);
}

.app-nav-divider-strong {
    margin-top: 1.5rem;
    border-top-width: 2px;
}

.bpu-legal-footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: 1.5rem 1rem 1rem;
    font-size: 0.8125rem;
    color: var(--mud-palette-text-disabled);
}

.bpu-legal-links {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

.bpu-legal-version {
    font-variant-numeric: tabular-nums;
    opacity: 0.75;
}

.app-nav-drawer .app-nav-theme {
    margin-top: auto;
}

.app-nav-drawer .bpu-legal-footer {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.125rem;
    padding: 0.875rem 1rem;
    border-top: 1px solid var(--mud-palette-lines-default);
}

.bpu-legal-footer a {
    color: var(--mud-palette-text-secondary);
    text-decoration: none;
}

.bpu-legal-footer a:hover {
    color: var(--mud-palette-text-primary);
    text-decoration: underline;
}

.tracker-preview {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-radius: 0.5rem;
    border: 1px solid var(--mud-palette-lines-default);
}

.tracker-preview-label {
    font-size: 0.9rem;
    opacity: 0.75;
}

.tracker-preview-shout {
    padding: 0.5rem 1rem;
    border-radius: 0.5rem;
    font-size: 1.25rem;
    font-weight: 700;
}

/* Introduction coachmark (BPU-69). Fixed, because the measured box comes from
   getBoundingClientRect and is therefore already viewport-relative. */
.tour-scrim {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 1400;
}

.tour-ring {
    position: fixed;
    border: 2px solid var(--mud-palette-primary);
    border-radius: 8px;
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.45);
    pointer-events: none;
    z-index: 1401;
    transition: top 120ms ease, left 120ms ease;
}

.tour-bubble {
    position: fixed;
    max-width: min(360px, 90vw);
    z-index: 1402;
}

.tour-fallback {
    max-width: min(360px, 90vw);
}

.tracker-signals-hint {
    margin-top: -0.75rem;
    max-width: 60ch;
}

.monitor-heading-image-preview {
    max-width: 160px;
    max-height: 72px;
    object-fit: contain;
    background: var(--mud-palette-background-grey);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 4px;
    padding: 4px;
}

.monitor-root:has(.monitor-banner) {
    display: flex;
    flex-direction: column;
}

.monitor-root:has(.monitor-banner) .monitor-stage {
    flex: 1 1 0;
    min-height: 0;
    height: auto;
}

.monitor-banner {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 3vw;
    padding: 1vh 2vw;
    box-sizing: border-box;
}

.monitor-banner-text {
    margin: 0;
    flex: 1 1 0;
    max-width: 32ch;
    font-size: 1.6vh;
    line-height: 1.35;
}

.monitor-banner:has(.monitor-banner-qr) .monitor-banner-text:first-child {
    text-align: right;
}

.monitor-banner-qr {
    flex: 0 0 auto;
    height: 100%;
    max-height: 22vh;
    width: auto;
    aspect-ratio: 1;
    background: #ffffff;
    padding: 0.6vh;
    border-radius: 0.4vh;
}

/* ── Media on the board (BPU-102) ──────────────────────────────────────────────────────────── */

/* The stage: the board, and beside it the side panel when there is one (BPU-125).

   Before this the panel was a sibling of .monitor-columns inside a plain block root. The columns are
   100% high, so the panel began at the bottom edge and ran off the screen — 759 px of it, in a 779 px
   window that does not scroll. It was never visible at any window size.

   :has() rather than a class passed down from the component, which is what BPU-90 already does for
   the bottom banner. The layout follows what is actually rendered, so a panel that is not drawn — no
   media, or the switch off — leaves the board exactly as it was. */
.monitor-stage {
    height: 100%;
    min-height: 0;
}

.monitor-stage:has(.monitor-media-panel) {
    display: grid;
    /* The same share the interruption gives its ready column, from the other side: the board is what
       the guest came for and keeps the room. minmax so a narrow screen cannot squeeze the panel into
       a stripe. */
    grid-template-columns: 1fr minmax(18rem, 26%);
    grid-template-rows: minmax(0, 1fr);
    gap: 10px;
}

/* A board with no columns is a screen for the window (BPU-205). The empty .monitor-columns would
   still hold its 1fr track and leave the media in the quarter beside it, so the track goes away and
   the panel takes the stage. */
.monitor-stage.media-only:has(.monitor-media-panel) {
    grid-template-columns: minmax(0, 1fr);
}

.monitor-stage.media-only .monitor-columns {
    display: none;
}

.monitor-media-panel {
    position: relative;
    overflow: hidden;
    width: 100%;
    height: 100%;
}

.monitor-media-frame {
    position: absolute;
    inset: 0;
    transition: opacity var(--media-transition-ms, 400ms) cubic-bezier(0.16, 1, 0.3, 1);
}

.monitor-media-frame.is-on { opacity: 1; z-index: 2; }
.monitor-media-frame.is-off { opacity: 0; z-index: 1; }

/* Die drei Arten (BPU-149). Die Dauer und die Farbe kommen als Variablen vom Bauteil, alles andere
   steht hier: zwei Zahlen unterscheiden zwei Läden, der Rest ist überall gleich. */
.monitor-media-panel.transition-none .monitor-media-frame { transition: none; }

/* Beim Wisch tauschen die Rahmen hart, verdeckt von der Fläche darüber. Blendeten sie zusätzlich
   über, wären für einen Moment beide Bilder zu sehen, sobald die Blende länger dauert als die
   Fläche deckt, und genau das soll der Wisch verhindern. */
.monitor-media-panel.transition-wipe .monitor-media-frame { transition: none; }

.monitor-media-wipe {
    position: absolute;
    inset: 0;
    z-index: 3;
    pointer-events: none;
    background: var(--media-wipe-color, #0b0b0d);
    transform: translateX(-100%);
    animation: monitor-media-wipe var(--media-transition-ms, 400ms) linear forwards;
}

/* Eine Richtung, von links. Bei 50 % deckt die Fläche die ganze Seite, und das ist der Moment, in
   dem das Bauteil die Rahmen tauscht. `forwards` lässt sie danach rechts außerhalb stehen. */
@keyframes monitor-media-wipe {
    0% { transform: translateX(-100%); }
    50% { transform: translateX(0); }
    100% { transform: translateX(100%); }
}

.monitor-media-frame img,
.monitor-media-frame video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.monitor-ad {
    position: fixed;
    inset: 0;
    z-index: 40;
    display: grid;
    /* Rows, not columns (BPU-126). The picture had 74 % of the width and the ready orders a tall
       narrow column beside it — the worst shape for both: a landscape advertisement went small, and
       pickup numbers went into a strip that shows few of them and each one tiny. The row is `auto`,
       so a board with nothing ready gives the picture the whole screen instead of an empty bar. */
    grid-template-rows: 1fr auto;
    background: #000;
}

.monitor-ad-media { position: relative; overflow: hidden; }

.monitor-ad-media img,
.monitor-ad-media video {
    width: 100%;
    height: 100%;
    /* contain, and that is what "centred" means here: the whole picture, in the middle, never cropped
       and never stretched. A shop's own artwork has writing on it. */
    object-fit: contain;
    display: block;
}

/* The strip along the bottom. It never disappears while an advertisement runs — that is the condition
   under which the interruption exists at all: the guest is standing there for a number. */
.monitor-ad-ready {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 1.5rem;
    overflow: hidden;
    padding: 0.75rem 1rem;
    background: rgba(0, 0, 0, 0.85);
}

/* A tile in the strip sizes itself to its number instead of filling a column, and the strip is read
   from across a room. The board's own tiles carry an inline `font-size: N%` from MonitorStyleCss, and
   a percentage resolves against the PARENT — so the strip has to name a base or the numbers inherit
   the page's and come out at 29 px on a wall. 5vh is the board's 8vh scaled to a strip. */
.monitor-ad-ready {
    font-size: 5vh;
}

/* Das Wort tritt zurück, die Nummern bleiben das Laute: aus zwei Metern trifft die Zahl, das Wort
   erklärt sie. Es schrumpft nicht mit, wenn viele Nummern anstehen — dann weicht es lieber. */
.monitor-ad-ready-label {
    flex: 0 1 auto;
    margin-right: 0.5rem;
    font-size: 0.5em;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    opacity: 0.75;
    white-space: nowrap;
}

.monitor-ad-ready .monitor-tile {
    flex: 0 0 auto;
    padding: 0.25rem 1rem;
}

/* Nothing ready means no strip, not an empty black bar across the picture. The fragment is always
   handed over — it is the board's own ready markup — so the element is there with no children in it,
   and :empty is what tells the two apart. */
.monitor-ad-ready:empty {
    display: none;
}

.monitor-sound-unlock {
    position: fixed;
    right: 1.5rem;
    bottom: 1.5rem;
    z-index: 60;
    padding: 0.75rem 1.25rem;
    border: 1px solid rgba(255, 255, 255, 0.35);
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.6);
    color: #fff;
    font-size: 1rem;
    cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
    .monitor-media-frame { transition: none; }

    /* Wer Bewegung abbestellt hat, bekommt auch keinen Wisch: die Fläche bleibt links außerhalb,
       das Bauteil tauscht weiter zur halben Zeit, und übrig bleibt ein harter Schnitt. */
    .monitor-media-wipe {
        animation: none;
        transform: translateX(-100%);
    }
}

/* Symbol und Wort werden getrennt bemessen (BPU-128).

   Die Größe hier stammt aus BPU-113, wo die Reiter größer werden sollten — damals trugen sie NUR ein
   Symbol, und `font-size` am Reiter war schlicht die Symbolgröße. Mit einer Beschriftung daneben ist
   dieselbe Zahl eine 38-px-Schrift: die Leiste lief über und zeigte Blätterpfeile, und von fünf
   Zuständen waren vier zu sehen.

   Das Symbol behält also seine Größe, das Wort bekommt eine eigene. Der Reiter bleibt so groß, wie er
   für einen Daumen sein muss — das ist `min-height`, nicht die Schrift. */
/* Auf schmalen Geräten müssen alle fünf Reiter ohne Blättern hineinpassen (BPU-134). Gemessen bei
   375 px: 495 px Reiterbreite und zwei Blätterpfeile. Ein Bedienpult, auf dem man erst blättern muss,
   um den Zustand zu treffen, ist an einer Theke unbrauchbar. */
@media (max-width: 600px) {
    .cp-tabview-root .mud-tabs .mud-tab {
        font-size: 0.625rem;
        min-height: 3.75rem;
        padding: 0.375rem 0.125rem;
        max-width: 20vw;
    }

    .cp-tabview-root .mud-tabs .mud-tab .mud-icon-root {
        font-size: 1.5rem;
    }

    /* Kein Reitertext auf schmalen Geräten. Er war bei 10 px in einem 75 px breiten Reiter nicht
       mehr zu lesen, und was man nicht lesen kann, soll auch keinen Platz kosten. Das Wort bleibt
       im Baum stehen — `font-size: 0` nimmt es dem Auge, nicht der Vorlesehilfe —, und das Symbol
       trägt seine eigene Größe und schrumpft deshalb nicht mit. */
    .cp-tabview-root .mud-tabs .mud-tab {
        /* !important, weil die Regel weiter unten ohne Medienabfrage dieselbe Spezifitaet hat und
           spaeter im Stylesheet steht — ohne das gewinnt sie, und der Text bleibt am Telefon stehen.
           Von Alexander gefunden. */
        font-size: 0 !important;
    }
}

.cp-tabview-root .mud-tabs .mud-tab {
    flex-direction: column;
    gap: 0.125rem;
    font-size: 0.8125rem;
    line-height: 1.2;
    text-transform: none;
    letter-spacing: 0;
    min-height: 4.5rem;
    padding: 0.5rem 0.5rem;

    /* Das Wort steht unter dem Symbol und tritt zurück: das Symbol ist das, was aus zwei Metern
       Entfernung trifft, das Wort das, was am ersten Arbeitstag erklärt, welches Symbol das war. */
    color: var(--mud-palette-text-secondary);
}

.cp-tabview-root .mud-tabs .mud-tab .mud-icon-root,
.cp-tabview-root .mud-tabs .mud-tab .mud-badge-wrapper {
    /* MudBlazor gibt dem Symbol einen Abstand nach rechts, weil ein Reiter normalerweise waagerecht
       gebaut ist: Symbol, Lücke, Wort. Untereinander gestellt schiebt derselbe Abstand das Symbol aus
       der Mitte — die Randbox wird zentriert, das Symbol darin sitzt 4 px links davon. Beim kurzen
       Wort "Offen" ist das zu sehen, bei "Nicht abgeholt / Fehler" nicht; falsch ist es überall. */
    margin: 0;
}

.cp-tabview-root .mud-tabs .mud-tab .mud-icon-root {
    font-size: 2rem;
    color: var(--mud-palette-text-primary);
}

/* Der aktive Reiter nimmt beides zurück in die volle Schrift — sonst ist der Zustand, in dem man
   gerade arbeitet, der leiseste auf der Leiste. */
.cp-tabview-root .mud-tabs .mud-tab.mud-tab-active,
.cp-tabview-root .mud-tabs .mud-tab.mud-tab-active .mud-icon-root {
    color: var(--mud-palette-text-primary);
}

@media (min-width: 1280px) {
    .cp-tabview-root .mud-tabs .mud-tab {
        font-size: 0.875rem;
        min-height: 5.25rem;
        padding: 0.75rem 0.75rem;
    }

    .cp-tabview-root .mud-tabs .mud-tab .mud-icon-root {
        font-size: 2.375rem;
    }
}

@media (min-width: 1920px) {
    .cp-tabview-root .mud-tabs .mud-tab {
        font-size: 1rem;
        min-height: 6.25rem;
        padding: 1rem 1rem;
    }

    .cp-tabview-root .mud-tabs .mud-tab .mud-icon-root {
        font-size: 2.75rem;
    }
}

.cp-tabview-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 12rem;
    height: 100%;
    padding: 1rem;
}

.fact-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 1.5rem 3rem;
    margin: 0;
}

.fact-grid > div {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.fact-grid dt {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--mud-palette-text-secondary) 65%, var(--mud-palette-text-primary));
}

.fact-grid dd {
    margin: 0;
    font-size: 1rem;
    line-height: 1.4;
}

.fact-inline {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.cp-figures {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.cp-figures li {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    padding: 1.25rem 1.5rem;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    background-color: var(--mud-palette-surface);
}

.cp-figure-value {
    font-size: 2rem;
    font-weight: 600;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.cp-figure-label {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--mud-palette-text-secondary) 65%, var(--mud-palette-text-primary));
}

.bpu-tenantsel-popover .mud-list {
    min-width: 15rem;
}

.bpu-tenantsel-popover .mud-menu-item {
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
}

.app-nav-theme {
    justify-content: flex-start;
    padding-left: 1.25rem;
    padding-right: 1.25rem;
    text-transform: none;
    font-weight: 400;
    color: var(--mud-palette-text-primary);
}

.app-nav-theme .mud-button-label {
    justify-content: flex-start;
}

.device-groups {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1rem;
}

.device-card {
    display: flex;
    flex-direction: column;
    gap: 0.875rem;
    padding: 1.25rem 1.5rem;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    background-color: var(--mud-palette-surface);
}

.device-card-title {
    margin: 0;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--mud-palette-text-secondary) 65%, var(--mud-palette-text-primary));
}

.device-state {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.device-state-age {
    font-size: 1.125rem;
}

.device-week {
    margin: 0;
    margin-top: auto;
    padding-top: 0.875rem;
    border-top: 1px solid var(--mud-palette-lines-default);
    font-size: 0.875rem;
    color: color-mix(in srgb, var(--mud-palette-text-secondary) 65%, var(--mud-palette-text-primary));
}

.fact-grid--stacked {
    grid-template-columns: 1fr;
    gap: 0.875rem;
}

/* Die App-Leiste des Bedienpults, dreigeteilt (BPU-129).

   1fr auto 1fr statt zweier Flex-Abstandhalter: zwei gleiche Bruchteile links und rechts, das Logo
   dazwischen. Nur so liegt es auf der Mitte des FENSTERS und nicht auf der Mitte dessen, was übrig
   bleibt — vorher schob der Menüknopf mit Titel es nach rechts.

   min-width: 0 auf den Randspalten ist die Bedingung dafür: ohne sie wächst eine Spalte über ihren
   Anteil hinaus, sobald ihr Inhalt breiter ist, und die Mitte wandert wieder. */
/* Eine feste Höhe, weil zwei Stellen sie kennen müssen: die Leiste selbst und die Arbeitsfläche, die
   direkt darunter beginnt. MudBlazors --mud-appbar-height bleibt bei 3.5rem, auch wenn die Leiste
   dense ist — die Fläche hätte sonst 13 px Luft über sich, die niemand bestellt hat. */
.cp-appbar-bar.mud-appbar {
    height: 3rem;
    min-height: 3rem;
}

/* Luft unter der App-Leiste, und ueberhaupt erst Platz (BPU-136).

   Die Leiste ist seit BPU-129 3rem hoch. MudMainContent rechnet aber weiter mit seiner eigenen
   Voreinstellung — gemessen 42 px Abstand nach oben gegen eine Leiste, die bei 48 endet. Die
   Ueberschrift lag also SECHS Pixel unter der Leiste, nicht bloss eng daran. Bei der Tafel war das
   nachgezogen, weil sie ihr `top` selbst setzt; jede andere Seite des Bedienpults nicht.

   3rem fuer die Leiste plus 1.5rem, damit eine Ueberschrift oben atmen kann statt an der Kante zu
   kleben. */
.cp-appbar-bar ~ .mud-main-content,
.mud-layout:has(.cp-appbar-bar) .mud-main-content {
    padding-top: calc(3rem + 1.5rem) !important;
}

.cp-appbar {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
}

.cp-appbar-side {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
}

.cp-appbar-left { justify-self: start; }
.cp-appbar-right { justify-self: end; }
.cp-appbar-center {
    justify-self: center;
    display: flex;
    align-items: center;
    height: 100%;
    min-width: 0;
    /* Damit ein sehr breites Logo die Randspalten nicht auf null drückt und die Knöpfe hinausschiebt.
       Die Mitte bleibt die Mitte, solange die beiden 1fr-Spalten gleich breit sind — und das sind sie,
       bis eine an ihre Inhaltsbreite stößt. */
    max-width: 40vw;
    overflow: hidden;
}

/* Das Logo füllt die Fläche, die ihm bleibt: bis zur Höhe der Leiste abzüglich eines Randes, oder bis
   zur Breite der Mittelspalte — je nachdem, welche Grenze zuerst erreicht ist. `contain` sorgt dafür,
   dass es dabei nie verzerrt. */
.cp-appbar-logo {
    /* Absolute Grenzen, keine Prozente: `height: 100%` löst in der Toolbar nicht auf — die Kette aus
       Toolbar, Raster und Flex-Zelle gibt keine bestimmte Höhe weiter —, und das Bild fällt dann auf
       seine Naturgröße zurück. Bei einem Logo mit 1000 Pixeln Kantenlänge steht es danach quer über
       der halben Seite. Gesehen, nicht vermutet.

       Die Höhe der Leiste ist 3rem; 2.375rem lässt oben und unten je fünf Pixel Luft. Die Breite
       begrenzt die Mittelspalte. Was zuerst greift, entscheidet das Seitenverhältnis des Logos —
       genau das ist "füllt die Fläche, die ihm bleibt". */
    max-height: 2.375rem;
    max-width: 100%;
    height: auto;
    width: auto;
    object-fit: contain;
}


/* Das Kontomenü sitzt jetzt in der Navigationsleiste und richtet sich an deren Zeilen aus. */
.app-nav-account {
    display: flex;
    align-items: center;
    padding: 0.25rem 0.5rem 0.5rem;
}

/* Die Vorgangskarte auf dem Telefon (BPU-134).

   Ziel sind vier gleichzeitig sichtbare Karten statt drei. Platz entsteht nur, wenn die Knöpfe
   schrumpfen, und der Name kann nur wachsen, wenn daneben etwas weicht — deshalb sind das hier
   dieselbe Änderung und nicht drei.

   Der Name wird GRÖSSER, nicht kleiner: er ist das, was das Personal aus der Entfernung liest und
   ausruft. Alles andere auf der Karte tritt zurück. */
@media (max-width: 600px) {
    .order-card {
        padding: 0.375rem 0.5rem !important;
    }

    .order-card-name {
        font-size: 1.375rem;
        line-height: 1.05;
        font-weight: 700;
    }

    /* Preis und Herkunft sind am Tresen keine Entscheidungsgrundlage — der Name ist es, und der
       Zustand. Sie bleiben im Markup, damit die Info-Ansicht sie weiter zeigt. */
    .order-card .order-card-secondary {
        display: none;
    }

    .order-card .mud-chip {
        height: 18px;
        font-size: 0.625rem;
    }

    /* Symbol mit kleinem Wort darunter, wie die Reiter seit BPU-128. Das Wort bleibt stehen, es tritt
       nur zurück: ein Symbol allein muss man sich erklären lassen. */
    .order-card .mud-button {
        flex-direction: column;
        gap: 0;
        min-width: 0;
        min-height: 0;
        padding: 0.0625rem 0.375rem;
        font-size: 0.5625rem;
        line-height: 1.1;
        letter-spacing: 0;
    }

    .order-card .mud-button .mud-icon-root {
        font-size: 1.125rem;
        margin: 0;
    }

    /* Die Zeilen der Karte rücken zusammen. Vier Karten auf 402 px Fläche heißt rund 95 px je Karte,
       und die kommen nicht aus einer einzelnen Kürzung, sondern aus allen zusammen. */
    .order-card .mud-stack {
        gap: 0.25rem !important;
    }

    .order-card .mud-icon-button {
        padding: 0.25rem;
    }

    .order-card .mud-icon-button .mud-icon-root {
        font-size: 1.125rem;
    }

    /* Die Uhrzeit bleibt — wie lange ein Vorgang schon steht, ist am Tresen eine Entscheidung —,
       aber sie braucht keine eigene Zeile in voller Höhe. */
    .order-card .mud-typography-caption {
        font-size: 0.6875rem;
        line-height: 1.2;
    }

    /* Die Nebenangaben bleiben auf einer Zeile und weichen, bevor sie umbrechen (BPU-135). Ein
       Umbruch hier wäre die Zeile zurück, die gerade eingespart wurde. */
    .order-card-meta {
        flex-wrap: nowrap;
        overflow: hidden;
        min-height: 0;
    }

    /* Der Info-Knopf darf den Namen nicht überragen — er war 36 px hoch neben einem 26 px hohen
       Namen und bestimmte damit die Höhe der obersten Zeile. */
    .order-card .mud-stack .mud-icon-button {
        padding: 0.125rem;
        height: 1.5rem;
        width: 1.5rem;
    }

    /* Die Zeilen bekommen keine Höhe über ihren Inhalt hinaus. MudStack setzt align-items:center,
       und dann bestimmt das höchste Element die Zeile — beim Namen war das der Info-Knopf. */
    .order-card .mud-stack > * {
        min-height: 0;
    }

    .order-card .mud-button-text .mud-button-label,
    .order-card .mud-button-filled .mud-button-label {
        opacity: 0.85;
    }
}

/* Der Vorgangsname ist größer als die Knöpfe, die ihn bewegen (BPU-134).

   Er ist das, was das Personal liest und ausruft; die Knöpfe sind, was es danach drückt. Vorher stand
   18 px gegen 14 px — zu wenig Abstand, um aus einem Meter Entfernung eine Rangfolge zu sein. */
@media (min-width: 601px) {
    .order-card-name {
        font-size: 1.5rem;
        line-height: 1.15;
        font-weight: 700;
    }
}

.media-thumb {
    width: 5rem;
    height: 3.25rem;
    flex: 0 0 auto;
    padding: 0;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 0.375rem;
    overflow: hidden;
    background: var(--mud-palette-background-gray);
    color: var(--mud-palette-text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.media-thumb:hover,
.media-thumb:focus-visible {
    border-color: var(--mud-palette-primary);
}

.bpu-upload-inline {
    align-items: flex-start;
}

.media-thumb img,
.media-thumb video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.media-thumb-sm {
    width: 3.5rem;
    height: 2.25rem;
}

.media-thumb-static {
    cursor: default;
}

.media-thumb-static:hover {
    border-color: var(--mud-palette-lines-default);
}

.media-preview {
    display: flex;
    align-items: center;
    justify-content: center;
}

.media-preview img,
.media-preview video {
    max-width: 100%;
    max-height: 60vh;
    display: block;
}

.media-preview audio {
    width: 100%;
}

.order-card-name-quick {
    cursor: pointer;
    text-decoration: underline;
    text-decoration-style: dotted;
    text-underline-offset: 0.25em;
}

.order-card-name-quick:hover,
.order-card-name-quick:focus-visible {
    text-decoration-style: solid;
}

.device-pairing {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: clamp(1rem, 4vh, 2.5rem);
    padding: clamp(0.5rem, 3vh, 2rem) clamp(1rem, 4vw, 2rem);
    background: var(--mud-palette-background, #101418);
    color: var(--mud-palette-text-primary, #f4f6f8);
}

.device-pairing-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
}

.device-pairing-brand .bpu-mark {
    --bpu-mark-plate: #0D9488;
    --bpu-mark-ink: #FFFFFF;
}

.device-pairing-mark {
    margin: 0;
    font-size: clamp(1rem, 1.6vw, 1.5rem);
    letter-spacing: -0.01em;
}

.device-pairing-mark .bpu-wordmark-bold {
    color: #14B8A6;
}

.device-pairing-panel {
    text-align: center;
}

.device-pairing-lead {
    font-size: clamp(1.25rem, 2.5vw, 2rem);
    max-width: 40rem;
    margin: 0 auto 1.5rem;
    opacity: 0.85;
}

.device-pairing-code {
    --device-pairing-tracking: clamp(0.25rem, 1.5vw, 1rem);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: clamp(2.5rem, min(12vw, 15vh), 8rem);
    font-weight: 700;
    letter-spacing: var(--device-pairing-tracking);
    text-indent: var(--device-pairing-tracking);
    margin: 0 0 2rem;
    line-height: 1.1;
}

.device-pairing-qr {
    width: clamp(7rem, min(28vw, 24vh), 18rem);
    height: auto;
    background: #ffffff;
    padding: 0.75rem;
    border-radius: 0.75rem;
}

.device-pairing-hint {
    font-size: clamp(0.95rem, 1.6vw, 1.25rem);
    max-width: 40rem;
    margin: 1.5rem auto 0;
    opacity: 0.7;
}

.device-pairing-retry {
    font: inherit;
    font-size: 1.1rem;
    padding: 0.75rem 2rem;
    border-radius: 0.5rem;
    border: 1px solid currentColor;
    background: transparent;
    color: inherit;
    cursor: pointer;
}

.mud-nav-link.active {
    position: relative;
}

.mud-nav-link.active::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.375rem;
    bottom: 0.375rem;
    width: 3px;
    border-radius: 0 2px 2px 0;
    background: var(--mud-palette-primary);
}
