﻿/* What this port adds on top of veloce.css.

   veloce.css is the Python platform's app.css, carried over unchanged on purpose — while both
   applications run side by side a difference in rendering should mean something. So anything
   genuinely new here goes in this file instead, which also keeps it identifiable once veloce.css
   is trimmed down to the part the customer pages actually use. */

/* The time-option tiles are labels wrapping a radio (see _PricePanel.cshtml), where the Python
   page used <button> plus a click handler. The radio is not drawn — the tile is — but it has to
   stay focusable, so it is moved out of sight rather than removed with display:none, which would
   take it out of the tab order and hide it from screen readers.

   input[type="radio"] in the selector on purpose: veloce.css styles every radio with that
   selector (position: relative, 18x18), which outranks a class alone. With only the class the
   radio stayed in the layout - clipped, but still an empty 18px box above every tile's title. */
input[type="radio"].bkf-svc-radio {
    position: absolute;
    width: 1px;
    height: 1px;
    min-width: 0;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Without this, a keyboard user moving through the tiles gets no indication of where they are:
   the focus ring belongs to the hidden radio, not to the tile that is actually drawn. */
.bkf-service:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent) inset;
}

/* Which tile looks chosen follows the radio inside it, not a class rendered by the server.

   The parcel tiles sit outside the htmx swap, so a server-rendered class there was simply
   stale: clicking a different sending type left the highlight on the previous one. Driving it
   from :checked also means the tile lights up the moment it is clicked, rather than when the
   response arrives - and it is one rule for both kinds of tile instead of two code paths.

   The declarations match .bkf-parcel.sel / .bkf-service.sel in veloce.css, which stays
   untouched. */
.bkf-parcel:has(.bkf-svc-radio:checked),
.bkf-service:has(.bkf-svc-radio:checked) {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent) inset;
    background: var(--accent-soft);
}

/* The description follows the sending-type tiles, which are a row of large targets. Without a
   gap it reads as part of the last tile rather than as the next thing to fill in. */
.bkf-desc {
    margin-top: 16px;
}

/* The honeypot field: in the form and in the DOM, out of sight and out of reach.

   Moved off-screen rather than display:none or hidden, because the simplest bots skip anything
   obviously hidden - and those are exactly the ones this is for. A person never sees it, and
   tabindex and aria-hidden in the markup keep the keyboard and screen readers away from it. */
.hp {
    position: absolute;
    left: -10000px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* The tools under an address - swap, add, remove, Auch retour - sit at the right edge of their
   card. veloce.css lays the row out as a flex line but leaves it aligned left, where the buttons
   ran into the fields above them; against the right edge they read as what they are, actions on
   the card rather than more of its content.

   One rule for every card, so the swap on the sender, the retour and add on the receiver and the
   remove buttons on the extra stops all line up the same way. */
.bkf-addr-tools {
    justify-content: flex-end;
}

/* The proposal list under the street is the third child of the street | number grid. Empty, it
   wrapped onto a second grid row of its own and added one more row gap below the street, so the
   street sat further from the postcode than any other two lines. Filled it is .bkf-ac, absolutely
   positioned and out of the grid; until then it takes no room at all. */
.bkf-ac-anchor > div[id^="ac-"]:not(.bkf-ac) {
    display: none;
}

/* The optional parts of the payment box, folded away until asked for.

   <details> rather than a button and a script: it is the element for this, and the fields stay
   in the form whether it is open or shut, so what was typed is still submitted and still priced.

   The summary is styled as the ghost button the Python page uses, and the default disclosure
   triangle goes - the marker is the button itself. Both are needed: WebKit has its own pseudo
   element for it. */
.bkf-fold > summary {
    display: block;
    cursor: pointer;
    list-style: none;
    text-align: left;
    width: 100%;
}

.bkf-fold > summary::-webkit-details-marker {
    display: none;
}

/* Says which way it goes, since the triangle is gone. */
.bkf-fold > summary::after {
    content: " +";
}

.bkf-fold[open] > summary::after {
    content: " −";
}

.bkf-fold + .bkf-fold {
    margin-top: 8px;
}

/* A page that is only forms gets a wrapper as wide as the forms.

   .kp-wrap is 920px and centred, while .kp-form is capped at 520px with no automatic margins, so
   on Mein Konto the forms sat hard against the left edge of a box twice their width - centred by
   the rules, off-centre to the eye. Narrowing the wrapper centres the column as a whole and keeps
   heading, messages and fields on one left edge, rather than centring the forms and leaving the
   heading behind.

   Here and not in veloce.css: that file is the Python platform's app.css, kept as it is while both
   applications run. Its own account page has the same gap. */
.kp-wrap-form {
    max-width: 520px;
}

/* Space between the blocks on Mein Konto, so "Ihre Daten" and "Passwort ändern" read as two
   separate things to do rather than one long form.

   The general sibling combinator, not the adjacent one: a saved or failed message renders between
   the blocks, so the two forms are only sometimes neighbours and "+" would drop the spacing
   exactly when a message pushed them apart anyway. */
.kp-wrap-form .kp-form ~ .kp-form {
    margin-top: 26px;
}

/* Every section is a card now, as on the Python page, and these are the gaps between them: the
   address columns, the e-mail card, Sendungstyp, Zeitoption and the bottom row. The Python form
   gets its gap from class "bkf"; this one has an id rather than that class, so it is set here,
   at the 10px of the Python page's compact form. */
#bkf {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* The Wunschzeit fields sit inside the Zeitoption card below the tiles, without a heading of
   their own - the Wunschzeit tile above names them - and need a little air above them. */
#time-panel {
    margin-top: 12px;
}

