/*
 * BdS Oberstenfeld - application styles.
 *
 * Design direction: draft 6 in design/mockups/look-and-feel.html, with the controls of
 * design/mockups/members-2026.html (owner decision of 2026-11-04). Three themes, chosen per user
 * with the dots in the top bar (data-theme on <html>):
 *   bds    club colors, the default: lime band with the slanted edge of the website, purple
 *          actions
 *   light  porcelain and white, near-black actions, petrol accents
 *   dark   the same on charcoal
 * A theme sets colors only. Every shape, size, weight and movement lives once in the shared
 * :root block, so all three themes show the same controls (owner decision of 2026-11-04).
 * Typography: Nunito Sans only, self-hosted (static/fonts/README.md). Text colors are checked
 * for WCAG 2.2 AA in all three themes by bds/core/tests/test_contrast.py; add a pair there when
 * you put a new token combination on screen.
 *
 * Shared vocabulary - templates in every module use these classes:
 *   frame      .app-head stays on screen while the page scrolls (wider screens keep only
 *              the navigation row); .nav-toggle opens .app-menu (popover) on compact
 *              screens: below 761 px, or below 481 px height in landscape
 *   layout     .page-head .page-title .page-lead .page-actions .stack .cluster .grid-2
 *              .button-stack (buttons below each other, full width)
 *              .breadcrumb a (a trail's lone link above the title is a 24 px target)
 *              A .page-head directly in the content sits on the band; .page-head-raised lifts
 *              the element after it onto the band's edge
 *   surfaces   .card .card-title .panel .raised (a surface with a deeper shadow)
 *   tables     .table-wrap (a rounded surface that scrolls wide tables on phones)
 *              .data-table (th, td, tfoot .sum-row, td.num for amounts, td.link-cell for a
 *              link that must not break, td small for a second line)
 *   lists      templates/core/filter_bar.html with bds/core/filters.py: search, switch and
 *              chips of a list on one .filter-bar, filtering live on every keystroke;
 *              .filter-results (the region it swaps) .list-bar .list-count (rows found),
 *              templates/core/pagination.html; under a log the earlier years:
 *              templates/core/year_archive.html with bds/core/years.py (.year-archive)
 *   forms      templates/core/field.html renders every field: .field .field-check .check
 *              (checkbox with its label) .choice-group (radio or checkbox list) .field-help
 *              .field-error; .form-grid .form-stack .form-actions; the member picker
 *              .member-search .member-choices-group .member-choice
 *              (bds/members/templates/members/_member_choices.html); Django's .errorlist and
 *              .helptext work too. Selects, checkboxes, radios, dates, file fields, meters
 *              and progress bars are styled everywhere, without a class
 *   buttons    .btn (secondary) .btn-primary .btn-quiet .btn-danger .btn-small
 *   choosing   .segmented (radios as a switch with a sliding thumb, app.js)
 *              .filter-chip (a filter that names itself and its value, opens a .menu)
 *              .menu (a popover list of radios or links, placed under its button by app.js)
 *   status     .status[data-status="ok|pending|warn|neutral|draft|info|waiting"] and .badge[...]
 *              .tag (a small label next to a name, such as "geändert")
 *   feedback   .messages .alert .alert-success|info|warning|error .empty-state
 *   details    .facts (dl with dt/dd pairs) .pagination (links, aria-current="page")
 *   touch      44 px targets on coarse pointers; hover motion only under (hover: hover)
 *   misc       .muted .num .toolbar .skip-link .visually-hidden .rule (hr)
 *              .icon (see templates/core/icon.html) .htmx-indicator
 *              .no-print (hidden on paper, for filter forms)
 *
 * Blocks of templates/base.html: title, body_class, extra_head, nav_extra (more links
 * at the end of the main navigation), masthead (area on the band under the top bar,
 * the start page puts its greeting there), layout (wraps content; the allauth
 * layouts use it), content, extra_body.
 *
 * Motion: entrance animations are CSS only and every animation honors
 * prefers-reduced-motion (bottom of this file). htmx swaps can opt into a view
 * transition with hx-swap="innerHTML transition:true".
 */

/* ---------- Fonts ---------- */

