/* ════════════════════════════════════════════════════════════════
   mobile.css — the responsive layer.
   Extracted verbatim from styles.css. This sheet is loaded AFTER
   styles.css, and several rules here override the desktop base purely
   by source order, so it MUST stay last in the <link> order.
   styles.css = base / desktop; mobile.css = all @media blocks + the
   mobile-only nav components (tab bar, gear menu).
   ════════════════════════════════════════════════════════════════ */

@media (max-width: 900px) {
  .dash-kpi-grid       { grid-template-columns: repeat(2, 1fr); }
  .dash-chart-grid     { grid-template-columns: 1fr; }
}
/* ════════════════════════════════════════════════════════════════
   MOBILE — responsive foundation (Checkpoint 1)
   Goal: make the app comfortable on a phone instead of a shrunk
   desktop view. Built page-by-page; this block is the base layer.
   Scope: responsive web only (no native app / PWA).
   ════════════════════════════════════════════════════════════════ */

/* Tablet & down — pull the generous desktop gutters in a bit. */
@media (max-width: 768px) {
  .page         { padding: 24px 20px; }
  .nav-inner    { padding: 10px 20px; }
  .footer-inner { padding: 16px 20px; }
}

/* Phone — tight gutters, no accidental sideways scroll, fluid media. */
@media (max-width: 640px) {
  .page         { padding: 16px 14px; }
  .nav-inner    { padding: 10px 14px; gap: 12px; }
  .footer-inner { padding: 14px 14px; }

  /* Images & embeds never force the viewport wider than the screen. */
  img, svg, canvas { max-width: 100%; height: auto; }

  /* Interim: until a table is reshaped into cards (Members/Finance,
     later checkpoints), let it scroll sideways *within* the page so a
     wide table can't blow out the whole viewport width. */
  table {
    display: block;
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
}

/* ════════════════════════════════════════════════════════════════
   MOBILE navigation — bottom tab bar.
   The account/admin/logout dropdown (gear menu) is now a SHARED
   component (in styles.css) used on every viewport; the only mobile
   difference is that its version line + pinned-doc links show here
   (on desktop those live in the footer, which is hidden on mobile).
   Mobile (≤900px): the top-bar page links collapse to a fixed bottom
   tab bar; the footer is hidden.
   ════════════════════════════════════════════════════════════════ */

/* Bottom bar hidden on desktop (it's a <nav>, so it's also auto-hidden
   pre-login by the `body.logged-out nav` rule). */
.tabbar { display: none; }

@media (max-width: 900px) {
  /* Top bar: keep logo + utility cluster; page links go to the bottom bar. */
  .nav-menu    { display: none; }
  .nav-divider { display: none; }
  footer       { display: none; }   /* its info now lives in the gear menu */

  /* The gear dropdown's version line + pinned-doc links are mobile-only —
     on desktop the footer carries them (and the footer is hidden here). */
  .gear-meta { display: block; }
  .gear-docs { display: block; }

  /* Slightly larger tap targets for the top-bar icons. */
  .nav-user .nav-help-btn,
  .nav-gear-btn { width: 34px; height: 34px; }
  .nav-gear-btn svg { width: 19px; height: 19px; }

  /* The bell is the LEFTMOST icon in the cluster, so the desktop default
     (feed anchored to the bell's own right edge) would push it off-screen to the
     left on a phone. Pin the feed just under the nav at the viewport's right edge
     instead — like the gear menu, which only works because the gear is rightmost. */
  .nav-bell-feed {
    position: fixed;
    top: calc(var(--nav-height) + 4px);
    right: 8px; left: auto;
    max-width: calc(100vw - 16px);
  }
  /* Cap the scrollable list to the viewport so a short/landscape phone can't push
     the last items below the screen (the fixed feed can't be scrolled to). */
  .bell-feed-list { max-height: calc(100vh - var(--nav-height) - 80px); }

  /* Leave room so the fixed bottom bar never covers page content. */
  body { padding-bottom: calc(60px + env(safe-area-inset-bottom, 0px)); }
  /* …but not pre-login: dort ist die Tab-Bar versteckt, und das Polster
     würde die Login-Seite um 60px scrollbar machen. */
  body.logged-out { padding-bottom: 0; }

  /* ── Bottom tab bar ── */
  .tabbar {
    display: flex;
    position: fixed;
    top: auto;                       /* cancel the global `nav { top: 0 }` — with */
    bottom: 0; left: 0; right: 0;    /* both set, the bar would fill the viewport */
    z-index: 200;
    background: #1A1A2E;
    border-top: 1px solid rgba(255,255,255,0.10);
    box-shadow: 0 -2px 10px rgba(0,0,0,0.25);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .tabbar-btn {
    flex: 1;
    background: none;
    border: none;
    cursor: pointer;
    color: rgba(255,255,255,0.6);
    font-family: inherit;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 8px 2px 7px;
    min-height: 56px;
    position: relative;
    transition: color 0.15s;
  }
  .tabbar-btn svg  { width: 23px; height: 23px; display: block; }
  .tabbar-btn span { font-size: 10.5px; font-weight: 600; letter-spacing: 0.2px; }
  .tabbar-btn:active { background: rgba(255,255,255,0.06); }
  .tabbar-btn.active { color: #fff; }
  /* Orange indicator bar above the active tab. */
  .tabbar-btn.active::before {
    content: "";
    position: absolute;
    top: 0; left: 22%; right: 22%;
    height: 3px;
    border-radius: 0 0 3px 3px;
    background: #D95F02;
  }
}

/* ════════════════════════════════════════════════════════════════
   MOBILE in-page section nav (Finance / Admin / Help).
   Desktop: a fixed 220px left sidebar. On a phone that, plus the
   244px content indent, leaves almost no room — so on mobile it
   becomes a sticky, horizontally-scrollable strip of pills above
   the content.
   ════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .admin-layout { padding-left: 0; }

  /* Sub-tab pages (Hilfe / Finanzen / Admin / E-Mail): drop the page's own
     gutters so the sub-tab strip sits FLUSH under the global header (no gap
     above it) and runs full-bleed edge-to-edge — instead of floating as an
     inset card. The content gutters are restored on .admin-content just below,
     so only the strip goes full-width. */
  #page-help, #page-finance, #page-admin, #page-email { padding: 0; }
  .admin-content { padding: 16px 20px 24px; }

  /* On the Hilfe page the strip must stay put even on the messenger view, where
     the chat is position:fixed and pulls its section out of flow — that
     collapses the layout, leaving a *sticky* strip no room, so it drifts up on
     rubber-band scroll. Pin it for real with position:fixed and offset the
     content to clear it. --subtab-h is the strip's deterministic single-row
     height (measured 47px); it also drives the messenger's top offset below. */
  #page-help { --subtab-h: 47px; }
  #page-help .admin-sidebar { position: fixed; top: var(--nav-height); left: 0; right: 0; }
  #page-help .admin-content { padding-top: calc(var(--subtab-h) + 16px); }
  /* A .help-table has 3 or 4 columns of reference text, which does not fit a phone.
     It scrolls inside ITS OWN box: the page body must never scroll sideways. The
     wrapper is the table itself, made a block so overflow applies (a display:table
     element ignores overflow-x). */
  .help-table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .help-table thead, .help-table tbody, .help-table tr { display: table; width: 100%; }
  .help-table th, .help-table td { min-width: 92px; }

  .admin-sidebar {
    position: sticky;
    top: var(--nav-height);
    left: auto; right: auto; bottom: auto;
    width: auto;
    overflow: visible;
    padding: 0;
    margin: 0;            /* flush (was 0 0 16px) — content carries its own top gap */
    border-radius: 0;     /* full-bleed bar under the header (was 8px) */
    z-index: 30;
  }
  .admin-sidebar-title { display: none; }   /* page name already shown in the bar */

  /* The list of section links → a swipeable horizontal row. */
  .admin-sidebar nav {
    display: flex;
    gap: 4px;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    padding: 6px 8px;
    scrollbar-width: none;                  /* hide scrollbar (Firefox) */
  }
  .admin-sidebar nav::-webkit-scrollbar { display: none; }  /* hide (WebKit) */

  .admin-nav-item {
    flex: 0 0 auto;                         /* keep size; scroll instead of wrap */
    white-space: nowrap;
    border-left: none;                      /* drop the desktop left accent */
    border-radius: 6px;
    padding: 8px 14px;
  }
  /* The section icons are a desktop-sidebar affordance. Here the nav is a
     horizontal chip scroller, and an icon per chip would add ~28px each. With
     17 chips on the Hilfe page that is a lot more sideways scrolling for no
     gain, since the label is already the whole chip. */
  .admin-nav-item > svg { display: none; }
  .admin-nav-item.active {
    border-left-color: transparent;
    background: rgba(255,255,255,0.12);
    box-shadow: inset 0 -2px 0 #D95F02;     /* orange underline accent */
  }

  /* ── askDSI → where the phone's messenger pane has its edges ──────────────
     The SHAPE is shared and lives in styles.css. This block only says where the
     pane sits on a phone: pinned straight to the viewport, under the flush
     sub-tab strip and clear of the fixed tab bar (+ iPhone safe area).

     position:fixed rather than a height, so there is no 100dvh height-chain to
     misbehave on iOS Safari. --subtab-h offsets it below the sub-tab strip;
     that strip is a single non-wrapping pill row with fixed font and padding,
     so its height is deterministic and centralized on #page-help above. */
  #page-help #help-ai.active {
    position: fixed;
    top: calc(var(--nav-height) + var(--subtab-h));
    left: 0; right: 0;
    bottom: calc(57px + env(safe-area-inset-bottom, 0px));  /* clear the fixed tab bar */
    z-index: 20;                 /* above page content, below the tab bar (z 200) */
    padding: 0;
  }
}

/* ── askDSI → where the desktop's messenger pane has its edges ───────────────
   The SHAPE is shared and lives in styles.css. This block only says where the
   pane sits on the desktop, and it is the counterpart to the phone's
   position:fixed above: a height rather than an overlay, because here the pane
   fills the content column between the sticky nav and the site footer.

   Why a bounded pane at all. .askchat-messages caps the feed at
   min(60vh, 520px), a share of the viewport, while everything around it is a
   CONSTANT, so the taller the window the taller the feed. Below roughly 1000px
   the whole PAGE scrolled instead of the feed: measured on 2026-08-02 it
   overflowed by 142px at 1440x900 and by 215px at 1366x768. Hiding the search
   row was 58px of that and was never going to be enough on its own.

   The negative margins cancel .page's 40px padding so the pane meets the nav
   and the right edge, and butt it against the fixed sidebar on the left. That
   last one is 64px, not the 24px gutter it looks like: .admin-layout sits
   INSIDE .page's 40px padding and then adds its own 244px, so the content
   column starts at 284 while the fixed sidebar ends at 220.

   The footer's margin has to go with it, and the reason is arithmetic rather
   than taste. The pane's height feeds straight back into the page height (the
   page is `flex: 1`, so a taller child makes it grow), which means
   pane + nav + footer-margin + footer must fit the viewport on its own. With
   the 60px margin in place a flush meeting is impossible: the pane would have
   to overflow, and the overflow lands back in the page height and reappears as
   60px of page scroll. Dropping the margin for this one state is what lets the
   pane meet the dark footer edge to edge, the way it meets the dark sidebar.
   The footer is a SIBLING of #page-help, so `~` reaches it without touching an
   ancestor, and the class it keys on is the same one the search row uses.

   min-height is the floor: below it the pane stops shrinking and the page
   scrolls again, which is what running out of room should honestly look like.
   Nothing else needs a number, because with a definite height flex distributes
   the rest on its own and the feed is the only item that grows. Verified by
   measurement, never by eye: `check-help-ai-scroll.js`. */
@media (min-width: 901px) {
  #page-help #help-ai.active {
    height: calc(100vh - var(--nav-height) - 56px);
    min-height: 320px;
    margin: -40px -40px -40px -64px;
  }
  #page-help.help-ai-open ~ footer { margin-top: 0; }
}