/* The wish fields belong to the Wunschzeit tile and are shown only while it is chosen. The
   Python page does this with a click handler that sets timePanel.hidden; here the form itself
   states the condition, so it holds on first render, after an htmx swap and with JavaScript
   switched off alike - there is no moment at which markup and handler can disagree.

   Hidden, not removed: the fields keep their values, so switching to a tariff and back does not
   make the customer type the time again. They are still submitted, which is why the server gates
   them on WishChosen rather than trusting that what is invisible is also empty. */
#bkf:not(:has(.bkf-svc-radio[value="WUNSCH"]:checked)) #time-panel {
    display: none;
}

/* Without :has() there is no way to style a tile from the radio it contains, and the radio is
   moved out of sight - so the customer would see no selection at all. Show the radio instead:
   plainer, but it says which one is chosen, which is the part that matters. */
@supports not selector(:has(*)) {
    input[type="radio"].bkf-svc-radio {
        position: static;
        width: 18px;
        height: 18px;
        margin: 0 6px 0 0;
        clip-path: none;
    }
}

/* The proposal list is an absolutely positioned dropdown. Empty it has nothing to show, and a
   bordered empty box under the street field is worse than nothing - so it collapses until the
   server puts something in it. */
.bkf-ac:empty {
    display: none;
}

/* The proposals are buttons rather than the Python page's list items, so that choosing one is a
   plain request and needs no key handling of its own. They still have to look like rows. */
.bkf-ac-item {
    width: 100%;
    text-align: left;
    background: none;
    border: 0;
    border-bottom: 1px solid var(--line);
    font: inherit;
    color: inherit;
}

/* The layout puts the contact strip after the page content, on every page. On the standalone
   pages that lands it inside .login-body, which is a row flex container - it carries the
   platform's two-column login design, stage beside panel. A third child therefore sat *next to*
   the card rather than under it, and because .ks-standalone aligns to flex-start it appeared at
   the top of the page.

   Standing the standalone variant up as a column puts the strip where a footer belongs. The card
   stays top-aligned and centred, as it was: justify-content now governs the vertical axis and
   align-items the horizontal, so both swap roles. */
.login-body.ks-standalone {
    flex-direction: column;
    justify-content: flex-start;
    align-items: center;
}

/* Room between the page and the strip, wherever it ends up, and below it to the window edge. */
.site-contact {
    margin-top: 28px;
    padding-bottom: 24px;
}