@font-face {
  font-family: "Nunito Sans";
  font-style: normal;
  font-display: swap;
  font-weight: 200 1000;
  src: url("../fonts/nunito-sans-latin-wght-normal.e010923d59d4.woff2") format("woff2-variations"),
       url("../fonts/nunito-sans-latin-wght-normal.e010923d59d4.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Nunito Sans";
  font-style: normal;
  font-display: swap;
  font-weight: 200 1000;
  src: url("../fonts/nunito-sans-latin-ext-wght-normal.9359f35055cf.woff2") format("woff2-variations"),
       url("../fonts/nunito-sans-latin-ext-wght-normal.9359f35055cf.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* ---------- Tokens ---------- */

/* Shared by every theme: shapes, sizes, weights and motion. */
:root {
  --r: 22px; --r-sm: 12px; --r-lg: 16px; --r-field: 12px; --r-badge: 999px; --r-pill: 999px; --slant: 52px;
  --display-weight: 750; --display-track: -.02em; --h-weight: 750; --strong: 700;
  --nav-weight: 650; --btn-weight: 650; --label-weight: 700; --th-weight: 700;
  --greet-size: 36px; --hero-size: 26px; --total-size: 32px; --title-size: clamp(30px, 3.6vw, 42px);
  --masthead-pad: 88px; --hero-shift: -62px; --entrance-shift: -184px; --raise: 96px;
  --rise: 10px; --reveal: 700ms; --ease-reveal: cubic-bezier(.16, 1, .3, 1);

  --container: 1240px;
  --bar-pad: 16px; --brand-height: 56px; --bar-row-gap: 12px;
  --gutter: clamp(16px, 4vw, 40px);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);
  --ease-pop: cubic-bezier(.34, 1.56, .64, 1);
  --ease-glide: cubic-bezier(.3, 1.3, .5, 1);
}

/* Club colors from the website (brand/README.md). Also the fallback without a theme. */
:root,
[data-theme="bds"] {
  --chrome: #C7D301;
  --page: #F5F6EF; --surface: #FFFFFF; --surface-2: #F1F3E8; --surface-3: #E8EBDC;
  --field: #FFFFFF; --field-border: #8B9080; --field-inset: rgba(40, 44, 0, .06);
  --ink: #2C2C2C; --muted: #5D5D66; --line: #E3E6DA; --line-strong: #D2D6C4;
  --heading: #00756C; --th-ink: #00756C; --th-bg: #FAFBF6; --th-rule: #E3E6DA; --decor: #C7D301;
  --band: #C7D301; --band-ink: #2C2C2C; --band-title: #2C2C2C; --band-muted: #45472A; --band-hover: rgba(255, 255, 255, .45);
  --band-current: #59358C; --band-current-ink: #FFFFFF; --band-current-shadow: 0 1px 2px rgba(40, 20, 70, .3);
  --band-btn-bg: rgba(255, 255, 255, .5); --band-btn-border: rgba(255, 255, 255, 0); --band-btn-hover: rgba(255, 255, 255, .75);
  --head-rule: rgba(44, 44, 44, 0); --head-shadow: rgba(40, 44, 0, .22);
  --task-bg: #FFFFFF; --task-border: #FFFFFF;
  --accent: #59358C; --accent-hover: #4A2C76; --accent-ink: #FFFFFF; --accent-soft: #EFE9F7; --accent-text: #59358C;
  --btn-bg: #FFFFFF; --btn-ink: #2C2C2C; --btn-border: #D2D6C4; --btn-hover-bg: #F1F3E8;
  --hero: #59358C; --hero-ink: #FFFFFF; --hero-muted: rgba(255, 255, 255, .9); --hero-line: rgba(255, 255, 255, .35);
  --hero-border: #59358C; --hero-focus: #C7D301; --hero-btn-bg: #C7D301; --hero-btn-ink: #2C2C2C;
  --signal: #C7D301; --signal-ink: #2C2C2C;
  --highlight: #F8F9F1;
  --ok: #00756C; --ok-soft: #DDF1EF; --ok-text: #00665E;
  --pending: #59358C; --pending-soft: #EFE9F7; --pending-text: #59358C;
  --warn: #C63368; --warn-soft: #FBE6ED; --warn-text: #A3204F;
  --draft-soft: #F1F5C4; --draft-text: #4A5000;
  --info-soft: #E2EEFA; --info-text: #1B5690;
  --waiting-soft: #FCEEDB; --waiting-text: #864500;
  --neutral-soft: #EEEFE9; --focus: #59358C; --halo: rgba(89, 53, 140, .2);
  --seg-track: #ECEEE2; --seg-thumb: #C7D301; --seg-thumb-ink: #2C2C2C;
  --seg-count: rgba(44, 44, 44, .08); --seg-count-on: rgba(44, 44, 44, .14);
  --seg-thumb-shadow: 0 1px 2px rgba(60, 64, 0, .3), inset 0 1px 0 rgba(255, 255, 255, .45);
  --chip-on-bg: #EFE9F7; --chip-on-ink: #59358C; --chip-on-border: #CDBDE6;
  --menu-bg: rgba(255, 255, 255, .94);
  --check-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E");
  --select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26'%3E%3Crect width='26' height='26' rx='8' fill='%23EFE9F7'/%3E%3Cpath d='M9 10.5l4-4 4 4M9 15.5l4 4 4-4' fill='none' stroke='%2359358C' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --search-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235D5D66' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='6.5'/%3E%3Cpath d='m16 16 4.5 4.5'/%3E%3C/svg%3E");
  --sky: #583F99; --town-filter: none; --people: #C7D301; --people-opacity: 1;
  --shadow-card: 0 1px 2px rgba(40, 44, 0, .06);
  --shadow-btn: 0 1px 2px rgba(40, 44, 0, .08), inset 0 1px 0 rgba(255, 255, 255, .7);
  --shadow-primary: 0 1px 2px rgba(40, 20, 70, .3), 0 6px 14px -6px rgba(89, 53, 140, .5), inset 0 1px 0 rgba(255, 255, 255, .16);
  --shadow-raised: 0 1px 2px rgba(40, 44, 0, .06), 0 28px 56px -28px rgba(40, 44, 0, .35);
  --shadow-pop: 0 0 0 .5px rgba(30, 32, 0, .14), 0 2px 6px rgba(30, 32, 0, .08), 0 18px 40px -10px rgba(30, 32, 0, .3);
  --hero-shadow: 0 10px 30px rgba(89, 53, 140, .25);
  color-scheme: light;
  accent-color: var(--accent);
}

/* Light: porcelain and white, near-black actions, petrol accents and a pale lime signal. */
[data-theme="light"] {
  --chrome: #F5F6F4;
  --page: #F5F6F4; --surface: #FFFFFF; --surface-2: #F0F2EF; --surface-3: #E6E9E5;
  --field: #FFFFFF; --field-border: #8F9590; --field-inset: rgba(20, 24, 22, .05);
  --ink: #1A1D1C; --muted: #646A67; --line: #E5E7E3; --line-strong: #D3D7D2;
  --heading: #1A1D1C; --th-ink: #646A67; --th-bg: #FAFBFA; --th-rule: #E5E7E3; --decor: #D3D7D2;
  --band: #F5F6F4; --band-ink: #1A1D1C; --band-title: #1A1D1C; --band-muted: #646A67; --band-hover: rgba(26, 29, 28, .06);
  --band-current: #FFFFFF; --band-current-ink: #1A1D1C; --band-current-shadow: 0 0 0 .5px rgba(26, 29, 28, .12), 0 1px 3px rgba(26, 29, 28, .12);
  --band-btn-bg: #FFFFFF; --band-btn-border: #D3D7D2; --band-btn-hover: #F0F2EF;
  --head-rule: #E5E7E3; --head-shadow: rgba(20, 24, 22, .14);
  --task-bg: #FFFFFF; --task-border: #E5E7E3;
  --accent: #1A1D1C; --accent-hover: #343A37; --accent-ink: #FFFFFF; --accent-soft: #EEF1EE; --accent-text: #0E5E57;
  --btn-bg: #FFFFFF; --btn-ink: #1A1D1C; --btn-border: #D3D7D2; --btn-hover-bg: #F0F2EF;
  --hero: #10302D; --hero-ink: #F4F1E8; --hero-muted: rgba(244, 241, 232, .7); --hero-line: rgba(244, 241, 232, .16);
  --hero-border: #10302D; --hero-focus: #DCE29A; --hero-btn-bg: #F4F1E8; --hero-btn-ink: #10302D;
  --signal: #DCE29A; --signal-ink: #10302D;
  --highlight: #F8F9F7;
  --ok: #2F8F84; --ok-soft: #E6F2EF; --ok-text: #1F6E66;
  --pending: #5E4E9A; --pending-soft: #EFECF8; --pending-text: #5E4E9A;
  --warn: #C2456E; --warn-soft: #FBF0F3; --warn-text: #A0325A;
  --draft-soft: #F3F6D2; --draft-text: #4A5000;
  --info-soft: #E8F1FA; --info-text: #1B5690;
  --waiting-soft: #FCF1E2; --waiting-text: #864500;
  --neutral-soft: #F0F2EF; --focus: #0E5E57; --halo: rgba(14, 94, 87, .2);
  --seg-track: #ECEEEB; --seg-thumb: #FFFFFF; --seg-thumb-ink: #1A1D1C;
  --seg-count: rgba(26, 29, 28, .06); --seg-count-on: #E6F2EF;
  --seg-thumb-shadow: 0 0 0 .5px rgba(20, 24, 22, .1), 0 1px 3px rgba(20, 24, 22, .14);
  --chip-on-bg: #E6F2EF; --chip-on-ink: #1F6E66; --chip-on-border: #BCDCD5;
  --menu-bg: rgba(255, 255, 255, .94);
  --check-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E");
  --select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26'%3E%3Crect width='26' height='26' rx='8' fill='%23EEF1EE'/%3E%3Cpath d='M9 10.5l4-4 4 4M9 15.5l4 4 4-4' fill='none' stroke='%230E5E57' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --search-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23646A67' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='6.5'/%3E%3Cpath d='m16 16 4.5 4.5'/%3E%3C/svg%3E");
  --sky: #59358C; --town-filter: none; --people: #DCE29A; --people-opacity: .5;
  --shadow-card: none;
  --shadow-btn: 0 1px 2px rgba(20, 24, 22, .06), inset 0 1px 0 rgba(255, 255, 255, .8);
  --shadow-primary: 0 1px 2px rgba(0, 0, 0, .2), 0 6px 14px -6px rgba(0, 0, 0, .35), inset 0 1px 0 rgba(255, 255, 255, .12);
  --shadow-raised: 0 1px 2px rgba(20, 24, 22, .04), 0 24px 48px -28px rgba(20, 24, 22, .22);
  --shadow-pop: 0 0 0 .5px rgba(20, 24, 22, .12), 0 2px 6px rgba(20, 24, 22, .06), 0 20px 44px -12px rgba(20, 24, 22, .24);
  --hero-shadow: 0 34px 60px -30px rgba(16, 48, 45, .6);
  color-scheme: light;
}

/* Dark: charcoal with a hint of green, ivory actions. */
[data-theme="dark"] {
  --chrome: #0F1211;
  --page: #0F1211; --surface: #151918; --surface-2: #1B201E; --surface-3: #242A28;
  --field: #121615; --field-border: #5E6662; --field-inset: rgba(0, 0, 0, .3);
  --ink: #ECEEEA; --muted: #8E9692; --line: #232927; --line-strong: #333A37;
  --heading: #ECEEEA; --th-ink: #8E9692; --th-bg: #171B1A; --th-rule: #232927; --decor: #333A37;
  --band: #0F1211; --band-ink: #ECEEEA; --band-title: #ECEEEA; --band-muted: #8E9692; --band-hover: rgba(255, 255, 255, .06);
  --band-current: #242A28; --band-current-ink: #ECEEEA; --band-current-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
  --band-btn-bg: #151918; --band-btn-border: #333A37; --band-btn-hover: #1B201E;
  --head-rule: #232927; --head-shadow: rgba(0, 0, 0, .6);
  --task-bg: #151918; --task-border: #232927;
  --accent: #ECEEEA; --accent-hover: #FFFFFF; --accent-ink: #0F1211; --accent-soft: #1E2422; --accent-text: #A8D8CF;
  --btn-bg: #151918; --btn-ink: #ECEEEA; --btn-border: #333A37; --btn-hover-bg: #1B201E;
  --hero: #132523; --hero-ink: #ECEEEA; --hero-muted: rgba(236, 238, 234, .66); --hero-line: rgba(236, 238, 234, .13);
  --hero-border: #21403C; --hero-focus: #D9DE9E; --hero-btn-bg: #ECEEEA; --hero-btn-ink: #132523;
  --signal: #D9DE9E; --signal-ink: #132523;
  --highlight: #181D1B;
  --ok: #5BBFB2; --ok-soft: rgba(91, 191, 178, .12); --ok-text: #8FD3C8;
  --pending: #A796E0; --pending-soft: rgba(167, 150, 224, .14); --pending-text: #C3B7EE;
  --warn: #E57A9E; --warn-soft: rgba(229, 122, 158, .1); --warn-text: #F0A3BD;
  --draft-soft: rgba(199, 211, 1, .13); --draft-text: #D5E06A;
  --info-soft: rgba(110, 168, 230, .14); --info-text: #A9CDF3;
  --waiting-soft: rgba(240, 170, 80, .13); --waiting-text: #F2C68A;
  --neutral-soft: rgba(255, 255, 255, .06); --focus: #A8D8CF; --halo: rgba(168, 216, 207, .22);
  --seg-track: #1B201E; --seg-thumb: #2C3331; --seg-thumb-ink: #ECEEEA;
  --seg-count: rgba(255, 255, 255, .06); --seg-count-on: rgba(255, 255, 255, .1);
  --seg-thumb-shadow: 0 1px 2px rgba(0, 0, 0, .5), inset 0 1px 0 rgba(255, 255, 255, .07);
  --chip-on-bg: rgba(168, 216, 207, .12); --chip-on-ink: #A8D8CF; --chip-on-border: rgba(168, 216, 207, .3);
  --menu-bg: rgba(30, 36, 34, .96);
  --check-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230F1211' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E");
  --select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 26'%3E%3Crect width='26' height='26' rx='8' fill='%231E2422'/%3E%3Cpath d='M9 10.5l4-4 4 4M9 15.5l4 4 4-4' fill='none' stroke='%23A8D8CF' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --search-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238E9692' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='6.5'/%3E%3Cpath d='m16 16 4.5 4.5'/%3E%3C/svg%3E");
  --sky: #A99BDB; --town-filter: brightness(0) invert(.88); --people: #D9DE9E; --people-opacity: .5;
  --shadow-card: none;
  --shadow-btn: 0 1px 2px rgba(0, 0, 0, .4), inset 0 1px 0 rgba(255, 255, 255, .04);
  --shadow-primary: 0 1px 2px rgba(0, 0, 0, .5), inset 0 1px 0 rgba(255, 255, 255, .6);
  --shadow-raised: 0 30px 60px -30px rgba(0, 0, 0, .8);
  --shadow-pop: 0 0 0 .5px rgba(255, 255, 255, .12), 0 20px 48px -8px rgba(0, 0, 0, .7);
  --hero-shadow: 0 34px 60px -26px rgba(0, 0, 0, .75);
  color-scheme: dark;
}

/* ---------- Base ---------- */

*, *::before, *::after { box-sizing: border-box; }

/* Focus and jump targets stop below the bar that stays on screen (app.js measures it). */
html { scroll-padding-top: calc(var(--head-stuck, 0px) + 12px); }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-family: "Nunito Sans", system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--ink);
  background: var(--page);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 { font-weight: var(--h-weight); line-height: 1.2; }
a { color: var(--accent-text); text-underline-offset: .2em; text-decoration-thickness: 1px; }
img, svg { max-width: 100%; }
button, input, select, textarea { font: inherit; }
::selection { background: var(--signal); color: var(--signal-ink); }

:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

.skip-link { position: absolute; left: -9999px; top: 12px; z-index: 20; padding: 10px 16px; border-radius: var(--r-sm); background: var(--surface); color: var(--ink); font-weight: var(--strong); box-shadow: var(--shadow-pop); }
.skip-link:focus { left: 16px; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* The hidden attribute wins over every display rule, so a hidden .btn or .filter-chip stays hidden. */
[hidden] { display: none !important; }

.icon { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; vertical-align: middle; }

/* ---------- Frame: top bar, band, content, footer ---------- */

.app-bar, .masthead-inner, .app-content { width: min(var(--container), 100% - 2 * var(--gutter)); margin-inline: auto; }

/* The bar stays on screen while the page scrolls, so the menu is always one tap away (owner
   feedback of 2026-11-04). On wider screens only the navigation row stays: --head-tuck pulls the
   logo row, of known height, above the screen edge once the page scrolls; half the row gap stays
   above the navigation. app.js keeps --head-stuck, the part that stays, current for the scroll
   padding, and marks the bar .is-stuck once rows pass under it. The bar stays opaque: rows
   shining through it were hard to read (same feedback). */
.app-head {
  position: sticky; top: calc(-1 * var(--head-tuck)); z-index: 10;
  background: var(--band); color: var(--band-ink); box-shadow: 0 1px 0 var(--head-rule);
  transition: box-shadow .25s;
  --head-tuck: calc(var(--bar-pad) + var(--brand-height) + var(--bar-row-gap) / 2);
}
.app-head.is-stuck { box-shadow: 0 1px 0 var(--head-rule), 0 12px 24px -20px var(--head-shadow); }
.app-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--bar-row-gap) 20px; padding-block: var(--bar-pad); }
.brand { display: block; height: var(--brand-height); flex: none; border-radius: var(--r-sm); }
.logo { display: block; height: 100%; width: auto; aspect-ratio: 1900 / 420; overflow: visible; }
.logo-sky { stroke: var(--sky); }
.logo-sky path { stroke-dasharray: 1; stroke-dashoffset: 0; }
.logo-town { filter: var(--town-filter); }