@media (max-width: 640px) {
  /* Phone: tighter content gutters (the sub-tab strip stays full-bleed). */
  .admin-content { padding: 16px 14px 24px; }

  /* Unified control bar → compact: search grows, Filter/Sort + the mobile-only
     Auswählen toggle become icon-only, the primary action shrinks to a square +. */
  .ctrl-bar { gap: 6px; margin: 14px 0; }
  /* flex-basis 140 + min-width 0 lets the search shrink so the icon cluster
     stays on one row even on narrow phones (flex-basis auto refused to). */
  .ctrl-search { flex: 1 1 140px; min-width: 0; }
  .ctrl-spacer { display: none; }
  .ctrl-btn-label { display: none; }
  .ctrl-btn { padding: 0 10px; }
  .ctrl-add { padding: 0; width: 38px; justify-content: center; }
  .ctrl-add .ctrl-add-icon  { display: block; width: 20px; height: 20px; }
  .ctrl-add .ctrl-add-label { display: none; }
  .ctrl-pop { left: auto; right: 0; max-width: calc(100vw - 28px); }
  /* Set by toggleMemberPop when a right-anchored popover (Filter / Sort) would
     overflow the left screen edge after the control bar wraps. */
  .ctrl-pop--left { left: 0; right: auto; }

  /* Table → cards (override the foundation table-scroll). Also drop the desktop
     table's white "sheet" (bg/shadow/radius) so the page background shows
     through between the individual cards. */
  #membersTable       { display: block; overflow: visible; background: transparent; box-shadow: none; border-radius: 0; }
  #membersTable tbody { display: block; }            /* implicit tbody */
  #membersTable tr:first-child { display: none; }    /* hide the <th> header row */

  /* Cells that don't belong on the compact card face. Hidden via the explicit
     .mcard-hide class (not data-label text) so translating the labels can never
     break the match. */
  #membersTable tr:not(:first-child):not(.notes-row) td.mcard-hide { display: none; }

  /* Each member row → a single-line card. */
  #membersTable tr:not(:first-child):not(.notes-row) {
    display: flex;
    align-items: center;
    gap: 10px;
    background: #fff;
    border: 1px solid #ececf0;
    border-radius: 12px;
    padding: 11px 12px;
    margin-bottom: 6px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
  }
  #membersTable tr:not(:first-child):not(.notes-row) td { border: none; padding: 0; }
  /* Handlungsbedarf marker on the card: the desktop inset-shadow sits on the
     hidden .col-select cell, so on the card we paint the left edge of the card
     itself (mirrors the prototype's .mcard.flagged). Full mobile panel is Stage 4. */
  #membersTable tr.flagged:not(:first-child):not(.notes-row) { border-left: 3px solid #E8662A; }
  /* No touch "hover" highlight on the cards (the desktop peach tr:hover). */
  #membersTable tr:not(:first-child):hover td { background-color: transparent; }

  /* #id pill (left). */
  #membersTable td.mcard-id {
    flex: 0 0 auto;
    padding: 2px 8px;
    background: #f2f2f4; color: #888;
    font-size: 12px; font-weight: 700;
    border-radius: 20px;
  }
  #membersTable td.mcard-id::before { content: "#"; color: #aaa; }

  /* Name + membership badge (flexible middle, one line). */
  #membersTable td.mcard-name {
    flex: 1 1 auto; min-width: 0;
    display: flex; align-items: center; gap: 8px;
  }
  .mcard-name-text {
    min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 15px; font-weight: 700; color: #1A1A2E;
  }
  .mcard-mship {
    display: inline-block; flex: 0 0 auto;
    padding: 2px 9px; border-radius: 20px;
    font-size: 11px; font-weight: 700; white-space: nowrap;
  }
  .mship-active-member { background: #eaf5ec; color: #2e7d32; }
  .mship-supporter     { background: #eef1f8; color: #3949ab; }
  .mship-former-member { background: #f2f2f4; color: #777; }

  /* Actions = ⋮ kebab → dropdown menu. */
  #membersTable td.mcard-actions { flex: 0 0 auto; position: relative; }
  .mcard-kebab {
    display: flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    background: none; border: none; cursor: pointer;
    color: #888; border-radius: 8px;
  }
  .mcard-kebab svg { width: 20px; height: 20px; }
  .mcard-kebab:active { background: #f2f2f4; }

  /* The dropdown (replaces the desktop inline icon row). Generic across every
     table that opts in via a td.mcard-actions cell (Members, Transactions,
     Fees) — one shared component, no per-table duplication. */
  td.mcard-actions .mcard-menu {
    display: none;
    position: absolute;
    top: 100%; right: 0;
    min-width: 168px;
    background: #fff;
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.22);
    padding: 6px;
    z-index: 60;
  }
  td.mcard-actions .mcard-menu.open { display: block; }
  /* Menu rows: icon + label, full width (resets the bordered-icon look). */
  td.mcard-actions .mcard-menu button,
  td.mcard-actions .mcard-menu a {
    display: flex; align-items: center; gap: 12px;
    width: 100%; box-sizing: border-box;
    border: none; background: none; cursor: pointer;
    padding: 11px 12px; border-radius: 8px;
    font-family: inherit; font-size: 15px; font-weight: 600;
    color: #1A1A2E; text-align: left; text-decoration: none;
    min-height: 44px;
  }
  td.mcard-actions .mcard-menu button svg,
  td.mcard-actions .mcard-menu a svg { width: 18px; height: 18px; }
  td.mcard-actions .mcard-menu button:active,
  td.mcard-actions .mcard-menu a:active { background: #f4f4f6; }
  td.mcard-actions .mcard-menu .btn-delete { color: #c0392b; }
  td.mcard-actions .mcard-mlabel { display: inline; }   /* show labels in the menu */

  /* Detail panels under the card — Kommentar + Handlungsbedarf. Each opens as
     a rounded "sheet" tucked under its card (mirrors the prototype's .m-sheet),
     replacing the desktop's flush top-bordered block. The shared .notes-row td
     carries the desktop peach background, so reset it to transparent here — else
     it shows as a flush band peeking past the rounded sheet's corners.

     ── The card-gap rule, for EVERY mobile card list in this file ──
     One rhythm: `margin-bottom: 6px` on the card, and the same 6px on a detail
     row that follows it. Never a NEGATIVE top margin to "cancel" the card's
     bottom margin. A closed detail row is empty and self-collapsing, so its two
     margins collapse together and with the card's, and the arithmetic is not
     sequential: `.mand-table` used -10px against a 10px card and rendered a 0px
     gap, while these lists used -4px/-6px and landed on 4-6px by luck. Every list
     was reconciled to 6px on 2026-08-01 (see HANDOFF.md → CSS). */
  #membersTable tr.notes-row { display: block; margin: 0 0 6px; }
  #membersTable tr.notes-row td { display: block; padding: 0; border: none; background: transparent; }
  #membersTable .notes-content.active,
  #membersTable .hb-content.active {
    padding: 12px;
    border: 1px solid #F0E6DD;
    border-radius: 12px;
    background: #FFFAF7;
  }
  /* Both panels open at once → keep the two sheets visually distinct. */
  #membersTable .notes-content.active + .hb-content.active { margin-top: 8px; }
  /* On a narrow phone the reason line wraps — pin the tag + Erledigt/Entfernen
     button so only the reason TEXT reflows, never the chips (they'd squish and
     wrap their own label otherwise). */
  #membersTable .hb-reason .hb-tag,
  #membersTable .hb-reason .hb-clear { flex: none; }
}

/* ════════════════════════════════════════════════════════════════
   Mobile multi-select (Stage 5). A modal selection mode on the member
   cards, entered via the "Auswählen" control-bar icon (toggles
   body.members-selmode in members.js). It reveals a per-card checkbox +
   tap-to-toggle, hides the kebab, and swaps the bottom tab bar for the
   pinned bulk bar — the SAME #membersBulkBar, reshaped by CSS. It drives
   the shared selectedIds + /members/bulk* endpoints (no new backend).
   ════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  /* Entry point: shown only on mobile (desktop uses the checkbox column). */
  .ctrl-bar .ctrl-select { display: inline-flex; align-items: center; justify-content: center; }

  /* In select mode the fixed tab bar steps aside for the pinned action bar. */
  body.members-selmode .tabbar { display: none; }

  /* Reveal the per-card checkbox (normally .mcard-hide). Mirrors the mcard-hide
     selector + the mode class, so it wins on specificity. */
  body.members-selmode #membersTable tr:not(:first-child):not(.notes-row) td.col-select {
    display: flex; align-items: center; justify-content: center;
    flex: 0 0 auto; width: auto; padding: 0; margin-right: 2px;
  }
  body.members-selmode #membersTable td.col-select input.bulk-select {
    width: 22px; height: 22px; accent-color: #E8662A; margin: 0;
    pointer-events: none;   /* the whole card is the tap target — see members.js */
  }
  /* Selected card → peach highlight (mirrors the prototype's .mcard.sel). */
  body.members-selmode #membersTable tr.row-selected:not(:first-child):not(.notes-row) {
    background: #FEF5EC; border-color: #f3d8be;
  }
  /* Kebab out of the way while selecting. */
  body.members-selmode #membersTable td.mcard-actions { display: none; }
  /* Room so the last card can scroll clear of the pinned bar; the tab bar is
     hidden in this mode, so drop the body's tab-bar bottom padding too. */
  body.members-selmode { padding-bottom: 0; }
  body.members-selmode #membersTable { padding-bottom: 160px; }

  /* ── The pinned bulk bar (reshaped #membersBulkBar) ── */
  body.members-selmode #membersBulkBar {
    display: flex; flex-direction: column; gap: 10px;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 210;
    margin: 0; border: none; border-radius: 16px 16px 0 0;
    background: #1A1A2E;
    padding: 12px 14px calc(14px + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -4px 20px rgba(0,0,0,0.30);
  }
  /* Inner reshape rules are gated on body.members-selmode too (not just the
     #membersBulkBar container), so the dark pinned styling is tied to select
     mode as one unit — it can never apply to the bar in any other context. */
  body.members-selmode #membersBulkBar .bulk-toprow {
    display: flex; align-items: center; gap: 12px;
    color: #fff; font-size: 13px; font-weight: 700;
  }
  body.members-selmode #membersBulkBar .bulk-bar-count { color: #fff; }
  body.members-selmode #membersBulkBar .bulk-selall,
  body.members-selmode #membersBulkBar .bulk-done {
    display: inline; background: none; border: none;
    font-family: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
  }
  body.members-selmode #membersBulkBar .bulk-selall { color: #c9cede; }
  body.members-selmode #membersBulkBar .bulk-done   { margin-left: auto; color: #f0a868; }
  body.members-selmode #membersBulkBar .bulk-bar-spacer { display: none; }
  body.members-selmode #membersBulkBar .bulk-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  body.members-selmode #membersBulkBar .bulk-actions .bulk-btn {
    width: 100%; margin: 0; padding: 12px 10px;
    background: #2c2c46; color: #fff; border: none; border-radius: 8px;
    font-size: 13px; font-weight: 700;
  }
  body.members-selmode #membersBulkBar .bulk-actions .bulk-btn--danger { background: #4a2630; color: #ff9b9b; }
  body.members-selmode #membersBulkBar .bulk-actions .bulk-btn:disabled { opacity: .45; }
  body.members-selmode #membersBulkBar .bulk-btn--ghost { display: none; }   /* Auswahl aufheben — Fertig replaces it */
}