/* --- Selbstbedienung: Registrierung, Passwort vergessen, Passwort neu ---
   Ergänzt die .login-* Karten aus veloce.css. Die Anrede ist ein <select>, das dort nicht
   vorkommt, und die Formulare brauchen Kontrollkästchen sowie Hinweise pro Feld. */
.login-field select{ width:100%; box-sizing:border-box; padding:11px 13px; font-size:15px;
  background:var(--surface-2); color:var(--ink); border:1px solid var(--line-strong);
  border-radius:var(--radius-sm); outline:none; transition:border-color .12s, box-shadow .12s; }
.login-field select:focus{ border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }

.login-check{ display:flex; align-items:flex-start; gap:9px; font-size:13px; color:var(--ink);
  line-height:1.45; }
.login-check input{ margin-top:2px; flex:0 0 auto; }
/* --link, nicht --accent: das Gelb ist auf hellem Grund kaum lesbar. Hell dunkel, dunkel gelb. */
.login-check a{ color:var(--link); text-decoration:underline; text-underline-offset:2px; }

/* Fehler am einzelnen Feld. Leer, solange nichts zu sagen ist — kein Platzhalter,
   der eine leere Zeile hinterlässt. */
.login-fielderr{ font-size:12px; font-weight:600; color:var(--bad); }
.login-fielderr:empty{ display:none; }

/* Zwei Felder nebeneinander (Vor-/Nachname, Straße/Hausnummer, PLZ/Ort); Hausnummer und PLZ schmäler. Unter 360px untereinander. */
/* Etwas Abstand zwischen den Feldern und den Einwilligungen darunter. */
.reg-newsletter{ margin-top:10px; }

.login-row{ display:grid; grid-template-columns:1fr 1fr; gap:12px; align-items:start; }
.login-row-zip{ grid-template-columns:minmax(80px,1fr) 2fr; }
.login-row-street{ grid-template-columns:2fr minmax(80px,1fr); }
@media (max-width:360px){ .login-row, .login-row-zip, .login-row-street{ grid-template-columns:1fr; } }

/* Hinweis unter einem Feld. */
.login-hint{ font-size:12px; line-height:1.4; color:var(--muted); }

.login-note{ margin:0; font-size:12.5px; color:var(--muted); line-height:1.5; }

/* --- Kopfzeile auf nicht angemeldeten Seiten ---
   Dieselbe Leiste wie nach der Anmeldung: über die ganze Fensterbreite, mit Hintergrund und
   Linie unten aus veloce.css, die Wortmarke links in derselben Breite wie dort (1040px, mittig)
   und gleich groß. Nur ohne Navigation - vor der Anmeldung gibt es nichts zu navigieren.

   Der Body dieser Seiten hat seitlich 16px Innenabstand; die negativen Ränder holen die Leiste
   an die Fensterkanten, und der obere Abstand wandert vom Body unter die Leiste. */
.login-body.ks-standalone {
    padding-top: 0;
}

.login-body.ks-standalone > header {
    align-self: stretch;
    margin: 0 -16px 34px;
    padding: 9px max(16px, calc((100vw - 1040px) / 2));
    justify-content: flex-start;
}

.login-body.ks-standalone > header .logo {
    height: 24px;
    box-sizing: content-box;
}

.auth-logo {
    display: block;
    line-height: 0;
}

/* The Auftraggeber card sits above the form rather than inside it, so it does not get the form's
   own gap and needs its distance to the address cards spelled out. */
.bkf-page > .bkf-client {
    margin-bottom: 12px;
}

/* Wunschzeit: date and both times in one row per stop. Each block needs room for three fields
   rather than the 210px veloce.css gives it; the date takes a little more than a time. On a
   phone r-3 stacks them again (veloce.css, max-width:520px). */
.bkf-times {
    grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
}

.bkf-row.r-wish {
    grid-template-columns: 1.4fr 1fr 1fr;
}

@media (max-width: 520px) {
    .bkf-row.r-wish {
        grid-template-columns: 1fr;
    }
}

/* The tiles are <label>s here (Python's are <button>s), and veloce.css styles every label as a
   form caption: 10px, bold, uppercase, spaced. Undone for the tiles; only the title is set in
   capitals. */