/* Wider screens: the menu panel draws no box of its own, so the navigation and the user controls
   stay items of the bar. Author styles beat the browser's display: none for a closed popover;
   its text color (CanvasText) is still inherited without a box, so the bar's ink is restored. */
.app-menu { display: contents; color: inherit; }

/* Eleven sections, the user and the theme dots do not fit one row: the navigation takes the row
   below the logo, the row that stays on screen while the page scrolls. Its pills reach 12 px
   past the content edge, so their text lines up with the logo and the page title. */
.app-nav { display: flex; flex-wrap: wrap; gap: 2px; min-width: 0; order: 3; flex-basis: 100%; margin-inline: -12px; }
.app-nav a { display: inline-flex; align-items: center; min-height: 34px; padding: 4px 12px; border-radius: var(--r-pill); color: var(--band-ink); text-decoration: none; font-weight: var(--nav-weight); font-size: 14px; white-space: nowrap; transition: background-color .2s, color .2s, box-shadow .2s; }
.app-nav a:hover { background: var(--band-hover); }
.app-nav a[aria-current] { background: var(--band-current); color: var(--band-current-ink); box-shadow: var(--band-current-shadow); }

.app-user { margin-left: auto; display: flex; align-items: center; gap: 12px; font-size: 14px; font-weight: 600; }
.app-user-name { max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 24px; color: inherit; text-decoration: none; border-radius: var(--r-sm); }
.app-user-name:hover { text-decoration: underline; }
.app-user form { margin: 0; }
.app-logout .btn { min-height: 34px; padding: 6px 12px; font-size: 14px; }
.app-logout .btn:hover { background: var(--band-hover); }

/* "Hilfe" (static/js/tour.js) takes the end of the logo row before the user controls, and on
   compact screens the place before the menu button, so it is one tap away on every device. */
.app-bar .help-toggle { margin-left: auto; min-height: 34px; padding: 6px 14px 6px 10px; font-size: 14px; background: var(--band-btn-bg); border-color: var(--band-btn-border); }
.app-bar .help-toggle:hover { background: var(--band-btn-hover); }
.help-toggle ~ .nav-toggle, .help-toggle ~ .app-menu .app-user { margin-left: 0; }