/* ════════════════════════════════════════════════════════════════
   Finance tables → mobile cards (Checkpoint 4). Transactions (#txTable)
   and the fee log (#feesLogTable) become stacked cards ≤640px; the
   desktop tables are untouched. Row actions collapse into the shared
   .mcard-actions kebab menu defined in the Members block above.
   ════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

  /* ── Transactions (#txTable) ── */
  #txTable       { display: block; overflow: visible; background: transparent; box-shadow: none; border-radius: 0; }   /* override foundation table-scroll + drop white sheet */
  #txTable tbody { display: block; }
  #txTable tr:first-child { display: none; }               /* hide the <th> header row */

  /* Cells folded into the gray meta line, or dropped from the mobile face:
     date + method appear via .tx-mmeta; the auto badge (inside col-method)
     and the status dot are intentionally hidden on phones. */
  #txTable tr.tx-row td.col-date,
  #txTable tr.tx-row td.col-method,
  #txTable tr.tx-row td.col-status { display: none; }
  /* Read-only note is off the face — revealed when the card is tapped. */
  #txTable tr.tx-row td.col-note { display: none; }

  /* Each transaction → a card:
       row 1  gray meta line (method · date · tag)
       row 2  From/To name | amount | ⋮
       row 3  read-only note (only when tapped open) */
  #txTable tr.tx-row {
    display: grid;
    grid-template-columns: 1fr auto auto;
    grid-template-areas:
      "meta meta   meta"
      "name amount kebab";
    column-gap: 10px; row-gap: 3px;
    background: #fff;
    border: 1px solid #ececf0;
    border-radius: 12px;
    padding: 11px 13px;
    margin-bottom: 6px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
    cursor: pointer;
  }
  #txTable tr.tx-row.note-open {
    grid-template-areas:
      "meta meta   meta"
      "name amount kebab"
      "note note   note";
  }
  /* width:auto resets the desktop column percentages (e.g. .col-fromto 18%),
     which would otherwise pin the grid cells and re-crop the name. */
  #txTable tr.tx-row td { border: none; padding: 0; width: auto; }

  /* No touch "hover" highlight on the cards (the desktop peach tr:hover). */
  #txTable tr.tx-row:hover td,
  #txTable tr.tx-row td:hover { background-color: transparent; }

  #txTable td.tx-mmeta {
    display: block; grid-area: meta;
    min-width: 0;   /* spans all 3 columns — without this its nowrap text forces
                       the auto columns wide and starves the 1fr name column */
    font-size: 11px; color: #9a9aa5;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #txTable td.tx-mmeta .tx-mtag { color: #C2185B; }

  #txTable td.col-fromto { grid-area: name; align-self: center; min-width: 0; }
  #txTable td.col-fromto .fromto-cell {
    font-size: 13px; font-weight: 400; color: #1A1A2E;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #txTable td.col-amount {
    grid-area: amount; align-self: center;
    font-size: 13px; font-weight: 400; white-space: nowrap;
  }
  #txTable td.col-action { grid-area: kebab; align-self: center; position: relative; }

  /* Read-only note (Verwendungszweck), shown only when the card is tapped. */
  #txTable tr.tx-row.note-open td.col-note {
    display: block; grid-area: note;
    margin-top: 6px; padding-top: 8px; border-top: 1px solid #f0f0f0;
    font-size: 13px; color: #555;
  }
  #txTable tr.tx-row.note-open td.col-note .note-cell {
    white-space: normal; overflow: visible; max-width: none;
  }

  /* Comment + donation panels sit directly under their card. */
  #txTable tr.notes-row, #txTable tr.donation-row { display: block; margin: 0 0 6px; }
  #txTable tr.notes-row td, #txTable tr.donation-row td { display: block; padding: 0; border: none; }

  /* ── Fees log (#feesLogTable) → cards ── */
  #feesLogTable       { display: block; overflow: visible; background: transparent; box-shadow: none; border-radius: 0; }   /* override foundation table-scroll + drop white sheet */
  #feesLogTable tbody { display: block; }
  #feesLogTable tr:first-child { display: none; }              /* hide the <th> header row */

  /* Each fee → a static card:
       row 1  gray meta line (period · date · method · Mandatsreferenz)
       row 2  member name | amount | ⋮ */
  #feesLogTable tr.fee-card-row {
    display: grid;
    grid-template-columns: 1fr auto auto;
    grid-template-areas:
      "meta   meta   meta"
      "member amount kebab";
    column-gap: 10px; row-gap: 3px;
    background: #fff;
    border: 1px solid #ececf0;
    border-radius: 12px;
    padding: 11px 13px;
    margin-bottom: 6px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
  }
  /* width:auto resets the shared .tbl-cell paddings/borders for the grid. */
  #feesLogTable tr.fee-card-row td { border: none; padding: 0; width: auto; }
  #feesLogTable tr.fee-card-row:hover td { background-color: transparent; }

  #feesLogTable td.fee-mmeta {
    display: block; grid-area: meta; min-width: 0;
    font-size: 11px; color: #9a9aa5;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #feesLogTable td.fee-mmeta .fee-mmeta-sub { margin-left: 6px; }

  /* col 1 = member (+ expand-older arrow), col 4 = amount, col 7 = ⋮.
     Period/date/method (2/3/5) are folded into the meta line. */
  #feesLogTable tr.fee-card-row td:nth-child(1) {
    grid-area: member; align-self: center; min-width: 0;
    font-size: 13px; color: #1A1A2E;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #feesLogTable tr.fee-card-row td:nth-child(2),
  #feesLogTable tr.fee-card-row td:nth-child(3),
  #feesLogTable tr.fee-card-row td:nth-child(5) { display: none; }
  #feesLogTable tr.fee-card-row td:nth-child(4) {
    grid-area: amount; align-self: center;
    font-size: 13px; font-weight: 400; color: #2E7D32; white-space: nowrap;
  }
  #feesLogTable tr.fee-card-row td:nth-child(7) {
    grid-area: kebab; align-self: center; position: relative; white-space: nowrap;
  }

  /* Mandatsreferenz (col 6) is folded into the meta line — hidden as a column. */
  #feesLogTable tr.fee-card-row td:nth-child(6) { display: none; }

  /* Comment panel sits directly under its card. */
  #feesLogTable tr.notes-row { display: block; margin: 0 0 6px; }
  #feesLogTable tr.notes-row td { display: block; padding: 0; border: none; }

  /* ── Overdue members — the card grid is div-based and reflows on its own
     (auto-fill collapses to one column on narrow screens). Only tighten the
     section padding; the stacked quick-pay form comes from the .fq-form
     rules below. */
  .overdue-section { padding: 16px 14px; }
}

