:root {
    color-scheme: light;
    font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    color: #20231f;
    background: #f3f5f1;
    line-height: 1.5;
    scroll-padding-top: 5.5rem;
}

* { box-sizing: border-box; }
body { margin: 0; overflow-wrap: anywhere; }
.skip-link { position: fixed; top: .5rem; left: .5rem; z-index: 100; padding: .65rem .9rem; border-radius: 8px; background: white; color: #173f35; transform: translateY(-160%); }
.skip-link:focus { transform: translateY(0); }
/* Announced by screen readers, never shown: the live region reporting an in-place table update. */
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
.shell { width: min(1180px, calc(100% - 3rem)); margin-inline: auto; }
header { position: sticky; top: 0; z-index: 50; background: #173f35; color: white; }
.header-inner { min-height: 64px; display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
header a { color: white; text-decoration: none; }
.brand { font-size: 1.2rem; font-weight: 750; display: flex; align-items: center; gap: .7rem; }
.brand .logo { height: 42px; width: auto; display: block; background: white; border-radius: 8px; padding: 3px; }
.cover img { width: 100%; height: clamp(180px, 32vw, 340px); object-fit: cover; display: block; }
.nav { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem 1rem; }
.admin-menu { position: relative; }
.admin-menu > summary { cursor: pointer; font-weight: 650; }
.admin-menu.current > summary { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: .3rem; }
.admin-menu-panel { position: absolute; top: calc(100% + .7rem); right: 0; display: grid; width: min(19rem, calc(100vw - 2rem)); padding: .5rem; border: 1px solid #cbd5cf; border-radius: 10px; background: white; color: #20231f; box-shadow: 0 10px 28px rgb(10 35 28 / 24%); }
.admin-menu-panel a, .admin-menu-panel button { display: block; width: 100%; padding: .65rem .75rem; border: 0; border-radius: 7px; background: transparent; color: #173f35; font: inherit; text-align: left; cursor: pointer; }
.admin-menu-panel a:hover, .admin-menu-panel button:hover { background: #edf4f0; }
.admin-menu-panel a.current { background: #dcebe3; font-weight: 700; }
.admin-menu-panel form { margin: .35rem 0 0; padding-top: .35rem; border-top: 1px solid #dfe5e0; }
main { padding-block: 2.5rem 5rem; }
h1 { font-size: clamp(2rem, 7vw, 3.25rem); line-height: 1.08; margin: 0 0 .75rem; }
h2 { font-size: 1.25rem; margin: 0 0 1rem; }
h3 { font-size: 1rem; }
.card, .notice { background: white; padding: clamp(1.1rem, 4vw, 1.75rem); border-radius: 14px; margin: 1.25rem 0; box-shadow: 0 2px 16px rgb(20 50 40 / 7%); }
.notice { border-left: 5px solid #559b7b; }
.field { display: grid; gap: .35rem; margin-bottom: 1rem; min-width: 0; }
.field[hidden] { display: none; }
.field > label { font-weight: 650; }
input, textarea, select { width: 100%; min-width: 0; padding: .72rem .8rem; border: 1px solid #b8c2bb; border-radius: 8px; background: white; color: inherit; font: inherit; }
input:focus, textarea:focus, select:focus { outline: 3px solid rgb(33 124 96 / 20%); border-color: #217c60; }
a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible { outline: 3px solid #f0b429; outline-offset: 3px; }
.columns { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
.columns-2 { grid-template-columns: repeat(2, 1fr); }
.booking-filter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); gap: 1rem; }
.booking-filter-grid .field { margin-bottom: 0; }
.export-columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); gap: 0 1rem; }
.export-columns .choice { margin: .5rem 0; }
.choice { display: flex; align-items: flex-start; gap: .65rem; margin: .8rem 0; }
.choice[hidden] { display: none; }
.choice input { width: auto; margin-top: .35rem; }
.choice label { flex: 1; }
.hint { color: #59635d; font-size: .92rem; }
.calendar-nav { display: flex; align-items: center; justify-content: space-between; gap: .6rem; margin-bottom: .5rem; }
.calendar-nav .hint { margin: 0; text-align: center; }
.calendar-nav button { width: auto; flex: none; padding: .35rem .75rem; border: 1px solid #b8c2bb; border-radius: 8px; background: white; font: inherit; font-size: 1.05rem; line-height: 1; cursor: pointer; }
.calendar-nav button:disabled { color: #b8c2bb; cursor: default; }
.calendar-months { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); gap: 1rem 1.75rem; margin-bottom: .75rem; }
.cal-month h3 { margin: 0 0 .45rem; text-align: center; }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-weekday { text-align: center; font-size: .78rem; color: #59635d; padding-block: .15rem; }
/* The day cells read as one ladder, strongest last: a day still to come is a plain green a reader
   can pick out at a glance, a day already gone recedes to near-white, and the two selection states
   deepen from there. The previous free and past greens differed by about six values per channel,
   which made a whole calendar look uniformly washed out. */
.cal-day { width: auto; border: 0; border-radius: 7px; padding: .45rem 0; background: #dcebe3; color: inherit; font: inherit; font-size: .9rem; text-align: center; cursor: pointer; }
.cal-day:hover:not(:disabled) { outline: 2px solid #217c60; }
.cal-empty { background: transparent; }
.cal-day:disabled { background: #f3f5f1; color: #b8c2bb; cursor: default; }
/* A day gone by recedes on every calendar, keeping the same green family so it still reads as
   part of one scale. Placed after :disabled so a past day looks the same whether or not it can
   still be chosen — the booking forms cannot select it, the administrator forms can. */
.cal-day.past { background: #eef2ee; }
/* Only where the markup asks for it does the past go flat grey and drop its occupancy: on the
   host-facing forms, where what was free or booked last month is not something anyone can act on.
   The administration keeps its colours, so a past turnover day there still shows its two halves.
   Selection still wins everywhere: `.in-range` and `.selected` follow. */
.cal-day.past-plain { background: #ecefec; color: #6b736d; }
/* Half-open occupancy: the morning belongs to the night before, the evening to the night after,
   so a turnover day renders half free and half occupied. Placed after :disabled so occupied days
   keep their marking when they are not selectable. */
.cal-day.occ-pm { background: linear-gradient(135deg, #dcebe3 50%, #f5dddd 50%); }
.cal-day.occ-am { background: linear-gradient(135deg, #f5dddd 50%, #dcebe3 50%); }
.cal-day.occ-am.occ-pm { background: #f5dddd; color: #7c2019; }
/* A turnover day that has gone by keeps the red of its booked half, because that is still a record
   worth reading, but its free half takes the past colour rather than the green of a day still to
   come. Otherwise a single past arrival or departure day carried the strongest green on the
   calendar and pulled the eye straight to the one date nobody can book. */
.cal-day.past.occ-pm { background: linear-gradient(135deg, #eef2ee 50%, #f5dddd 50%); }
.cal-day.past.occ-am { background: linear-gradient(135deg, #f5dddd 50%, #eef2ee 50%); }
/* Restated for the past: a fully booked day has no free half to grey, and the two rules above
   would otherwise split it — they match it just as specifically and come later in the file. */
.cal-day.past.occ-am.occ-pm { background: #f5dddd; color: #7c2019; }
.cal-day.in-range { background: #b3d8c4; }
.cal-day.selected { background: #173f35; color: white; }
.quote { background: #edf6f1; border-radius: 10px; padding: .8rem 1rem; }
.quote p { margin: .35rem 0; }
.primary, .button { display: inline-block; border: 0; border-radius: 9px; padding: .8rem 1.1rem; background: #173f35; color: white; font: inherit; font-weight: 700; text-decoration: none; cursor: pointer; }
.primary:hover, .button:hover { background: #245b4d; }
.danger { background: #8a241d; }
.danger:hover { background: #a52d24; }
/* Secondary action beside a primary one: the flipped, "lighter" variant for minor routes such as
   going back. The border keeps the same footprint as the borderless primary via padding. */
.secondary { border: 1px solid #789286; padding: calc(.8rem - 1px) calc(1.1rem - 1px); background: white; color: #173f35; font-weight: 500; }
.secondary:hover { background: #edf4f0; }
.alert { border-radius: 10px; padding: .8rem 1rem; margin: 1rem 0; }
.error { background: #feeceb; color: #8a1e18; }
.success { background: #e4f5eb; color: #155d36; }
.summary-row { display: grid; grid-template-columns: minmax(9rem, 1fr) 2fr; gap: 1rem; padding: .65rem 0; border-bottom: 1px solid #dfe5e0; }
.summary-label { font-weight: 700; }
.admin-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; }
.admin-actions form { margin: 0; }
/* Back link left, the page's primary action right; both wrap onto their own line when narrow. */
.page-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .6rem; margin: 1rem 0; }
.page-actions form { margin: 0; }
.table-card { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; min-width: 700px; }
th, td { padding: .7rem .55rem; border-bottom: 1px solid #dfe5e0; text-align: left; vertical-align: top; }
th { font-size: .85rem; color: #59635d; }
/* No width floor here on purpose. The floor this table needs belongs to the narrow layout below,
   where the generic `min-width: 0` would otherwise crush eight columns into a phone screen. Applied
   at every width it also overrode the card on desktop: the columns ask for less room than the floor
   demanded, so the card scrolled and the table ran past its own padding while the space to fit it
   was right there. Sized by its content, the table fills the card and scrolls only when the data
   genuinely needs more room than the card can give. */
/* Dates, references, enum labels and email addresses are semantic units. The page-wide
   overflow-wrap rule is useful for prose, but splitting these values makes them harder to scan
   and copy. The table already scrolls horizontally when an unusually long token needs room. */
.admin-bookings-table .table-token { white-space: nowrap; overflow-wrap: normal; word-break: normal; }
/* The address is the one token here with no length limit, so it is the one allowed to wrap. The
   markup marks its seams with <wbr>, and `normal` lets those be used; `break-word` is a last resort
   for an address whose own local part is longer than the column, and applies only when the run
   would otherwise overflow. Without this a single long address widens the column enough to push
   the table past its card. */
.admin-bookings-table .copyable-token { user-select: all; white-space: normal; overflow-wrap: break-word; }
.admin-bookings-table button { overflow-wrap: normal; word-break: normal; }
/* An action label may take a second line but never a third. Once the other columns squeeze this
   one, "Als bezahlt markieren" broke onto three lines and the row grew to match. The floor is the
   widest half of the longest label's two-line split, so it only binds where the column is already
   at its narrowest — where the table scrolls anyway — and never widens a table that fits. */
.admin-bookings-table .admin-actions button { min-width: 6.5rem; text-align: center; }
/* The heading is the sort control and the icon is the filter control; they sit side by side so a
   click lands on exactly one of them. */
.column-header { display: flex; align-items: center; gap: .3rem; white-space: nowrap; }
.column-sort { display: flex; align-items: center; gap: .3rem; color: #173f35; text-decoration: none; }
.column-sort:hover { text-decoration: underline; text-underline-offset: .2rem; }
/* Unsorted columns keep a dimmed marker, so the heading reads as sortable and the row does not
   change width when one becomes the sorted column. */
.column-sort-indicator { font-size: .72rem; color: #a7b2ab; }
[aria-sort="ascending"] .column-sort-indicator, [aria-sort="descending"] .column-sort-indicator { color: #12624b; }
[aria-sort="ascending"] .column-sort, [aria-sort="descending"] .column-sort { font-weight: 750; }
.column-filter-toggle { margin-left: auto; padding: .15rem .3rem; border: 1px solid transparent; border-radius: 6px; background: none; color: #59635d; font-size: .62rem; line-height: 1; cursor: pointer; }
.column-filter-toggle:hover { border-color: #cbd5cf; background: #edf4f0; }
.column-filter-toggle.active { border-color: #a9cdbd; background: #dcf1e5; color: #12624b; }
/* The panel is a popover, so it renders in the top layer: as ordinary table content it grew the
   header row and pushed the data down, and .table-card's scroll container would clip it. Script
   anchors it under its icon; without script the browser still opens it, centred. */
.column-filter-popover { width: 15rem; max-width: calc(100vw - 1rem); padding: .75rem; border: 1px solid #cbd5cf; border-radius: 9px; background: white; color: #20231f; box-shadow: 0 5px 14px rgb(10 35 28 / 12%); font-size: .9rem; font-weight: 400; }
.column-filter-popover .field { margin-bottom: .75rem; }
.column-filter-popover select { width: 100%; }
.column-filter-actions { display: flex; flex-wrap: wrap; gap: .5rem; }
/* GW-19: the second verification before a booking is confirmed from the overview. Opened modally,
   so it renders in the top layer and .table-card's scroll container cannot clip it — the same
   reason the filter panel above is a popover. Framed like that panel, one width wider because it
   carries five labelled rows rather than one field. */
.confirm-dialog { width: min(26rem, calc(100vw - 2rem)); padding: 1.25rem; border: 1px solid #cbd5cf; border-radius: 14px; background: white; color: #20231f; box-shadow: 0 10px 28px rgb(10 35 28 / 24%); }
.confirm-dialog h2 { margin-bottom: .35rem; }
/* The two answers, laid out like the filter panel's. The last summary row above them keeps its
   rule on purpose: it separates what is being confirmed from what confirms it. */
.confirm-dialog-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1rem; }
.confirm-dialog::backdrop { background: rgb(10 35 28 / 45%); }
.compact { padding: .5rem .65rem; font-size: .88rem; }
.status { display: inline-block; padding: .18rem .45rem; border-radius: 999px; background: #ecefec; font-size: .82rem; font-weight: 700; }
.status.confirmed { background: #dcf1e5; color: #155d36; }
.status.cancelled { background: #f5dddd; color: #7c2019; }
.payment-qr { margin: 1.25rem 0; }
.payment-qr img { width: min(320px, 100%); height: auto; display: block; }
/* The swappable amount block (UC-11): the transferable amount, its payment coordinates, its EPC QR
   code and the field for an already made transfer. The field belongs to the amount above it, so it
   stays inside the block instead of reading as a separate form. */
.transfer-amount form { margin-top: 1.25rem; }
.transfer-amount .field { max-width: 18rem; margin-bottom: .5rem; }
.integration-tests { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1rem; }
/* Colors come from the shared .secondary class; this rule only keeps the compact sizing. */
.integration-tests button { padding: .65rem .85rem; font: inherit; border-radius: 8px; white-space: normal; cursor: pointer; }
a { color: #12624b; }

@media (max-width: 600px) {
    :root { scroll-padding-top: 9rem; }
    .shell { width: min(100% - 2rem, 1180px); }
    .header-inner { align-items: flex-start; flex-direction: column; padding-block: .75rem; }
    .nav { width: 100%; }
    .admin-menu { margin-left: auto; }
    .columns { grid-template-columns: 1fr; gap: 0; }
    .summary-row { grid-template-columns: 1fr; gap: .15rem; }
    .integration-tests button { width: 100%; }

    /* Tables collapse into stacked cards; each cell renders its column name
       from the data-label attribute set by the markup. */
    table { min-width: 0; }
    thead { display: none; }
    tr { display: block; border: 1px solid #dfe5e0; border-radius: 10px; padding: .3rem .8rem; margin-bottom: .8rem; }
    tr:last-child { margin-bottom: 0; }
    td { display: grid; grid-template-columns: minmax(6.5rem, 2fr) 5fr; gap: .15rem .7rem; padding: .5rem 0; }
    td:last-child { border-bottom: 0; }
    td::before { content: attr(data-label); font-size: .85rem; font-weight: 650; color: #59635d; }

    /* UC-26 keeps the interactive headers reachable on small screens. This one table remains a
       horizontally scrollable data grid instead of turning into cards whose hidden headers could
       no longer expose their sort and filter menus. 1050px was tuned for seven columns; Abreise
       (GW-20) added an eighth. Rendered the nowrap "08.11.2026" cell and the nowrap "Abreise ⇅"
       heading in the site's own font stack, padding included (both are `border-box`) — both came
       out to the same ~97px, so the floor grows by that and rounds up to 1150px. */
    .admin-bookings-table { min-width: 1150px; }
    .admin-bookings-table thead { display: table-header-group; }
    .admin-bookings-table tr { display: table-row; border: 0; border-radius: 0; padding: 0; margin: 0; }
    .admin-bookings-table th, .admin-bookings-table td { display: table-cell; padding: .7rem .55rem; }
    .admin-bookings-table td::before { content: none; }
}