.theme-switch { display: flex; gap: 6px; }
.theme-dot { width: 24px; height: 24px; padding: 0; border-radius: 50%; border: 2px solid var(--chrome); box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--band-ink) 28%, transparent); cursor: pointer; transition: box-shadow .2s, transform .25s var(--ease-pop); }
.theme-dot[aria-pressed="true"] { box-shadow: 0 0 0 2.5px var(--band-ink); }
/* The dots preview the other themes, so their colors are fixed. */
.theme-dot[value="bds"] { background: conic-gradient(from 225deg, #C7D301 0 50%, #59358C 0); }
.theme-dot[value="light"] { background: conic-gradient(from 225deg, #F5F6F4 0 50%, #10302D 0); }
.theme-dot[value="dark"] { background: conic-gradient(from 225deg, #0F1211 0 50%, #D9DE9E 0); }

/* The band ends in the slanted edge of the website; the start page draws it under its greeting
   instead, and a page with a page head draws it behind the head (Layout vocabulary). */
.band-tail { height: calc(var(--slant) + 12px); background: var(--band); clip-path: polygon(0 0, 100% 0, 100% 12px, 0 100%); }
.band-tail-tall { height: calc(var(--slant) + 150px); clip-path: polygon(0 0, 100% 0, 100% 150px, 0 100%); }
.app-main:has(> .app-content > .page-head) > .band-tail { display: none; }

.app-main { flex: 1; }
/* The start page's fee panel slides in from the side; clipping keeps it from widening the page
   meanwhile. Only there: on other pages too wide content must stay reachable by scrolling. */
.page-home .app-main { overflow-x: clip; }
.app-main:focus { outline: none; }
.app-content { padding-block: 24px 64px; }

.app-foot { padding: 20px var(--gutter) 28px; text-align: center; font-size: 11px; color: var(--muted); }
.deploy-info { margin: 0; font-variant-numeric: tabular-nums; }

/* Hover effects only where a pointer can hover: on a touch screen the last tapped element would keep
   the effect. Hover only restyles what is on screen already, it never reveals content. */
@media (hover: hover) {
  .theme-dot:hover { transform: scale(1.1); }
  .finder-submit:hover .icon { transform: translateX(2px); }
  .shortcut:hover { border-color: var(--accent); transform: translateY(-2px); }
  .hero-btn:hover .icon { transform: translateX(3px); }
}

/* ---------- Layout vocabulary ---------- */

.page-head > :first-child { min-width: 0; }
.page-head { display: flex; flex-wrap: wrap; align-items: end; gap: 12px 24px; margin: 0 0 24px; }
.page-title { overflow-wrap: anywhere; margin: 0; font-weight: var(--display-weight); color: var(--heading); font-size: var(--title-size); line-height: 1.1; letter-spacing: var(--display-track); }
.page-lead { overflow-wrap: anywhere; margin: 6px 0 0; color: var(--muted); max-width: 70ch; }
/* A lone link such as "Alle Benutzer" or a breadcrumb trail's "Mitglieder" is no inline text link:
   padding makes it a 24 px target (WCAG 2.5.8). */
.page-lead a, .breadcrumb a { padding-block: 4px; }
.breadcrumb { margin: 0 0 4px; font-size: 14px; color: var(--muted); }
.breadcrumb a { color: var(--accent-text); }
.page-actions { margin-left: auto; display: flex; flex-wrap: wrap; gap: 8px; }

/* The page head of a content page sits on the band: the club colors draw it in lime with the
   slanted edge of the website, light and dark in the page color. A pseudo-element behind the head
   paints the band from under the top bar out to both screen edges; the screen-wide part is ink
   overflow of a border image, so it never scrolls the page sideways. The slanted edge lies in the
   head's own padding, so the content after the head stays on the page color. Inside the head the
   tokens switch to their band variants, so text and buttons keep their contrast on lime. */
.app-content > .page-head {
  position: relative; padding-bottom: calc(var(--slant) + 4px); margin-bottom: 4px;
  color: var(--band-ink);
  --heading: var(--band-title); --muted: var(--band-muted);
  --btn-bg: var(--band-btn-bg); --btn-border: var(--band-btn-border); --btn-hover-bg: var(--band-btn-hover);
}
.app-content > .page-head::before {
  content: ""; position: absolute; z-index: -1; inset: -100vh 0 0;
  border-image: linear-gradient(var(--band) 0 0) fill 0 / / 0 100vw;
  clip-path: polygon(calc(50% - 50vw) 0, calc(50% + 50vw) 0, calc(50% + 50vw) calc(100% - var(--slant)), calc(50% - 50vw) 100%);
}
/* The element after a raised head moves up onto the band's edge, as the register's search does. */
.app-content > .page-head-raised { padding-bottom: calc(var(--slant) + var(--raise)); }
.app-content > .page-head-raised + * { position: relative; margin-top: calc(-1 * var(--raise)); }

.stack > * + * { margin-top: 16px; }
.cluster { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.button-stack { display: grid; gap: 10px; }
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); gap: 24px; }
.muted { color: var(--muted); }
.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.toolbar { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin-bottom: 16px; }
.rule { border: 0; border-top: 1px solid var(--line); margin: 8px 0; }

/* ---------- Surfaces ---------- */

.card, .panel { overflow-wrap: break-word; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: 26px 28px; box-shadow: var(--shadow-card); }
.card-title { margin: 0 0 12px; font-size: 19px; font-weight: var(--h-weight); color: var(--heading); letter-spacing: -.01em; }
/* Without weight, so a card that stacks its parts (.stack) keeps its gap above a paragraph. */
:where(.card, .panel) > p { margin: 0 0 12px; }
.raised { box-shadow: var(--shadow-raised); }

/* ---------- Tables ---------- */

/* Positioned, so absolutely positioned content such as a .visually-hidden header label scrolls
   with the table instead of escaping the wrap at the far end of a wide table. */
/* A table stands on its own surface with rounded corners, the same on every page. */
.table-wrap { position: relative; max-width: 100%; overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.table-wrap > .data-table > tbody:last-child > tr:last-child > :is(th, td) { border-bottom: 0; }
.data-table { width: 100%; border-collapse: collapse; background: var(--surface); font-size: 15px; }
.data-table th { text-align: left; font-size: 13px; font-weight: var(--th-weight); color: var(--th-ink); background: var(--th-bg); padding: 11px 12px; border-bottom: 1px solid var(--th-rule); white-space: nowrap; }
.data-table td:not(.num) { overflow-wrap: anywhere; }
.data-table td > a { padding-block: 2px; }
.data-table td { padding: 12px; border-bottom: 1px solid var(--line); vertical-align: top; transition: background-color .15s; }
.data-table tbody tr:hover td { background: var(--highlight); }
.data-table td small { display: block; color: var(--muted); font-size: 13.5px; }
.data-table td.num, .data-table th.num { text-align: right; white-space: nowrap; }
.data-table td.link-cell { overflow-wrap: normal; white-space: nowrap; }
/* In a scrolling table a text cell keeps a readable width: the wrap scrolls sideways instead of
   breaking every word, and only a value longer than that still breaks. */
.table-wrap .data-table td:not(.num):not(.link-cell) { min-width: 6em; }
.data-table tfoot .sum-row td { font-weight: var(--strong); background: var(--th-bg); border-top: 1px solid var(--th-rule); border-bottom: 0; }
/* In a card or panel the card is the frame (owner, 2026-11-05: a box in a box looked cramped).
   The table drops its own box, bands and row fill and runs on hairlines, flush with the card's
   text; whatever follows it, such as a button to the log, keeps its distance. */
:is(.card, .panel) .table-wrap { border: 0; border-radius: 0; background: none; }
:is(.card, .panel) .data-table, :is(.card, .panel) .data-table th, :is(.card, .panel) .data-table tfoot .sum-row td { background: none; }
:is(.card, .panel) .data-table :is(th, td):first-child { padding-left: 0; }
:is(.card, .panel) .data-table :is(th, td):last-child { padding-right: 0; }
:is(.card, .panel) .data-table tbody tr:hover td { background: none; }
:is(.card, .panel) > .table-wrap + * { margin-top: 20px; }

/* ---------- Forms ---------- */

.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); gap: 18px 20px; }
.form-stack { display: flex; flex-direction: column; gap: 16px; margin: 0; }
.field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.field > label { font-size: 14px; font-weight: var(--label-weight); }
/* A select anywhere looks like a Mac pop-up button: the arrows sit in a tinted box at the right.
   Where the browser can style the open list (appearance: base-select), the list matches .menu;
   other browsers open their own list. */
select:not([multiple]) {
  /* overflow: a long option, such as a folder name, is cut at the field's edge instead of
     widening the page; the styled select of base-select would let it run on. */
  appearance: none; max-width: 100%; min-height: 40px; padding: 7px 46px 7px 14px; cursor: pointer; overflow: hidden;
  color: var(--ink); border: 1px solid var(--field-border); border-radius: var(--r-field);
  background: var(--field) var(--select-arrow) no-repeat right 8px center / 26px 26px;
  box-shadow: inset 0 1px 2px var(--field-inset);
}
/* A date outside a form layout, such as "Bezahlt am" in a table row: the field look, compact.
   Inside a .field the rule below takes over. */
input[type="date"] {
  min-height: 38px; padding: 6px 10px; font: inherit; color: var(--ink);
  background-color: var(--field); border: 1px solid var(--field-border); border-radius: var(--r-field);
  box-shadow: inset 0 1px 2px var(--field-inset);
}
:where(.field, .form-grid, .form-stack) :is(input:not([type="checkbox"], [type="radio"], [type="hidden"], [type="file"]), select, textarea) {
  width: 100%; min-height: 44px; color: var(--ink); background-color: var(--field);
  border: 1px solid var(--field-border); border-radius: var(--r-field); padding: 9px 14px;
  box-shadow: inset 0 1px 2px var(--field-inset);
  transition: border-color .18s, box-shadow .18s, background-color .18s;
}
/* The focus shows as a solid ring in the accent with a soft halo around it, as on a Mac. */
:where(.field, .form-grid, .form-stack) :is(input, select, textarea):focus-visible,
select:focus-visible, input[type="date"]:focus-visible { outline: none; border-color: var(--focus); box-shadow: 0 0 0 1px var(--focus), 0 0 0 5px var(--halo); }
:where(.field, .form-grid, .form-stack) :is(input, select, textarea)[aria-invalid="true"] { border-color: var(--warn); }
:where(.field, .form-grid, .form-stack) :is(input, textarea):is([readonly], [disabled]) { background-color: var(--surface-2); }

:where(.field, .form-grid, .form-stack) select:not([multiple]) { padding-right: 46px; }
@supports (appearance: base-select) {
  select:not([multiple]), select:not([multiple])::picker(select) { appearance: base-select; }
  select:not([multiple]) { display: flex; align-items: center; }
  select:not([multiple])::picker-icon { display: none; }
  select:not([multiple])::picker(select) {
    margin-block: 6px; padding: 6px; border: 0; border-radius: var(--r-lg);
    background: var(--menu-bg); color: var(--ink); box-shadow: var(--shadow-pop);
    -webkit-backdrop-filter: blur(24px) saturate(1.8); backdrop-filter: blur(24px) saturate(1.8);
  }
  select:not([multiple]) option { display: flex; align-items: center; gap: 8px; min-height: 38px; padding: 6px 10px; border-radius: 10px; }
  select:not([multiple]) option::checkmark { order: 1; margin-left: auto; color: var(--accent-text); }
  select:not([multiple]) option:checked { font-weight: var(--strong); }
  select:not([multiple]) option:is(:hover, :focus-visible) { background: var(--accent); color: var(--accent-ink); outline: none; }
  select:not([multiple]) option:is(:hover, :focus-visible)::checkmark { color: inherit; }
}

/* Checkboxes and radios in the club's shape and colors. 24 px is the WCAG 2.5.8 minimum target. */
input[type="checkbox"], input[type="radio"] {
  appearance: none; width: 24px; height: 24px; flex: none; cursor: pointer; vertical-align: middle;
  border: 1.5px solid var(--field-border); background: var(--field) center / 18px no-repeat;
  box-shadow: inset 0 1px 2px var(--field-inset);
  transition: background-color .15s, border-color .15s, border-width .2s var(--ease-glide);
}
input[type="checkbox"] { border-radius: 7px; }
input[type="checkbox"]:checked { background-color: var(--accent); border-color: var(--accent); background-image: var(--check-mark); }
/* Part of a group ticked, such as some of the members of a payment group: a dash in the box. */
input[type="checkbox"]:indeterminate { border-color: var(--accent); background-image: linear-gradient(var(--accent), var(--accent)); background-size: 12px 3px; }
input[type="radio"] { border-radius: 50%; }
input[type="radio"]:checked { border: 7px solid var(--accent); }
input:is([type="checkbox"], [type="radio"]):disabled { opacity: .5; cursor: not-allowed; }
.field-check { flex-flow: row wrap; align-items: center; gap: 4px 10px; }
.field-check input { margin: 0; }
.field-check > label { font-weight: 400; }
/* Help and errors of a checkbox stand below its label, in line with the label's text. */
.field-check > :is(.field-help, .field-error) { flex-basis: 100%; padding-left: 34px; }
.field-help, .helptext { font-size: 13px; color: var(--muted); }
/* Help and errors of a field are paragraphs (core/field.html); the field's gap spaces them. */
.field > :is(.field-help, .field-error) { margin: 0; }
.field-help ul { margin: 4px 0 0; padding-left: 18px; }
/* The padding makes a help link such as "Passwort vergessen?" a 24 px target (WCAG 2.5.8) without moving any text. */
.field-help a { padding-block: 4px; }
.field-error, .errorlist { font-size: 13px; font-weight: 600; color: var(--warn-text); }
.field-error { margin: 0; }
.errorlist { list-style: none; margin: 0; padding: 0; }
.errorlist.nonfield { padding: 12px 16px; border-radius: var(--r-field); background: var(--warn-soft); }
.form-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 24px 0 0; }
.form-stack > .form-actions { margin-top: 4px; }

/* A file field shows its choose button as a .btn and the chosen file's name beside it. */
input[type="file"] { max-width: 100%; min-height: 42px; color: var(--muted); font-size: 16px; }
input[type="file"]::file-selector-button {
  min-height: 40px; margin-right: 12px; padding: 8px 16px; cursor: pointer;
  font: inherit; font-size: 15px; font-weight: var(--btn-weight); color: var(--btn-ink);
  border: 1px solid var(--btn-border); border-radius: var(--r-sm); background-color: var(--btn-bg); box-shadow: var(--shadow-btn);
  transition: background-color .2s;
}
input[type="file"]:hover::file-selector-button { background-color: var(--btn-hover-bg); }
input[type="file"]:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: var(--r-sm); }

/* Meters and progress bars: a rounded track in the switch's tint, filled with the accent; a
   meter past its warning mark turns to the warning color. */
meter, progress {
  -webkit-appearance: none; appearance: none; display: block; width: 100%; height: 10px;
  border: 0; border-radius: var(--r-pill); background: var(--seg-track); overflow: hidden;
}
progress::-webkit-progress-bar, meter::-webkit-meter-bar { height: 10px; border: 0; border-radius: var(--r-pill); background: var(--seg-track); }
progress::-webkit-progress-value, meter::-webkit-meter-optimum-value { border-radius: var(--r-pill); background: var(--accent); transition: width .3s var(--ease-out); }
meter::-webkit-meter-suboptimum-value, meter::-webkit-meter-even-less-good-value { border-radius: var(--r-pill); background: var(--warn); }
progress::-moz-progress-bar, meter::-moz-meter-bar { border-radius: var(--r-pill); background: var(--accent); }
meter:-moz-meter-sub-optimum::-moz-meter-bar, meter:-moz-meter-sub-sub-optimum::-moz-meter-bar { background: var(--warn); }

/* Fields shared by every form (templates/core/field.html). */
.field textarea { resize: vertical; }
.field-error p { margin: 0; }
.check { display: inline-flex; align-items: center; gap: 10px; font-size: 15px; cursor: pointer; }
.choice-group { min-inline-size: 0; margin: 0; padding: 0; border: 0; }
.choice-group legend { margin-bottom: 8px; padding: 0; font-size: 14px; font-weight: var(--label-weight); }
.choice-group > div { display: flex; flex-wrap: wrap; gap: 8px 20px; }
.choice-group label { display: inline-flex; align-items: center; gap: 8px; min-height: 32px; font-weight: 400; cursor: pointer; }
/* The member picker (serial mailing, distribution list, event): ticked members and what a search
   found as checkbox rows; long organisation names wrap instead of widening the page. */
.member-choices-group > div { max-height: 360px; overflow-y: auto; }
.member-choice { align-items: flex-start; }
.member-choice span { overflow-wrap: anywhere; min-width: 0; }
.member-search { display: flex; flex-wrap: wrap; gap: 8px; }
.member-search input { flex: 1 1 14rem; min-width: 0; }
/* Fields and field grids that follow each other in a card keep the grid's row gap. */
:is(.card, .panel) > :is(.form-grid, .field) + :is(.form-grid, .field) { margin-top: 18px; }

/* ---------- Filter bar ----------
   Search, switch and chips of a list on one raised surface (templates/core/filter_bar.html);
   on a page with .page-head-raised it sits on the band's edge. The list below it is the
   .filter-results region, which dims while a live update is on its way. */

.filter-bar { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; margin-bottom: 24px; padding: 12px; border-radius: 26px; }
.filter-search {
  display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 0 14px 0 18px;
  background: var(--surface-2); border: 1px solid transparent; border-radius: var(--r-lg);
  transition: background-color .2s, border-color .2s, box-shadow .2s;
}
.filter-search:focus-within { background: var(--field); border-color: var(--focus); box-shadow: 0 0 0 1px var(--focus), 0 0 0 5px var(--halo); }
.filter-search .icon { width: 22px; height: 22px; color: var(--muted); }
.filter-search input { flex: 1; min-width: 0; min-height: 52px; padding: 0; border: 0; outline: 0; background: transparent; color: var(--ink); font-size: 17px; }
.filter-search input::placeholder { color: var(--muted); opacity: 1; }
.filter-bar > .field-help { margin: -4px 6px 0; }
.filter-choices { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 8px; }
/* A search field inside a form, such as the member search of a mailing, looks like the
   search of the filter bar: tinted, with the magnifier inside. */
:where(.field, .form-grid, .form-stack) input[type="search"] {
  min-height: 48px; padding-left: 46px; border-color: transparent; border-radius: var(--r-lg);
  background: var(--surface-2) var(--search-icon) no-repeat 16px center / 20px 20px; box-shadow: none;
}
:where(.field, .form-grid, .form-stack) input[type="search"]:focus-visible { background-color: var(--field); }
.filter-results { transition: opacity .2s; }
.filter-results.htmx-request { opacity: .55; }
/* The number of rows a list shows, and its tools, between the filter bar and the table. */
.list-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px; margin: 0 2px 12px; }
.list-count { margin: 0; color: var(--muted); }
.list-count strong { color: var(--ink); font-size: 17px; font-weight: 800; }
/* The earlier years of a log, a card under its list and pager. */
.year-archive { margin-top: 28px; }

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 42px; padding: 9px 18px;
  font-weight: var(--btn-weight); font-size: 15px; line-height: 1.3; border-radius: var(--r-sm);
  border: 1px solid var(--btn-border); background-color: var(--btn-bg); color: var(--btn-ink); box-shadow: var(--shadow-btn);
  cursor: pointer; text-decoration: none;
  transition: background-color .2s, border-color .2s, color .2s, box-shadow .2s, transform .2s var(--ease-out);
}
.btn:hover { background-color: var(--btn-hover-bg); }
.btn:active { transform: scale(.975); }
.btn .icon { width: 18px; height: 18px; }
/* A faint light from above, as on a Mac's default button. */
.btn-primary { background-color: var(--accent); background-image: linear-gradient(rgba(255, 255, 255, .12), rgba(255, 255, 255, 0)); border-color: transparent; color: var(--accent-ink); box-shadow: var(--shadow-primary); }
.btn-primary:hover { background-color: var(--accent-hover); }
.btn-quiet { background-color: transparent; border-color: transparent; color: inherit; box-shadow: none; }
.btn-quiet:hover { background-color: color-mix(in srgb, currentColor 9%, transparent); }
.btn-danger { color: var(--warn-text); border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
.btn-danger:hover { background-color: var(--warn-soft); }
.btn-small { min-height: 32px; padding: 4px 12px; font-size: 13.5px; border-radius: 10px; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; transform: none; }
/* Only compact screens show the menu buttons (see Compact menu); after .btn, which they carry too. */
.nav-toggle, .nav-close { display: none; }

/* ---------- Choosing: segmented switch, filter chips, menus ---------- */

/* Radios as a switch: the thumb slides to the chosen option (app.js measures it). Without
   JavaScript the chosen option shows its own background instead. Options that do not fit one
   row wrap to the next, so none is hidden off screen. */
.segmented {
  position: relative; display: inline-flex; flex-wrap: wrap; gap: 2px; margin: 0; padding: 4px; border: 0;
  min-width: 0; max-width: 100%;
  border-radius: 14px; background: var(--seg-track); box-shadow: inset 0 1px 2px var(--field-inset);
}
.segmented > legend { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.segmented-thumb {
  position: absolute; top: 0; left: 0; width: var(--thumb-width, 0px); height: var(--thumb-height, 0px);
  transform: translate(var(--thumb-x, 0px), var(--thumb-y, 0px));
  border-radius: 10px; background: var(--seg-thumb); box-shadow: var(--seg-thumb-shadow);
  transition: transform .42s var(--ease-glide), width .42s var(--ease-glide), height .42s var(--ease-glide);
}
.segmented:not(.has-thumb) .segmented-thumb, .segmented.is-placing .segmented-thumb { transition: none; }
.segmented:not(.has-thumb) .segmented-thumb { display: none; }
.segmented label {
  position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 8px;
  min-height: 38px; padding: 4px 10px 4px 12px; border-radius: 10px;
  font-size: 14px; font-weight: 650; color: var(--muted); white-space: nowrap; cursor: pointer;
  transition: color .2s;
}
.segmented label:hover { color: var(--ink); }
.segmented label:has(input:checked) { color: var(--seg-thumb-ink); font-weight: 750; }
.segmented:not(.has-thumb) label:has(input:checked) { background: var(--seg-thumb); box-shadow: var(--seg-thumb-shadow); }
.segmented label:has(input:focus-visible) { outline: 3px solid var(--focus); outline-offset: 1px; }
/* The radio covers its whole option, invisible: the option is the target, for mouse and finger. */
.segmented input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; border: 0; border-radius: inherit; opacity: 0; cursor: pointer; }
.segmented-count { flex: none; white-space: nowrap; min-width: 24px; padding: 1px 7px; border-radius: var(--r-pill); background: var(--seg-count); font-size: 12px; font-weight: 750; text-align: center; transition: background-color .2s; }
.segmented label:has(input:checked) .segmented-count { background: var(--seg-count-on); }

/* A filter chip names its filter and shows the value; a set filter turns tinted and offers ×. */
.filter-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.filter-chip {
  display: inline-flex; align-items: center; border-radius: var(--r-pill);
  background: var(--surface); border: 1px solid var(--line-strong); box-shadow: var(--shadow-btn);
  transition: background-color .2s, border-color .2s;
}
.filter-chip:hover { border-color: var(--field-border); }
.filter-chip-button { display: inline-flex; align-items: center; gap: 6px; min-height: 40px; padding: 4px 10px 4px 14px; border: 0; border-radius: var(--r-pill); background: transparent; color: var(--ink); font-size: 14px; cursor: pointer; }
.filter-chip-label { color: var(--muted); font-weight: 600; }
.filter-chip-value { font-weight: 750; }
/* The sprite's chevron points right; turned down, it turns up while the menu is open. */
.filter-chip-button .icon { width: 16px; height: 16px; color: var(--muted); transform: rotate(90deg); transition: transform .3s var(--ease-out); }
.filter-chip-button[aria-expanded="true"] .icon { transform: rotate(-90deg); }
.filter-chip-clear { display: none; place-items: center; width: 30px; height: 30px; margin-right: 5px; border-radius: 50%; color: inherit; }
.filter-chip-clear .icon { width: 15px; height: 15px; }
.filter-chip-clear:hover { background: color-mix(in srgb, currentColor 14%, transparent); }
/* Set as soon as an option other than the first ("Alle ...") is chosen, with or without
   JavaScript; a chip of fields is set by the server and by app.js (.is-set). */
.filter-chip:is(.is-set, :has(.menu input[type="radio"]:checked:not([value=""]))) { background: var(--chip-on-bg); border-color: var(--chip-on-border); color: var(--chip-on-ink); }
.filter-chip:is(.is-set, :has(.menu input[type="radio"]:checked:not([value=""]))) :is(.filter-chip-button, .filter-chip-label, .filter-chip-button .icon) { color: inherit; }
.filter-chip:is(.is-set, :has(.menu input[type="radio"]:checked:not([value=""]))) .filter-chip-button { padding-right: 4px; }
.filter-chip:is(.is-set, :has(.menu input[type="radio"]:checked:not([value=""]))) .filter-chip-clear { display: grid; }

/* A menu: a popover list of radios or links. app.js places it under its button; without
   JavaScript the browser shows it in the middle of the screen. */
.menu[popover] {
  min-width: 248px; max-width: min(340px, calc(100vw - 24px)); max-height: min(440px, 70vh); overflow: auto;
  padding: 6px; border: 0; border-radius: var(--r-lg);
  background: var(--menu-bg); color: var(--ink); box-shadow: var(--shadow-pop);
  -webkit-backdrop-filter: blur(24px) saturate(1.8); backdrop-filter: blur(24px) saturate(1.8);
  opacity: 0; transform: translateY(-6px) scale(.97); transform-origin: top left;
  transition: opacity .16s ease, transform .24s var(--ease-out), overlay .24s allow-discrete, display .24s allow-discrete;
}
.menu[popover].is-anchored { position: fixed; inset: auto; margin: 0; }
.menu[popover][data-align="end"] { transform-origin: top right; }
.menu[popover]:popover-open { opacity: 1; transform: none; }
@starting-style { .menu[popover]:popover-open { opacity: 0; transform: translateY(-6px) scale(.97); } }
.menu fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
.menu-title { margin: 0; padding: 6px 10px; font-size: 13px; font-weight: 700; color: var(--muted); }
.menu-item {
  position: relative; display: grid; grid-template-columns: 18px minmax(0, 1fr) auto; align-items: center; gap: 8px;
  min-height: 40px; padding: 6px 10px 6px 8px; border-radius: 10px;
  font-size: 15px; color: var(--ink); text-decoration: none; cursor: pointer;
}
.menu-item input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; border: 0; border-radius: inherit; opacity: 0; cursor: pointer; }
.menu-tick { width: 16px; height: 16px; stroke-width: 2.4; color: var(--accent-text); opacity: 0; }
.menu-item:has(input:checked) { font-weight: var(--strong); }
.menu-item:has(input:checked) .menu-tick { opacity: 1; }
.menu-item small { display: block; font-size: 13px; color: var(--muted); font-weight: 400; }
.menu-item > .icon:not(.menu-tick) { width: 18px; height: 18px; color: var(--muted); }
/* As on a Mac: the row under the pointer or the keyboard fills with the accent color. */
/* A menu item can be a button too, such as the two modes under "Hilfe". */
button.menu-item { width: 100%; margin: 0; border: 0; background: none; font: inherit; font-size: 15px; text-align: left; }
.menu-item:hover, .menu-item:has(input:focus-visible), :is(a, button).menu-item:focus-visible { background: var(--accent); color: var(--accent-ink); outline: none; }
.menu-item:hover :is(.icon, small), .menu-item:has(input:focus-visible) :is(.icon, small), :is(a, button).menu-item:focus-visible :is(.icon, small) { color: inherit; }
.menu-sep { height: 1px; margin: 6px 8px; background: var(--line); }
/* A menu of fields, such as the two dates of a period: the fields stand below each other. */
.menu-fields fieldset { display: grid; gap: 12px; padding: 0 8px 10px; }
.menu-fields .menu-title { padding-inline: 2px; }