.bkf-service,
.bkf-parcel {
    text-transform: none;
    letter-spacing: normal;
    font-weight: normal;
}

/* Weight and measurements on a line each ("– 10 kg", "60×40×20"), which reads more easily than
   the two run together. */
.bkf-parcel-spec-line {
    display: block;
}

.bkf-service-name,
.bkf-parcel-name {
    text-transform: uppercase;
    letter-spacing: .4px;
}

/* A refused booking: the message as a box like the rest of the page, and the fields it names
   marked (booking-form.js). The colours are the page's own tokens, so dark mode follows. */
.bkf-refused {
    padding: 10px 12px;
    margin-bottom: 12px;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.4;
    color: var(--bad);
    background: var(--bad-bg);
    border: var(--border-w) solid var(--bad);
    border-radius: var(--radius-sm);
}

input.bkf-missing,
select.bkf-missing,
textarea.bkf-missing {
    border-color: var(--bad);
    box-shadow: 0 0 0 2px var(--bad-bg);
}

/* A tile choice nobody made: the whole group. */
[data-missing-group].bkf-missing {
    outline: 2px solid var(--bad);
    outline-offset: 4px;
    border-radius: var(--radius-sm);
}

/* The AGB line. */
label.bkf-missing {
    color: var(--bad);
}

/* The AGB link. veloce.css colours links in .ks-check with --accent, which in light mode is the
   veloce yellow - unreadable on white. --link is what every other link on the page uses: dark in
   light mode, turquoise in dark mode. Underlined so it still reads as a link at that weight. */
.ks-check a {
    color: var(--link);
    text-decoration: underline;
    font-weight: 600;
}

/* Ladehilfe: the checkbox on each address card and the explanation under the Sendungstyp tiles
   only for the cargo types - Mini Cargo, Cargo, Mega Cargo (ParcelType.OffersLoadingAid). The
   server ignores the checkbox for the others. */
#bkf:not(:has(input[name="SendingType"][value="MIC"]:checked, input[name="SendingType"][value="CGO"]:checked, input[name="SendingType"][value="MCG"]:checked)) .bkf-aid {
    display: none;
}

/* On the tools line: at the left, the card's buttons stay at the right. */
.bkf-addr-tools .bkf-aid {
    margin-right: auto;
}

.bkf-aid-info {
    display: none;
    margin-top: 10px;
    font-size: 12px;
    color: var(--ink-2);
}

#bkf:has(input[name="SendingType"][value="MIC"]:checked) .bkf-aid-info[data-for="MIC"],
#bkf:has(input[name="SendingType"][value="CGO"]:checked) .bkf-aid-info[data-for="CGO"],
#bkf:has(input[name="SendingType"][value="MCG"]:checked) .bkf-aid-info[data-for="MCG"] {
    display: block;
}

/* "Meine Aufträge": the delivery range above the list, on one line. */
.kp-filter {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 10px;
    margin-bottom: 12px;
}

.kp-filter .bkf-tl {
    min-width: 150px;
    /* veloce.css gives every label a 3px bottom margin, which lifted the date fields above the
       button they are aligned with. */
    margin: 0;
}

/* "Anzeigen" as tall as the date fields beside it: their padding and text size, not the smaller
   ghost button's. */
.kp-filter .btn-ghost {
    padding: 7px 14px;
    font-size: 13px;
    line-height: normal;
}

/* "Kunde wählen": each customer is a button that looks like an order card, the whole width, with
   the chosen one marked as a selected tile is. */
.kp-customer {
    margin: 0;
}

