﻿/* Ocean theme — ported from the classic Razor Pages app's site.css "Ocean / Wave Theme"
   section. Global (not component-scoped) because it targets MudBlazor's own layout classes
   and fixed-position decoration, neither of which a scoped stylesheet's auto-appended
   attribute selectors can reach. See OceanBackground.razor and MainLayout.razor. */

/* Ocean mode uses the Dark palette (see AppTheme.cs) but also makes MudBlazor's own opaque
   layout surfaces transparent, the same way the classic app's Bootstrap cards float over a
   plain page background instead of each other's surface color. */
.mud-layout.theme-ocean,
.theme-ocean .mud-appbar,
.theme-ocean .mud-drawer,
.theme-ocean .mud-main-content {
    background-color: transparent !important;
}

.ocean-gradient {
    position: fixed;
    inset: 0;
    z-index: -2;
    background: linear-gradient(180deg, #0a2a4a 0%, #1a5276 60%, #1f6f8b 100%);
    pointer-events: none;
}

/* Login card header — ported from the classic Login.cshtml's .card-header, which uses this
   gradient instead of Bootstrap's default. mud-theme-primary would render a flat bright blue
   instead, mismatching the classic page. */
.login-card-header {
    background: linear-gradient(135deg, #0a2a4a 0%, #1a5276 100%);
}

.ocean-waves {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 90px;
    pointer-events: none;
    z-index: -1;
}

.wave {
    width: 200%;
    position: absolute;
    bottom: 0;
    left: 0;
    background-repeat: repeat-x;
    background-position: 0 bottom;
}

.wave-1 {
    height: 80px;
    opacity: 0.45;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 80'%3E%3Cpath fill='%230e4d7b' d='M0,40 C360,80 1080,0 1440,40 L1440,80 L0,80 Z'/%3E%3C/svg%3E");
    background-size: 50% 80px;
    animation: wave-drift 10s linear infinite;
}

.wave-2 {
    height: 60px;
    opacity: 0.30;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 80'%3E%3Cpath fill='%23117a8b' d='M0,40 C360,80 1080,0 1440,40 L1440,80 L0,80 Z'/%3E%3C/svg%3E");
    background-size: 50% 60px;
    animation: wave-drift 14s linear infinite reverse;
}

.wave-3 {
    height: 40px;
    opacity: 0.20;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 80'%3E%3Cpath fill='%231abc9c' d='M0,40 C360,80 1080,0 1440,40 L1440,80 L0,80 Z'/%3E%3C/svg%3E");
    background-size: 50% 40px;
    animation: wave-drift 8s linear infinite;
}

@keyframes wave-drift {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

/* Distinguished section/dialog headers — the classic Razor Pages app always separates a
   card's/modal's header from its body with a visible border (Bootstrap's .card-header and
   .modal-header both do this by default). MudBlazor's own title elements have no such
   border out of the box, which is what made ported dialogs look flatter/less structured than
   the pages they replace. Applied globally so every MudDialog gets it for free, rather than
   relying on each dialog's own markup to add a border-bottom by hand. */
.mud-dialog-title {
    border-bottom: 1px solid var(--mud-palette-lines-default);
    padding-bottom: 12px !important;
    margin-bottom: 4px;
}

.mud-dialog-actions {
    border-top: 1px solid var(--mud-palette-lines-default);
    margin-top: 8px;
    padding-top: 12px !important;
}

/* The app bar's content wants ~453px, so on a 375px phone the trailing items run past the
   edge. The account menu's label is the whole sign-in address (228px of it), which is what
   pushes it over — so below sm that text is dropped and the menu falls back to its account
   icon, the usual mobile pattern. The title still gets an ellipsis as a backstop for a long
   school name, but keeps a floor so it can never be flexed away to nothing. */
/* The address is a bare text node next to the icon span inside .mud-button-label, so it
   cannot be targeted on its own — collapsing the label's font-size drops the text, and the
   icon span gets its size back explicitly. Hiding the whole label instead would take the
   account icon with it and leave no way into Account settings or Logout. */
@media (max-width: 599px) {
    .mud-appbar .mud-menu .mud-button-label {
        font-size: 0;
    }

    .mud-appbar .mud-menu .mud-button-label .mud-button-icon-start {
        font-size: 1.25rem;
        margin: 0;
    }
}

.mud-appbar .mud-typography-h6 {
    min-width: 4rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Attendance grid (GroupAttendance.razor) ───────────────────────────────────
   A roster × training-day matrix, not a list, so it is a hand-built <table>
   rather than a MudTable. Three things it needs that MudBlazor's table styling
   does not give it:

   1. Pinned column widths, with the card sized to its content instead of stretched.
      Left to itself the browser distributes the full page width across however many
      session columns exist, so a group with one training day gets a 600px-wide
      checkbox column.
   2. Real cell dividers. Tracking a row across a dozen session columns by eye is
      the whole job of this screen; the classic Razor Pages version used Bootstrap's
      bordered table for exactly this.
   3. A sticky name column, so the student stays readable once a term's worth of
      sessions scrolls horizontally. (border-collapse must stay `separate` —
      collapsed borders are dropped on sticky cells, hence per-cell right/bottom
      borders and a top/left border on the table itself.) */
.attendance-grid-card {
    width: max-content;
    max-width: 100%;
    overflow-x: auto;
}

/* max-content on the table as well as the card: without it the card's max-width
   caps the table, and the columns squash below their pinned widths instead of the
   card scrolling — which also strands the sticky column, since there is then no
   overflow to scroll. */
.attendance-grid {
    width: max-content;
    border-collapse: separate;
    border-spacing: 0;
    white-space: nowrap;
    border-top: 1px solid var(--mud-palette-lines-default);
    border-left: 1px solid var(--mud-palette-lines-default);
}

.attendance-grid th,
.attendance-grid td {
    border-right: 1px solid var(--mud-palette-lines-default);
    border-bottom: 1px solid var(--mud-palette-lines-default);
    padding: 4px 10px;
    vertical-align: middle;
}

.attendance-grid thead th {
    background-color: var(--mud-palette-background-gray);
    vertical-align: bottom;
    font-size: 0.8125rem;
    font-weight: 600;
    text-align: center;
    padding-top: 8px;
}

.attendance-grid .col-name {
    position: sticky;
    left: 0;
    z-index: 2;
    min-width: 220px;
    text-align: left;
    background-color: var(--mud-palette-surface);
}

.attendance-grid thead .col-name {
    z-index: 3;
    background-color: var(--mud-palette-background-gray);
}

.attendance-grid .col-dob {
    width: 110px;
    text-align: center;
}

/* Notes are free text, and the table is nowrap — so cap the width and ellipsize rather
   than letting one long note stretch the whole grid. Full text is in the title attribute.
   Only .col-name is sticky: pinning all four leading columns (as the classic page did)
   would freeze ~570px of a narrow viewport. */
.attendance-grid .col-notes {
    max-width: 170px;
    overflow: hidden;
    text-overflow: ellipsis;
}

.attendance-grid .col-rate {
    width: 76px;
    text-align: center;
}

.attendance-grid .col-session {
    width: 120px;
    text-align: center;
}

.attendance-grid tbody tr:hover td {
    background-color: var(--mud-palette-action-default-hover);
}

/* Re-assert on the sticky cell: it paints its own background, so the row-hover
   rule above would otherwise stop at the second column. */
.attendance-grid tbody tr:hover .col-name {
    background-color: var(--mud-palette-action-default-hover);
}

/* A translucent tint rather than success-lighten, which is a fixed pastel and
   washes out the checkbox in the dark/ocean palettes. */
.attendance-grid td.cell-present {
    background-color: rgba(var(--mud-palette-success-rgb), 0.18);
}

.attendance-grid tbody tr:hover td.cell-present {
    background-color: rgba(var(--mud-palette-success-rgb), 0.28);
}

.attendance-grid .session-date {
    font-size: 0.8125rem;
    line-height: 1.2;
}

.attendance-grid .session-year {
    font-size: 0.6875rem;
    font-weight: 400;
    line-height: 1.2;
    color: var(--mud-palette-text-secondary);
}

.attendance-grid .session-note {
    margin-top: 4px;
}

.attendance-grid .session-note input {
    font-size: 0.75rem;
    text-align: center;
}

.attendance-grid .session-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
    margin-top: 2px;
}

.attendance-grid .session-lock {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
}

/* The checkboxes carry MudBlazor's default 9px ripple padding, which on a grid
   this dense adds ~20px to every row. */
.attendance-grid .mud-checkbox .mud-icon-button {
    padding: 4px;
}

/* ── Focus mode ───────────────────────────────────────────────────────────────
   The "Take Attendance" view: one session, one big switch per student, meant for
   a phone poolside rather than a desk reviewing a term. Rows get a 48px minimum
   height regardless of the coarse-pointer media query below, since this view's
   whole point is being usable on a touch device. */
.attendance-focus-card {
    max-width: 480px;
}

.attendance-focus-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-height: 48px;
    padding: 6px 16px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.attendance-focus-row:last-child {
    border-bottom: none;
}

.attendance-focus-row.is-present {
    background-color: rgba(var(--mud-palette-success-rgb), 0.12);
}

/* ── Compact attendance grid (phone) ──────────────────────────────────────────
   The same matrix below Md, cut down to what still reads at 375px: DOB, notes and badges
   are dropped in the markup, the name column is capped and ellipsized, and each session
   column shrinks to its date and one menu, which holds what the desktop header shows
   inline (note, mark-all, cancel, lock). That leaves the name plus three or four sessions
   on screen instead of the name plus one. */
.attendance-grid.is-compact th,
.attendance-grid.is-compact td {
    padding: 2px 4px;
}

.attendance-grid.is-compact .col-name {
    min-width: 0;
}

.attendance-grid.is-compact .name-cell {
    max-width: 124px;
    overflow: hidden;
}

.attendance-grid.is-compact .name-cell .mud-link {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.attendance-grid.is-compact .col-rate {
    width: 44px;
}

.attendance-grid.is-compact .col-session {
    width: 52px;
    min-width: 52px;
    position: relative;
}

/* The absence reason overlays the cell's corner instead of sitting beside the checkbox,
   which would widen every column it appears in. */
.attendance-grid.is-compact .reason-mark {
    position: absolute;
    top: 1px;
    right: 1px;
    width: 14px;
    height: 14px;
}

/* ── Phone-width utilities and dialogs ────────────────────────────────────────
   hide-xs drops a low-value column or label below Sm. Only for tables without colspans —
   a display:none cell leaves the table grid, so a colspan row beside it misaligns (Finance
   renders its columns out from IsMobile instead, for that reason).

   Dialogs: MudBlazor keeps its desktop 32px margins and 24px padding at every width, which
   leaves ~263px of a 375px phone for content — narrower than the tables and tab strips
   several dialogs hold. Below Sm they go nearly edge to edge instead. A dialog opened
   FullScreen is left alone. */
@media (max-width: 599px) {
    .hide-xs {
        display: none !important;
    }

    .mud-dialog:not(.mud-dialog-fullscreen) {
        width: calc(100% - 16px);
        max-width: calc(100% - 16px);
    }

    .mud-dialog .mud-dialog-title {
        padding: 12px 16px;
    }

    .mud-dialog .mud-dialog-content:not(.mud-dialog-no-side-padding) {
        padding: 8px 16px;
    }
}

/* StudentProfileDialog's body: a fixed desktop size so switching tabs does not resize the
   dialog under the pointer — but on a phone a 640px width and 520px minimum height are
   what made it scroll sideways and nest one scroll area inside another. */
.profile-dialog-body {
    width: 640px;
    max-width: 100%;
    min-height: 520px;
    max-height: 70vh;
    overflow-y: auto;
}

@media (max-width: 599px) {
    .profile-dialog-body {
        width: auto;
        min-height: 0;
    }
}

/* Schedule's multi-select apply bar sticks to the bottom of the viewport — which on a
   phone is where the bottom navigation is, so it has to sit above it, as .settings-save
   does. */
.schedule-apply-bar {
    position: sticky;
    bottom: 16px;
    z-index: 1;
}

.mud-main-content.has-bottom-nav .schedule-apply-bar {
    bottom: calc(56px + 16px + env(safe-area-inset-bottom, 0px));
}

/* ── Stacked rows (phone layouts of dense tables) ─────────────────────────────
   For a MudSimpleTable whose cells hold inputs — which MudTable's DataLabel stacking would
   turn into one labelled line per cell — the phone layout is a row per record instead:
   the main text flexes and ellipsizes, and the controls keep their size at the end.
   `is-wrapping` lets a `.stacked-row-full` child take its own line under the rest. */
.stacked-row {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 48px;
    padding: 8px 0;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.stacked-row:last-child {
    border-bottom: none;
}

.stacked-row.is-wrapping {
    flex-wrap: wrap;
}

.stacked-row-main {
    flex: 1 1 auto;
    min-width: 0;
}

.stacked-row-main > * {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.stacked-row-full {
    flex: 1 1 100%;
}

/* ── Touch targets ────────────────────────────────────────────────────────────
   Size.Small icon buttons measure 26px, well under both touch minimums (44px in
   Apple's HIG, 48dp in Material), and the row-action columns line up five of
   them. Raising `Size` at the call sites would fix touch at the cost of the
   density the tables are dense for, so instead the *hit area* grows only where
   the primary pointer is coarse. `pointer: coarse` means touch is the main
   input — a hybrid laptop on its trackpad keeps the dense sizing, and a
   trackpad has no trouble with 26px.

   Only padding grows; the icon keeps its size, so nothing reads any larger.
   This reaches the checkbox and switch bases too (both carry .mud-icon-button),
   which is wanted — ticking attendance on a poolside tablet is the case that
   matters most. Fields are untouched because their adornment buttons — the date
   picker's calendar, Clearable's × — already ship at 48px; a dense input's
   height is unchanged, measured. */
@media (pointer: coarse) {
    .mud-icon-button {
        min-width: 44px;
        min-height: 44px;
    }

    /* Dropdown options — MudSelectItem renders a MudListItem, and the Dense
       selects (finance, attendance, group edit) put those at 40px. Non-dense
       options are already 48px, as are the app-bar menus (.mud-menu-item). */
    .mud-list-item {
        min-height: 44px;
    }
}

/* Row-action cells must never wrap, at either target size. The alternative is a
   per-page pixel width re-guessed every time an action is added or the pointer
   changes — Groups was already on its second such guess. `nowrap` raises the
   cell's min-content width instead, so the declared width acts as a floor and
   the column takes what the buttons actually need. */
.row-actions {
    white-space: nowrap;
}

/* ── Rich text editor (mail composer) ─────────────────────────────────────
   Quill's snow theme ships fixed light colours. Left alone, the editor is a
   white rectangle glowing in the middle of the Dark and Ocean themes, with
   near-invisible toolbar icons. These rules re-point it at MudBlazor's palette
   variables so it follows whichever theme is active, including one added later. */

.rich-text-editor {
    border: 1px solid var(--mud-palette-lines-inputs);
    border-radius: var(--mud-default-borderradius);
    overflow: hidden;
}

.rich-text-editor--invalid {
    border-color: var(--mud-palette-error);
}

.rich-text-editor__label {
    display: block;
    padding: 8px 12px 0;
    color: var(--mud-palette-text-secondary);
}

.rich-text-editor .ql-toolbar.ql-snow {
    border: none;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    background: var(--mud-palette-background-gray);
}

.rich-text-editor .ql-container.ql-snow {
    border: none;
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    font-family: var(--mud-typography-body1-family);
    font-size: 0.95rem;
}

/* MudBlazor hard-codes resize:none on every multiline MudTextField (Lines > 1) via
   ".mud-input > textarea.mud-input-root" — the classic app's plain <textarea>s
   (description, notes) could always be dragged taller. That selector's specificity (a class
   plus an element type) beats a same-depth class-only override, hence !important here rather
   than chasing MudBlazor's internal markup shape across versions. Vertical only, so the field
   can't grow past the input's own fixed width and wrap surrounding layout. */
.mud-input-slot.mud-input-root-text {
    resize: vertical !important;
    min-height: 2.5em;
}

/* SectionCard's header bar — the tinted strip is what the classic app's Bootstrap
   ".card-header" had that GroupEdit's original icon+title (border-bottom only, no fill)
   didn't quite reproduce. */
.section-card-header {
    background-color: var(--mud-palette-background-gray);
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.rich-text-editor .ql-editor.ql-blank::before {
    color: var(--mud-palette-text-disabled);
}

/* Quill draws its toolbar icons as inline SVG with hard-coded stroke/fill, so
   the theme colour has to be pushed onto the SVG primitives themselves. */
.rich-text-editor .ql-snow .ql-stroke {
    stroke: var(--mud-palette-text-primary);
}

.rich-text-editor .ql-snow .ql-fill {
    fill: var(--mud-palette-text-primary);
}

.rich-text-editor .ql-snow .ql-picker {
    color: var(--mud-palette-text-primary);
}

/* The dropdowns render in a panel positioned over the editor; without an opaque
   themed background they show the text underneath straight through. */
.rich-text-editor .ql-snow .ql-picker-options {
    background: var(--mud-palette-surface);
    border-color: var(--mud-palette-lines-default);
}

.rich-text-editor .ql-snow.ql-toolbar button:hover .ql-stroke,
.rich-text-editor .ql-snow.ql-toolbar button.ql-active .ql-stroke {
    stroke: var(--mud-palette-primary);
}

.rich-text-editor .ql-snow.ql-toolbar button:hover .ql-fill,
.rich-text-editor .ql-snow.ql-toolbar button.ql-active .ql-fill {
    fill: var(--mud-palette-primary);
}

/* The preview pane renders sanitized, already-substituted mail HTML. Scoped so
   the mail's own inline styles cannot leak into the surrounding admin UI. */
.mail-preview {
    padding: 16px;
    background: var(--mud-palette-surface);
    color: var(--mud-palette-text-primary);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    overflow-x: auto;
}

.mail-preview img {
    max-width: 100%;
}

/* ── Mobile bottom navigation ─────────────────────────────────────────────────
   MobileBottomNav.razor, rendered by MainLayout only below the drawer's breakpoint.
   MudAppBar Bottom="true" gives the fixed bar; everything here is the row of targets
   inside it, which MudBlazor has no component for.

   The safe-area inset is what keeps the labels clear of an iPhone's home indicator once
   the app is installed and running full-bleed (index.html sets viewport-fit=cover). It
   resolves to 0px in a normal browser tab, so the same rule is correct in both. */
.mobile-bottom-nav {
    padding-bottom: env(safe-area-inset-bottom, 0px);
    border-top: 1px solid var(--mud-palette-lines-default);
}

.mobile-bottom-nav__bar {
    display: flex;
    justify-content: space-around;
    align-items: stretch;
    padding: 0;
    gap: 0;
}

/* 56px is Material's bottom-navigation height and comfortably over the 44/48px touch
   minimum; the items divide the width evenly so the target is the whole column, not just
   the icon. */
.mobile-bottom-nav__item {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-height: 56px;
    padding: 6px 2px;
    border: none;
    background: none;
    cursor: pointer;
    text-decoration: none;
    color: var(--mud-palette-text-secondary);
    font-family: inherit;
}

.mobile-bottom-nav__item:hover,
.mobile-bottom-nav__item:focus-visible {
    background-color: var(--mud-palette-action-default-hover);
    text-decoration: none;
}

.mobile-bottom-nav__item.is-active {
    color: var(--mud-palette-primary);
}

.mobile-bottom-nav__label {
    font-size: 0.6875rem;
    line-height: 1.1;
    text-align: center;
}

/* MudMainContent only reserves room for the top app bar, so without this the last row of
   any page sits underneath the bottom bar — worst on the pages that end in a submit
   button. 56px bar + the same safe-area inset it pads itself with. */
.mud-main-content.has-bottom-nav {
    padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px));
}

/* ── Small-viewport spacing ───────────────────────────────────────────────────
   MudContainer's gutters plus MainLayout's py-6 spend ~72px of a 375px-wide screen on
   whitespace. Desktop keeps both; a phone gets a 16px gutter and a shorter vertical
   rhythm, which is roughly one extra table row per screen. */
@media (max-width: 599px) {
    .mud-main-content .mud-container {
        padding-left: 16px;
        padding-right: 16px;
    }

    .mud-main-content .mud-container.py-6 {
        padding-top: 16px;
        padding-bottom: 16px;
    }

    /* The app bar's own safe-area inset, for a landscape notch. */
    .mud-appbar {
        padding-left: env(safe-area-inset-left, 0px);
        padding-right: env(safe-area-inset-right, 0px);
    }
}

/* ── Today screen ─────────────────────────────────────────────────────────────
   Read at arm's length on a wet phone: cards rather than rows, Size.Large buttons, and
   no table anywhere. The cancelled state is desaturated rather than hidden — a cancelled
   session still has to be visible, or the coach cannot tell it apart from one that was
   never scheduled. */
.today-card {
    max-width: 640px;
}

.today-card.is-cancelled {
    opacity: 0.72;
}

/* The action row is the whole point of the card, so on a narrow screen its buttons get the
   full width each rather than shrinking to fit side by side. */
@media (max-width: 599px) {
    .today-card .mud-button-root {
        flex: 1 1 100%;
    }
}

/* A cancelled session's column stays in the grid — it has to, or a gap in the register
   looks like a missing week rather than a cancelled one — but is visibly not a column
   anybody can act on. */
.attendance-grid .col-session.is-cancelled {
    background-image: repeating-linear-gradient(
        45deg,
        transparent,
        transparent 6px,
        rgba(var(--mud-palette-error-rgb), 0.10) 6px,
        rgba(var(--mud-palette-error-rgb), 0.10) 12px
    );
}

.attendance-grid thead th.col-session.is-cancelled .session-date,
.attendance-grid thead th.col-session.is-cancelled .session-year {
    text-decoration: line-through;
}

/* ── Schedule agenda (phone) ──────────────────────────────────────────────────
   Replaces the month grid below Sm. 56px rows so the whole row is the tap target, and the
   date block is fixed-width so the group chips all start at the same x. */
.schedule-agenda-row {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 56px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
    cursor: pointer;
}

.schedule-agenda-row:last-child {
    border-bottom: none;
}

.schedule-agenda-row:hover {
    background-color: var(--mud-palette-action-default-hover);
}

.schedule-agenda-row.is-selected {
    background-color: var(--mud-palette-primary-hover);
}

.schedule-agenda-date {
    flex: 0 0 44px;
    text-align: center;
    line-height: 1.1;
}

.schedule-agenda-row.is-today .schedule-agenda-date {
    color: var(--mud-palette-primary);
    font-weight: 600;
}

.schedule-agenda-day {
    font-size: 1.125rem;
}

.schedule-agenda-weekday {
    font-size: 0.6875rem;
    color: var(--mud-palette-text-secondary);
    text-transform: uppercase;
}

/* ── Site notice (Impressum) ──────────────────────────────────────────────────
   The stored value is plain text and is rendered as text, never as markup — the page is
   anonymous, so treating it as HTML would turn the settings form into a way to publish
   script to every visitor. pre-wrap is what keeps the author's paragraphs and line breaks
   without needing any markup at all. */
.impressum-body {
    white-space: pre-wrap;
    line-height: 1.6;
}

/* ── Settings shell ───────────────────────────────────────────────────────────
   A section list beside one section's form, replacing the single column of four cards the
   page used to be. Grid rather than MudTabs: MudTabs' left position scrolls its tab strip
   horizontally on a narrow viewport, which hides the very sections it exists to expose —
   so the page swaps the list for a select below Sm instead (see .is-mobile). */
.settings-shell {
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr);
    gap: 24px;
    align-items: start;
}

.settings-shell.is-mobile {
    display: block;
}

/* Sticks while the form scrolls: the list is the page's orientation, and losing it behind a
   long section is what makes a settings screen feel like a pile of boxes. */
.settings-nav {
    position: sticky;
    top: 88px;
    overflow: hidden;
}

/* min-width:0 on the content column so a wide field (the 10-row Impressum box) cannot push
   the grid wider than its container and take the sidebar off screen. */
.settings-content {
    min-width: 0;
}

/* The one save button for the three sections that share a record. Sticky to the bottom of
   the viewport so it is reachable from anywhere in a long section without scrolling back,
   and carrying its own explanation of what it covers. */
.settings-save {
    position: sticky;
    bottom: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 16px;
    padding: 12px 0;
    background: var(--mud-palette-background);
    border-top: 1px solid var(--mud-palette-lines-default);
}

/* The bottom nav owns the bottom of a phone screen, so the save bar sits above it. */
.mud-main-content.has-bottom-nav .settings-save {
    bottom: calc(56px + env(safe-area-inset-bottom, 0px));
}