/* ---------- Status ---------- */

/* A soft pill with a dot: the word carries the meaning, the color only supports it. */
.status, .badge { display: inline-flex; align-items: center; gap: 7px; min-height: 26px; padding: 2px 11px 2px 9px; border-radius: var(--r-badge); font-size: 13px; font-weight: 700; line-height: 1.3; white-space: nowrap; background: var(--neutral-soft); color: var(--ink); }
.status::before, .badge::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--muted); flex: none; }
.status[data-status="ok"], .badge[data-status="ok"] { background: var(--ok-soft); color: var(--ok-text); }
.status[data-status="pending"], .badge[data-status="pending"] { background: var(--pending-soft); color: var(--pending-text); }
.status[data-status="warn"], .badge[data-status="warn"] { background: var(--warn-soft); color: var(--warn-text); }
/* The steps of a contribution run: prepared, bank file, at the bank (contributions templatetags). */
.status[data-status="draft"], .badge[data-status="draft"] { background: var(--draft-soft); color: var(--draft-text); }
.status[data-status="info"], .badge[data-status="info"] { background: var(--info-soft); color: var(--info-text); }
.status[data-status="waiting"], .badge[data-status="waiting"] { background: var(--waiting-soft); color: var(--waiting-text); }
/* A small label next to a name or reference, such as "geändert"; quieter than a status. */
.tag { display: inline-block; padding: 1px 8px; border-radius: var(--r-badge); background: var(--pending-soft); color: var(--pending-text); font-size: 12px; font-weight: 700; vertical-align: middle; }
:is(.status, .badge)[data-status]:not([data-status="neutral"])::before { background: currentColor; }