.kp-customer-btn {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    width: 100%;
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.kp-customer-btn > span:first-child {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.kp-customer-btn:hover {
    border-color: var(--primary);
}

.kp-customer-btn.is-chosen {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent) inset;
    background: var(--accent-soft);
}

/* "Neuer Auftrag" on Meine Aufträge is a link, not a button, so veloce.css gives it only the
   accent colour: no padding, no rounded corners, and the link underline. Drawn as the button it
   stands for, and centred on the heading line rather than sitting on its baseline. */
a.btn-new {
    padding: 8px 14px;
    border-radius: var(--radius-sm);
    font-size: 12.5px;
    font-weight: 700;
    letter-spacing: .2px;
    text-decoration: none;
    white-space: nowrap;
    transition: box-shadow .16s ease, filter .16s ease;
}

.page-head > a.btn-new { align-self: center; }

a.btn-new:hover {
    filter: brightness(1.06);
    box-shadow: var(--card-hover);
}

/* The login's greeting: a quiet line directly above "Anmelden", pulled close to it by the card's
   gap being taken back, so the two read as one heading block. */
.login-welcome {
    margin: 0 0 -9px;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .02em;
    color: var(--muted);
}

/* The customer navigation stays a row at every width. veloce.css turns .topnav into a drawer below
   1360px, opened by a hamburger button these pages do not have, and only undoes that for
   .kundennav below 1080px - so between the two the navigation collapsed to nothing. The same
   override, from the drawer's own breakpoint down. */
@media (max-width: 1360px) {
    .kundennav {
        order: 0;
        flex: 1 1 auto;
        flex-direction: row;
        align-items: center;
        max-height: none;
        overflow-x: auto;
        overflow-y: hidden;
        padding: 0;
        border-top: 0;
        margin-top: 0;
    }

    .kundennav a {
        width: auto;
        white-space: nowrap;
        padding: 8px 10px;
        font-size: 14px;
    }
}

/* Dark mode in Veloce's colours. veloce.css (the Python platform's) draws it turquoise on a blue
   black, which is not Veloce; light mode already is - black and the Veloce yellow on warm white.
   This keeps the dark layout and swaps the palette: warm near-black, and the same yellow as the
   accent, with black text on it as on the light side. Only colour tokens; nothing else moves.
   Both selectors, as in veloce.css: the switch, and the system setting when nothing is chosen. */
:root[data-theme="dark"] {
    --bg: #141311; --bg-2: #1A1916; --card: #1F1E1A; --surface-2: #272621; --overlay: #29281F;
    --ink: #F4F3EE; --ink-2: #CAC6BB; --muted: #908C81;
    --line: rgba(255, 255, 255, .08); --line-strong: rgba(255, 255, 255, .17); --frame: rgba(255, 255, 255, .14);
    --primary: #E8E22A; --primary-2: #C9C31F; --on-primary: #1A1917;
    --accent: #E8E22A; --accent-soft: rgba(232, 226, 42, .14); --accent-ink: #1A1917;
    --link: #F0EB5A;
    --nav-active-fg: #F0EB5A; --nav-active-ic-bg: rgba(232, 226, 42, .18); --nav-active-ic-fg: #F0EB5A;
    --focus: rgba(232, 226, 42, .5);
    --shadow-lg: 0 0 30px -8px rgba(232, 226, 42, .28); --card-hover: 0 0 24px -10px rgba(232, 226, 42, .35);
    --header-bg: #1A1916;
    --body-bg:
        radial-gradient(1100px 460px at 88% -10%, rgba(232, 226, 42, .07), transparent 60%),
        linear-gradient(180deg, #141311, #1A1916);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --bg: #141311; --bg-2: #1A1916; --card: #1F1E1A; --surface-2: #272621; --overlay: #29281F;
        --ink: #F4F3EE; --ink-2: #CAC6BB; --muted: #908C81;
        --line: rgba(255, 255, 255, .08); --line-strong: rgba(255, 255, 255, .17); --frame: rgba(255, 255, 255, .14);
        --primary: #E8E22A; --primary-2: #C9C31F; --on-primary: #1A1917;
        --accent: #E8E22A; --accent-soft: rgba(232, 226, 42, .14); --accent-ink: #1A1917;
        --link: #F0EB5A;
        --nav-active-fg: #F0EB5A; --nav-active-ic-bg: rgba(232, 226, 42, .18); --nav-active-ic-fg: #F0EB5A;
        --focus: rgba(232, 226, 42, .5);
        --shadow-lg: 0 0 30px -8px rgba(232, 226, 42, .28); --card-hover: 0 0 24px -10px rgba(232, 226, 42, .35);
        --header-bg: #1A1916;
        --body-bg:
            radial-gradient(1100px 460px at 88% -10%, rgba(232, 226, 42, .07), transparent 60%),
            linear-gradient(180deg, #141311, #1A1916);
    }
}

/* The signed-in header: the bar still spans the window - background and bottom line - but what is
   in it keeps to the width of the booking form (.bkf-page, 1040px) and is centred like it. On a
   wide screen the logo, the menu and the user button then sit above the content instead of at the
   window's edges. Below that width it keeps veloce.css's own 20px (16px under 1360px). */
body:not(.login-body) > header {
    padding-left: max(20px, calc((100% - 1040px) / 2));
    padding-right: max(20px, calc((100% - 1040px) / 2));
}

@media (max-width: 1360px) {
    body:not(.login-body) > header {
        padding-left: max(16px, calc((100% - 1040px) / 2));
        padding-right: max(16px, calc((100% - 1040px) / 2));
    }
}

/* Aufträge: status and the Lieferinfo button together at the right end of the row. The button is
   a link, so it gets the ghost button's shape without the link underline. */
.kp-order-end {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    flex-wrap: wrap;
}

a.btn-ghost.kp-lieferinfo {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    white-space: nowrap;
}

/* The heading row of Aufträge, Adressen, Konto and Kunde sat 2px below the header bar - tight
   for the heading, and the taller "Neuer Auftrag" button all but touched it. */
.kp-wrap > .page-head {
    margin-top: 18px;
}

/* Registrieren: "Neue Kundennummer beantragen". The company fields only while the box is ticked,
   decided by the form itself, so it holds on the first render and without script. A browser
   without :has() shows them always, which is how the form was before. */
.login-sub {
    margin: 14px 0 0;
    font-size: 15px;
    font-weight: 800;
}

form:has(.reg-new-toggle:not(:checked)) .reg-new {
    display: none;
}

.reg-new {
    display: flex;
    flex-direction: column;
    gap: 15px;
}

/* Auftrag buchen: while the order is being placed (booking-submit.js sets .bkf-booking on the
   form), the button shows a spinner and says what is happening, and a line below it explains
   the wait. The idle label keeps its width, so the button does not jump. */
.bkf-book { display: grid; justify-items: center; }
.bkf-book-idle, .bkf-book-busy { grid-area: 1 / 1; display: inline-flex; align-items: center;
    justify-content: center; gap: 8px; }
.bkf-book-busy { visibility: hidden; }
.bkf-booking .bkf-book-idle { visibility: hidden; }
.bkf-booking .bkf-book-busy { visibility: visible; }
/* pointer-events as well as disabled: htmx re-enables the button once the answer is in, while
   a booked order's confirmation page is still loading. */
.bkf-booking .bkf-book { cursor: progress; opacity: .85; pointer-events: none; }

.bkf-spinner { width: 15px; height: 15px; border-radius: 50%; flex: 0 0 auto;
    border: 2px solid currentColor; border-right-color: transparent;
    animation: bkf-spin .8s linear infinite; }
@keyframes bkf-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .bkf-spinner { animation-duration: 2.4s; } }

.bkf-book-note { margin: 0; font-size: 12px; color: var(--muted); text-align: center; }
.bkf-book-note:empty { display: none; }

/* Auftragsbestätigung (/buchung/bestaetigung): what classic shows after a booking in place of the
   form. One column as wide as the booking form's forms, the order number up top. */
.bc-wrap { max-width: 640px; display: flex; flex-direction: column; gap: 14px; }
.bc-wrap .card { padding: 16px 18px; }

.bc-done { display: flex; gap: 14px; align-items: flex-start;
    border-color: color-mix(in srgb, var(--ok) 45%, var(--line-strong)); }
.bc-check { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%; display: grid;
    place-items: center; font-size: 18px; font-weight: 800; color: var(--ok); background: var(--ok-bg); }
.bc-done p { margin: 0; }
.bc-lead { font-size: 16px; font-weight: 800; }
.bc-number { margin-top: 4px !important; font-size: 15px; }
.bc-number strong { font-size: 17px; letter-spacing: .02em; }
.bc-note { margin-top: 8px !important; font-size: 13px; color: var(--muted); }

.bc-h { margin: 0 0 10px; font-size: 13px; font-weight: 800; text-transform: uppercase;
    letter-spacing: .04em; color: var(--muted); }

.bc-stops { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.bc-stop { display: grid; grid-template-columns: 110px 1fr; gap: 2px 12px; }
.bc-role { font-size: 12px; font-weight: 800; color: var(--muted); padding-top: 2px; }
.bc-addr { line-height: 1.45; }
.bc-when { grid-column: 2; font-size: 13px; font-weight: 700; }

.bc-facts { display: grid; grid-template-columns: 110px 1fr; gap: 6px 12px; margin: 0; }
.bc-facts dt { font-size: 12px; font-weight: 800; color: var(--muted); padding-top: 2px; }
.bc-facts dd { margin: 0; }

.bc-actions { display: flex; flex-wrap: wrap; gap: 10px; }

@media (max-width: 480px) {
    .bc-stop, .bc-facts { grid-template-columns: 1fr; }
    .bc-when { grid-column: 1; }
}

/* A time option that cannot be booked online: no Richtzeit for every stop, typically the way
   back. Dimmed and not selectable, with classic's words in place of times and price. */
.bkf-service.is-unbookable { opacity: .6; cursor: not-allowed; }
.bkf-svc-unbookable { white-space: normal; font-weight: 600; color: var(--bad); }

/* The wordmark in the signed-in header, the same size in both themes and as tall as the menu
   buttons. veloce.css gives it height 22px with border-box sizing, and in light mode the dark
   plate's padding sits inside those 22px - the wordmark itself came out at 14px there, 22px in
   dark mode. content-box sizes the wordmark; the plate adds its padding around it. The login and
   registration pages size theirs the same way, in their own rule. */
body:not(.login-body) > header .logo { height: 24px; box-sizing: content-box; }

/* While the form is being priced (htmx marks it .htmx-request): the time option tiles dim, show
   a small spinner and take no clicks - an option's price and time are not known yet, and a click
   made meanwhile would only be lost when the answer redraws the tiles. Other changes to the form
   still go through; the newest price request replaces a running one (hx-sync on #bkf). */
#bkf.htmx-request #services .bkf-service { position: relative; pointer-events: none; cursor: progress; }
#bkf.htmx-request #services { cursor: progress; }
#bkf.htmx-request #services .bkf-service-detail { opacity: .45; transition: opacity .15s; }
#bkf.htmx-request #services .bkf-service::after {
    content: ""; position: absolute; top: 10px; right: 10px; width: 12px; height: 12px;
    border-radius: 50%; border: 2px solid var(--muted); border-right-color: transparent;
    animation: bkf-spin .8s linear infinite;
}

/* The wordmark without a plate in light mode too: Veloce yellow straight on the light background,
   as in dark mode. veloce.css puts it on a dark plate there for contrast. Both selectors, as
   veloce.css sets it: with the theme switch on "light" its :root[data-theme="light"] would
   otherwise outrank a bare :root. */
:root, :root[data-theme="light"] {
    --logo-plate: transparent;
    --logo-pad: 0;
}

/* Login, registration and the password pages: the form in a card like the booking form's -
   the same background, border, corners and shadow as veloce.css's .card - rather than floating
   on the page. */
.ks-standalone .login-card {
    box-sizing: border-box;
    padding: 26px 28px 28px;
    background: var(--card);
    border: var(--border-w) solid var(--line-strong);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}

@media (max-width: 520px) {
    .ks-standalone .login-card { padding: 20px 16px 22px; }
}

/* "FIXTERMIN" under a Wunschzeit window that costs a Fixtermin surcharge, at the right of the
   window's box, below its times; nothing otherwise. */
/* The box spaces its rows 7px apart (.bkf-time gap); pulled up so the mark sits close under the
   times. */
.bkf-ft-note { text-align: right; margin-top: -4px; }
.bkf-ft-badge {
    display: inline-block; padding: 2px 7px; border-radius: 4px;
    font-size: 11px; font-weight: 800; letter-spacing: .04em;
    color: var(--accent-ink); background: var(--accent);
}