/* ════════════════════════════════════════════════════════════════
   Mobile forms, modals & touch targets (≤640px).
   Everything below is phone-only; desktop (>640px) is untouched.
   Kept as one grouped block so the mobile-CSS-file
   extraction can lift it out cleanly. Four parts:
     A. iOS-zoom fix — every form control ≥16px (Safari zooms on focus
        for anything smaller; this is the single biggest "feels native"
        win). Inline-styled inputs need !important to beat their attr.
     B. Stack rows + full-width fields.
     C. Touch targets — ≥44px tall controls, full-width form buttons.
     D. Modals — tighter padding, stacked full-width actions.
   ════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

  /* ── A. iOS-zoom fix: 16px on EVERY entry field ────────────────────
     Mobile Safari zooms in on focus for any field below 16px. One global
     rule (with !important to beat inline style="font-size:…" attributes)
     covers the lot — form fields, search bars, filter dates, admin
     settings, modals — so nothing zooms. On a phone you never want input
     text under 16px anyway. */
  input, select, textarea { font-size: 16px !important; }

  /* ── B. Stack form rows; fields go full-width ──────────────────── */
  .form-row { flex-direction: column; align-items: stretch; gap: 12px; }
  .form-row > input, .form-row > select, .form-row > textarea {
    flex: none; width: 100%;
  }
  .form-field { flex: none; width: 100%; min-width: 0; }

  /* Profile rows: label above the value/input instead of beside it —
     a roomier, more readable layout on a narrow screen (read + edit). */
  .pf-row { flex-direction: column; align-items: stretch; gap: 5px; }
  .pf-label { min-width: 0; }

  /* Record-fee forms (profile + the deferred overdue quick-form) stack
     too, so each control gets the full card width. */
  .pp-fee-form, .fq-form { flex-direction: column; align-items: stretch; }
  .pp-fee-form .form-field, .fq-field { min-width: 0; width: 100%; }

  /* ── C. Touch targets: ≥44px tall controls ─────────────────────── */
  .form-row input, .form-row select,
  .form-field input, .form-field select,
  .pf-input,
  .pp-fee-form input, .pp-fee-form select,
  .fq-field input, .fq-field select,
  .login-card input,
  .tk-type-select {
    min-height: 44px; padding: 10px 12px;
  }
  /* Inline-padded controls need !important on padding too.
     ⚠ CHECKBOXES ARE EXCLUDED, and that is the rule's own intent rather than an
     exception: 44px plus 12px of padding is a comfortable target for something you
     TYPE INTO, and it turns a 16px tick box into a 40x44 slab that `width`/`height`
     cannot win back (min-height beats height). Both composers now hold a list of
     Beitrags-Kästchen, so without this the picker rendered as a column of slabs and
     only three rows fitted in its 168px box. The rows themselves are the touch
     target: `.composer-attach-opt` is a full-width label, so tapping anywhere on the
     line ticks it. */
  #emailComposePanel input:not([type="checkbox"]):not([type="radio"]),
  #emailComposePanel select,
  #ppComposePanel input:not([type="checkbox"]):not([type="radio"]),
  #ppComposePanel select,
  #resetPasswordInput {
    min-height: 44px; padding: 10px 12px !important;
  }
  /* …and the rows get the height instead, so the list is still thumb-friendly. A row
     measures 52px here (the 16px font floor plus its own padding) against 33px on
     desktop, so the desktop 168px box would show three of them and read as broken.
     ⚠ `.empf-member` needs the same floor and for the same reason: the Empfänger panel
     is NESTED inside #emailComposePanel, so its recipient checkboxes were carrying the
     44px too and the exclusion above took it away from them as well. */
  .composer-attach-opt, .empf-member { min-height: 40px; }
  .composer-attach-list { max-height: 240px; }
  /* …but the Empfänger search field must keep room for its icon (the rule
     above would otherwise let the placeholder sit on top of the icon). */
  #emailComposePanel .empf-search .empf-input { padding-left: 34px !important; }

  /* Full-width, comfortably tall buttons in the main forms + fee forms.
     Stacked, each on its own line; clear the desktop inline left-margin
     on the Add-Member Cancel button. */
  /* display:flex, not block: the text-button family is inline-flex on desktop
     for its icon + centring, and block would strand the label at the left. */
  .form-section .btn-add, .form-section .btn-cancel,
  .pp-fee-form .btn-add, .pp-fee-form .btn-cancel,
  .fq-actions .btn-add, .fq-actions .btn-cancel {
    display: flex; width: 100%; margin: 10px 0 0;
    min-height: 46px; padding: 12px; font-size: 15px;
  }
  #cancelAddMemberBtn { margin-left: 0; }
  /* Fee-form action buttons sit in their own full-width row. No !important
     needed: nothing inline competes for the padding any more. */
  .fq-actions { width: 100%; flex-direction: column; align-items: stretch; }

  /* Bump the email compose action button to a touch-friendly height. */
  #emailPreviewSendBtn { min-height: 44px; }

  /* NO mobile size bump for the 30×30 icon family (edit/notes/delete/fee/hb/info).
     There used to be one here taking four of the six to 40×40 for a roomier tap
     area, and it was wrong twice over: it never listed .btn-hb, and .btn-info did
     not exist yet, so on a phone the family rendered at two different sizes and a
     pencil sat 10px taller than the (i) beside it in every admin card head. The
     family has ONE geometry, defined once in styles.css, and it stays 30×30 on
     every viewport — deliberately, because screen space is scarcer on a phone than
     on the desktop, not because the tap target was forgotten. If a bigger touch
     target is ever wanted, grow the family in styles.css so all six move together. */
  .btn-icon, .btn-icon.btn-sm { width: 38px; min-height: 38px; }

  /* ── D. Modals: tighter padding, stacked full-width actions ────── */
  .modal-box { padding: 24px 20px; }
  .modal-actions { flex-direction: column; gap: 10px; }
  .modal-actions button { width: 100%; min-height: 46px; }
}