/* ---------- Feedback ---------- */

.messages { position: relative; list-style: none; padding: 0; margin: 0 0 24px; display: grid; gap: 8px; }
.alert { overflow-wrap: anywhere; padding: 13px 16px; border-radius: 14px; box-shadow: inset 3px 0 0 currentColor; background: var(--neutral-soft); color: var(--ink); }
.alert > p { margin: 0; }
.alert > p + p { margin-top: 4px; }
.alert-success { background: var(--ok-soft); color: var(--ok-text); }
.alert-info { background: var(--pending-soft); color: var(--pending-text); }
.alert-warning, .alert-error { background: var(--warn-soft); color: var(--warn-text); }

.empty-state { overflow-wrap: anywhere; margin: 0; padding: 40px 24px; text-align: center; color: var(--muted); background: var(--surface); border: 1px dashed var(--line-strong); border-radius: var(--r); }

.facts { display: grid; grid-template-columns: minmax(120px, max-content) minmax(0, 1fr); gap: 6px 16px; margin: 0; }
.facts dt { color: var(--muted); font-size: 14px; }
.facts dd { margin: 0; overflow-wrap: anywhere; }
/* The padding makes a link in a value a 24 px target (WCAG 2.5.8) without moving any text. */
.facts dd a { padding-block: 4px; }
/* On a phone each label stands above its value. */
@media (max-width: 640px) {
  .facts { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .facts dd { margin-bottom: 8px; }
}

.pagination { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 6px; margin-top: 20px; font-size: 14px; }
.pagination a, .pagination span { min-width: 36px; padding: 6px 12px; border-radius: var(--r-pill); text-align: center; }
.pagination a { display: inline-flex; align-items: center; gap: 4px; min-height: 36px; color: var(--ink); font-weight: var(--btn-weight); text-decoration: none; border: 1px solid var(--line-strong); background: var(--surface); box-shadow: var(--shadow-btn); }
.pagination a .icon { width: 16px; height: 16px; color: var(--muted); }
.pagination a:hover { background: var(--btn-hover-bg); }
.pagination [aria-current] { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }

.htmx-indicator { opacity: 0; transition: opacity .2s; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }

/* ---------- Start page ---------- */

.masthead { background: var(--band); color: var(--band-ink); padding-bottom: var(--masthead-pad); clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--slant)), 0 100%); }
.masthead-inner { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px 48px; align-items: end; padding-top: 24px; }
.greeting { margin: 0 0 20px; font-size: var(--greet-size); line-height: 1.12; font-weight: var(--display-weight); letter-spacing: var(--display-track); color: inherit; }
.greeting-question { display: block; }

.finder { display: flex; align-items: center; gap: 8px; background: var(--field); color: var(--ink); border: 1px solid var(--field-border); border-radius: var(--r-lg); padding: 6px 6px 6px 16px; box-shadow: inset 0 1px 2px var(--field-inset); transition: box-shadow .3s; }
.finder:focus-within { outline: 3px solid var(--focus); outline-offset: 2px; }
.finder-field { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0; }
.finder-field .icon { width: 24px; height: 24px; color: var(--muted); }
.finder input { flex: 1; min-width: 0; padding: 8px 0; border: 0; outline: 0; background: transparent; color: var(--ink); font-size: 18px; }
.finder input::placeholder { color: var(--muted); opacity: 1; }
.finder input::-webkit-search-cancel-button { cursor: pointer; }
.finder-submit { flex: none; display: grid; place-items: center; width: 44px; height: 44px; padding: 0; border: 0; border-radius: calc(var(--r-lg) - 4px); background: var(--accent); color: var(--accent-ink); cursor: pointer; box-shadow: var(--shadow-primary); transition: background-color .2s, transform .25s var(--ease-pop); }
.finder-submit:hover { background: var(--accent-hover); }
.finder-submit .icon { transition: transform .25s var(--ease-pop); }
/* The matches while typing (members:finder): in the flow under the field, since the masthead's
   slanted edge would clip a box that hangs over the page. Empty until something is typed. */
.finder-results { margin-top: 10px; border-radius: var(--r); background: var(--surface); color: var(--ink); box-shadow: var(--shadow-pop); overflow: hidden; animation: rise .25s var(--ease-out) both; }
.finder-results:empty { display: none; }
.finder-count { margin: 0; padding: 10px 16px 6px; font-size: 13px; font-weight: var(--strong); color: var(--muted); }
.finder-list { margin: 0; padding: 0 6px; list-style: none; }
.finder-list a { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 12px; align-items: center; padding: 8px 10px; border-radius: var(--r-sm); color: inherit; text-decoration: none; }
.finder-list a:hover { background: var(--accent-soft); }
.finder-list a:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; }
.finder-name { font-weight: var(--strong); overflow-wrap: anywhere; }
.finder-meta { grid-column: 1; font-size: 14px; color: var(--muted); }
.finder-list .status { grid-row: 1 / span 2; grid-column: 2; }
.finder-results-all { display: block; margin-top: 4px; padding: 10px 16px 12px; border-top: 1px solid var(--line); font-weight: var(--strong); color: var(--accent-text); text-decoration: none; }
.finder-results-all:hover { text-decoration: underline; }

.shortcuts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.shortcut { display: grid; grid-template-columns: 40px minmax(0, 1fr); column-gap: 12px; align-items: center; align-content: center; padding: 12px 14px; background: var(--task-bg); color: var(--ink); border: 1px solid var(--task-border); border-radius: var(--r-lg); box-shadow: var(--shadow-card); text-decoration: none; transition: border-color .2s, background-color .2s, transform .25s var(--ease-pop), box-shadow .25s; }
.shortcut-icon { grid-row: span 2; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 12px; background: var(--accent-soft); color: var(--accent-text); }
.shortcut strong { font-size: 15.5px; line-height: 1.25; font-weight: var(--h-weight); }
.shortcut > span:last-child { font-size: 13.5px; color: var(--muted); }

.page-home .app-content { padding-top: 0; }
.hero { position: relative; z-index: 1; margin-top: var(--hero-shift); display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(300px, 1fr); gap: 24px; align-items: start; }
.page-home .messages { position: relative; z-index: 2; margin-top: var(--hero-shift); }
.page-home .messages + .hero { margin-top: 0; }
.hero-card { background: var(--hero); color: var(--hero-ink); border: 1px solid var(--hero-border); border-radius: var(--r); padding: 28px 32px 32px; box-shadow: var(--hero-shadow); }
.hero-card :focus-visible { outline-color: var(--hero-focus); }
.hero-title { margin: 0; font-size: var(--hero-size); line-height: 1.1; font-weight: var(--display-weight); letter-spacing: var(--display-track); }
.figures { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; margin: 22px 0 26px; }
.figure::before { content: ""; display: block; height: 3px; margin-bottom: 12px; border-radius: 2px; background: var(--signal); transform-origin: left center; }
.figure dt { font-size: 14px; font-weight: 600; color: var(--hero-muted); }
.figure dd { margin: 6px 0 0; font-size: clamp(34px, 5vw, 48px); line-height: 1; font-weight: var(--display-weight); letter-spacing: var(--display-track); }
/* A figure opens the members it counts; the number keeps the look of the card until pointed at. */
.figure a { display: inline-block; min-width: 24px; color: inherit; text-decoration: none; }
.figure a:hover { text-decoration: underline; text-decoration-thickness: 2px; }
.hero-actions { margin: 0; }
.hero-btn { background: var(--hero-btn-bg); border-color: var(--hero-btn-bg); color: var(--hero-btn-ink); }
.hero-btn:hover { background: var(--hero-btn-bg); box-shadow: 0 0 0 4px color-mix(in srgb, var(--hero-btn-bg) 30%, transparent); }
.hero-btn .icon { transition: transform .25s var(--ease-pop); }

.fee-panel .muted { margin: 0; font-size: 14px; }
.fee-panel .fee-total { margin: 22px 0 0; }
.fee-total-num { position: relative; display: inline-block; padding-bottom: 10px; font-size: var(--total-size); font-weight: var(--display-weight); line-height: 1; letter-spacing: var(--display-track); }
/* The double rule under a total, as in a cash book; the link adds no third line to it. */
.fee-total a { text-decoration: none; }
.fee-total-num::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 6px; border-top: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform-origin: left center; }

/* ---------- Sign-in and account pages (allauth) ---------- */

.entrance { position: relative; z-index: 1; display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); max-width: 980px; margin: var(--entrance-shift) auto 0; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow-pop); overflow: hidden; }
.page-entrance .messages { position: relative; z-index: 2; max-width: 980px; margin: var(--entrance-shift) auto 24px; }
.page-entrance .messages + .entrance { margin-top: 0; }
.entrance-hero { display: flex; flex-direction: column; gap: 10px; padding: 36px 32px 0; background: var(--hero); color: var(--hero-ink); }
.entrance-hero > p { margin: 0; }
.entrance-kicker { font-size: 13px; font-weight: 750; letter-spacing: .08em; text-transform: uppercase; color: var(--signal); }
.entrance-welcome { font-size: 28px; line-height: 1.15; font-weight: var(--display-weight); letter-spacing: var(--display-track); }
.entrance-note { color: var(--hero-muted); font-size: 15px; }
.entrance-people { margin-top: auto; padding-top: 24px; aspect-ratio: 600 / 227; background: var(--people); opacity: var(--people-opacity); -webkit-mask: url("../img/people-lime.ec576bc9f3e7.png") center bottom / contain no-repeat; mask: url("../img/people-lime.ec576bc9f3e7.png") center bottom / contain no-repeat; }
.entrance-body { display: flex; flex-direction: column; gap: 16px; padding: 36px 36px 32px; }
.entrance-body .page-head { margin: 0; }
.entrance-body .page-lead { margin: 0; }
.entrance-body p { margin: 0; }
.entrance-body .form-actions .btn, .entrance-body > .btn, .button-stack .btn { width: 100%; }
.divider { display: flex; align-items: center; gap: 12px; color: var(--muted); font-size: 13px; }
/* One-click demo sign-in, only with DEBUG on this machine (bds/accounts/demo.py). */
.demo-login { display: grid; gap: 6px; text-align: center; }
.demo-login .btn { width: 100%; justify-content: center; border-style: dashed; }
.divider::before, .divider::after { content: ""; flex: 1; border-top: 1px solid var(--line); }

/* The column is capped at the page width: an auto column would grow to a wide table, so its
   .table-wrap could never scroll and the row's last buttons would sit past the screen edge. */