/* ════════════════════════════════════════════════════════════════
   CP5b — Remaining tables → mobile cards (≤640px).
   A generic "stacked labeled-card" pattern applied to the tables that
   weren't part of the first two card-list rounds: Admin Users (#usersTable), the profile fee
   history (#feesTable), Tickets (#ticketsTable), and the two email
   logs (.data-table inside #emailSentTableWrap / #ppEmailLog). Each row
   becomes a bordered card; each cell becomes a labeled line (label from
   the cell's data-label attr). Layout only — no behaviour/handler change.
   Desktop (>640px) is untouched. (The richer meta-line grid cards for
   Members/Transactions/Fees-log live in the blocks above.)
   ════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

  /* Let these tables flow as blocks (override the foundation table-scroll). */
  #usersTable, #ticketsTable,
  #emailSentTableWrap .data-table, #ppEmailLog .data-table {
    display: block; overflow: visible; width: 100%;
    background: transparent; box-shadow: none; border-radius: 0;   /* drop white sheet behind cards */
  }
  #usersTable tbody, #ticketsTable tbody,
  #emailSentTableWrap .data-table tbody, #ppEmailLog .data-table tbody {
    display: block;
  }
  /* Hide the header. All four have a <thead> now: #usersTable got one on
     2026-08-02 with the shared table typography, which also retired the
     `tr:first-child` selector this used to need. Keeping that selector would
     have hidden the FIRST USER as well, since a tbody's first row is a
     first-child too. */
  #usersTable thead,
  #ticketsTable thead,
  #emailSentTableWrap .data-table thead,
  #ppEmailLog .data-table thead { display: none; }

  /* Card rows. */
  #usersTable tbody tr,
  #ticketsTable tr.tk-row,
  #emailSentTableWrap .data-table tbody tr,
  #ppEmailLog .data-table tbody tr {
    display: block;
    background: #fff; border: 1px solid #ececf0; border-radius: 12px;
    padding: 10px 13px; margin-bottom: 6px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
  }
  /* No touch "hover" highlight on the card rows. */
  #usersTable tbody tr:hover td,
  #ticketsTable tr.tk-row:hover td { background-color: transparent; }

  /* Cells → stacked labeled lines. */
  #usersTable tbody tr > td,
  #ticketsTable tr.tk-row > td,
  #emailSentTableWrap .data-table tbody td,
  #ppEmailLog .data-table tbody td {
    display: block; width: auto; border: none;
    padding: 4px 0; white-space: normal;
  }
  /* The little uppercase label above each value (from data-label). */
  #usersTable td[data-label]::before,
  #ticketsTable td[data-label]::before,
  #emailSentTableWrap .data-table td[data-label]::before,
  #ppEmailLog .data-table td[data-label]::before {
    content: attr(data-label);
    display: block; margin-bottom: 2px;
    font-size: 10.5px; font-weight: 700; letter-spacing: 0.4px;
    text-transform: uppercase; color: #9a9aa5;
  }

  /* Full-width inputs/selects inside the cards. */
  #usersTable td input.editable-cell, #usersTable td .user-role-select,
  #ticketsTable td .tk-inline-select {
    width: 100%; box-sizing: border-box; min-height: 40px; font-size: 16px;
  }

  /* Action cells → a button row with a divider above (no label). */
  #usersTable td.user-row-actions,
  #ticketsTable td.tk-action-cell {
    display: flex; gap: 10px; align-items: center;
    margin-top: 6px; padding-top: 8px; border-top: 1px solid #f1f1f4;
  }
  /* An empty action cell (e.g. the "you" user row) shouldn't draw a divider. */
  #usersTable td.user-row-actions:empty { display: none; }

  /* Description panels sit directly under their card. */
  #ticketsTable tr.tk-desc-row { display: block; margin: 0 0 6px; }
  #ticketsTable tr.tk-desc-row td { display: block; padding: 0; border: none; }

  /* ── Profile fee history (#feesTable) → mirror the Finance fees-log static card ──
     meta line (period · date · method · Mandatsreferenz) on top; amount + ⋮ below;
     inline edit-row + comment panel beneath. */
  #feesTable       { display: block; overflow: visible; background: transparent; box-shadow: none; border-radius: 0; }   /* drop white sheet behind cards */
  #feesTable tbody { display: block; }
  #feesTable tr:first-child { display: none; }            /* header row */
  #feesTable tr.fee-card-row {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "meta meta" "amount kebab";
    column-gap: 10px; row-gap: 3px;
    background: #fff; border: 1px solid #ececf0; border-radius: 12px;
    padding: 11px 13px; margin-bottom: 6px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
  }
  #feesTable tr.fee-card-row td { border: none; padding: 0; width: auto; }
  #feesTable tr.fee-card-row:hover td { background-color: transparent; }
  #feesTable td.fee-mmeta {
    display: block; grid-area: meta; min-width: 0;
    font-size: 11px; color: #9a9aa5;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #feesTable td.fee-mmeta .fee-mmeta-sub { margin-left: 6px; }
  /* period(1), date(2), method(4) fold into the meta line. */
  #feesTable tr.fee-card-row td:nth-child(1),
  #feesTable tr.fee-card-row td:nth-child(2),
  #feesTable tr.fee-card-row td:nth-child(4) { display: none; }
  #feesTable tr.fee-card-row td:nth-child(3) {            /* amount */
    grid-area: amount; align-self: center;
    font-size: 13px; font-weight: 400;
  }
  #feesTable tr.fee-card-row td.mcard-actions {           /* ⋮ kebab */
    grid-area: kebab; align-self: center; position: relative;
  }
  /* Mandatsreferenz (col 5) is folded into the meta line — hidden as a column. */
  #feesTable tr.fee-card-row td:nth-child(5) { display: none; }
  /* Inline fee-edit row renders as a block card in the mobile fee list. */
  #feesTable tr.fee-edit-row, #feesTable tr.fee-edit-row > td { display: block; width: 100%; }
  /* Comment panel beneath the card. */
  #feesTable tr.notes-row { display: block; margin: 0 0 6px; }
  #feesTable tr.notes-row td { display: block; padding: 0; border: none; }

  /* ── Member profile page ── */
  /* Stack the header: Back · name+badges · the single Actions button — and
     drop the big info grid to one column. */
  .pp-grid { grid-template-columns: 1fr; gap: 14px; }
  .pp-header { flex-direction: column; align-items: stretch; gap: 14px; margin-bottom: 20px; }
  .pp-identity h1, .pp-name-row h1 { font-size: 1.55rem; line-height: 1.2; }
  .btn-back { align-self: flex-start; }

  .pp-actions { width: 100%; }
  #ppReadActions, .pp-actions-dd { width: 100%; }
  .pp-actions-toggle { width: 100%; justify-content: center; }
  /* Full-width dropdown menu directly under the full-width button. */
  .pp-actions-menu { left: 0; right: 0; min-width: 0; }
  #ppEditActions { width: 100%; flex-wrap: wrap; gap: 8px; }
  #ppEditActions > * { flex: 1 1 auto; }

  .pp-card { padding: 18px 16px; }
}

/* ════════════════════════════════════════════════════════════════
   CP5c — Admin Console (+ Finance/Help sidebar pages) mobile polish.
   Fixes: (1) the org "Details" field grid is a fixed 3 columns → collapse
   so long German labels/inputs stop spilling outside the card.
   (2) tighten card padding on small screens.
   NOTE: the page gutter is owned by .admin-content since 2026-06-15, and the
   sub-tab strip runs full-bleed — so #page-admin carries NO left padding here.
   (Earlier `#page-admin{padding-left:20px/14px}` rules were removed: they
   re-indented the strip on the LEFT only, leaving a white gap beside it.)
   ════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  /* Field grid: 3 cols is too tight here → 2. */
  .admin-field-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  /* Field grid → single column; the side-by-side logos stack. */
  .admin-field-grid, .admin-field-grid.two-col { grid-template-columns: 1fr; }
  .admin-field-grid .full { flex-direction: column; gap: 16px; }

  /* Roomier-but-not-bloated card padding; titles/sub-text never overflow. */
  .admin-card { padding: 16px 16px; }
  .admin-card-title, .admin-section-subtitle { overflow-wrap: anywhere; }

  /* Logo previews never wider than the card. */
  #orgLogoPreview, #orgLogoNavPreview, #appIconPreview { max-width: 100%; }
}