.manage { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; max-width: 760px; }
.manage-body { display: flex; flex-direction: column; gap: 16px; }
.manage-body > p { margin: 0; }
.manage-body .page-head { margin: 0; }
.subnav { display: flex; flex-wrap: wrap; gap: 8px; }
.subnav a { display: inline-flex; align-items: center; gap: 8px; padding: 7px 14px; border: 1px solid var(--line-strong); border-radius: var(--r-pill); background: var(--surface); color: var(--ink); text-decoration: none; font-size: 14px; font-weight: 600; transition: background-color .2s, border-color .2s; }
.subnav a:hover { background: var(--btn-hover-bg); }
.subnav a[aria-current] { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.subnav .icon { width: 18px; height: 18px; }

/* QR codes need dark modules on white in every theme, or phones cannot read them. */
.qr { display: block; width: min(200px, 100%); height: auto; aspect-ratio: 1; padding: 12px; background: #FFFFFF; border: 1px solid var(--line); border-radius: var(--r-field); }
.codes { overflow-wrap: anywhere; font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; letter-spacing: .08em; line-height: 1.7; }

/* ---------- Error pages ---------- */

.error-page { max-width: 640px; padding: 8px 0 32px; }
.error-code { margin: 0 0 8px; font-size: clamp(72px, 14vw, 132px); line-height: .9; font-weight: 800; letter-spacing: -.02em; color: var(--decor); }

/* ---------- Motion ---------- */

@keyframes rise { from { opacity: 0; transform: translateY(var(--rise)); } }
@keyframes slide-in { from { opacity: 0; transform: translateX(18px); } }
@keyframes grow { from { transform: scaleX(0); } }
@keyframes draw { from { stroke-dashoffset: 1; } }
@keyframes logo-rise { from { opacity: 0; transform: translateY(60px); } }
@keyframes wipe { from { opacity: 0; clip-path: inset(0 100% 0 0); } }
@keyframes band-settle { from { clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); } }

/* The head's children rise, not the head: the band behind the head stays put. */
.page-head > *, .error-code, .messages .alert { animation: rise var(--reveal) var(--ease-reveal) both; }
.error-page .page-title { animation: rise var(--reveal) var(--ease-out) 80ms both; }

.page-home .greeting { animation: rise var(--reveal) var(--ease-reveal) 120ms both; }
.page-home .finder { animation: rise var(--reveal) var(--ease-reveal) 220ms both; }
.page-home .shortcut { animation: rise var(--reveal) var(--ease-reveal) 300ms both; }
.page-home .shortcut:nth-child(2) { animation-delay: 350ms; }
.page-home .shortcut:nth-child(3) { animation-delay: 400ms; }
.page-home .shortcut:nth-child(4) { animation-delay: 450ms; }
.page-home .shortcut:nth-child(5) { animation-delay: 500ms; }
.page-home .shortcut:nth-child(6) { animation-delay: 550ms; }
.page-home .shortcut:nth-child(7) { animation-delay: 600ms; }
/* The grid is tested with eight shortcuts; any further one arrives with the eighth, never first. */
.page-home .shortcut:nth-child(n + 8) { animation-delay: 650ms; }
.hero-card { animation: rise calc(var(--reveal) + 200ms) var(--ease-out) 450ms both; }
.fee-panel { animation: slide-in calc(var(--reveal) + 100ms) var(--ease-out) 600ms both; }
.figure::before { animation: grow 700ms var(--ease-out) 800ms both; }
.figure:nth-child(2)::before { animation-delay: 920ms; }
.figure:nth-child(3)::before { animation-delay: 1040ms; }
.fee-total-num::after { animation: grow 700ms var(--ease-in-out) 1300ms both; }
/* The band arrives flat and settles into its slanted edge, as on the website. */
.page-home .masthead { animation: band-settle 1000ms var(--ease-in-out) 150ms backwards; }

.entrance { animation: rise calc(var(--reveal) + 100ms) var(--ease-out) 100ms both; }
.entrance-people { animation: rise 900ms var(--ease-out) 500ms both; }
.page-entrance .logo-sky path { animation: draw 1500ms var(--ease-in-out) both; }
.page-entrance .logo-sky path + path { animation-delay: 300ms; }
.page-entrance .logo-letters { animation: logo-rise 800ms var(--ease-out) 450ms both; }
.page-entrance .logo-town { animation: wipe 900ms var(--ease-out) 850ms both; }

/* Page changes cross-fade; the top bar stays put. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
html:not(.theme-reveal) .app-head { view-transition-name: app-head; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 240ms; }
/* The theme switch reveals the new colors in a circle (app.js); the default cross-fade would fight it. */
html.theme-reveal::view-transition-old(root), html.theme-reveal::view-transition-new(root) { animation: none; mix-blend-mode: normal; }

/* ---------- Small screens ---------- */

@media (max-width: 1100px) {
  .masthead-inner, .hero { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 860px) {
  .entrance { grid-template-columns: minmax(0, 1fr); }
  .entrance-hero { padding: 24px 22px 0; }
  .entrance-welcome { font-size: 22px; }
  .entrance-people { max-height: 96px; padding-top: 12px; }
  .entrance-body { padding: 26px 22px 24px; }
}

@media (max-width: 760px) {
  :root { --gutter: 16px; --greet-size: 28px; --hero-size: 22px; --total-size: 28px; --masthead-pad: 72px; --hero-shift: -56px; --entrance-shift: -170px; --slant: 36px; --raise: 80px; }
  :root { --bar-pad: 12px; }
  .app-bar { gap: 12px; }
  .app-user { gap: 10px; }
  .app-content { padding-block: 20px 48px; }
  .shortcut { grid-template-columns: minmax(0, 1fr); row-gap: 8px; }
  .shortcut-icon { grid-row: auto; }
  .shortcut > span:last-child { display: none; }
  .hero-card { padding: 22px 18px; }
  .figures { gap: 12px; }
  :is(.card, .panel) { padding: 18px 16px; }
  .page-actions { margin-left: 0; }
  .data-table th, .data-table td { padding-inline: 8px; }
  /* Two options per row, each a wide target with its count. */
  .segmented { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; }
  .segmented label { justify-content: space-between; white-space: normal; }
}

/* Compact: phones held either way. The menu button takes the place of the navigation (Compact menu). */
@media (max-width: 760px), (max-height: 480px) and (orientation: landscape) {
  :root { --brand-height: 40px; }
}

/* A phone held sideways has about 360 px of height: a slimmer bar leaves room for the content. */
@media (max-height: 480px) and (orientation: landscape) {
  :root { --bar-pad: 8px; --brand-height: 36px; }

  /* Start page and sign-in: the search and the login field must sit on the first screen.
     The sign-in card overlaps the slanted band by its slant. */
  :root { --masthead-pad: 24px; --greet-size: 24px; --hero-shift: 0px; --entrance-shift: calc(-1 * var(--slant)); }
  .band-tail-tall { height: calc(var(--slant) + 40px); clip-path: polygon(0 0, 100% 0, 100% 40px, 0 100%); }
  .entrance { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
  .entrance-people, .entrance-note { display: none; }
  .entrance-hero, .entrance-body { padding: 20px; }
}

/* Logo, help and menu share a phone's bar: the help keeps its icon and its name for screen readers. */
@media (max-width: 520px) {
  .app-bar .help-toggle { padding-inline: 10px; }
  .help-toggle-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

@media (max-width: 380px) {
  :root { --brand-height: 34px; }
  .theme-switch { gap: 4px; }
  .codes { letter-spacing: .04em; }
}

/* ---------- Touch ---------- */

/* Fingers need 44 px targets (the 24 px of WCAG 2.5.8 is the floor for a mouse). */
@media (pointer: coarse) {
  /* Also with only its icon on a phone. */
  .app-bar .help-toggle { min-width: 44px; min-height: 44px; justify-content: center; }
  .btn, .btn-small, .app-nav a, .subnav a, .pagination a, .app-user-name { min-height: 44px; }
  .filter-chip-button, .segmented label, .menu-item, select:not([multiple]), input[type="date"] { min-height: 44px; }
  .filter-chip-clear { width: 44px; height: 44px; margin-right: 0; }
  .app-nav a, .pagination a { display: inline-flex; align-items: center; }
  /* A flex container would drop the ellipsis of a long name: pad the block instead (24 px line + 2 x 10 px). */
  .app-user-name { padding-block: 10px; }
  .pagination a { min-width: 44px; justify-content: center; }
  /* A figure of one digit is narrower than a finger. */
  .figure a { min-width: 44px; }
  /* The dot stays a 24 px disc inside a 44 px box: the transparent border is the touch area. */
  .theme-dot { width: 44px; height: 44px; border: 10px solid transparent; background-clip: padding-box; box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--band-ink) 28%, transparent); }
  .theme-dot[aria-pressed="true"] { box-shadow: inset 0 0 0 2.5px var(--band-ink); }
}

/* ---------- Compact menu ---------- */

/* Ten sections, the user link, the theme dots and logout do not fit a phone's bar. A native popover
   opens them as a side panel without JavaScript and closes on Escape and on a tap outside.
   The panel look depends on the open state alone, so a menu opened on a phone stays a panel when
   the screen grows (a tablet turned sideways) until it is closed. */
@supports selector(:popover-open) {
  @media (max-width: 760px), (max-height: 480px) and (orientation: landscape) {
    .nav-toggle { display: inline-flex; margin-left: auto; min-height: 44px; }
    .app-bar .help-toggle { min-height: 44px; }
    .app-menu:not(:popover-open) { display: none; }
    /* One row with the menu button: nothing to tuck away, the whole bar stays. */
    .app-head { --head-tuck: 0px; }
  }

  .app-menu:popover-open {
    display: flex; flex-direction: column; gap: 20px;
    position: fixed; inset: 0 0 0 auto; width: min(100%, 340px); height: 100dvh; margin: 0;
    padding: max(16px, env(safe-area-inset-top)) var(--gutter) 24px; overflow-y: auto; overscroll-behavior: contain;
    border: 0; border-left: 1px solid var(--line); background: var(--surface); color: var(--ink); box-shadow: var(--shadow-pop);
  }
  .app-menu::backdrop { background: rgba(0, 0, 0, .35); }
  .app-menu:popover-open .nav-close { display: inline-flex; align-self: flex-end; min-width: 44px; min-height: 44px; padding: 0; }

  /* One section per row; resets the bar's own row and the pills' offset. */
  .app-menu:popover-open .app-nav { flex-direction: column; flex-wrap: nowrap; gap: 4px; margin: 0; order: 0; flex-basis: auto; }
  .app-menu:popover-open .app-nav a { display: flex; align-items: center; min-height: 44px; padding: 10px 12px; border-radius: var(--r-field); color: var(--ink); box-shadow: none; }
  /* The bar's hover tints are made for the band and vanish on the panel. */
  .app-menu:popover-open .app-nav a:hover, .app-menu:popover-open .app-logout .btn:hover { background: var(--surface-2); }
  .app-menu:popover-open .app-nav a[aria-current] { background: var(--accent); color: var(--accent-ink); }

  .app-menu:popover-open .app-user { flex-direction: column; align-items: stretch; gap: 8px; margin: 0; padding-top: 16px; border-top: 1px solid var(--line); }
  .app-menu:popover-open .app-user-name { display: block; max-width: none; min-height: 44px; padding: 10px 12px; white-space: normal; overflow-wrap: anywhere; }
  .app-menu:popover-open .theme-switch { padding-inline: 12px; }
  .app-menu:popover-open .theme-dot { border-color: var(--surface); }
  .app-menu:popover-open .app-logout .btn { width: 100%; justify-content: flex-start; min-height: 44px; padding: 10px 12px; }
}

@supports not selector(:popover-open) {
  @media (max-width: 760px) {
    .app-user-name { display: none; }
    .app-logout .btn { padding: 6px 8px; }
    .app-logout-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
    /* Browsers without popover keep the wrapped navigation. */
    .app-nav { gap: 4px; }
  }
}

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}

/* ---------- Print ---------- */

@page { margin: 15mm; }

@media print {
  /* Own selector list, distinct from the theme blocks that test_contrast.py reads. */
  :root, :root[data-theme] {
    --page: #FFFFFF;
    --surface: #FFFFFF;
    --surface-2: #FFFFFF;
    --highlight: #FFFFFF;
    --ink: #000000;
    --heading: #000000;
    --th-ink: #000000;
    --muted: #444444;
    --line: #CCCCCC;
    --shadow-card: none;
    --shadow-pop: none;
    color-scheme: light;
  }
  /* The dark theme's text, link, tag, badge and alert colors are pale and made for charcoal:
     on paper it prints with the light theme's values. Club colors and light print as they are. */
  :root[data-theme="dark"] {
    --accent: #1A1D1C; --accent-hover: #343A37; --accent-ink: #FFFFFF; --accent-soft: #F0F2EF; --accent-text: #0E5E57;
    --btn-ink: #1A1D1C; --field: #FFFFFF; --neutral-soft: #F0F2EF;
    --ok: #2F8F84; --ok-soft: #E6F2EF; --ok-text: #1F6E66;
    --pending: #5E4E9A; --pending-soft: #EFECF8; --pending-text: #5E4E9A;
    --warn: #C2456E; --warn-soft: #FBF0F3; --warn-text: #A0325A;
    --draft-soft: #F3F6D2; --draft-text: #4A5000;
    --info-soft: #E8F1FA; --info-text: #1B5690;
    --waiting-soft: #FCF1E2; --waiting-text: #864500;
  }
  .app-head, .app-foot, .band-tail, .masthead, .skip-link, .nav-toggle,
  .page-actions, .form-actions, .toolbar, .pagination { display: none; }
  /* The modules' stylesheets load after this one; their display rules must not win on paper. */
  .no-print { display: none !important; }
  .app-content { width: 100%; padding: 0; }
  .card, .panel { box-shadow: none; border: 0; padding: 0; }
  .table-wrap { overflow: visible; }
  /* The same selector as the screen rule: a shorter one would lose on specificity. */
  .table-wrap .data-table td:not(.num):not(.link-cell) { min-width: 0; }
  thead { display: table-header-group; }
  tr { break-inside: avoid; }
  .data-table { font-size: 10pt; }
  /* Wide register tables wrap on the page instead of running past the right edge. */
  .data-table th, .data-table td:not(.num) { white-space: normal; }
  a { color: inherit; text-decoration: none; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* Text links in table rows: WCAG 2.5.8 asks for 24 px targets. Shared by the mandate and
   contribution lists, which load different page stylesheets. */
.row-link { display: inline-flex; align-items: center; min-height: 24px; min-width: 24px; }
/* A row whose object has a page opens it on a click anywhere in the row (data-row-link, app.js).
   The row lights up under the pointer, in a card too, so it shows that it can be clicked. */
.data-table tbody tr:has(a[data-row-link]) { cursor: pointer; }
.data-table tbody tr:has(a[data-row-link]):hover td { background: var(--highlight); }