/* My Account: collapse the 2-column card grid to one column once it gets
   tight. The notification matrix needs ~360px, so two columns only fit
   comfortably on wide screens; below ~980px the cards stack full-width. */
@media (max-width: 980px) {
  .acct-grid { grid-template-columns: 1fr; }
}

/* Notification settings matrix (My Account → Benachrichtigungen) on phones.
   Same idea as desktop — labels left, the three channel checkboxes a neat group
   aligned to the card's right border — just a touch tighter, since the phone
   card is ~half the desktop width. Drop the desktop min-width:360px (it would
   force a sideways scroll on a narrow phone). On a very narrow phone the two
   longest labels may wrap to a second line — there isn't room for both the full
   labels and three right-aligned columns; on 390px+ everything is one line. */
@media (max-width: 640px) {
  /* Cancel the global mobile `table { display:block; overflow-x:auto }` (that rule
     is for wide data tables that must scroll sideways). The matrix fits, so keep it
     a normal full-width table — otherwise it becomes a scroll container (a shadow
     line down/under it) and, as a block, won't stretch to push the checkboxes flush
     to the right border. */
  table.notif-matrix { min-width: 0; display: table; overflow-x: visible; }
  table.notif-matrix thead th.ch,
  table.notif-matrix td.ch { width: 44px; }   /* narrower columns; right-align is in the base */
  table.notif-matrix thead th.ch { font-size: 10px; letter-spacing: .2px; }
  .notif-ev-label { font-size: 13px; overflow-wrap: anywhere; }
  .notif-ev-row td { padding: 18px 0; }   /* roomier rows */
}

/* The floating "nach oben" button overlaps the bottom tab bar and the thumb
   zone on phones, so hide it there; the desktop view keeps it. */
@media (max-width: 640px) {
  #scrollTopBtn { display: none; }
}

/* ════════════════════════════════════════════════════════════════
   E-Mail page mobile polish (≤640px) — the composer, and one line for the
   Vorlagen editor.

   The Vorlagen list needs nothing here. It renders .email-card divs whose
   content is fluid by construction: .auto-row wraps at min-width 180px and
   .auto-input is width:100% with border-box, so it lays out cleanly down to
   320px, and the shared ≤640px rule forcing every input to 16px already kills
   the iOS focus-zoom.

   This block used to carry ~40 more lines aimed at
   "#emailTemplatesWrap .data-table" and "#emailTemplateEditor". Those were
   written when the Vorlagen tab really was a table plus a separate editor
   panel; the inline card list replaced both on 2026-06-13 and left every one of
   those selectors matching nothing, so the tab read as mobile-styled while none
   of it applied. Removed 2026-08-02.

   Why DELETED rather than repointed at the card markup, which is the tempting
   fix: the Vorlagen list is the "same pattern as automations" (both files say so
   in their headers), and the automations card list has no mobile rule at all. It
   sits in the very next .admin-card on the same screen and is the more demanding
   of the two, with four buttons in its row against Vorlagen's two, and it
   measures clean at 360px. Repointing would therefore give Vorlagen a different
   look from the list directly below it: two card lists doing the same job two
   ways, which is the thing to avoid.

   Their intent is met already, which is why nothing replaces them: the 16px
   floor comes from the global input rule above, and the 43-45px control height
   falls out of that font size plus .auto-input's own padding. The dropped
   "min-height: 44px" on Save/Cancel must not come back in any form. The text
   button family owns one geometry, and a local override on a button is what
   CLAUDE.md forbids; add a family size step if a bigger target is ever wanted.
   ════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  /* The lone survivor of that template block, and it does still match: the save
     status sits in the editor's .auto-edit-actions flex row, and its own row
     keeps a message from squeezing Abbrechen and Speichern. */
  #emailTemplateFormStatus { flex: 1 0 100%; }

  /* ── Composer (chip + rich-text redesign) on mobile ── */
  /* Engere Zeilen + kleineres Label, damit die Karte nicht zu groß wirkt. */
  .composer-row { padding: 10px 14px; gap: 10px; }
  .composer-row-label { min-width: 52px; line-height: 28px; }
  /* Empfänger-Dropdown ist auf dem schmalen Schmalbild zu eng für eine
     Zeile — Suche + Typ stapeln (je volle Breite). */
  .empf-panel-filters { flex-wrap: wrap; }
  .empf-search, .empf-type-select { flex: 1 1 100%; }
  /* Toolbar kompakter + darf umbrechen, statt zu überlaufen. */
  .composer-toolbar { flex-wrap: wrap; padding: 4px 8px; }
  .composer-tool { width: 32px; height: 32px; }
  /* contentEditable: kleinere Mindesthöhe (240px füllt sonst den halben
     Bildschirm) + 16px Schrift verhindert iOS-Zoom beim Fokus. */
  .composer-body { min-height: 150px; padding: 12px 14px; font-size: 16px; }
  .composer-subject-input { font-size: 16px; }
  /* Senden-Button voll breit + komfortable Höhe. */
  #emailPreviewSendBtn { width: 100%; justify-content: center; min-height: 44px; }
  .composer-footer { flex-wrap: wrap; padding: 12px 14px; }
}

/* ════════════════════════════════════════════════════════════════
   Profile header actions — inline buttons on desktop.
   The actions live in one #ppActionsMenu (a ⋮ kebab dropdown on phones,
   handled by the ≤640 rules above). On desktop (≥641) show them as an
   inline button bar instead and hide the kebab toggle.
   ════════════════════════════════════════════════════════════════ */
@media (min-width: 641px) {
  .pp-actions-dd .pp-actions-toggle { display: none; }

  /* The dropdown menu becomes a static inline row (overrides the absolute
     popover base + the JS .open toggle). */
  .pp-actions-menu {
    display: flex !important; position: static;
    background: none; border: none; box-shadow: none;
    overflow: visible;   /* base .gdpr-dropdown-menu sets overflow:hidden, which
                            would clip the DSGVO sub-dropdown below the row */
    padding: 0; min-width: 0; gap: 8px; flex-wrap: wrap; align-items: center;
  }
  /* Top-level items (Edit / Send / Mitgliedsbestätigung) + the DSGVO toggle
     render as inline buttons. The three DSGVO items stay rows inside the
     sub-dropdown below. */
  .pp-actions-menu > .gdpr-dropdown-item,
  .pp-actions-menu #ppGdprToggle {
    width: auto; gap: 7px;
    border: 1px solid #d8d8e0; border-radius: 8px;
    padding: 8px 14px; font-size: 13px; font-weight: 600;
    background: #fff; color: #1A1A2E;
  }
  .pp-actions-menu > .gdpr-dropdown-item:hover,
  .pp-actions-menu #ppGdprToggle:hover {
    background: #fff; border-color: #D95F02; color: #D95F02;
  }
  .pp-actions-menu .gdpr-dropdown-item svg { width: 14px; height: 14px; }
  /* Edit Profile = filled primary (the main action). */
  .pp-actions-menu #ppEditProfileBtn { background: #1A1A2E; border-color: #1A1A2E; color: #fff; }
  .pp-actions-menu #ppEditProfileBtn:hover { background: #2d2d4e; border-color: #2d2d4e; color: #fff; }

  /* DSGVO actions → a sub-dropdown under the "DSGVO ▾" button. */
  #ppGdprGroup { position: relative; }
  #ppGdprToggle { display: inline-flex; align-items: center; }
  #ppGdprToggle .pp-gdpr-caret { width: 12px; height: 12px; }
  .pp-actions-menu .gdpr-dropdown-divider { display: none; }   /* no flat divider on desktop */
  #ppGdprItems {
    display: none; position: absolute; top: calc(100% + 6px); right: 0;
    min-width: 232px; background: #fff; border: 1px solid #ddd; border-radius: 8px;
    box-shadow: 0 4px 18px rgba(0,0,0,0.13); padding: 4px 0; z-index: 300;
  }
  #ppGdprItems.open { display: block; }
}

/* ── Acceptance gate on phones ───────────────────────────────────────
   Trim the generous side padding for more reading width, use a bit more
   viewport height, and shorten each document's scroll box. */
@media (max-width: 640px) {
  .terms-card { max-height: 92dvh; }
  .terms-head { padding: 24px 22px 10px; }
  .terms-docs { padding: 8px 22px; }
  .terms-foot { padding: 16px 22px 22px; }
  .terms-doc-body { height: 180px; }
}

/* ── E-Mail-Konten form: stack the field grids on phones ───────────── */
@media (max-width: 640px) {
  .ea-grid, .ea-grid-wide { grid-template-columns: 1fr; }
}


/* ── Configurable member import (member-import.js) — phone layout ───────── */
@media (max-width: 640px) {
  /* Undo the global `table { display:block; overflow-x:auto }` — these tables
     are laid out for narrow screens directly, not horizontally scrolled. */
  .mi-wrap table.mi-map,
  .mi-wrap table.mi-vis { display: table; overflow: visible; }

  .mi-card-head, .mi-source-grid, .mi-source-bar, .mi-tabs, .mi-pane, .mi-foot, .mi-src-foot, .mi-conn, .mi-analyze-status { padding-left: 16px; padding-right: 16px; }
  .mi-sync-result { margin-left: 16px; margin-right: 16px; }
  .mi-source-grid { gap: 10px; }
  .mi-src-opt { min-width: 0; flex: 1 1 100%; }
  .mi-id-input { min-width: 0; width: 100%; }
  .mi-src-id { flex: 1 1 100%; }
  .mi-src-config { gap: 10px; }

  /* The mapping row stacks: column label on top, target select below, no arrow. */
  .mi-wrap table.mi-map,
  .mi-wrap table.mi-map thead,
  .mi-wrap table.mi-map tbody,
  .mi-wrap table.mi-map tr,
  .mi-wrap table.mi-map td { display: block; width: auto; }
  .mi-wrap table.mi-map thead { display: none; }
  .mi-wrap tr.mi-row > td.mi-col { border-bottom: none; padding-bottom: 4px; }
  .mi-wrap tr.mi-row > td.mi-arrow { display: none; }
  .mi-wrap tr.mi-row > td.mi-target { border-bottom: 1px solid #f4f4f4; padding-bottom: 12px; width: auto; }
  .mi-wrap td.mi-target { width: auto; }
  .mi-wrap td select.mi-fieldsel { width: 100%; min-width: 0; }
  .mi-vm-row { grid-template-columns: 1fr 20px 1fr; }

  /* The "auto" guess badge is desktop-only — too noisy next to a full-width select. */
  .mi-wrap .mi-badge { display: none; }
}

/* ════════════════════════════════════════════════════════════════
   SEPA (Mandate + Beitragsläufe) → mobile (≤640px).
   The SEPA deployment shipped desktop-only — its tables just scrolled
   sideways (min-width 900/full). Reuse the "stacked labeled-card" pattern
   from the log tables: each row → a bordered card, each cell → a labeled
   line (label from the cell's data-label attr), headers hidden. Toolbars,
   KPI chips, summary blocks and the create form stack full-width. Layout
   only — no behaviour/handler change. Desktop (>640px) untouched.
   ════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

  /* ── Mandate tab (#fin-mandates) ── */

  /* KPI chips fill the row two-up, wrapping tidily. */
  .mand-kpi-row { gap: 8px; }
  .mand-kpi { flex: 1 1 calc(50% - 4px); min-width: 0; padding: 10px 12px; }

  /* Toolbar: search + select-open button stack full-width. The BUTTON needs no
     rule of its own for that: align-items:stretch on the column already gives it
     the full row, at the family's 36px. A ".mand-toolbar .btn-cancel" sat in the
     group below until 2026-08-02, from a rename (the button is .btn-secondary),
     and it matched nothing. Do not repoint it: that would put min-height and
     font-size on a button, which CLAUDE.md forbids, and would leave this the one
     42px button in the app. Only the search input needs the override, because
     styles.css caps it at max-width 320px for the desktop row. */
  .mand-toolbar { flex-direction: column; align-items: stretch; gap: 10px; }
  .mand-toolbar > span[style*="flex"] { display: none; }   /* the desktop spacer */
  .mand-toolbar .ctrl-search {
    max-width: none; width: 100%; box-sizing: border-box; min-height: 42px; font-size: 16px;
  }

  /* Bulk bar: the action button drops full-width below the count. */
  .mand-bulk { flex-wrap: wrap; }
  .mand-bulk .btn-primary { flex: 1 1 100%; }

  /* Table → cards. Drop the sideways scroll + min-width, and the desktop table's
     white "sheet" (bg/shadow/radius/clip) so the page background shows through
     BETWEEN the cards instead of a continuous white slab — same reset the Members,
     Transaktionen and Beitrags-log tables above already carry. */
  .mand-table-wrap { overflow: visible; }
  table.mand-table {
    display: block; min-width: 0; width: 100%;
    overflow: visible; background: transparent; box-shadow: none; border-radius: 0;
  }
  table.mand-table thead { display: none; }
  table.mand-table tbody { display: block; }
  table.mand-table tbody tr {
    display: block; position: relative;
    background: #fff; border: 1px solid #ececf0; border-radius: 12px;
    padding: 12px 14px 10px; margin-bottom: 6px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
  }
  table.mand-table tbody tr:hover td { background: transparent; }
  table.mand-table tbody td {
    display: block; width: auto; border: none;
    padding: 4px 0; white-space: normal; text-align: left;
  }
  table.mand-table td[data-label]::before {
    content: attr(data-label);
    display: block; margin-bottom: 2px;
    font-size: 10.5px; font-weight: 700; letter-spacing: .4px;
    text-transform: uppercase; color: #9a9aa5;
  }
  /* Name = card title; leave room for the checkbox pinned top-right. */
  table.mand-table td.mand-m-name { font-size: 16px; font-weight: 700; padding: 0 42px 8px 0; }
  table.mand-table td.mand-check-cell {
    position: absolute; top: 12px; right: 12px; width: auto; padding: 0; text-align: right;
  }
  /* Actions = a button row with a divider above (no label). */
  table.mand-table td.mand-actions-cell { margin-top: 8px; padding-top: 10px; border-top: 1px solid #f1f1f4; }
  table.mand-table td.mand-actions-cell .mand-row-actions { justify-content: flex-start; }
  /* Empty-message row: centered, no label. */
  table.mand-table td.mand-empty-row { text-align: center; }
  table.mand-table td.mand-empty-row::before { content: none; }

  /* Comment (notes) row: NOT a card of its own — it hangs under its member card
     like the other tables' comment panels, and carries the SAME bottom margin as a
     card so the list rhythm is identical whether a row has one (mandate) or not
     (Kein Mandat).
     No negative top margin here. A closed notes-row is empty and self-collapsing,
     so its top and bottom margins collapse together with the card's: a -10px top
     against the card's bottom margin does not "cancel" it sequentially, it collapses
     the whole thing to ZERO and the cards end up touching. That was invisible while
     the white table sheet sat behind them and obvious the moment it was dropped. */
  table.mand-table tbody tr.notes-row {
    background: transparent; border: none; border-radius: 0;
    padding: 0; margin: 0 0 6px; box-shadow: none;
  }
  table.mand-table tbody tr.notes-row td { padding: 0; }

  /* ── Abrechnung (#fin-runs) und Rechnungen (#fin-invoices) ── */
  /* The .bl-table → card rules below carry BOTH ids. They were written scoped to
     #fin-runs, and a second Finanzen tab reusing the same table class would have
     rendered a desktop grid on a phone with nothing to show for it: the desktop
     styles are class-based and only the mobile treatment is id-scoped, so the break
     is invisible until somebody opens it on a phone. The toolbar and create-card
     rules above stay Beitragsläufe-only, because that is what they are about. */

  /* Toolbar: "Neuer Beitragslauf" drops full-width below the title. */
  #fin-runs .bl-toolbar { gap: 10px; }
  #fin-runs .bl-toolbar > span[style*="flex"] { display: none; }
  #fin-runs .bl-toolbar .btn-primary { flex: 1 1 100%; }
  /* ⚠ Die Weg-Spalte bekommt auf dem Handy KEINE Beschriftungszeile. Die Zeile wird
     dort ohnehin zur Karte, und der Weg steht schon als Abzeichen ganz oben in ihr:
     ein vorangestelltes „Weg" wäre dieselbe Angabe zweimal untereinander. */
  #fin-runs table.bl-table td.abr-weg::before { content: none; }
  #fin-runs table.bl-table td.abr-weg { padding-bottom: 2px; }

  /* Create card: fields + date field stack full-width. */
  .bl-card { padding: 16px; }
  .bl-field-row { flex-direction: column; gap: 14px; }
  .bl-field { width: 100%; }
  .bl-field select, .bl-field input {
    min-width: 0; width: 100%; box-sizing: border-box; min-height: 42px; font-size: 16px;
  }
  /* ⚠ Deliberately NOT scoped to #fin-runs like the toolbar rules above: .dfield is
     the app-wide date field, and a date field belongs full-width on a phone wherever
     it appears. The rule it replaced was unscoped too, but by accident.
     Note the picker inside it keeps its own 1×1 rule in styles.css, which outranks
     the `.bl-field input` line directly above on specificity rather than order. */
  .dfield { display: block; }

  /* Summary blocks + detail meta stack full-width. */
  .bl-blocks { gap: 10px; }
  .bl-block { flex: 1 1 100%; min-width: 0; }
  .bl-detail-meta { gap: 14px 24px; }
  .bl-detail-panel { padding: 14px; }
  .bl-actions { gap: 8px; }

  /* .bl-table (runs list AND positions) → cards. Drop scroll + the white sheet
     (see the .mand-table reset above for why). margin-top:0 because the foundation
     table rule adds 24px, which reads as a stray gap once the sheet is gone. */
  #fin-runs .bl-table-wrap,
  #fin-invoices .bl-table-wrap { overflow: visible; }
  #fin-runs table.bl-table,
  #fin-invoices table.bl-table {
    display: block; width: 100%; margin-top: 0;
    overflow: visible; background: transparent; box-shadow: none; border-radius: 0;
  }
  #fin-runs table.bl-table thead,
  #fin-invoices table.bl-table thead { display: none; }
  #fin-runs table.bl-table tbody,
  #fin-invoices table.bl-table tbody { display: block; }
  #fin-runs table.bl-table tbody tr,
  #fin-invoices table.bl-table tbody tr { display: block; }   /* baseline; cards decorated below */

  /* Data rows → cards: the runs-list rows are .clickable; positions rows (in a
     run's detail panel and the create preview) are plain <tr>. */
  #fin-runs table.bl-table tbody tr.clickable,
  #fin-runs .bl-detail-panel table.bl-table tbody tr,
  #runPreview table.bl-table tbody tr,
  /* Every invoice row is a card: unlike a run, an invoice has no detail to expand,
     so its rows are plain <tr> and would otherwise miss the decoration entirely. */
  #fin-invoices table.bl-table tbody tr {
    position: relative;
    background: #fff; border: 1px solid #ececf0; border-radius: 12px;
    padding: 12px 14px 10px; margin-bottom: 6px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
  }
  #fin-runs table.bl-table tbody tr.clickable:hover,
  #fin-invoices table.bl-table tbody tr.clickable:hover { background: #fff; }
  #fin-runs table.bl-table tbody td,
  #fin-invoices table.bl-table tbody td {
    display: block; width: auto; border: none;
    padding: 4px 0; white-space: normal; text-align: left;
  }
  #fin-runs table.bl-table td.r,
  #fin-invoices table.bl-table td.r { text-align: left; }
  #fin-runs table.bl-table td[data-label]::before,
  #fin-invoices table.bl-table td[data-label]::before {
    content: attr(data-label);
    display: block; margin-bottom: 2px;
    font-size: 10.5px; font-weight: 700; letter-spacing: .4px;
    text-transform: uppercase; color: #9a9aa5;
  }
  #fin-runs table.bl-table td.bl-m-name,
  #fin-invoices table.bl-table td.bl-m-name { font-size: 16px; font-weight: 700; padding: 0 0 8px; }
  #fin-runs table.bl-table td.bl-actions-cell,
  #fin-invoices table.bl-table td.bl-actions-cell { margin-top: 8px; padding-top: 10px; border-top: 1px solid #f1f1f4; }
  #fin-runs table.bl-table td.bl-empty-row,
  #fin-invoices table.bl-table td.bl-empty-row { text-align: center; }
  #fin-runs table.bl-table td.bl-empty-row::before,
  #fin-invoices table.bl-table td.bl-empty-row::before { content: none; }

  /* The inline detail row is a full-width container, NOT a card. */
  #fin-runs table.bl-table tbody tr.bl-detail-row,
  #fin-invoices table.bl-table tbody tr.bl-detail-row {
    display: none; background: transparent; border: none; box-shadow: none; padding: 0; margin: 0;
  }
  #fin-runs table.bl-table tbody tr.bl-detail-row.open,
  #fin-invoices table.bl-table tbody tr.bl-detail-row.open { display: block; }
  #fin-runs tr.bl-detail-row > td,
  #fin-invoices tr.bl-detail-row > td { display: block; padding: 0; border: none; background: transparent; }

  /* ── EÜR Buchungen table (#euerTable) → cards ── */
  /* Drop the desktop scroll container and the white sheet (see .mand-table above). */
  .euer-table-wrap { overflow: visible; }
  #euerTable {
    display: block; width: 100%; font-size: 14px; margin-top: 0;
    overflow: visible; background: transparent; box-shadow: none; border-radius: 0;
  }
  #euerTable thead { display: none; }
  #euerTable tbody { display: block; }
  /* 6px between cards — the same rhythm the Transaktionen and Beitrags-log lists
     render (their 10px card margin minus a -4px notes-row overlap). */
  #euerTable tbody tr {
    display: block; position: relative;
    background: #fff; border: 1px solid #ececf0; border-radius: 12px;
    padding: 12px 14px 10px; margin-bottom: 6px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
  }
  #euerTable tbody tr:hover td { background: transparent; }
  #euerTable tbody td {
    display: block; width: auto; border: none;
    padding: 4px 0; white-space: normal; text-align: left;
  }
  #euerTable td[data-label]::before {
    content: attr(data-label);
    display: block; margin-bottom: 2px;
    font-size: 10.5px; font-weight: 700; letter-spacing: .4px;
    text-transform: uppercase; color: #9a9aa5;
  }
  /* Counterparty = card title; amount prominent + left-aligned in the card. */
  #euerTable td.euer-c-name { font-size: 15px; font-weight: 700; }
  #euerTable td.num { text-align: left; font-size: 15px; white-space: normal; }
  #euerTable select.cat { max-width: none; width: 100%; min-height: 40px; font-size: 15px; }
  #euerTable td.euer-empty-row { text-align: center; }
  #euerTable td.euer-empty-row::before { content: none; }

  /* ── EÜR Regeln editor: each rule → a labeled card ── */
  .rgl-head { display: none; }
  .rgl-row {
    position: relative; grid-template-columns: 1fr; gap: 0;
    padding: 12px; border: 1px solid #ededf1; border-radius: 12px;
    background: #fdfdfe; margin-bottom: 10px;
  }
  .rgl-flabel {
    display: block; margin-bottom: 5px;
    font-size: 11px; font-weight: 700; letter-spacing: .04em;
    text-transform: uppercase; color: #b3b3bd;
  }
  .rgl-cell { margin-bottom: 12px; }
  .rgl-cell:last-child { margin-bottom: 0; }
  .rgl-cell-art { padding-right: 46px; }        /* room for the absolute delete */
  .rgl-cell-art .rgl-seg { width: auto; }
  .rgl-seg button { padding: 9px 12px; }
  .rgl-cell-del { position: absolute; top: 12px; right: 12px; margin: 0; }
  /* Single column already, see styles.css; only the card chrome is mobile. */
  .rgl-sysrow {
    padding: 10px 12px;
    border: 1px solid #f0f0f4; border-radius: 10px; background: #fafafb; margin-bottom: 8px;
  }
  .rgl-footer .ctrl-btn, .rgl-footer .ctrl-add { flex: 1; justify-content: center; text-align: center; }
}

/* ── The (i) popover becomes a bottom sheet ──────────────────────────────────
   Hover does not exist here, which is the whole reason the existing
   .note-tooltip could not be reused for this. A sheet also removes the
   viewport-edge placement problem entirely: nothing to flip, nothing to clamp. */
@media (max-width: 640px) {
  .info-pop {
    width: auto; max-width: none;
    left: 0 !important; right: 0; bottom: 0; top: auto !important;
    border-radius: 16px 16px 0 0; border-bottom: 0;
    padding: 18px 20px 22px;
    font-size: 14px;
    max-height: 76vh; overflow-y: auto;
    box-shadow: 0 -8px 34px rgba(26,26,46,.22);
    animation: info-sheet-up .18s ease-out;
  }
  /* The grab handle, so it reads as a sheet rather than a stuck tooltip. */
  .info-pop::before {
    content: ""; display: block; width: 38px; height: 4px; border-radius: 2px;
    background: #D9DCE4; margin: -6px auto 13px;
  }
  .info-pop h4 { font-size: 14px; }
  /* An explicit close: on touch there is no Escape and an outside tap on a
     full-width sheet is not discoverable. */
  .info-pop-close {
    display: block; width: 100%; margin-top: 16px;
    background: #F4F5F8; border: 1px solid #d5d7e0; border-radius: 9px;
    color: #4b5261; font: inherit; font-size: 14px; padding: 11px; cursor: pointer;
  }
}
@keyframes info-sheet-up { from { transform: translateY(100%); } to { transform: translateY(0); } }
