/* app.css — the app's one stylesheet (CI: design/DESIGN.md + design/styleguide.html, colors: tokens.css).
   Structure: structural tokens → base → auth → chrome (header/overlays/drawer/footer) →
   shared components → dashboard → calendar → notes → baby → entity manager/settings →
   system indicators. Every color runs through the tokens — no hex in component rules. */

/* Fonts — SELF-HOSTED (assets/fonts/), not a CDN: the service worker precaches them with the
   rest of the shell, so headings and body text look the same offline as online, and no
   third-party sees a request per page load. Both are VARIABLE files, so one file per subset
   covers 400–700 and `font-weight: 400 700` lets the browser interpolate any weight between.
   latin + latin-ext only (DE/EN plus accented names); the unicode-range split means the browser
   fetches latin-ext only when a glyph actually needs it.
   Updating: refetch from fonts.googleapis.com/css2, drop the woff2 in, bump the SW. */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('../fonts/inter-latin.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: 'Inter';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('../fonts/inter-latin-ext.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;
}
@font-face {
    font-family: 'Newsreader';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('../fonts/newsreader-latin.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: 'Newsreader';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('../fonts/newsreader-latin-ext.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;
}

/* structural tokens — layout/type constants; the color system lives in tokens.css */
:root {
    --font-family: 'Inter', system-ui, sans-serif;
    /* Display serif — ONLY the big module headings (see the rule at the end of this file).
       Nothing else in the app gets a second font. */
    --disp: 'Newsreader';
    --pad: 16px;                 /* screen-edge padding */
    --r-card: 16px;              /* cards */
    --r-ctl: 12px;               /* inputs, segmented controls */
    --r-pill: 99px;              /* pills, chips, round buttons */
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --transition-fast: 120ms ease;
    --transition-base: 200ms ease;
    --button-click-scale: 0.9;
    /* --scrim / --scrim-strong / --scroll-shadow live in tokens.css (shared with the landing) */
    /* theme-independent constants — these paint OVER photos / the lightbox scrim, where the
       page theme must not change them (same family as --moon-glyph/--pdf-paper in tokens.css) */
    --photo-edge: rgba(0, 0, 0, 0.10);           /* hairline inset on photo thumbnails */
    --photo-text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55); /* text legibility on photos */
    --page-shadow: 0 1px 4px rgba(0, 0, 0, 0.25); /* paper page on the lightbox scrim */
    /* type scale (prototype sizes) — one-off sizes stay inline where they occur once */
    --fs-label: 10.5px;          /* uppercase section labels */
    --fs-cap: 11px;              /* captions, counts, meta lines */
    --fs-sub: 11.5px;            /* secondary lines, times */
    --fs-ui: 12px;               /* tabs, small buttons, widget titles */
    --fs-hint: 12.5px;           /* hints, subtitles, empty states */
    --fs-body: 13px;             /* row titles */
    --fs-md: 13.5px;             /* event titles, menu items, inputs */
    /* navigation cluster fill — ‹ Heute › steppers and head pencils: a tonal ink wash,
       deliberately its own family (chrome/navigation), distinct from bordered action
       buttons and ink-filled primaries. Derived from --ink, so it rides both themes. */
    --nav-fill: color-mix(in srgb, var(--ink) 8%, transparent);
}

/* focus — pointer interaction stays outline-free; keyboard focus gets a visible ink ring.
   Text fields are excluded (they always match :focus-visible) — they carry their own
   border/background focus treatment. */
*:focus {
    outline: none;
}
:focus-visible {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
}
input:not([type="checkbox"]):not([type="radio"]):focus-visible,
textarea:focus-visible,
select:focus-visible {
    outline: none;
}

/* selection — ink on paper, inverted with the theme (same rule as the landing) */
::selection {
    background: var(--ink);
    color: var(--bg);
}

/* keyframes */
@keyframes fadeSlideUp {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}

@keyframes pendingPulse {
    50% { opacity: 0.3; }
}

/* body */
body {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    position: fixed;
    left: 0;
    top: 0;
    font-weight: 400;
    font-family: var(--font-family);
    background: var(--bg);
    color: var(--ink);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* offline — a red hairline across the very top of the screen; it vanishes the moment
   the connection is back. Red stays reserved for overdue and THIS. */
#offline {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--due);
    z-index: 999;
}
#offline span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
}

/* iOS install nudge (B3/P7) — a quiet card pinned above everything, only ever rendered
   in a non-installed iOS Safari tab; the × dismisses it for good on this device */
/* IN THE FLOW, not floating: #app is a flex column, so the hint as its first child pushes the
   header/main/footer down instead of covering them. Fixed positioning put an opaque card over
   the header — search, bell and ⋮ were unreachable until it was dismissed. */
#ios-install-hint,
#install-prompt {
    flex: none;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 8px 8px 0;
    padding: 10px 12px;
    background: var(--card);
    color: var(--ink);
    border: 1px solid var(--line2);
    border-radius: var(--r-ctl);
    box-shadow: var(--shadow);
    font-size: var(--fs-ui);
    line-height: 1.45;
}
#ios-install-hint > i,
#install-prompt > i { margin-top: 2px; color: var(--ink2); }
#ios-install-hint span { flex: 1; }

/* Chromium install banner: text above a real Install button (ink pill, theme-inverting) */
#install-prompt .install-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
}
/* THE INK PILL — the app's primary-action voice, declared ONCE for every CTA that wears it.
   It lives here, early, so each surface below can still add the one thing its own row needs
   (a wider form button, a bordered sheet button, an icon+label flex) without re-stating the
   look. The three ink-pill CHIPS (.sleepBtn, .plan-chip, .fm-selchip) are deliberately NOT in
   here: they are a different scale, not this button. */
#install-prompt .install-go,
#app form .formSubmit button,
.action-btn.reusable,
.wx-empty-btn,
.cal-bday-go {
    border: 0;
    border-radius: var(--r-pill);
    background: var(--ink);
    color: var(--bg);
    font-family: var(--font-family);
    font-size: var(--fs-hint);
    font-weight: 600;
    padding: 10px 16px;
    cursor: pointer;
    transition: transform var(--transition-fast);
}
#install-prompt .install-go:active { transform: scale(var(--button-click-scale)); }
.ios-hint-x {
    border: 0;
    background: none;
    padding: 2px;
    color: var(--ink3);
    cursor: pointer;
    font-size: 13px;
    -webkit-tap-highlight-color: transparent;
}

/* app */
#app {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    background: var(--bg);
    color: var(--ink);
    font-size: var(--fs-md);
}

/* auth form — pill fields with a leading icon (login / signup / forgot / reset / join) */
#app form .formGroup {
    display: flex;
    align-items: center;
    gap: 11px;
    width: 100%;
    max-width: 320px;
    box-sizing: border-box;
    background: var(--card);
    border: 1px solid var(--line2);
    border-radius: var(--r-pill);
    padding: 13px 19px;
    margin-bottom: 10px;
}

#app form .formGroup i {
    color: var(--ink3);
    font-size: 15px;
    flex-shrink: 0;
    transition: color var(--transition-base);
}

#app form .formGroup:focus-within i {
    color: var(--ink2);
}

#app form .formGroup input {
    font-family: var(--font-family);
    background: transparent;
    border: 0;
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 400;
    color: var(--ink);
}

#app form .formGroup input::placeholder {
    color: var(--ink3);
}

/* show/hide-password eye — the tap target spans the pill's full height and right edge */
#app form .formGroup .pwToggle {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    margin: -13px -19px -13px 0;
    padding: 13px 19px 13px 8px;
    background: none;
    border: 0;
    color: var(--ink3);
    font-size: 15px;
    cursor: pointer;
    transition: color var(--transition-base);
}

#app form .formGroup .pwToggle:active {
    color: var(--ink2);
}

#app form .formSubmit {
    text-align: center;
    margin-top: 10px;
}

/* the ink pill, in its FORM size: a login/registration button carries more weight than a
   sheet's action row (the look itself is declared once, above) */
#app form .formSubmit button {
    font-size: 14px;
    padding: 12px 30px;
}

#app form .formSubmit button:active {
    transform: scale(var(--button-click-scale));
}

#app form .formSubmit button:disabled {
    opacity: 0.45;
    cursor: not-allowed;
    transform: none;
}

/* live password checklist (new-password forms): shared-policy rules flip ok/fail per
   keystroke; before the first character every line sits neutral (.empty) */
#app form .pwRules {
    list-style: none;
    margin: 6px 4px 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
}
#app form .pwRules li {
    font-size: var(--fs-ui);
    line-height: 1.35;
    color: var(--ink);
    display: flex;
    align-items: baseline;
    gap: 6px;
}
#app form .pwRules li::before {
    content: "✓";
    font-weight: 700;
}
#app form .pwRules li.fail {
    color: var(--due-ink);
}
#app form .pwRules li.fail::before {
    content: "✗";
}
#app form .pwRules.empty li {
    color: var(--ink3);
}
#app form .pwRules.empty li::before {
    content: "·";
}

#app form .formMessage {
    font-size: var(--fs-hint);
    color: var(--due-ink);
    text-align: center;
    margin-top: 1rem;
    animation: fadeSlideUp var(--transition-base) forwards;
}

#app form .authTitle {
    text-align: center;
    font-size: 18px;
    font-weight: 600;
    letter-spacing: -0.01em;
    margin-bottom: 18px;
}
#app form .authSubtitle {
    text-align: center;
    color: var(--ink2);
    font-size: var(--fs-hint);
    margin: -10px 0 14px;
}
#app form .authLinks {
    display: flex;
    justify-content: center;
    gap: 20px;
    margin-top: 20px;
}
#app form .authLinks a {
    color: var(--ink2);
    font-size: var(--fs-hint);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}
#app form .formMessage a {
    color: inherit;
    text-decoration: underline;
}

/* app main */
#app main {
    flex: auto;
    height: 100%;
    width: 100%;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
}

#app main #login {
    display: flex;
    min-width: 300px;
    flex-direction: column;
    align-items: center;
}

/* app header */
#app header {
    display: flex;
    align-items: center;
    gap: 4px;
    box-sizing: border-box;
    padding: calc(var(--safe-top) + var(--pad)) var(--pad) var(--pad);
    position: relative;
}

/* The active-module name lives in the footer labels now (prototype header: avatar ·
   spacer · actions only) — the element stays for the JS that updates it. */
#app header .module {
    display: none;
}

/* the wordmark above the login form — the brand's dotless ȷ + rosé person-dot */
#app.login main { flex-direction: column; gap: 30px; }
#app .wm {
    font-weight: 600;
    font-size: 34px;
    letter-spacing: -0.03em;
    line-height: 1;
    color: var(--ink);
    display: inline-flex;
}
#app .wm .jj { position: relative; display: inline-block; }
#app .wm .jj i {
    position: absolute;
    font-style: normal;
    left: 50%;
    transform: translateX(-58%);
    top: -0.06em;
    width: 0.14em;
    height: 0.14em;
    border-radius: 50%;
    background: var(--wm-dot);
}

/* ── Boot preloader ────────────────────────────────────────────────────────────
   Static HTML in index.html so it paints on the FIRST frame, before the JS module
   loads. boot.js sets [data-theme] + html.is-offline beforehand, so it matches the
   theme and connectivity with no flash. Render.appReady() (from app.view) fades it
   out once the first real screen is up. Above every popup layer (z 2000). */
#preloader {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 22px;
    background: var(--bg);
    padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
    opacity: 1;
    transition: opacity 0.32s ease;
}
html.app-ready #preloader { opacity: 0; pointer-events: none; }
#preloader .wm {
    font-weight: 600;
    font-size: 40px;
    letter-spacing: -0.03em;
    line-height: 1;
    color: var(--ink);
    display: inline-flex;
}
#preloader .wm .jj { position: relative; display: inline-block; }
#preloader .wm .jj i {
    position: absolute;
    font-style: normal;
    left: 50%;
    transform: translateX(-58%);
    top: -0.06em;
    width: 0.14em;
    height: 0.14em;
    border-radius: 50%;
    background: var(--wm-dot);
}
/* indeterminate three-dot loader — calm, understated */
#preloader .pl-dots { display: flex; gap: 7px; }
#preloader .pl-dots span {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--ink3);
    animation: plPulse 1.1s ease-in-out infinite;
}
#preloader .pl-dots span:nth-child(2) { animation-delay: 0.16s; }
#preloader .pl-dots span:nth-child(3) { animation-delay: 0.32s; }
@keyframes plPulse {
    0%, 80%, 100% { opacity: 0.28; transform: scale(0.82); }
    40%           { opacity: 1;    transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
    #preloader .pl-dots span { animation: none; opacity: 0.6; }
}
/* offline hint — swaps in for the dots while the browser reports no connection */
#preloader .pl-offline {
    display: none;
    align-items: center;
    gap: 7px;
    font-size: var(--fs-hint);
    font-weight: 600;
    color: var(--due-ink);
}
#preloader .pl-offline::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--due);
}
html.is-offline #preloader .pl-offline { display: inline-flex; }
html.is-offline #preloader .pl-dots { display: none; }

/* auth header — round "moon" button on the LEFT, DE|EN switch on the right */
#app.login header {
    justify-content: space-between;
}
#app .auth-tools {
    display: flex;
    align-items: center;
    gap: 8px;
}
#app .langSw {
    display: inline-flex;
    border: 1px solid var(--line2);
    border-radius: var(--r-pill);
    overflow: hidden;
    background: var(--card);
}
#app .langSw button {
    border: 0;
    background: transparent;
    color: var(--ink2);
    font-family: var(--font-family);
    font-size: var(--fs-cap);
    font-weight: 600;
    letter-spacing: 0.03em;
    padding: 6px 11px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
#app .langSw button.on {
    background: var(--ink);
    color: var(--bg);
}
#app.login header #darkmode-toggle {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 1px solid var(--line2);
    background: var(--card);
    display: flex;
    align-items: center;
    justify-content: center;
}

#app header #darkmode-toggle,
#app header #filter-toggle,
#app header #search-toggle,
#app header #overdue-toggle,
#app header #pending-toggle {
    background: transparent;
    border: none;
    cursor: pointer;
    font-size: 19px;
    color: var(--ink);
    padding: 0;
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

#app header #darkmode-toggle:active,
#app header #filter-toggle:active,
#app header #search-toggle:active,
#app header #overdue-toggle:active {
    transform: scale(var(--button-click-scale));
}

#app header .header-actions {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-left: auto;
}

/* Pending-writes counter — amber is the pending color; visible only while writes are queued */
#app header #pending-toggle { display: none; position: relative; }
#app header #pending-toggle.show { display: flex; }
#app .pending-badge {
    position: absolute;
    top: 1px;
    right: 0;
    min-width: 15px;
    height: 15px;
    box-sizing: border-box;
    padding: 0 3px;
    border-radius: var(--r-pill);
    background: var(--pend);
    color: var(--badge-fg);
    font-size: 9.5px;
    font-weight: 700;
    line-height: 11px;
    text-align: center;
    border: 2px solid var(--bg);
    font-variant-numeric: tabular-nums;
}
/* its popover: pulsing dot + count, the newest queued changes, the footnote */
.pending-pop {
    position: absolute;
    top: calc(var(--safe-top) + 66px);
    right: var(--pad);
    z-index: 900;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    box-shadow: var(--shadow);
    min-width: 235px;
    max-width: 300px;
    animation: fadeSlideUp var(--transition-fast) forwards;
}
.pending-head {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 12px;
    font-size: var(--fs-body);
    font-weight: 600;
    border-bottom: 1px solid var(--line);
}
.pending-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--pend);
    animation: pendingPulse 1.4s infinite;
    flex-shrink: 0;
}
.pending-row {
    display: flex;
    align-items: baseline;
    gap: 7px;
    padding: 6px 12px;
    font-size: var(--fs-ui);
    color: var(--ink2);
}
.pending-row:first-of-type { padding-top: 10px; }
.pending-row b { font-weight: 600; color: var(--ink); }
.pending-more { color: var(--ink3); }
.pending-note {
    font-size: var(--fs-cap);
    color: var(--ink3);
    padding: 9px 12px 11px;
    line-height: 1.5;
    border-top: 1px solid var(--line);
    margin-top: 8px;
}

/* The bell's count disc — red is meaning: it counts OVERDUE items. */
#app header #overdue-toggle { position: relative; }
#app .overdue-badge {
    display: none;
    position: absolute;
    top: 1px;
    right: 2px;
    min-width: 15px;
    height: 15px;
    box-sizing: border-box;
    padding: 0 3px;
    border-radius: var(--r-pill);
    background: var(--due);
    color: var(--badge-fg);
    font-size: 9.5px;
    font-weight: 700;
    line-height: 11px;
    text-align: center;
    border: 2px solid var(--bg);
    font-variant-numeric: tabular-nums;
}
#app .overdue-badge.show { display: block; }
/* the ⋮ sweep badge (bought/done waiting to clear) — same anatomy as the bell/pending badges
   but Ink, not red: not an alarm, just a count. */
#app #filter-toggle { position: relative; }
#app .filter-badge {
    position: absolute;
    top: 1px;
    right: 0;
    min-width: 15px;
    height: 15px;
    box-sizing: border-box;
    padding: 0 3px;
    border-radius: var(--r-pill);
    background: var(--ink);
    color: var(--badge-fg);
    font-size: 9.5px;
    font-weight: 700;
    line-height: 11px;
    text-align: center;
    border: 2px solid var(--bg);
    font-variant-numeric: tabular-nums;
    display: none;
}
#app .filter-badge.show { display: block; }

/* The bell dropdown reuses the search overlay shell; this is its static title. */
#app .notif-title { flex: 1; font-weight: 600; font-size: var(--fs-md); }

/* search / notifications overlay — card at the top, click-scrim behind */
#app .search-overlay {
    position: fixed;
    inset: 0;
    background: transparent;
    z-index: 40;
    display: flex;
    justify-content: center;
    align-items: flex-start;
}

#app .search-panel {
    width: min(560px, calc(100% - 20px));
    margin-top: calc(var(--safe-top) + 10px);
    background: var(--card);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: var(--r-card);
    box-shadow: var(--shadow);
    display: flex;
    flex-direction: column;
    max-height: 80dvh;
    overflow: hidden;
}

#app .search-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 2px 6px 2px 14px;
    border-bottom: 1px solid var(--line);
}
#app .search-bar > i { color: var(--ink3); font-size: 15px; }

#app .search-bar .search-input {
    flex: 1;
    min-width: 0;
    border: none;
    background: transparent;
    color: var(--ink);
    font-family: var(--font-family);
    font-size: 14px;
    padding: 12px 0;
    outline: none;
}
#app .search-bar .search-input::placeholder { color: var(--ink3); }
/* the panel's own ✕ closes; Chrome's native search-cancel would double it in blue */
#app .search-bar .search-input::-webkit-search-cancel-button { -webkit-appearance: none; }

#app .search-close {
    background: transparent;
    border: none;
    color: var(--ink);
    cursor: pointer;
    font-size: 16px;
    padding: 10px;
}

#app .search-results {
    overflow-y: auto;
}

#app .search-result {
    display: flex;
    align-items: center;
    gap: 11px;
    width: 100%;
    box-sizing: border-box;
    background: transparent;
    border: none;
    border-bottom: 1px solid var(--line);
    color: inherit;
    text-align: left;
    font-family: var(--font-family);
    padding: 11px 14px;
    cursor: pointer;
}
#app .search-result:last-child { border-bottom: 0; }

#app .search-result:active {
    background: var(--card2);
}

#app .search-result-text {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 0;
}

#app .search-result-title {
    font-size: var(--fs-body);
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

#app .search-result-sub {
    font-size: var(--fs-cap);
    color: var(--ink2);
    margin-top: 1px;
}

#app .search-result-group {
    font-size: var(--fs-label);
    font-weight: 600;
    color: var(--ink3);
    white-space: nowrap;
    flex-shrink: 0;
}

#app .search-empty {
    padding: 14px;
    color: var(--ink3);
    font-size: var(--fs-ui);
    text-align: center;
}

/* result icons ride in the prototype's rounded tile */
#app .search-result-ic {
    width: 30px;
    height: 30px;
    border-radius: 10px;
    background: var(--card2);
    border: 1px solid var(--line);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ink2);
    flex: none;
}
#app .search-result-ic i { font-size: 15px; }

/* the bell's leading date column — wide enough for "Mi., 15. Juli", red only when late */
#app .search-result-when {
    width: 64px;
    flex: none;
    font-size: var(--fs-cap);
    font-weight: 600;
    color: var(--ink2);
    font-variant-numeric: tabular-nums;
    line-height: 1.4;
}
#app .search-result-when.late { color: var(--due-ink); }

/* header avatar — opens the drawer */
#app header .profile {
    font-size: var(--fs-body);
    font-weight: 600;
    color: var(--pc-ink, var(--ink));
    width: 36px;
    height: 36px;
    box-sizing: border-box;
    background: var(--pc-soft, var(--card));
    /* the ring mirrors the member's person color (their auto slot without a chosen one) */
    border: 2px solid var(--pc, var(--line2));
    border-radius: 50%;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
    transition: transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

#app header .profile:active {
    transform: scale(var(--button-click-scale));
}

#app header .profile img {
    width: inherit;
    height: inherit;
    object-fit: cover;
    border-radius: 50%;
}

/* profile drawer */
#app .profile-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0);
    z-index: 30;
    transition: background var(--transition-base);
}

#app .profile-overlay.open {
    background: var(--scrim);
}

#app .profile-drawer {
    position: fixed;
    top: 0;
    left: 0;
    height: 100dvh;
    width: min(320px, 78vw);
    box-sizing: border-box;
    background: var(--card);
    color: var(--ink);
    border-right: 1px solid var(--line);
    display: flex;
    flex-direction: column;
    z-index: 31;
    padding: 0 18px;
    transform: translateX(-102%);
    transition: transform 280ms cubic-bezier(0.3, 0.9, 0.3, 1);
}

#app .profile-drawer.open {
    transform: translateX(0);
}

#app .profile-drawer-user {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: calc(22px + var(--safe-top)) 0 18px;
    border-bottom: 1px solid var(--line);
}

#app .profile-drawer-avatar {
    width: 46px;
    height: 46px;
    border-radius: 50%;
    background: var(--pc-soft, var(--card2));
    border: 2px solid var(--pc, var(--line));
    box-sizing: border-box;
    color: var(--pc-ink, var(--ink2));
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    font-weight: 600;
    flex-shrink: 0;
    overflow: hidden;
}

#app .profile-drawer-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
}

#app .profile-drawer-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

#app .profile-drawer-username {
    font-weight: 600;
    font-size: 15px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

#app .profile-drawer-role {
    font-size: var(--fs-cap);
    color: var(--ink2);
    text-transform: capitalize;
}

#app .profile-drawer-tier {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    align-self: flex-start;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    font-family: inherit;
    color: var(--ink2);
    background: var(--card2);
    border: 1px solid var(--line);
    padding: 3px 8px;
    border-radius: 6px;
    margin-top: 4px;
    text-transform: uppercase;
    cursor: pointer;
}
#app .profile-drawer-tier i { font-size: 8px; color: var(--ink3); }

#app .profile-drawer-menu {
    display: flex;
    flex-direction: column;
    flex: 1;
    padding: 10px 0 var(--safe-bottom);
    overflow-y: auto;
}

#app .profile-drawer-menu button {
    display: flex;
    align-items: center;
    gap: 13px;
    width: 100%;
    padding: 13px 6px;
    background: transparent;
    border: none;
    border-radius: var(--r-ctl);
    font-family: var(--font-family);
    font-size: 14px;
    font-weight: 500;
    color: var(--ink);
    cursor: pointer;
    text-align: left;
    transition: background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

#app .profile-drawer-menu button:hover,
#app .profile-drawer-menu button:active {
    background: var(--card2);
}

#app .profile-drawer-menu button i {
    color: var(--ink2);
    width: 20px;
    font-size: 17px;
    text-align: center;
    flex-shrink: 0;
}

/* items sit at the TOP under the profile; the spacer pushes only the logout down */
#app .profile-drawer-spacer {
    flex: 1;
    order: 5;
}
#app .profile-drawer-menu button#drawer-logout-btn { order: 6; }

#app .profile-drawer-menu button#drawer-darkmode-btn {
    border-top: 0;
}

/* logout — set apart above a hairline, in the app's red ink */
#app .profile-drawer-menu button#drawer-logout-btn {
    border-top: 1px solid var(--line);
    border-radius: 0 0 var(--r-ctl) var(--r-ctl);
    color: var(--due-ink);
}
#app .profile-drawer-menu button#drawer-logout-btn i {
    color: var(--due-ink);
}

/* the theme row's trailing mode label — Automatisch/Dunkel/Hell, updated on each cycle */
#app .profile-drawer-menu .theme-mode {
    margin-left: auto;
    color: var(--ink3);
    font-size: var(--fs-label);
    flex-shrink: 0;
}

/* app footer — tab bar: icon + label always visible, active = ink. Few tabs stretch to
   fill the row; many tabs (pro's nine modules) keep their comfortable width and the row
   scrolls/swipes horizontally instead of squeezing — the scrollbar itself stays hidden. */
#app footer {
    display: flex;
    justify-content: space-between;
    align-items: stretch;
    gap: 4px;
    background: color-mix(in srgb, var(--card) 92%, transparent);
    backdrop-filter: blur(16px);
    box-sizing: border-box;
    padding: 8px 8px calc(var(--safe-bottom) + 8px);
    overflow: hidden;
    overflow-x: auto;
    scrollbar-width: none;
}

#app footer::-webkit-scrollbar {
    display: none;
}

#app footer > div {
    display: flex;
    flex: 1 0 auto;
    min-width: 60px;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 3px;
    height: 100%;
    box-sizing: border-box;
    padding: 6px 10px;
    color: var(--ink3);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

#app footer > div i {
    font-size: 20px;
    line-height: 1;
    transition: transform var(--transition-fast);
}

#app footer > div:not(.active):active i {
    transform: scale(var(--button-click-scale));
}

#app footer > div span {
    font-size: 10px;
    font-weight: 600;
    white-space: nowrap;
}

#app footer > div.active {
    color: var(--ink);
}

#app main > div[data-module] {
    display: none;
    width: 100%;
    height: 100%;
    overflow-y: auto;
    position: absolute;
    top: 0;
    left: 0;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    /* module panels are container-query roots: grids inside respond to the PANEL's
       width (the PWA runs embedded at arbitrary widths), not the viewport's */
    container-type: inline-size;
}

#app main > div[data-module].active {
    display: flex;
    flex-direction: column;
}

/* header ⋮ popover — items come from the active module's menuActions() */
.head-menu {
    position: absolute;
    top: calc(var(--safe-top) + 66px);
    right: var(--pad);
    z-index: 900;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    box-shadow: var(--shadow);
    padding: 5px;
    display: flex;
    flex-direction: column;
    min-width: 210px;
    animation: fadeSlideUp var(--transition-fast) forwards;
    /* Never taller than the viewport allows — long filter lists scroll inside the menu. */
    max-height: calc(100dvh - var(--safe-top) - 70px);
    overflow-y: auto;
    scrollbar-width: thin;
}
/* Non-interactive section divider — keeps a growing menu scannable. */
.head-menu-heading {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink3);
    padding: 10px 12px 4px;
}
.head-menu-item {
    font-family: var(--font-family);
    font-size: var(--fs-md);
    font-weight: 500;
    color: var(--ink);
    background: transparent;
    border: 0;
    border-radius: 9px;
    padding: 11px 12px;
    text-align: left;
    cursor: pointer;
    white-space: nowrap;
    transition: background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
    display: flex;
    align-items: center;
    gap: 9px;
}
.head-menu-item:hover { background: var(--card2); }
/* subject filter entries lead with a 22px avatar circle: the photo when the subject has one,
   else the initial in the person color */
.head-menu-item .fava img { width: 100%; height: 100%; object-fit: cover; display: block; }
.head-menu-item .fava {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 9px;
    font-weight: 700;
    background: var(--pc-soft, var(--card2));
    color: var(--pc-ink, var(--ink2));
    border: 1px solid var(--line);
}
/* the "Alle" row's quiet icon tile */
.head-menu-item .tic {
    width: 22px;
    height: 22px;
    border-radius: 7px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--card2);
    border: 1px solid var(--line);
    color: var(--ink2);
    font-size: 11px;
}
/* a plain leading glyph on a menu entry (no tile) */
.head-menu-item .mic { font-size: 15px; color: var(--ink2); flex-shrink: 0; }
.head-menu-item .menu-hint { color: var(--ink3); font-size: var(--fs-cap); font-weight: 400; }
.head-menu-item .menu-label { flex: 1; text-align: left; }
.head-menu-item .menu-check { font-size: 11px; color: var(--ink); }
.head-menu-item.active { font-weight: 600; }

/* ============================== shared components ============================== */

/* borderless icon buttons (row pens, ×, stars …) */
.icon-btn {
    width: 34px;
    height: 34px;
    border: 0;
    background: transparent;
    color: var(--ink3);
    cursor: pointer;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    font-size: 15px;
    line-height: 1;
    transition: color var(--transition-fast), transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
.icon-btn:hover { color: var(--ink); }
.icon-btn:active { transform: scale(var(--button-click-scale)); }
.icon-btn svg { width: 15px; height: 15px; }

/* action buttons — filled ink pill; cancel = ghost; delete = red text */
/* the ink pill in an ACTION ROW: it sits next to ghost/red siblings, so it carries a border of
   its own ink (that is what .cancel-btn recolours), never wraps, and keeps a hair of margin */
.action-btn.reusable {
    border: 1px solid var(--ink);
    white-space: nowrap;
    margin: 2px;
    -webkit-tap-highlight-color: transparent;
}
.action-btn.reusable:active {
    transform: scale(var(--button-click-scale));
}
.action-btn.reusable.cancel-btn {
    background: transparent;
    color: var(--ink);
    border: 1px solid var(--line2);
    border-radius: var(--r-ctl);
    font-weight: 500;
}
/* Destructive action — always red, in every context (sheet or centered modal). */
.action-btn.reusable.delete-btn {
    background: transparent;
    color: var(--due-ink);
    border-color: transparent;
}

/* filter chips (Module.createFilterBar) */
.filter-bar.reusable {
    display: flex;
    gap: 5px;
    flex-wrap: wrap;
    margin: 4px 0;
}
.filter-btn.reusable {
    font-family: var(--font-family);
    font-size: var(--fs-label);
    font-weight: 600;
    padding: 4px 10px;
    background: var(--card2);
    color: var(--ink2);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    cursor: pointer;
    transition: background var(--transition-base), color var(--transition-base);
}
.filter-btn.reusable.active {
    background: var(--ink);
    color: var(--bg);
    border-color: var(--ink);
}

/* subject filter — the removable ×-chips for active person/thing filters */
.subject-filter {
    display: flex;
    gap: 6px;
    flex: none;
    padding: 12px var(--pad) 0;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
.subject-filter::-webkit-scrollbar { display: none; }
.subject-chip {
    flex: none;
    cursor: pointer;
    white-space: nowrap;
    background: var(--card2);
    color: var(--ink2);
    border: 1px solid var(--line);
    font-family: var(--font-family);
    font-size: var(--fs-sub);
    font-weight: 600;
    padding: 6px 12px;
    border-radius: var(--r-pill);
    transition: background var(--transition-base), color var(--transition-base), transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
.subject-chip:active { transform: scale(var(--button-click-scale)); }
.subject-chip.active { background: var(--ink); color: var(--bg); border-color: var(--ink); }

/* tab pill rows (notes kinds, baby tabs, entity categories) — hairline pills, active = ink */
.seg-tabs {
    display: flex;
    gap: 6px;
    padding: 2px;
    margin: 12px var(--pad) 0;
    flex: none;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
.seg-tabs::-webkit-scrollbar { display: none; }
.seg-tab {
    flex: none;
    /* No outline: the FILLED pill carries the active state, and a box around every word made a
       row of five of them read as five boxes. Kept as a transparent border so the active pill's
       own border-color still paints and nothing shifts by a pixel when it turns on. */
    border: 1px solid transparent;
    background: var(--card);
    font-family: var(--font-family);
    cursor: pointer;
    color: var(--ink2);
    font-size: var(--fs-ui);
    font-weight: 600;
    padding: 7px 13px;
    border-radius: var(--r-pill);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    white-space: nowrap;
    transition: background var(--transition-base), color var(--transition-base);
    -webkit-tap-highlight-color: transparent;
}
.seg-tab .seg-count {
    font-size: 10px;
    font-weight: 600;
    color: var(--ink3);
    font-variant-numeric: tabular-nums;
    transition: color var(--transition-base), opacity var(--transition-base);
}
.seg-tab.active {
    background: var(--ink);
    color: var(--bg);
    border-color: var(--ink);
}
.seg-tab.active .seg-count {
    color: var(--bg);
    opacity: 0.65;
}

/* segmented variant (notes kinds, baby views) — one shared track like the calendar
   view switcher; more tabs than fit scroll horizontally inside the track */
.seg-tabs.seg-track {
    gap: 2px;
    /* The --card2 fill already groups the strip; the outline on top of it drew a box around a
       box. (The pills lost theirs in the same pass — the FILLED pill is the state.) */
    background: var(--card2);
    border-radius: var(--r-ctl);
    padding: 3px;
}
.seg-tabs.seg-track .seg-tab {
    flex: 1 0 auto;
    border: 0;
    background: transparent;
    border-radius: 9px;
    padding: 7px 10px;
}
.seg-tabs.seg-track .seg-tab.active { background: var(--ink); color: var(--bg); }

/* overflow folding (Render.segOverflow) — the strip only shows the tabs that fit; folded
   ones live in the chevron chip's dropdown */
.seg-tabs .seg-hidden,
.cal-views .seg-hidden { display: none; }
.seg-tabs.seg-track .seg-more,
.cal-views .seg-more {
    flex: 0 0 auto;
    padding: 7px 9px;
    color: var(--ink2);
}
.cal-views .seg-more {
    border: 0;
    background: transparent;
    border-radius: 9px;
}
.seg-tabs.seg-track .seg-more i,
.cal-views .seg-more i { font-size: 11px; }
.seg-more-menu { min-width: 150px; }
.seg-more-menu .mg-select-opt {
    display: flex;
    align-items: center;
    gap: 10px;
}
.seg-more-menu .seg-count {
    margin-left: auto;
    font-size: 10px;
    font-weight: 600;
    color: var(--ink3);
    font-variant-numeric: tabular-nums;
}

/* segmented variant (Settings You|Group) — one inset track, buttons share it */
#app .settings-tabs {
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    padding: 3px;
    gap: 2px;
    margin: 2px 16px 10px;
}
#app .settings-tabs .seg-tab {
    flex: 1;
    border: 0;
    background: transparent;
    border-radius: 9px;
    padding: 8px 0;
    font-size: var(--fs-hint);
}
#app .settings-tabs .seg-tab.active {
    background: var(--ink);
    color: var(--bg);
}

/* segmented visibility toggle (Everyone / Only me) */
.seg-toggle {
    display: flex;
    gap: 2px;
    background: var(--card2);
    border: 1px solid var(--line);
    padding: 3px;
    border-radius: var(--r-ctl);
}
.seg-toggle button {
    flex: 1;
    border: 0;
    background: transparent;
    font-family: var(--font-family);
    cursor: pointer;
    color: var(--ink2);
    font-size: var(--fs-hint);
    font-weight: 600;
    padding: 8px 4px;
    border-radius: 9px;
    display: flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
    transition: background var(--transition-base), color var(--transition-base);
}
.seg-toggle button svg { width: 13px; height: 13px; }
.seg-toggle button.active {
    background: var(--ink);
    color: var(--bg);
}
.seg-toggle button:disabled { opacity: 0.55; cursor: default; }
.seg-hint {
    color: var(--ink3);
    font-size: var(--fs-label);
    margin: 7px 2px 0;
}

/* visibility as a text line (form law G3): "Sichtbar für alle · Ändern" — the segmented
   control only appears behind the Ändern tap */
.vis-line {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--fs-body);
    color: var(--ink2);
}
.vis-line > span:nth-child(2) { color: var(--ink3); }
.vis-change {
    border: 0;
    background: none;
    padding: 0;
    font-family: inherit;
    font-size: var(--fs-body);
    font-weight: 600;
    color: var(--ink);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

/* zone line (form law G3): "Zeit gilt in: Wien · ändern"; the entered start's viewer-clock
   equivalent sits beneath it as a quiet hint when the zone is not the viewer's */
.zone-line { flex-wrap: wrap; }
/* .vis-line > span:nth-child(2) (0,2,1) would otherwise mute this to --ink3 — the zone IS the
   statement of this line, so it needs the third class to outrank that inherited rule. */
.vis-line.zone-line .zone-val { color: var(--ink); font-weight: 600; }
.zone-hint {
    margin-top: 3px;
    font-size: var(--fs-cap);
    color: var(--ink3);
}
.zone-hint:empty { display: none; }
.zone-select { margin-top: 4px; }

/* "Für" as tappable avatar chips (form law G3) — active picks wear the ink ring,
   matching the msTile.on selection language */
.fuer-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.fuer-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 11px 4px 5px;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    font-family: inherit;
    font-size: var(--fs-ui);
    font-weight: 600;
    color: var(--ink2);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.fuer-chip.on {
    border-color: var(--ink);
    background: var(--card);
    color: var(--ink);
    box-shadow: 0 0 0 1px var(--ink) inset;
}
/* the avatar badge inside a chip — every .m rule elsewhere is context-scoped, so the
   chip needs its own (the .fm-chiplink .m twin) */
.fuer-chip .m {
    width: 19px;
    height: 19px;
    border-radius: 50%;
    font-size: 8.5px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    background: var(--pc-soft, var(--card2));
    color: var(--pc-ink, var(--ink2));
}
.fuer-chip .m.m-glyph i { font-size: 9px; }
/* rotation order on selected chips (chore context): tap order is the stored order —
   the number makes it visible */
.fuer-ord {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--ink);
    color: var(--bg);
    font-size: 9px;
    font-weight: 700;
    display: none;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-variant-numeric: tabular-nums;
}
.fuer-chips.ordered .fuer-chip.on .fuer-ord { display: flex; }

/* form pairs (form law G2): two labelled fields share one line — minmax(0,…) tracks,
   or a long native date/select control forces horizontal overflow */
.form-pair {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 10px;
    margin-bottom: 12px;
}
/* bottom-align the cells: a wrapping label (narrow column) must not push its input
   out of line with its neighbour's. .popup-body prefix: outranks the later
   `.popup-body .form-row { margin-bottom }` rule regardless of file order */
.popup-body .form-pair > .form-row {
    margin-bottom: 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
}
.form-pair.form-pair-qty { grid-template-columns: 88px minmax(0, 1fr); }

/* ingredient lines: a variable-length Menge × Zutat list inside one form row. The amount
   column matches .form-pair-qty above, so an ingredient reads exactly like a shopping item —
   which is what it becomes when the recipe goes onto the list. */
.ing-list { display: flex; flex-direction: column; gap: 6px; }
.ing-line {
    display: grid;
    grid-template-columns: 88px minmax(0, 1fr) 32px;
    gap: 6px;
    align-items: center;
}
.ing-line > input { min-width: 0; }
.ing-x {
    background: none;
    border: none;
    color: var(--ink3);
    padding: 0;
    height: 32px;
    cursor: pointer;
}
.ing-x:active { transform: scale(var(--button-click-scale)); }
.ing-add {
    align-self: flex-start;
    background: none;
    border: none;
    color: var(--ink);
    font: inherit;
    font-size: 14px;
    padding: 4px 0;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* the Kür's pin toggle — a state line, not a form row; ON = ink star */
.pin-line {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    background: none;
    color: var(--ink3);
    font-family: var(--font-family);
    font-size: var(--fs-hint);
    font-weight: 600;
    padding: 5px 12px;
    cursor: pointer;
    margin-top: 10px;
}
.pin-line.on { color: var(--ink); border-color: var(--ink2); }

/* container item lines: a todo/shopping note's own checkable entries in the editor —
   the ingredient list's visual language, plus the done tick in front of each line. */
.items-rows { display: flex; flex-direction: column; gap: 6px; }
.item-line { display: flex; gap: 6px; align-items: center; }
/* two class parts on purpose: the popup's generic `input` rule (width:100% + a text field's
   padding, border and border-radius) outranks the bare .notes-check inside a sheet — a 100%-wide
   checkbox eats the line, and the leaked padding/radius warped the box (oval, off-centre tick).
   Reset all of it so the editor tick matches the feed; .mg-round keeps a shopping line round. */
.item-line .notes-check { flex: none; width: 18px; height: 18px; padding: 0; border: 1.5px solid var(--line2); border-radius: 5px; }
.item-line .notes-check.mg-round { border-radius: 50%; }
.item-line .item-qty { width: 88px; flex: none; min-width: 0; }
.item-line .item-text { flex: 1 1 auto; min-width: 0; }
.item-line .notes-linkx { flex: none; height: 32px; }
.items-add {
    align-self: flex-start;
    background: none;
    border: none;
    color: var(--ink);
    font: inherit;
    font-size: 14px;
    padding: 4px 0;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* ── Zubereitung: die Faltliste ────────────────────────────────────────────────────
   A saved recipe opens with every section shut, so nine heading rows fit on one screen
   before any of the words do. The per-row × are gone into a ⋮ menu — nine sections used
   to put 27 armed deletes in front of a thumb. */
.prep { display: flex; flex-direction: column; gap: 6px; }
.prep-sec { border: 1px solid var(--line); border-radius: var(--r-ctl); overflow: hidden; }
.prep-sec.open { border-color: var(--line2); }
.prep-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 4px 0 8px;
    min-height: 44px;   /* PLAN_UX D2: a row you tap is at least this tall */
    cursor: pointer;
}
.prep-caret {
    flex: none;
    color: var(--ink3);
    font-size: 11px;
    transition: transform var(--transition-fast);
}
.prep-sec.open .prep-caret { transform: rotate(90deg); }
.prep-sum { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prep-sum.untitled { color: var(--ink3); }
.prep-cnt {
    flex: none;
    color: var(--ink3);
    font-size: var(--fs-ui);
    font-variant-numeric: tabular-nums;
}
/* the heading of the OPEN section stays put while you type in it — at 19 steps you
   otherwise lose track of what you are writing under */
.prep-sec.open .prep-head {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--card);
    border-bottom: 1px solid var(--line);
}
.popup-body .prep-title {
    flex: 1;
    min-width: 0;
    font-weight: 600;
    background: none;
    border: none;
    padding: 0;
}
.popup-body .prep-title:focus { outline: none; }
.prep-dots {
    flex: none;
    background: none;
    border: none;
    color: var(--ink3);
    width: 32px;
    height: 40px;
    padding: 0;
    cursor: pointer;
}
.prep-body { padding: 4px 4px 8px 8px; }
.prep-step { display: flex; align-items: flex-start; gap: 6px; }
.prep-no {
    flex: none;
    width: 18px;
    padding-top: 12px;
    color: var(--ink3);
    font-size: var(--fs-ui);
    font-variant-numeric: tabular-nums;
    text-align: right;
}
.popup-body .prep-step > textarea {
    flex: 1;
    min-width: 0;
    min-height: 44px;
    /* 16px and not --fs-md: below 16px iOS zooms the page in when the field takes focus,
       and a sheet that jumps on every step is unusable one-handed */
    font-size: 16px;
    overflow: hidden;
}
.prep-add {
    align-self: flex-start;
    background: none;
    border: 1px dashed var(--line2);
    border-radius: var(--r-ctl);
    color: var(--ink);
    font: inherit;
    font-size: 14px;
    padding: 9px 14px;
    cursor: pointer;
}
.prep-add:active { transform: scale(var(--button-click-scale)); }
.prep-menu .mg-select-opt { white-space: nowrap; }

/* the recipe photo: a tile in the editor, and the list's lead column */
.rcp-photo { display: flex; align-items: center; gap: 10px; }
.rcp-tile {
    width: 84px;
    height: 84px;
    flex: none;
    border: 1px dashed var(--line2);
    border-radius: var(--r-ctl);
    background: var(--card2);
    color: var(--ink3);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    font-size: 11px;
    padding: 4px;
    overflow: hidden;
    cursor: pointer;
}
.rcp-tile img { width: 100%; height: 100%; object-fit: cover; border-radius: calc(var(--r-ctl) - 1px); }
.rcp-tile:has(img) { border-style: solid; padding: 0; }
.rcp-photo-status, .rcp-photo-hint { color: var(--ink3); font-size: var(--fs-ui); }

/* the same tile with or without a photo — different heights per row would leave the
   recipe list fraying down the page */
.notes-thumb {
    width: 40px;
    height: 40px;
    margin-top: 6px;
    border-radius: var(--r-ctl);
    background: var(--card2);
    color: var(--ink3);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.notes-thumb img { width: 100%; height: 100%; object-fit: cover; }

/* the cooking mode's photo: small, in the HEAD. A band above step 1 would push the step
   down at exactly the moment you look at it, and be gone by step 2 */
.cook-shot {
    flex: none;
    width: 30px;
    height: 30px;
    padding: 0;
    border: none;
    border-radius: 6px;
    overflow: hidden;
    background: var(--card2);
    cursor: pointer;
}
.cook-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* the recipe → shopping picker: every ingredient pre-ticked, one already on the list
   unticked and saying so */
.pick-list { display: flex; flex-direction: column; }
.pick-line {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 2px;
    border-bottom: 1px solid var(--line);
    cursor: pointer;
}
.pick-line:last-child { border-bottom: none; }
/* `.popup-body input` sets width:100% AND a text field's padding — right for a text field, and
   it beats .w-check on specificity, so the checkbox came out 484px wide (pushing the ingredient
   off the sheet) and then 28×24 (an oval among the app's rounded squares). Two classes to
   outrank it; the size is .w-check's own. */
.pick-line > .w-check {
    width: 17px;
    height: 17px;
    padding: 0;
    box-sizing: border-box;
}
.pick-text { flex: 1; min-width: 0; }

/* ── Kochen ──────────────────────────────────────────────────────────────────────────
   A MODE, not a sheet: it covers the footer nav on purpose, because a thumb reaching for
   "Weiter" at the bottom of the screen would otherwise land on a module tab. Opaque, no
   scrim — there is nothing behind it worth seeing while the pan is hot. */
.cook-overlay {
    position: fixed;
    inset: 0;
    z-index: 1100;
    background: var(--bg);
    color: var(--ink);
    display: flex;
    flex-direction: column;
    padding-bottom: env(safe-area-inset-bottom);
}
.cook-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: calc(12px + env(safe-area-inset-top)) var(--pad) 10px;
    border-bottom: 1px solid var(--line);
    flex: none;
}
.cook-x {
    background: none;
    border: none;
    color: var(--ink);
    font-size: 18px;
    padding: 4px;
    cursor: pointer;
    flex: none;
}
.cook-title {
    flex: 1;
    min-width: 0;
    font-size: 17px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.cook-pos { color: var(--ink3); font-size: var(--fs-body); flex: none; font-variant-numeric: tabular-nums; }

/* One step at a time, centred — the mode IS the current step, big and legible from across the
   kitchen. The section it belongs to sits quietly above it; tapping the stage advances. */
.cook-stage {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 14px;
    padding: 28px calc(var(--pad) + 8px);
}
.cook-stage-sec {
    font-size: var(--fs-body);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink3);
}
.cook-stage-step {
    font-size: 22px;
    line-height: 1.5;
    color: var(--ink);
    max-width: 30rem;
    cursor: pointer;
}
.cook-foot {
    flex: none;
    padding: 10px var(--pad) 14px;
    border-top: 1px solid var(--line);
}
.cook-ing-toggle {
    background: none;
    border: none;
    color: var(--ink3);
    font: inherit;
    font-size: 14px;
    padding: 4px 0 8px;
    cursor: pointer;
}
.cook-ing-toggle.on { color: var(--ink); }
.cook-ing { max-height: 34vh; overflow-y: auto; padding-bottom: 8px; }
.cook-ing-line {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 5px 0;
    font-size: 15px;
}
.cook-ing-line > span:first-child { flex: 1; min-width: 0; }
/* information ("still on the shopping list"), not a deadline — amber, never the deadline red */
.cook-ing-open { color: var(--pend-ink); font-size: var(--fs-ui); flex: none; }
/* progress + ‹ › nav; the last step's › becomes a filled ✓ that ends the mode */
.cook-bar { height: 3px; border-radius: var(--r-pill); background: var(--card2); overflow: hidden; margin: 4px 0 12px; }
.cook-bar-fill { display: block; height: 100%; background: var(--ink); border-radius: var(--r-pill); transition: width var(--transition-base); }
.cook-nav { display: flex; align-items: center; gap: 12px; }
.cook-prev {
    width: 54px;
    height: 54px;
    border-radius: 50%;
    border: 1px solid var(--line);
    background: var(--card);
    color: var(--ink);
    font-size: 20px;
    cursor: pointer;
    flex: none;
}
.cook-prev:disabled { opacity: 0.3; }
/* the primary action is a clear labelled pill ("Weiter" / "Fertig"), not a bare arrow */
.cook-next {
    flex: 1;
    height: 54px;
    border: none;
    border-radius: var(--r-ctl);
    background: var(--ink);
    color: var(--bg);
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
}
.cook-prev:active, .cook-next:active { transform: scale(var(--button-click-scale)); }

/* "Noch zu tun" — a preview of the steps after the current one, each a tap-to-jump row */
.cook-upnext { width: 100%; max-width: 34rem; text-align: left; margin-top: 6px; }
.cook-upnext[hidden] { display: none; }
.cook-upnext-h { font-size: var(--fs-ui); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink3); margin: 6px 0; }
.cook-up-sec { font-size: var(--fs-cap); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink3); margin: 12px 0 4px; }
.cook-up {
    display: flex;
    gap: 12px;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    border-top: 1px solid var(--line);
    padding: 12px 2px;
    color: var(--ink3);
    font-size: 15px;
    line-height: 1.4;
    cursor: pointer;
}
.cook-up-n { flex: none; width: 22px; color: var(--ink3); font-variant-numeric: tabular-nums; }
.cook-up-t { flex: 1; }

/* recipe read view — a full-screen card layered above the sheets (like the file viewer) */
#recipe-view-overlay {
    position: fixed;
    inset: 0;
    z-index: 1100;
    background: var(--bg);
    color: var(--ink);
    display: flex;
    flex-direction: column;
    padding-bottom: env(safe-area-inset-bottom);
}
.rv-head { display: flex; justify-content: flex-end; gap: 6px; padding: calc(10px + env(safe-area-inset-top)) var(--pad) 6px; flex: none; }
.rv-btn { color: var(--ink); }
.rv-body { flex: 1; overflow-y: auto; box-sizing: border-box; padding: 0 20px 24px; width: 100%; max-width: 40rem; margin: 0 auto; }
.rv-hero {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    border: none;
    padding: 0;
    border-radius: var(--r-card);
    overflow: hidden;
    background: var(--card2);
    cursor: pointer;
}
.rv-hero img { width: 100%; height: 100%; object-fit: cover; }
.rv-title { margin: 16px 0 4px; }
.rv-source { display: inline-block; font-size: var(--fs-md); margin-bottom: 4px; }
.rv-sec { margin-top: 22px; }
.rv-sec-h { font-size: var(--fs-ui); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink3); margin-bottom: 12px; }
.rv-serv { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.rv-serv-btn {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 1px solid var(--line);
    background: var(--card);
    color: var(--ink);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    flex: none;
}
.rv-serv-btn:disabled { opacity: 0.3; }
.rv-serv-lab { font-size: var(--fs-md); color: var(--ink); font-variant-numeric: tabular-nums; }
.rv-ing { display: flex; gap: 14px; padding: 7px 0; border-bottom: 1px solid var(--line); font-size: 15px; }
.rv-ings .rv-ing:last-child { border-bottom: none; }
.rv-ing-q { color: var(--ink3); min-width: 72px; font-variant-numeric: tabular-nums; }
.rv-ing-t { color: var(--ink); }
.rv-cart { margin-top: 14px; }
.rv-step-sec { font-size: var(--fs-ui); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink3); margin: 16px 0 8px; }
.rv-step { display: flex; gap: 14px; padding: 10px 0; }
.rv-step-n {
    flex: none;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 1px solid var(--line);
    color: var(--ink2);
    font-size: var(--fs-body);
    display: flex;
    align-items: center;
    justify-content: center;
}
.rv-step-t { font-size: 15px; line-height: 1.55; color: var(--ink); }
.rv-foot { flex: none; display: flex; gap: 10px; padding: 10px 20px 14px; border-top: 1px solid var(--line); }
.rv-plan { flex: 1; }
.rv-cook { flex: 1.5; }

/* ── Weiterkochen (dashboard-pinned) + Rezepte widget — the wk-* family ─────────────────────── */
/* The pinned "Weiterkochen" card rides full-width at the very top; it is NOT an arrangeable widget.
   It wears the 3px top-bar idiom (weather = condition family, Für dich = person colour) in
   --pend: amber is the app's "running right now" voice (the pulsing wk-dot already speaks it) —
   never red, which stays reserved for overdue. */
#app .dash-grid > .wk-card { grid-column: 1 / -1; position: relative; background: var(--card); border-radius: var(--r-card); overflow: hidden; }
#app .dash-grid > .wk-card::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--pend); z-index: 2; }
#app .dash-grid > .wk-card > .w-head { padding-top: 13px; }
.wk-cook { display: flex; align-items: center; gap: 13px; padding: 11px 13px; border-top: 1px solid var(--line); cursor: pointer; }
.wk-ring { position: relative; width: 52px; height: 52px; flex: none; }
.wk-ring svg { width: 52px; height: 52px; transform: rotate(-90deg); display: block; }
.wk-ring-track { fill: none; stroke: var(--card2); stroke-width: 3.4; }
.wk-ring-arc { fill: none; stroke: var(--ink); stroke-width: 3.4; stroke-linecap: round; transition: stroke-dasharray var(--transition-base); }
.wk-ring-photo { position: absolute; inset: 7px; width: 38px; height: 38px; border-radius: 50%; object-fit: cover; box-shadow: inset 0 0 0 1px var(--photo-edge); }
.wk-ring-blank { display: grid; place-items: center; background: var(--card2); color: var(--ink3); font-size: 15px; }
.wk-ring-num { position: absolute; inset: 0; display: grid; place-items: center; font-size: 9px; font-weight: 700; color: var(--moon-glyph); text-shadow: var(--photo-text-shadow); font-variant-numeric: tabular-nums; }
.wk-cook-main { flex: 1; min-width: 0; }
.wk-cook-name { display: flex; align-items: center; gap: 6px; font-size: var(--fs-cap); font-weight: 600; letter-spacing: .03em; text-transform: uppercase; color: var(--ink2); }
.wk-cook-name span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wk-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--pend); flex: none; }
.wk-step { font-size: var(--fs-md); font-weight: 500; color: var(--ink); line-height: 1.35; margin: 3px 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.wk-cook-meta { font-size: var(--fs-cap); color: var(--ink3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wk-cook-meta .n { color: var(--ink2); font-weight: 600; font-variant-numeric: tabular-nums; }
.wk-go { flex: none; color: var(--ink3); font-size: 15px; line-height: 1; padding-left: 2px; }
@media (prefers-reduced-motion: no-preference) {
  .wk-dot { animation: wkPulse 2.4s ease-in-out infinite; }
  @keyframes wkPulse { 0%, 100% { opacity: .4; } 50% { opacity: 1; } }
}

/* the Rezepte widget: a search + diet pills + a compact scrolling list with a mini cover */
.wk-filter { padding: 8px 13px 6px; }
.wk-search { height: 34px; border: 1px solid var(--line); border-radius: var(--r-ctl); background: var(--card2); display: flex; align-items: center; gap: 8px; padding: 0 11px; }
.wk-search i { color: var(--ink3); font-size: 12px; flex: none; }
.wk-search input { border: 0; background: transparent; outline: none; color: var(--ink); flex: 1; min-width: 0; font-family: var(--font-family); font-size: var(--fs-md); }
.wk-search input::placeholder { color: var(--ink3); }
.wk-pills { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.wk-pill { flex: none; font-size: var(--fs-cap); font-weight: 500; padding: 4px 10px; border-radius: var(--r-pill); border: 1px solid var(--line2); background: transparent; color: var(--ink2); white-space: nowrap; cursor: pointer; }
.wk-pill.active { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.wk-pill-n { margin-left: 5px; font-variant-numeric: tabular-nums; opacity: 0.55; }
.wk-list { max-height: 264px; overflow-y: auto; scrollbar-width: thin; }
.wk-item { display: flex; align-items: center; gap: 11px; padding: 8px 13px; border-top: 1px solid var(--line); cursor: pointer; }
#app .wk-item[hidden] { display: none; }
.wk-thumb { width: 36px; height: 36px; border-radius: 9px; flex: none; object-fit: cover; box-shadow: inset 0 0 0 1px var(--photo-edge); }
.wk-thumb-blank { display: grid; place-items: center; background: var(--card2); color: var(--ink3); font-size: 13px; }
.wk-item .txt { flex: 1; min-width: 0; }
.wk-item .txt b { display: block; font-weight: 500; font-size: var(--fs-body); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wk-minitags { display: flex; gap: 5px; margin-top: 3px; flex-wrap: wrap; }
.wk-mtag { font-size: 9.5px; letter-spacing: .02em; color: var(--ink2); background: var(--card2); border: 1px solid var(--line); border-radius: var(--r-pill); padding: 1px 7px; white-space: nowrap; }
.wk-mtag.wk-plan { color: var(--pend-ink); background: var(--pend-soft); border-color: transparent; font-weight: 600; }
.wk-planbtn { width: 30px; height: 30px; border-radius: 10px; flex: none; background: var(--card2); border: 1px solid var(--line2); color: var(--ink2); display: grid; place-items: center; font-size: var(--fs-ui); cursor: pointer; }
.wk-none { padding: 10px 13px 13px; font-size: var(--fs-hint); color: var(--ink3); }

/* the "Kochen planen" sheet: Wann? chips + a date, in the form-row rhythm */
.cook-when { display: flex; gap: 8px; }
.cook-when-chip { flex: 1; height: 40px; border: 1px solid var(--line2); border-radius: var(--r-ctl); background: transparent; color: var(--ink2); font-family: var(--font-family); font-size: var(--fs-md); font-weight: 600; cursor: pointer; }
.cook-when-chip.active { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.cook-when-date { margin-top: 10px; box-sizing: border-box; width: 100%; height: 40px; border: 1px solid var(--line); border-radius: var(--r-ctl); background: var(--card); color: var(--ink); padding: 0 12px; font-family: var(--font-family); font-size: var(--fs-md); }
.cook-plan-hint { font-size: var(--fs-cap); color: var(--ink3); line-height: 1.5; margin: 4px 0 0; }
.cook-plan-recipes { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }
.cook-plan-recipe { display: flex; align-items: center; gap: 10px; padding: 8px 11px; border: 1px solid var(--line); border-radius: var(--r-ctl); background: var(--card2); }
.cook-plan-recipe-t { flex: 1; min-width: 0; font-size: var(--fs-md); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cook-plan-recipe-go { flex: none; font-size: var(--fs-cap); font-weight: 600; color: var(--bg); background: var(--ink); border: 0; border-radius: var(--r-pill); padding: 5px 12px; cursor: pointer; }
/* a planned recipe in the Rezepte widget: pinned to the top + a quiet amber left accent */
#app .wk-item.wk-planned { box-shadow: inset 2px 0 0 var(--pend); }

/* recipe diet/type chips (monochrome, reusing .notes-chip) on the list row + read view */
#recipe-view-overlay .rv-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 0; }
/* Curated store suggestions (dashboard recipe widget): a dashed tag marks a suggestion */
#app .wk-suggestion-tag { border-style: dashed; }
#app .wk-take.done { opacity: 0.5; }
.pick-hint { color: var(--ink3); font-size: var(--fs-ui); flex: none; white-space: nowrap; }

/* series capture (shopping): the quiet confirmation under Menge×Artikel — the sheet
   stays open between saves, so this line is the visible trace the item was written */
.form-saved {
    display: flex;
    align-items: center;
    gap: 6px;
    color: var(--ink3);
    font-size: var(--fs-label);
    margin: -4px 2px 12px;
}
.form-saved[hidden] { display: none; }
.form-saved i { font-size: 11px; }

/* "Zuletzt gekauft" quick-adds: the pill is a SPAN holding two buttons (file + forget) —
   text-only, so the avatar-sized left padding gives way to a symmetric one */
.recent-chips[hidden] { display: none; }
.recent-chips .fuer-chip { padding: 4px 8px 4px 11px; gap: 7px; }
.recent-chips .recent-add {
    border: 0;
    background: none;
    padding: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

/* baby chips (Wann-row backdating + Brei suggestions): plain text pills — the avatar-sized
   left padding gives way to a symmetric one */
.baby-chips .fuer-chip { padding: 4px 11px; }

/* the EXPECTED baby's status card (due date still ahead — derived state): a quiet
   countdown instead of a day that is not running yet */
.baby-expect {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 28px 16px;
    gap: 6px;
}
.baby-expect-count { font-size: 24px; font-weight: 600; letter-spacing: -.01em; font-variant-numeric: tabular-nums; color: var(--ink); }
.baby-expect-date { color: var(--ink2); font-size: var(--fs-body); }
.baby-expect-sub { color: var(--ink3); font-size: var(--fs-label); margin: 4px 0 0; max-width: 32ch; }

/* Kür fold (form law G1): the editor's Für/Verknüpft/Sichtbarkeit/Anhänge fields sit
   behind ONE collapsed state line; a tap unfolds the real controls */
.kuer-fold { margin-bottom: 12px; }
.kuer-line {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    box-sizing: border-box;
    padding: 11px 12px;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    color: var(--ink2);
    font-family: inherit;
    font-size: var(--fs-body);
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.kuer-line .kuer-sum {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.kuer-line i { flex-shrink: 0; font-size: 12px; color: var(--ink3); transition: transform .18s; }
.kuer-line[aria-expanded="false"] i { transform: rotate(-90deg); }
.kuer-body { padding-top: 12px; }
/* the body holds display:flex/grid rows — collapsed must WIN over them */
.kuer-body[hidden] { display: none; }

/* generic swipeable tab layer (calendar views, baby card tabs) — 1:1 finger follow via
   --tab-drag (CSSOM, CSP-safe), spring-back, directional slide-in; pan-y keeps vertical
   scrolling native AND stops horizontal ancestor scrollers from grabbing gestures here */
.tab-layer {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    touch-action: pan-y;
    transform: translateX(var(--tab-drag, 0px));
    transition: transform var(--transition-base);
}
.tab-layer.dragging { transition: none; }
.tab-layer.slide-from-right { animation: notesSlideFromRight var(--transition-base); }
.tab-layer.slide-from-left  { animation: notesSlideFromLeft  var(--transition-base); }
@media (prefers-reduced-motion: reduce) {
    .tab-layer.slide-from-right, .tab-layer.slide-from-left { animation: none; }
    .tab-layer { transition: none; }
}

/* popup / modal system (Module.openFormPopup) — card modal or bottom sheet */
.popup-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: var(--scrim);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}
.popup-modal {
    background: var(--card);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: var(--r-card);
    width: 90%;
    max-width: 420px;
    max-height: 80vh;
    overflow: auto;
    box-shadow: var(--shadow);
    display: flex;
    flex-direction: column;
}
.popup-header {
    padding: 12px 16px;
    border-bottom: 1px solid var(--line);
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
    font-size: 16px;
    letter-spacing: -0.01em;
    flex-shrink: 0;
}
.popup-header > span {
    flex: 1;
    text-align: center;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* keep the centered title optically centered when there is no back arrow */
.popup-header:not(:has(.popup-back)) > span { padding-left: 28px; }
.popup-close {
    background: none;
    border: none;
    font-size: 17px;
    color: var(--ink);
    cursor: pointer;
    line-height: 1;
    padding: 8px 10px;
    flex-shrink: 0;
    -webkit-tap-highlight-color: transparent;
}
.popup-back {
    background: none;
    border: 0;
    color: var(--ink);
    font-size: 19px;
    line-height: 1;
    cursor: pointer;
    padding: 8px 10px 8px 0;
    flex-shrink: 0;
    -webkit-tap-highlight-color: transparent;
}
.popup-body {
    padding: 16px;
    flex: 1;
    overflow: auto;
    scrollbar-width: none;
}
.popup-body::-webkit-scrollbar { display: none; }
.popup-footer {
    padding: 12px 16px;
    border-top: 1px solid var(--line);
    display: flex;
    gap: 9px;
    align-items: center;
    justify-content: flex-end;
    flex-shrink: 0;
}
/* Footer-less sheets end at the physical screen edge — the body then carries the
   safe-area inset the footer used to provide (footer-bearing sheets keep theirs) */
.popup-modal.sheet .popup-body:last-child { padding-bottom: calc(20px + var(--safe-bottom)); }
.popup-body .form-row {
    margin-bottom: 12px;
}
/* every native date input carries a ✕ that empties it (kit.js dateClearButtons) — iOS's picker
   has no Clear; the wrap stands where the input stood, the ✕ sits to the RIGHT of the field
   like the × of a list line (never inside it, where the native calendar icon lives) */
.date-wrap { display: flex; align-items: center; gap: 6px; }
.date-wrap > input { flex: 1 1 auto; min-width: 0; }
.date-clear {
    flex: none;
    border: 0;
    background: transparent;
    cursor: pointer;
    color: var(--ink3);
    display: inline-flex;
    align-items: center;
    padding: 3px 7px 3px 3px;
    font-size: 12px;
    line-height: 1;
}
.date-clear:hover, .date-clear:active { color: var(--due-ink); }
.date-clear[hidden] { display: none; }
/* form vocabulary — uppercase section labels + inset inputs */
.popup-body label {
    display: block;
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink3);
    margin-bottom: 7px;
}
.popup-body input,
.popup-body select,
.popup-body textarea {
    width: 100%;
    font-family: var(--font-family);
    font-size: var(--fs-md);
    color: var(--ink);
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    padding: 11px 13px;
    box-sizing: border-box;
}
.popup-body input:focus,
.popup-body select:focus,
.popup-body textarea:focus {
    outline: none;
    border-color: var(--line2);
}
.popup-body textarea { resize: none; min-height: 60px; line-height: 1.45; }
/* the note editor's TEXT field — it holds the note's whole body, so it gets real height */
.popup-body textarea.ta-tall { min-height: 200px; }

/* bottom-sheet variant */
.popup-overlay.sheet { align-items: flex-end; }
.popup-modal.sheet {
    width: 100%;
    max-width: 520px;
    margin: 0 auto;
    border-bottom: 0;
    border-radius: 22px 22px 0 0;
    animation: fadeSlideUp var(--transition-base) forwards;
}
.popup-modal.sheet::before {
    content: "";
    display: block;
    flex-shrink: 0;
    width: 36px;
    height: 4px;
    border-radius: var(--r-pill);
    background: var(--line2);
    margin: 9px auto 0;
}
.popup-modal.sheet .popup-header {
    border-bottom: 0;
    padding: 8px 14px 10px;
}
.popup-modal.sheet .popup-body { padding: 2px 16px 20px; }
.popup-modal.sheet .popup-footer {
    border-top: 1px solid var(--line);
    padding: 11px 16px calc(16px + var(--safe-bottom));
}
.popup-modal.sheet .popup-footer .action-btn {
    flex: 1;
    padding: 12px;
    font-size: var(--fs-md);
    border-radius: var(--r-ctl);
    margin: 0;
}
.popup-modal.sheet .popup-footer .action-btn.delete-btn {
    flex: 0 0 auto;
    margin-right: auto;
    background: transparent;
    border-color: transparent;
    color: var(--due-ink);
    font-size: var(--fs-body);
    font-weight: 600;
    padding: 12px 6px;
}

/* custom monochrome <select> replacement — the menu is portaled to #app (fixed-positioned) */
.mg-select { position: relative; }
.mg-select-btn {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    padding: 11px 13px;
    cursor: pointer;
    text-align: left;
    box-sizing: border-box;
    font-family: var(--font-family);
    font-size: var(--fs-md);
    color: var(--ink);
    transition: border-color var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
.mg-select.open .mg-select-btn { border-color: var(--line2); }
.mg-select-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mg-select-chev { flex: none; color: var(--ink3); font-size: 11px; transition: transform var(--transition-fast); }
.mg-select.open .mg-select-chev { transform: rotate(180deg); }
.mg-select-menu {
    position: fixed;
    z-index: 1000;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    box-shadow: var(--shadow);
    padding: 5px;
    overflow-y: auto;
    scrollbar-width: thin;
}
.mg-select-opt {
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    border-radius: 9px;
    padding: 9px 10px;
    cursor: pointer;
    font-family: var(--font-family);
    font-size: var(--fs-body);
    font-weight: 500;
    color: var(--ink);
    transition: background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
.mg-select-hint { color: var(--ink3); font-size: var(--fs-cap); margin-right: 6px; }
.mg-select-opt:hover { background: var(--card2); }
.mg-select-heading {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink3);
    padding: 10px 10px 3px;
}
.mg-select-opt.active { font-weight: 600; }
/* options that carry an avatar / glyph line up as a row; the lead sits in a FIXED column so
   every label starts on the same line, whether it follows a 20px avatar or a thin glyph */
.mg-select-opt { display: flex; align-items: center; gap: 7px; }
.mg-select-opt > i.fa-solid { flex: 0 0 20px; justify-content: center; }
.mg-select-opt .m {
    flex: 0 0 20px;
    height: 20px;
    border-radius: 50%;
    font-size: 10px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    background: var(--pc-soft, var(--card2));
    color: var(--pc-ink, var(--ink2));
}
.mg-select-opt .mg-select-check { margin-left: auto; }
/* collapsible groups (link pickers): the heading becomes the fold control, carrying
   "selected/total" so a folded group still says what is picked inside it */
button.mg-select-heading {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    background: transparent;
    border: 0;
    cursor: pointer;
    font-family: var(--font-family);
    padding: 9px 10px 6px;
    -webkit-tap-highlight-color: transparent;
}
button.mg-select-heading:hover { color: var(--ink2); }
/* the filter hides empty groups via [hidden] — a display rule on the element itself would
   otherwise outrank the UA's [hidden] { display: none } */
.mg-select-menu [hidden] { display: none; }
.mg-fold-label { flex: 1; text-align: left; }
.mg-fold-count {
    font-size: var(--fs-cap);
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ink3);
}
.mg-fold-count.has-sel { color: var(--ink); }
.mg-fold-chev { font-size: 10px; transition: transform var(--transition-fast); }
.mg-select-fold.open .mg-fold-chev { transform: rotate(180deg); }
/* type-to-filter box — sticky so it stays reachable while the options scroll under it */
.mg-select-filter {
    position: sticky;
    top: -5px;
    z-index: 1;
    background: var(--card);
    padding: 3px 2px 6px;
    margin: -2px 0 0;
}
.mg-filter-input {
    width: 100%;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: 9px;
    padding: 8px 10px;
    color: var(--ink);
    font-family: var(--font-family);
    font-size: var(--fs-body);
}
.mg-filter-input::placeholder { color: var(--ink3); }
.mg-filter-input:focus { outline: none; border-color: var(--ink3); }
.mg-select-nohit {
    padding: 10px;
    color: var(--ink3);
    font-size: var(--fs-body);
    text-align: center;
}
/* two classes deep: must outweigh icons.css's `i.fa-solid { display:inline-flex }`,
   which would otherwise show every option's ✓ */
.mg-select-opt .mg-select-check { display: none; }
.mg-select-opt.active .mg-select-check {
    /* inline-flex, not inline-block: the mask icon's ::before only takes its 1em size
       as a flex item; floated, this computes to a flex container */
    display: inline-flex;
    float: right;
    margin-top: 2px;
    font-size: 10px;
    color: var(--ink);
}

/* misc CSP-safe helpers */
.hidden-file-input {
    display: none;
}

/* person palette slots — each sets the element-scoped color vars; no class = neutral.
   Slots are chosen explicitly or assigned deterministically (members then entities). */
.pc-1  { --pc: var(--p1);  --pc-soft: var(--p1-soft);  --pc-ink: var(--p1-ink); }
.pc-2  { --pc: var(--p2);  --pc-soft: var(--p2-soft);  --pc-ink: var(--p2-ink); }
.pc-3  { --pc: var(--p3);  --pc-soft: var(--p3-soft);  --pc-ink: var(--p3-ink); }
.pc-4  { --pc: var(--p4);  --pc-soft: var(--p4-soft);  --pc-ink: var(--p4-ink); }
.pc-5  { --pc: var(--p5);  --pc-soft: var(--p5-soft);  --pc-ink: var(--p5-ink); }
.pc-6  { --pc: var(--p6);  --pc-soft: var(--p6-soft);  --pc-ink: var(--p6-ink); }
.pc-7  { --pc: var(--p7);  --pc-soft: var(--p7-soft);  --pc-ink: var(--p7-ink); }
.pc-8  { --pc: var(--p8);  --pc-soft: var(--p8-soft);  --pc-ink: var(--p8-ink); }
.pc-9  { --pc: var(--p9);  --pc-soft: var(--p9-soft);  --pc-ink: var(--p9-ink); }
.pc-10 { --pc: var(--p10); --pc-soft: var(--p10-soft); --pc-ink: var(--p10-ink); }

/* person badges: 19px initials circles, overlapping; .who sits right-aligned in rows,
   .ppl clusters under titles/in meta rows */
.who { display: flex; align-items: center; margin-left: auto; flex-shrink: 0; }
.ppl { display: inline-flex; align-items: center; flex-shrink: 0; }
.who .m, .ppl .m, .notes-avs .m {
    width: 19px;
    height: 19px;
    border-radius: 50%;
    font-size: 8.5px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    border: 1.5px solid var(--card);
    margin-left: -5px;
    background: var(--pc-soft, var(--card2));
    color: var(--pc-ink, var(--ink2));
}
.who .m:first-child, .ppl .m:first-child, .notes-avs .m:first-child { margin-left: 0; }
/* non-person subjects wear their type glyph in the badge circle instead of a letter */
.m.m-glyph { background: var(--card2); color: var(--ink2); }
.m.m-glyph i { font-size: 9px; }
/* subject badges inside strip chips (the Für / links strips, the entity hub) */
.notes-chip .m, .ent-link-go .m {
    width: 17px;
    height: 17px;
    border-radius: 50%;
    font-size: 8px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    margin-left: -3px;
    background: var(--pc-soft, var(--card2));
    color: var(--pc-ink, var(--ink2));
}
.notes-chip .m.m-glyph, .ent-link-go .m.m-glyph { background: var(--card2); color: var(--ink2); }

/* the color chooser: every palette swatch + an "auto" dot (deterministic assignment) */
.color-pick { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.color-dot {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 1px solid var(--line2);
    background: var(--pc, var(--card2));
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
    -webkit-tap-highlight-color: transparent;
}
.color-dot.auto {
    background: linear-gradient(135deg, var(--card2) 48%, var(--line2) 48%, var(--line2) 52%, var(--card2) 52%);
}
.color-dot.on { box-shadow: 0 0 0 2px var(--card), 0 0 0 3.5px var(--ink); }

/* the 6px person dot in widget rows */
.pdot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    flex-shrink: 0;
    background: var(--pc, var(--line2));
}


/* ============================== dashboard ============================== */

.module-dashboard {
    display: flex;
    flex-direction: column;
    height: 100%;
    position: relative;
}

/* widget grid — 2 columns on phones, 4 from 600px container width */
.dash-grid {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 4px var(--pad) 96px;
    display: grid;
    grid-template-columns: 1fr;
    grid-auto-rows: min-content;
    gap: 10px;
    align-content: start;
}
/* the greeting is a FIXED header above the swiping pager (flex-none) — it does not scroll with the
   widgets; only the pager beneath it moves. Aligned with the page padding. */
.module-dashboard > .pageTitle { flex: none; padding: 6px var(--pad) 8px; }
/* home-screen paging: the grid(s) live inside a horizontal scroll-snap pager, one .dash-grid per
   page. A single page keeps today's look (the pager has one child — no dots, no horizontal scroll).
   Each page scrolls vertically on its own, exactly like the calendar/baby pagers. */
.dash-pager {
    flex: 1;
    min-height: 0;
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
.dash-pager::-webkit-scrollbar { display: none; }
/* border-box so flex-basis:100% INCLUDES the grid's L/R padding — without it the padding is added
   on top, the page runs ~32px wider than the pager, and the surplus scrolls sideways (the right
   gutter looks eaten). Same reason .baby-page carries box-sizing. */
.dash-pager > .dash-grid { flex: 0 0 100%; min-width: 0; scroll-snap-align: start; box-sizing: border-box; }
/* page dots — the persistent page switcher pinned above the footer: big, comfortably tappable
   buttons, the active page a wide ink pill. The row is left empty (and hidden) with a single page
   when not arranging. */
.dash-dots {
    flex: none;
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 3px;
    padding: 8px 0 10px;
}
.dash-dots:empty { display: none; padding: 0; }
.dash-dot {
    border: 0;
    background: transparent;
    cursor: pointer;
    padding: 8px 6px;   /* a comfortable tap area around the visible dot */
    display: flex;
    align-items: center;
    -webkit-tap-highlight-color: transparent;
}
.dash-dot::before {
    content: "";
    width: 9px;
    height: 9px;
    border-radius: var(--r-pill);
    background: var(--line2);
    transition: width var(--transition-base), background var(--transition-base);
}
.dash-dot.on::before { width: 28px; background: var(--ink); }
.dash-dot.add::before { background: transparent; box-shadow: inset 0 0 0 1.5px var(--ink3); }
/* weather widget with no place yet — a real call to action to add one (opens Settings → Gruppe):
   a warm sun disc over an ink pill button, so it reads as a button, not a label. */
.wx-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    width: 100%;
    border: 0;
    background: transparent;
    padding: 24px 16px 28px;
    cursor: pointer;
    font-family: var(--font-family);
    -webkit-tap-highlight-color: transparent;
}
.wx-empty-ic {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--pend-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--pend-ink);
    font-size: 22px;
}
/* the ink pill carrying an ICON beside its label */
.wx-empty-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}
.wx-empty-btn i { font-size: 12px; }
.wx-empty:active .wx-empty-btn { transform: scale(var(--button-click-scale)); }
/* the "Neue Seite" page at the end of the pager (arrange mode only) */
.dash-page-add {
    flex: 0 0 100%;
    min-width: 0;
    scroll-snap-align: start;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px var(--pad) 96px;
}
.dash-page-add button {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    height: 62%;
    min-height: 220px;
    border: 1.5px dashed var(--line2);
    border-radius: var(--r-card);
    background: transparent;
    color: var(--ink2);
    font-family: var(--font-family);
    font-size: var(--fs-body);
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.dash-page-add button i { font-size: 26px; }
/* "Widget hinzufügen" tile — a dashed full-width placeholder shown only in edit mode */
.dash-add-tile {
    display: none;
    grid-column: 1 / -1;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 92px;
    border: 1.5px dashed var(--line2);
    border-radius: var(--r-card);
    background: transparent;
    color: var(--ink2);
    cursor: pointer;
    font-family: var(--font-family);
    font-size: var(--fs-hint);
    font-weight: 600;
    -webkit-tap-highlight-color: transparent;
}
.dash-add-tile i { font-size: 15px; }
.module-dashboard.editing .dash-add-tile { display: flex; }
.pageTitle { display: flex; align-items: flex-start; gap: 10px; padding: 2px 4px 4px; }
.pageTitle .tx { flex: 1; }
.pageTitle h2 { margin: 0; } /* type comes from the display-serif rule at the end of the file */
.pageTitle p { font-size: var(--fs-hint); color: var(--ink2); margin: 2px 0 0; }
/* the day line under the greeting — the day's shape in one quiet sentence; only the
   event count carries weight */
.pageTitle .dash-dayline b { font-weight: 600; color: var(--ink); }
/* Notizen: the Datum/Kategorie group switch, right of the title — plain text labels like the
   calendar's view switcher, the active one inked + bold. */
/* the Datum/Kategorie switch is a segmented control, like the calendar's view switch and the
   baby tabs: a raised track holding two pills, the active one filled INK (design system: ON=ink) */
.notes-groupsw { display: inline-flex; gap: 2px; align-self: center; flex: none; background: var(--card); padding: 3px; border-radius: var(--r-ctl); }
.notes-groupsw-opt { appearance: none; border: 0; background: transparent; cursor: pointer; font: inherit; font-size: var(--fs-ui); font-weight: 600; color: var(--ink2); padding: 6px 12px; line-height: 1; border-radius: 9px; }
.notes-groupsw-opt.on { background: var(--ink); color: var(--bg); }
/* column ladder: phones stack every widget full-width; wider containers get 2, then 4 tracks */
@container (min-width: 600px) {
    .dash-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
    .widget.full, .widget[data-wkey="weather"] { grid-column: span 2; }
}
@container (min-width: 1000px) {
    .dash-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .widget.full { grid-column: span 2; }
    .widget[data-wkey="weather"] { grid-column: 1 / -1; }
}

/* widget anatomy — a card: head (title · count · + · ›), rows — borderless, shadowless */
.widget {
    background: var(--card);
    border-radius: var(--r-card);
    overflow: hidden;
    position: relative;
    display: flex;
    flex-direction: column;
    min-width: 0;
    box-sizing: border-box;
}

.w-head {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 11px 13px 9px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.w-title {
    font-size: var(--fs-ui);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.w-spacer { flex: 1; }
/* the + — a quiet hairline disc in every widget head */
#app .w-add {
    width: 28px;
    height: 28px;
    box-sizing: border-box;
    border: 1px solid var(--line2);
    border-radius: 50%;
    background: transparent;
    color: var(--ink2);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    font-size: 13px;
    line-height: 1;
    flex-shrink: 0;
    transition: transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
#app .w-add:active { transform: scale(var(--button-click-scale)); }
#app .w-add.w-pen { border: 0; color: var(--ink2); } /* the weather ✎ */
.w-chev { color: var(--ink3); font-size: 14px; line-height: 1; flex-shrink: 0; }

.w-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* widget rows — hairline-separated, vertically centered */
.w-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    padding: 10px 13px;
    border-top: 1px solid var(--line);
    font-size: var(--fs-body);
    line-height: 1.35;
}
/* ONE checkbox for the whole app — the drawn ink check. The #app-scoped selectors pull the
   sheets' native checkboxes (import preview, export, support consent, med active, confirm
   extra) onto the same treatment, so no platform-styled box ever sits next to a drawn one. */
.w-check,
#app .ent-rec-active,
#app .settings-support input,
#app .hl-opt input,
#app .cal-imp-row input[type="checkbox"],
#app .exp-row input[type="checkbox"],
#app .confirm-sheet .confirm-extra input {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    padding: 0;           /* the generic .popup-body input padding must not inflate the box */
    box-sizing: border-box;
    cursor: pointer;
    flex: none;
    width: 17px;
    height: 17px;
    border-radius: 5px;
    border: 1.5px solid var(--line2);
    background: transparent;
    position: relative;
    transition: background var(--transition-fast), border-color var(--transition-fast);
}
.w-check:checked,
#app .ent-rec-active:checked,
#app .settings-support input:checked,
#app .hl-opt input:checked,
#app .cal-imp-row input[type="checkbox"]:checked,
#app .exp-row input[type="checkbox"]:checked,
#app .confirm-sheet .confirm-extra input:checked { background: var(--ink); border-color: var(--ink); }
.w-check:checked::after,
#app .ent-rec-active:checked::after,
#app .settings-support input:checked::after,
#app .hl-opt input:checked::after,
#app .cal-imp-row input[type="checkbox"]:checked::after,
#app .exp-row input[type="checkbox"]:checked::after,
#app .confirm-sheet .confirm-extra input:checked::after {
    content: "";
    position: absolute;
    left: 4.5px;
    top: 1.5px;
    width: 4px;
    height: 8px;
    border: solid var(--card);
    border-width: 0 1.8px 1.8px 0;
    transform: rotate(43deg);
}

/* signature moment — the drawn tick draws itself (short leg, then long) and the box gives
   one soft spring. Gated on html.mg-tick, the ~400ms window bindTickMoment() opens on a
   real checkbox tap: the optimistic rebuild that replaces the node replays it seamlessly,
   while first paint and later sync repaints stay silent. Tick geometry per checkbox size
   comes from --tick-w/--tick-h (default = the 17px .w-check family). */
.mg-tick input[type="checkbox"]:checked {
    animation: tickPop 260ms cubic-bezier(0.34, 1.4, 0.5, 1);
}
.mg-tick input[type="checkbox"]:checked::after {
    animation: tickDraw 220ms cubic-bezier(0.55, 0.06, 0.4, 1) backwards;
}
@keyframes tickPop {
    0%   { transform: scale(0.85); }
    60%  { transform: scale(1.06); }
    100% { transform: scale(1); }
}
@keyframes tickDraw {
    0%   { width: 0; height: 0; opacity: 0; }
    35%  { width: var(--tick-w, 4px); height: 0; opacity: 1; }
    100% { width: var(--tick-w, 4px); height: var(--tick-h, 8px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .mg-tick input[type="checkbox"]:checked,
    .mg-tick input[type="checkbox"]:checked::after { animation: none; }
}
.w-row .txt {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}
/* two-line row body: bold title line + muted subline (span, end time, kind, due state) */
.w-row .txt > b {
    display: block;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
}
.w-row .txt .w-sub {
    display: block;
    font-size: var(--fs-cap);
    font-weight: 400;
    color: var(--ink2);
    margin-top: 1px;
    overflow: hidden;
    text-overflow: ellipsis;
}
.w-row .txt .w-sub.notes-overdue { font-size: var(--fs-cap); }
/* calendar cards (Heute/Demnächst): titles wrap to TWO lines before ellipsizing, so an
   appointment name stays readable; the subline keeps its one-line clamp */
.cal-wcard .w-row .txt { white-space: normal; }
.cal-wcard .w-row .txt > b {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
}
.cal-wcard .w-row .txt .w-sub { white-space: nowrap; }
.w-row .q { color: var(--ink2); font-weight: 400; }
/* row linkages: glyph + label pills under the title; tapping opens the target's editor
   in place (no ×, no module switch — removal lives in the editors) */
.w-tags { display: flex; gap: 5px; margin: 4px 0 1px; flex-wrap: wrap; }
.w-link {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: var(--fs-label);
    font-weight: 600;
    padding: 3px 8px;
    border-radius: 6px;
    background: var(--card2);
    border: 1px solid var(--line);
    color: var(--ink2);
    white-space: nowrap;
    flex-shrink: 0;
    cursor: pointer;
    font-family: inherit;
    -webkit-tap-highlight-color: transparent;
}
.w-link i { font-size: 11px; opacity: .7; }
/* the folded link summary: one chip per row instead of a wrapping chip field */
.w-linksum-chev { transition: transform var(--transition-fast); }
.w-linksum.open .w-linksum-chev { transform: rotate(180deg); }
/* content-sized, unlike the field menus that inherit their anchor's width */
.w-linkmenu { min-width: 190px; max-width: min(320px, calc(100vw - 16px)); width: max-content; }
.w-linkmenu .mg-select-opt { display: flex; align-items: center; gap: 8px; }
/* one list row = the target (opens it) + an optional × (severs the link where it is stored) */
.w-linkrow { display: flex; align-items: center; gap: 2px; }
.w-linkrow .mg-select-opt { flex: 1; min-width: 0; }
.w-linkrow .mg-select-opt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.w-linkx {
    flex-shrink: 0;
    background: transparent;
    border: 0;
    color: var(--ink3);
    cursor: pointer;
    padding: 8px 8px;
    border-radius: 8px;
    font-size: 11px;
    -webkit-tap-highlight-color: transparent;
}
.w-linkx:hover, .w-linkx:active { color: var(--due-ink); background: var(--card2); }
/* person/thing chips lead with a mini initials circle in the subject's color */
.w-link .mi {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    font-size: 7.5px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    background: var(--pc-soft, var(--card2));
    color: var(--pc-ink, var(--ink2));
}
/* rows with a form behind them */
.w-row.tap { cursor: pointer; }
/* the bottom expander strip: "+ n weitere" + chevron; open flips the chevron, drops the text */
.w-foot {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    border: 0;
    background: transparent;
    color: var(--ink3);
    font-size: var(--fs-label);
    font-family: inherit;
    padding: 6px 13px 10px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.w-foot i { font-size: 12px; transition: transform 250ms ease; }
.widget.open .w-foot i { transform: rotate(180deg); }
.widget.open .w-foot span { display: none; }
/* rows beyond the collapsed cap — revealed by the expander */
.w-row.w-xtra { display: none; }
.widget.open .w-row.w-xtra { display: flex; }
/* inline links (bookmark / recipe titles): ink + underline, never browser blue */
a.notes-link { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
a.notes-link:visited { color: var(--ink); }
.w-emptyline { padding: 4px 13px 13px; font-size: var(--fs-hint); color: var(--ink3); }
.w-pin { color: var(--ink); flex: none; font-size: var(--fs-cap); }

/* time columns in rows (Today widget, gift nudge) — the fixed 48px tabular slot */
.cal-widget-time,
.gift-when {
    font-size: var(--fs-cap);
    font-weight: 600;
    color: var(--ink2);
    width: 48px;
    flex: none;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* Demnächst card: the left column stacks weekday over date */
.cal-widget-time.cal-wdate {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
}
.cal-widget-time.cal-wdate .d2 {
    color: var(--ink3);
    font-weight: 500;
}
/* "in 3 Tagen" replaces the weekday within days; it is longer than "Do." and must wrap inside
   the narrow lead instead of pushing the row's title around. */
.cal-widget-time.cal-wdate .rel {
    white-space: normal;
    line-height: 1.15;
    hyphens: none;
}

/* weather widget */
/* The condition family (wx-cond-* on each location page, mirrored on the widget root for the
   ACTIVE page) scopes the generic --wx vars — the pc-N idiom in weather colors. Every consumer
   carries a neutral fallback, so a missing class renders the plain card. */
.wx-cond-sun { --wx: var(--wx-sun); --wx-soft: var(--wx-sun-soft); --wx-ink: var(--wx-sun-ink); }
.wx-cond-suncloud { --wx: var(--wx-suncloud); --wx-soft: var(--wx-suncloud-soft); --wx-ink: var(--wx-suncloud-ink); }
.wx-cond-cloud { --wx: var(--wx-cloud); --wx-soft: var(--wx-cloud-soft); --wx-ink: var(--wx-cloud-ink); }
.wx-cond-fog { --wx: var(--wx-fog); --wx-soft: var(--wx-fog-soft); --wx-ink: var(--wx-fog-ink); }
.wx-cond-rain { --wx: var(--wx-rain); --wx-soft: var(--wx-rain-soft); --wx-ink: var(--wx-rain-ink); }
.wx-cond-snow { --wx: var(--wx-snow); --wx-soft: var(--wx-snow-soft); --wx-ink: var(--wx-snow-ink); }
.wx-cond-thunder { --wx: var(--wx-thunder); --wx-soft: var(--wx-thunder-soft); --wx-ink: var(--wx-thunder-ink); }
.wx-cond-night { --wx: var(--wx-night); --wx-soft: var(--wx-night-soft); --wx-ink: var(--wx-night-ink); }
/* The 3px condition bar (the wg-you top-bar idiom in weather color) — cross-fades when the
   pager settles on another location. The head takes the same padding bump as .wg-you. */
.widget[data-wkey="weather"]::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--wx, var(--line2)); z-index: 2; transition: background var(--transition-fast); }
.widget[data-wkey="weather"] > .w-head { padding-top: 13px; }
/* Multiple weather locations swipe horizontally (one full-width snap page per place) */
.wx-pager { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.wx-pager::-webkit-scrollbar { display: none; }
.wx-page { flex: 0 0 100%; min-width: 0; scroll-snap-align: start; }
.wx-now { display: flex; align-items: center; gap: 12px; padding: 6px 13px 12px; }
/* the condition badge — the current hour's icon on the family's soft disc */
.wx-badge {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--wx-soft, var(--card2));
    border: 1px solid color-mix(in srgb, var(--wx, var(--line2)) 20%, transparent);
    color: var(--wx-ink, var(--ink2));
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    flex-shrink: 0;
}
/* the sun's rays drift, one turn per 90s — alive on a second glance, invisible on the first */
@media (prefers-reduced-motion: no-preference) {
    .wx-cond-sun .wx-badge i { animation: wx-spin 90s linear infinite; }
}
@keyframes wx-spin { to { transform: rotate(360deg); } }
.wx-temp { font-size: 27px; font-weight: 600; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.wx-desc { font-size: var(--fs-body); line-height: 1.5; min-width: 0; }
.wx-desc b { font-weight: 500; }
.wx-hilo { font-size: var(--fs-cap); font-weight: 400; color: var(--ink2); }
/* the card face's 12-hour temperature curve — always visible, tinted by the page's
   wx-cond-* family (line --wx, fill --wx-soft); hour marks beneath, the rain glyph on
   the first mark at or after the arriving rain */
.wx-now:has(+ .wx-spark) { padding-bottom: 2px; }
.wx-spark { padding: 0 13px; }
.wx-spark svg { display: block; width: 100%; height: 54px; }
.wx-spark-hours { display: flex; justify-content: space-between; padding: 3px 13px 12px; font-size: var(--fs-label); color: var(--ink3); font-variant-numeric: tabular-nums; }
.wx-spark-hours span { display: inline-flex; align-items: center; gap: 3px; }
.wx-spark-hours b { color: var(--ink2); font-weight: 600; }
.wx-spark-hours .i { font-size: 9px; color: var(--wx-ink, var(--ink3)); }
/* the head's forecast toggle — rotates while the widget is open */
.wx-chev {
    border: 0;
    background: transparent;
    color: var(--ink3);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4px;
    font-size: 15px;
    flex-shrink: 0;
    transition: transform 250ms ease;
    -webkit-tap-highlight-color: transparent;
}
.widget.open .wx-chev { transform: rotate(180deg); }
.wx-detail { display: none; }
.widget.open .wx-detail { display: block; }
/* the weather ✎ carries a larger glyph than the small + discs */
#app .w-add.w-pen { font-size: 15px; }
/* hourly strip: a full day from the starting hour, scrolled horizontally */
.wx-strip {
    display: flex;
    gap: 2px;
    padding: 8px 8px 2px;
    border-top: 1px solid var(--line);
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
.wx-strip::-webkit-scrollbar { display: none; }
.wx-hour {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    flex: 1 0 44px;
    box-sizing: border-box;
    padding: 5px 2px;
    border-radius: 9px;
    font-size: 9.5px;
    font-weight: 600;
    color: var(--ink2);
    font-variant-numeric: tabular-nums;
}
/* the leading "Jetzt" chip is the anchored one — the only tinted cell in the strip (it shows
   the very code the card's tint comes from); the temperature stays --ink on every soft */
.wx-hour:first-child { background: var(--wx-soft, var(--card2)); border: 1px solid color-mix(in srgb, var(--wx, var(--line2)) 24%, transparent); color: var(--wx-ink, var(--ink2)); }
.wx-hour .i { font-size: 12px; color: var(--ink3); }
.wx-hour:first-child .i { color: var(--wx-ink, var(--ink3)); }
.wx-hour .t { font-weight: 600; font-size: var(--fs-sub); color: var(--ink); }

/* Swipe affordance on the hourly strip: a soft shadow at an edge means "more content that
   way". The cover gradients scroll WITH the content (local) and hide the shadow at the ends. */
.wx-strip {
    background:
        linear-gradient(to right, var(--card) 40%, transparent) left / 28px 100%,
        linear-gradient(to left,  var(--card) 40%, transparent) right / 28px 100%,
        radial-gradient(farthest-side at 0 50%, var(--scroll-shadow), transparent) left / 10px 100%,
        radial-gradient(farthest-side at 100% 50%, var(--scroll-shadow), transparent) right / 10px 100%;
    background-repeat: no-repeat;
    background-attachment: local, local, scroll, scroll;
}
/* the coming days as a CURVE (Wochenschau): the SVG holds only the min/max band geometry
   over a 0-100 viewBox stretched to the card — non-scaling strokes keep the lines hairline
   at every width. Labels, dots and rain bars are HTML pinned to the same percent space, so
   the type stays crisp instead of scaling with the SVG. */
.wxg { padding: 8px 13px 12px; }
.wxg-icons { display: grid; padding-bottom: 2px; }
/* each day's icon, inked in ITS OWN condition (the wx-cond class sits on the icon itself,
   so its --wx-ink beats the page's — today's tint never colors other days) */
.wxg-icons i { font-size: 14px; color: var(--wx-ink, var(--ink3)); justify-self: center; }
.wxg-plot { position: relative; height: 132px; }
.wxg-plot svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.wxg-area { fill: var(--line); fill-opacity: 0.45; }
.wxg-line { fill: none; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.wxg-line-max { stroke: var(--ink); stroke-width: 1.8px; }
.wxg-line-min { stroke: var(--ink3); stroke-width: 1.5px; }
/* the felt temperatures: faint dashed companions to their real twins */
.wxg-line-appmax { stroke: var(--ink); stroke-width: 1.1px; opacity: 0.4; stroke-dasharray: 3 3; }
.wxg-line-appmin { stroke: var(--ink3); stroke-width: 1.1px; opacity: 0.45; stroke-dasharray: 3 3; }
.wxg-dot { position: absolute; width: 6px; height: 6px; border-radius: 50%; background: var(--ink); transform: translate(-50%, -50%); }
.wxg-dot.min { width: 5px; height: 5px; background: var(--ink3); }
.wxg-hi { position: absolute; transform: translate(-50%, calc(-100% - 7px)); font-size: var(--fs-sub); font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.wxg-lo { position: absolute; transform: translate(-50%, 7px); font-size: var(--fs-cap); color: var(--ink3); font-variant-numeric: tabular-nums; }
/* probability bars grow up from the base in the rain family — no rain, no bar */
.wxg-rain { position: absolute; bottom: 0; width: 12px; border-radius: 3px; background: var(--wx-rain); opacity: 0.8; transform: translateX(-50%); }
.wxg-days { display: grid; text-align: center; padding-top: 5px; }
.wxg-days b { display: block; font-size: var(--fs-sub); font-weight: 600; color: var(--ink2); }
.wxg-sub { display: block; font-size: var(--fs-label); color: var(--ink3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.wxg-sub.wet { color: var(--wx-rain-ink, var(--ink2)); }
.weather-hourly-note {
    font-size: var(--fs-cap);
    color: var(--ink2);
    padding: 6px 4px;
    text-align: center;
    flex: 1;
}
/* Weather pager dots — which location page is active, and that there ARE more pages. */
.wx-dots { display: flex; justify-content: center; gap: 5px; padding: 6px 0 8px; }
.wx-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--line2); transition: background var(--transition-fast); }
.wx-dot.active { background: var(--ink); }

/* In stretched rows the body fills the card so bottom-pinned actions reach the bottom. */
.dash-grid .widget > .w-body { flex: 1; }
.dash-grid .widget > .wx-pager { flex: 1; }

/* EDIT MODE — drag & drop to reorder; each widget carries the prototype's edit FOOTER:
   drag grip · Aktiv · Groß · Details toggles */
.w-edit {
    display: none;
    align-items: center;
    gap: 7px 10px;
    flex-wrap: wrap;   /* narrow w1 footers wrap the toggles instead of clipping "Groß" */
    padding: 9px 13px;
    border-top: 1px dashed var(--line2);
    background: var(--card2);
    margin-top: auto;
}
.w-swgrp { display: inline-flex; align-items: center; gap: 7px; flex-shrink: 0; }
.module-dashboard.editing .w-edit { display: flex; }
/* × — remove the widget from the dashboard (edit mode), the prototype's wgDel */
.w-del {
    width: 24px;
    height: 24px;
    border-radius: 8px;
    border: 1px solid color-mix(in srgb, var(--due) 34%, transparent);
    background: var(--due-soft);
    color: var(--due-ink);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
    -webkit-tap-highlight-color: transparent;
}
.w-del i { font-size: 12px; }
/* ‹ › — move this card to the previous / next page (home-screen paging) */
.w-pgmove {
    width: 24px;
    height: 24px;
    border-radius: 8px;
    border: 1px solid var(--line);
    background: var(--card);
    color: var(--ink2);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.w-pgmove i { font-size: 12px; }
.w-grip { color: var(--ink3); display: flex; font-size: 15px; cursor: grab; }
.w-edit-lbl { font-size: var(--fs-label); font-weight: 600; color: var(--ink2); letter-spacing: 0.06em; }
/* the little switch — ON is ink on the card, like every done/on control (never green) */
.swT {
    width: 34px;
    height: 20px;
    border: 0;
    border-radius: var(--r-pill);
    background: var(--line2);
    position: relative;
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
    transition: background var(--transition-base);
    -webkit-tap-highlight-color: transparent;
}
.swT::after {
    content: "";
    position: absolute;
    top: 2.5px;
    left: 3px;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: var(--card);
    transition: left var(--transition-base);
}
.swT.on { background: var(--ink); }
.swT.on::after { left: 16px; }
.module-dashboard.editing .widget {
    border-style: dashed;
    border-width: 1.5px;
    border-color: var(--line2);
    touch-action: pan-y;  /* swipes scroll normally; a LONG-PRESS lifts the card (see _bindDrag) */
    cursor: grab;
    user-select: none;
    -webkit-user-select: none;
}
.module-dashboard.editing .w-head,
.module-dashboard.editing .w-body,
.module-dashboard.editing .wx-now,
.module-dashboard.editing .wx-strip { pointer-events: none; opacity: 0.55; }
.widget.drag-src {
    opacity: 0.85;
    transform: scale(0.97);
    box-shadow: var(--shadow);
    z-index: 4;
    cursor: grabbing;
}

/* the "Fertig" pill in the title row — leaves edit mode (changes save as they happen) */
.editBtn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: 1px solid var(--line2);
    background: var(--card);
    border-radius: var(--r-pill);
    padding: 7px 13px;
    font-family: var(--font-family);
    font-size: var(--fs-ui);
    font-weight: 600;
    color: var(--ink2);
    cursor: pointer;
    flex-shrink: 0;
    -webkit-tap-highlight-color: transparent;
}
.editBtn i { font-size: 13px; }
.editBtn.on {
    background: var(--ink);
    color: var(--bg);
    border-color: var(--ink);
}

/* Fresh-start screen — no card is ON yet, which is a PER-USER state (the layout row is
   private), not a per-household one: a member joining a live household sees it too. The empty state
   is the grid's only child, centred in the viewport by AUTO MARGINS, not by align-items:
   the grid scrolls, and `align-items: center` splits the overflow of a too-tall child evenly,
   which puts its top above the scroll origin where no gesture can reach it (a real phone with
   the URL bar visible or a larger system font cut the greeting off). Auto margins absorb only
   the free space there actually is, so the block centres while it fits and falls back to
   scrolling from the top when it does not. */
#app .dash-grid.dash-start {
    display: flex;
    align-items: flex-start;
    justify-content: center;
}
#app .dash-grid.dash-start > .dash-empty {
    margin-top: auto;
    margin-bottom: auto;
}
#app .dash-empty {
    padding: 24px 8px;
    text-align: center;
    width: 100%;
    max-width: 420px;
}
#app .dash-empty-title {
    /* type comes from the display-serif rule at the end of the file */
    margin-bottom: 6px;
}
#app .dash-empty-hint {
    font-size: var(--fs-body);
    color: var(--ink2);
    max-width: 260px;
    margin: 0 auto;
    line-height: 1.55;
}
#app .dash-empty-actions {
    display: flex;
    flex-direction: column;
    gap: 9px;
    margin: 26px auto 0;
    text-align: left;
}
#app .dash-empty-action {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 13px 14px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--card);
    color: var(--ink);
    font-family: var(--font-family);
    font-size: var(--fs-md);
    font-weight: 500;
    cursor: pointer;
    text-align: left;
    -webkit-tap-highlight-color: transparent;
}
#app .dash-empty-action i {
    width: 34px;
    height: 34px;
    flex: none;
    box-sizing: border-box;
    border-radius: 10px;
    background: var(--card2);
    border: 1px solid var(--line);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    color: var(--ink2);
}
#app .dash-empty-action:active { transform: scale(0.98); }

/* ============================== calendar ============================== */

.module-calendar { display: flex; flex-direction: column; height: 100%; position: relative; }

.cal-head { display: flex; align-items: center; gap: 6px; padding: 12px var(--pad) 10px; flex: none; }
/* the two-line title composition: the big serif MAIN line (type from the display-serif rule
   at the end of the file) over a small sans INFO line (year, KW, date) — nothing gets cut
   off; each line ellipsizes on its own as a last resort */
.cal-title { flex: 1; min-width: 0; }
.cal-title-main, .cal-title-info { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-title-main { line-height: 1.1; }
.cal-title-info {
    font-family: var(--font-family);
    font-size: var(--fs-cap);
    font-weight: 500;
    letter-spacing: 0.02em;
    color: var(--ink2);
    line-height: 1.3;
    margin-top: 1px;
}
/* the nav cluster wears --nav-fill (see the structural tokens): navigation, not action */
.cal-nav {
    width: 30px;
    height: 30px;
    flex: none;
    border: 0;
    background: var(--nav-fill);
    color: var(--ink);
    border-radius: var(--r-pill);
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
    transition: transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
.cal-nav:active { transform: scale(var(--button-click-scale)); }
.cal-today {
    height: 30px;
    flex: none;
    font-family: var(--font-family);
    font-size: var(--fs-ui);
    font-weight: 600;
    color: var(--ink);
    background: var(--nav-fill);
    border: 0;
    border-radius: var(--r-pill);
    padding: 0 12px;
    cursor: pointer;
    transition: transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
.cal-today:active { transform: scale(var(--button-click-scale)); }

/* view switcher — one segmented control (Monat/Woche/Tag/Demnächst), active = ink */
.cal-views {
    display: flex;
    gap: 2px;
    background: var(--card);
    padding: 3px;
    border-radius: var(--r-ctl);
    margin: 0 var(--pad) 8px;
    flex: none;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
.cal-views::-webkit-scrollbar { display: none; }
.cal-view-btn {
    flex: 1 0 auto;
    border: 0;
    background: transparent;
    cursor: pointer;
    font-family: var(--font-family);
    font-size: var(--fs-ui);
    font-weight: 600;
    color: var(--ink2);
    padding: 7px 8px;
    border-radius: 9px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    transition: background var(--transition-base), color var(--transition-base);
    -webkit-tap-highlight-color: transparent;
}
.cal-view-btn.active { background: var(--ink); color: var(--bg); }

/* month grid — one card; a narrow KW gutter (ISO week numbers) leads the 7 day columns */
.cal-grid {
    display: grid;
    grid-template-columns: auto repeat(7, minmax(0, 1fr));
    gap: 2px;
    margin: 3px var(--pad) 12px;
    padding: 13px 8px 8px;
    flex: none;
}
.cal-wd, .cal-kwhd { text-align: center; font-size: 10px; font-weight: 600; color: var(--ink3); padding-bottom: 7px; }
.cal-kw {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    padding-right: 2px;
    font-size: 10px;
    font-weight: 500;
    color: var(--ink3);
    font-variant-numeric: tabular-nums;
}
.cal-cell {
    position: relative;
    min-height: 44px;
    border: 0;
    background: transparent;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    border-radius: 10px;
    padding: 5px 0 6px;
    -webkit-tap-highlight-color: transparent;
}
.cal-num {
    font-size: var(--fs-hint);
    font-weight: 500;
    color: var(--ink);
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-variant-numeric: tabular-nums;
}
.cal-other .cal-num { color: var(--ink3); }
/* today = filled ink; a selected other day = ink ring */
.cal-todaycell .cal-num { background: var(--ink); color: var(--bg); font-weight: 600; }
.cal-selected:not(.cal-todaycell) .cal-num { box-shadow: inset 0 0 0 1.5px var(--ink); }
/* month-grid dots — person colors (neutral ink without a subject), ring = entity dates,
   red = an overdue todo that day, muted = public holidays */
.cal-dots { display: flex; gap: 2.5px; height: 5px; align-items: center; }
.cal-dot { width: 4px; height: 4px; border-radius: 50%; background: var(--pc, var(--ink)); box-sizing: border-box; }
.cal-dot.ent { width: 5px; height: 5px; background: transparent; border: 1.2px solid var(--pc, var(--ink)); }
.cal-dot.due { background: var(--due); }
.cal-dot.holiday { background: var(--ink3); }
.cal-other .cal-dot { opacity: 0.55; }

/* month view: grid + agenda share ONE scroller; wide containers set them side by side */
.cal-cols {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    display: flex;
    flex-direction: column;
}
.cal-agenda { padding: 0 var(--pad) 96px; }
@container (min-width: 600px) {
    .cal-cols {
        display: grid;
        grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
        gap: 12px;
        align-items: start;
        align-content: start;
        padding: 0 var(--pad);
    }
    .cal-cols .cal-grid { margin: 3px 0 12px; }
    .cal-cols .cal-agenda { padding: 0 0 96px; }
}
/* week/day/upcoming shells — day cards fill the shell's width (the shell is the centered
   app column on wide screens, so no separate cap is needed) */
.cal-week, .cal-day, .cal-upcoming {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 6px var(--pad) 96px;
}

/* day headers ARE the app's section heading now (Module.sectionHead / .sec-head); these three
   keep only their spacing, because a day header sits over a card and not over a plain list */
.cal-agenda-label, .cal-up-day, .cal-week-hd { margin: 4px 2px 4px; padding-top: 10px; }
/* day-header forecast ("☀️ 31°/20°") sits on the RIGHT in every day header */
.cal-wx { margin-left: 8px; font-size: var(--fs-sub); font-weight: 400; color: var(--ink2); white-space: nowrap; font-variant-numeric: tabular-nums; }
.cal-week-hd .cal-wx { margin-left: auto; }
.cal-agenda-label .cal-wx, .cal-up-day .cal-wx { margin-left: auto; }
.cal-wx + .cal-week-add { margin-left: 8px; } /* the forecast takes the auto-gap when present */
/* the day-header + — the same quiet hairline disc as the widget + */
.cal-week-add {
    margin-left: auto;
    flex: none;
    width: 28px;
    height: 28px;
    box-sizing: border-box;
    border-radius: 50%;
    border: 1px solid var(--line2);
    background: transparent;
    color: var(--ink2);
    cursor: pointer;
    font-size: 13px;
    line-height: 1;
    display: grid;
    place-items: center;
    transition: transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
.cal-week-add:active { transform: scale(var(--button-click-scale)); }

/* one CARD per day: event rows inside, hairline-separated — borderless like the notes cards */
.cal-daylist {
    background: var(--card);
    border-radius: var(--r-card);
    overflow: hidden;
    margin-bottom: 16px;
    padding-bottom: 0;
}
/* the week day is a bare SECTION like the month agenda: label outside, only the list is a card */
.cal-week-day.cal-todaycell .cal-week-name { text-decoration: underline; text-underline-offset: 3px; }

/* Upcoming — month separators above the day sections */
.cal-up-month {
    font-size: 17px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ink);
    margin: 20px 2px 8px;
}
.cal-up-month:first-child { margin-top: 4px; }

.cal-empty { color: var(--ink3); font-size: var(--fs-hint); text-align: center; margin-top: 1.5rem; }

/* event row */
.cal-event {
    display: flex;
    gap: 11px;
    align-items: center;
    padding: 12px 14px;
    border-bottom: 1px solid var(--line);
    cursor: pointer;
}
.cal-event:last-child { border-bottom: 0; }
/* the "Für" capsule at the row's right edge (the pencil's old seat) */
.cal-event > .notes-avs { margin-left: auto; flex: none; }
.cal-event .cal-edit { flex: none; align-self: center; margin: -4px -6px -4px 0; }
.cal-event.cal-static { cursor: default; } /* nothing to open (holiday, someone else's birthday) */
.cal-time {
    font-size: var(--fs-sub);
    font-weight: 600;
    color: var(--ink2);
    width: 50px;
    flex: none;
    font-variant-numeric: tabular-nums;
    padding-top: 1px;
    line-height: 1.5;
}
.cal-time-end { display: block; }
/* the vertical connector between a timed event's start and end */
.cal-time-line { display: block; width: 2px; height: 8px; border-radius: 1px; background: var(--line2); margin: 2px 0 2px 16px; }
/* the 3px color bar beside the time — the first subject's person color */
.cal-bar {
    width: 3px;
    border-radius: var(--r-pill);
    align-self: stretch;
    flex-shrink: 0;
    background: var(--pc, var(--line2));
}
.cal-event-meta .ppl { margin-top: 0; }
.cal-event-body { min-width: 0; flex: 1; }
.cal-event-title { font-size: var(--fs-md); font-weight: 500; line-height: 1.35; word-break: break-word; }
.cal-event-meta { display: flex; flex-wrap: wrap; gap: 5px 8px; margin-top: 4px; align-items: center; }
.cal-meta-chip { font-size: var(--fs-sub); color: var(--ink2); }
/* the foreign-zone marker: quieter than the other meta chips, led by a small clock glyph */
.cal-tz-chip { display: inline-flex; align-items: center; gap: 4px; color: var(--ink3); }
.cal-tz-chip i { font-size: 10px; }
/* clickable attachment chip (attachChip): tap opens the viewer (or a menu when several).
   The host class carries the look; a button host gets the interactive basics here. */
button.attach-chip { font-family: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; }
/* the category line (TERMIN / EINKAUF / …) — quiet uppercase ABOVE the title */
.cal-badge {
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink3);
    margin-bottom: 1px;
}

.cal-fab {
    position: absolute;
    right: 18px;
    bottom: 18px;
    z-index: 5;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    border: 0;
    background: var(--ink);
    color: var(--bg);
    box-shadow: var(--shadow);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    cursor: pointer;
    transition: transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
.cal-fab:active { transform: scale(var(--button-click-scale)); }
.cal-fab svg { width: 24px; height: 24px; }

/* editor sheet extras */
.cal-hidden { display: none !important; }
.cal-skip-list { display: flex; flex-direction: column; gap: 6px; }
.cal-skip-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.cal-skip-date { font-size: var(--fs-body); color: var(--ink2); font-variant-numeric: tabular-nums; }
.cal-skip-row .cal-skip-restore { width: auto; flex: none; padding: 5px 12px; font-size: var(--fs-body); }
.cal-check-row { flex-direction: row; align-items: center; justify-content: space-between; display: flex; }
.cal-check-row label { margin-bottom: 0; }
.popup-body input.cal-check {   /* beat the generic .popup-body input width:100% */
    width: 20px;
    height: 20px;
    flex: none;
    padding: 0;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    border: 1.5px solid var(--line2);
    border-radius: 6px;
    background: transparent;
    position: relative;
}
.popup-body input.cal-check:checked { background: var(--ink); border-color: var(--ink); }
.popup-body input.cal-check:checked::after {
    content: "";
    position: absolute;
    left: 6px;
    top: 2.5px;
    --tick-w: 5px;
    --tick-h: 9px;
    width: 5px;
    height: 9px;
    border: solid var(--card);
    border-width: 0 1.8px 1.8px 0;
    transform: rotate(43deg);
}

/* ============================== notes ============================== */

.module-notes {
    display: flex;
    flex-direction: column;
    height: 100%;
    position: relative;
}
/* the headline block insets to the screen edge like every other notes child */
.module-notes .pageTitle { margin: 10px var(--pad) 0; }

/* the one scrolling feed */
.notes-layer {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    touch-action: pan-y;
    padding: 12px var(--pad) 96px;
    display: flex;
    flex-direction: column;
}
/* A scrollable flex column SHRINKS its children once content overflows — every card lost
   a few px and overflow:hidden clipped the meta line (visible on phones). Never shrink. */
.notes-layer > * { flex-shrink: 0; }
/* directional slide of the shared .tab-layer surfaces (baby, calendar, entity manager) */
@keyframes notesSlideFromRight { from { opacity: 0.5; transform: translateX(20px); } to { opacity: 1; transform: none; } }
@keyframes notesSlideFromLeft  { from { opacity: 0.5; transform: translateX(-20px); } to { opacity: 1; transform: none; } }

/* the card head every feed card leads with: kind line left, "Für wen" avatars right */
.notes-kindhead { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
/* the "Für" capsule: the app's .m person badges stacked inside ONE quiet pill */
.notes-avs { display: inline-flex; align-items: center; background: var(--card2);
    border-radius: var(--r-pill); padding: 2px; }
.notes-av.all, .notes-av.more, .notes-av.lock { height: 19px; display: inline-grid; place-items: center;
    border-radius: var(--r-pill); padding: 0 6px; font-size: 9.5px; font-weight: 600;
    letter-spacing: 0.04em; color: var(--ink2); }
.notes-av.more { margin-left: -3px; }
.notes-av.lock i { font-size: 9px; }

/* the live feed filter under the page title — a quiet field, no frame */
.notes-search {
    display: block;
    background: var(--card);
    border: 0;
    border-radius: var(--r-ctl);
    padding: 9px 13px;
    margin: 12px var(--pad) 0;
    font-family: var(--font-family);
    font-size: var(--fs-md);
    color: var(--ink);
}
.notes-search::placeholder { color: var(--ink3); }
.notes-search:focus { outline: none; background: var(--card2); }

/* date-section headers of the grouped view */
.notes-sect { font-size: var(--fs-ui); font-weight: 700; color: var(--ink); margin: 16px 2px 8px; }
.notes-sect:first-child { margin-top: 2px; }

/* the editor's type rail (create only): every kind as a sliding segment */
.notes-typerail { display: flex; gap: 6px; overflow-x: auto; padding: 2px 2px 10px; scrollbar-width: none; }
.notes-typerail::-webkit-scrollbar { display: none; }
.notes-typ { display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; border: 1px solid var(--line); background: none; color: var(--ink2); border-radius: var(--r-pill); padding: 6px 12px; font-size: var(--fs-hint); white-space: nowrap; cursor: pointer; }
.notes-typ i { font-size: 12px; }
.notes-typ.on { background: var(--ink); border-color: var(--ink); color: var(--bg); font-weight: 600; }

.notes-selbar-act i, .notes-selbar-x i { font-size: 13px; }
.notes-empty {
    color: var(--ink3);
    font-size: var(--fs-hint);
    text-align: center;
    margin-top: 2rem;
}

/* blank state of a truly empty kind — icon tile, title, benefit line, create CTA */
/* in the Notes tabs the blank sits directly under the tab strip — give it the breathing
   room the Baby section cards get from their own card head */
.notes-layer .notes-blank { margin-top: 40px; }
.notes-blank,
.fin-blank {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 0 20px 28px;
}
.notes-blank .nb-mark,
.fin-blank .nb-mark {
    width: 46px;
    height: 46px;
    border-radius: 14px;
    background: var(--card);
    border: 1px solid var(--line);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ink3);
    font-size: 21px;
    margin-bottom: 13px;
}
.notes-blank b,
.fin-blank b {
    font-size: 14px;
    font-weight: 600;
    color: var(--ink);
}
.notes-blank p,
.fin-blank p {
    font-size: var(--fs-hint);
    color: var(--ink2);
    margin-top: 5px;
    line-height: 1.55;
    max-width: 250px;
}
.notes-blank .action-btn,
.fin-blank .action-btn { margin-top: 15px; }

/* item card — checkbox/glyph + title + status + chips + authorship */
.notes-item {
    /* borderless card on the normal card ground — the card is a quiet field, not a box
       (the whole card opens the editor; only its buttons/inputs keep their taps). No
       min-height: the card is exactly as tall as its content; the 44px halo on every
       checkbox keeps the touch targets comfortable. */
    background: var(--card);
    border-radius: var(--r-card);
    padding: 12px 14px;
    margin-bottom: 8px;
    display: grid;
    grid-template-columns: 24px minmax(0, 1fr) auto;
    gap: 2px 10px;
    /* icon, content and Für-capsule share ONE top line, however tall the card grows —
       the side columns are sized to optically centre on the title's first line */
    align-items: start;
    position: relative;
    overflow: hidden;
    cursor: pointer;
}
/* the kind column: one quiet glyph, always in the same place — the card's only label */
.notes-ki {
    width: 24px;
    height: 19px;
    display: grid;
    place-items: center;
    color: var(--ink3);
    font-size: var(--fs-body);
}
/* the right column: avatars, and (recipes) the photo tile beneath them */
.notes-right { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; margin-top: -2px; }
/* checkbox + title as ONE first row (single items, chores, wishes) */
.notes-oneline { display: flex; gap: 10px; align-items: center; min-width: 0; }
.notes-check {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    cursor: pointer;
    flex: none;
    width: 18px;
    height: 18px;
    border-radius: 5px;
    border: 1.5px solid var(--line2);
    background: transparent;
    position: relative;
    transition: background var(--transition-fast), border-color var(--transition-fast);
}
.notes-check:hover { border-color: var(--ink3); }
.notes-check:checked { background: var(--ink); border-color: var(--ink); }
.notes-check:checked::after {
    content: "";
    position: absolute;
    left: 5px;
    top: 1.5px;
    --tick-w: 4.5px;
    --tick-h: 9px;
    width: 4.5px;
    height: 9px;
    border: solid var(--card);
    border-width: 0 1.8px 1.8px 0;
    transform: rotate(43deg);
}
/* Einkauf reads as a ROUND box; todo/chore stay square (kind-shaped, feed + dashboard) */
.notes-check.mg-round, .w-check.mg-round { border-radius: 50%; }
/* body: title + status + meta */
.notes-body { min-width: 0; }
.notes-title {
    font-size: var(--fs-md);
    font-weight: 600;
    line-height: 1.4;
    word-break: break-word;
    /* pre-line keeps the line breaks typed into a note's textarea (inherits into .notes-q) */
    white-space: pre-line;
}
.notes-q { color: var(--ink2); font-weight: 400; font-size: var(--fs-ui); }
/* a note's body under its title — ONE clipped preview line (the editor holds the prose) */
.notes-text { color: var(--ink2); font-size: var(--fs-ui); line-height: 1.5; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
/* status lines: overdue = red + weight; due today = the same weight in plain ink */
#app .notes-overdue { color: var(--due-ink); font-weight: 600; font-size: var(--fs-sub); }
#app .notes-duetoday { color: var(--ink); font-weight: 600; font-size: var(--fs-sub); }
.notes-item.done .notes-title { color: var(--ink3); text-decoration: line-through; }
/* container card (a todo/shopping note holding its own lines): no lead column — every
   line carries its own tick; every line always shows */
.nc-lines { display: flex; flex-direction: column; gap: 7px; margin-top: 2px; }
.notes-title + .nc-lines { margin-top: 8px; }
.nc-line { display: flex; gap: 10px; align-items: flex-start; }
.nc-line .notes-check { margin-top: 1px; }
.nc-text { font-size: var(--fs-body); line-height: 1.4; word-break: break-word; min-width: 0; }
.nc-line.done .nc-text { color: var(--ink3); text-decoration: line-through; }
.notes-meta {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 3px;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
}
.notes-meta .notes-by { overflow: hidden; text-overflow: ellipsis; }
/* a "·" between the meta WORDS (never before the first); the tally chips are self-delimiting
   pills (border + gap), so no dot rides before a w-link or notes-chip */
.notes-meta > * + *::before { content: "·"; color: var(--ink3); margin-right: 6px; }
.notes-meta > * + .w-link::before,
.notes-meta > * + .notes-chip::before { content: none; }
/* landing pulse: a link chip navigated here — say WHICH row it meant, then fade out */
.notes-item.flash { animation: rowFlash 1.6s ease; }
@keyframes rowFlash {
    0%, 45% { box-shadow: inset 0 0 0 1.5px var(--line2); }
    100% { box-shadow: none; }
}
/* person chip — soft pill with a name */
.notes-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: var(--fs-label);
    font-weight: 600;
    padding: 0;
    border: 0;
    background: none;
    color: var(--ink3);
    white-space: nowrap;
    flex: none;
}
button.notes-chip { cursor: pointer; }
button.notes-chip:hover, button.notes-chip:active { color: var(--ink); }
.notes-chip svg { width: 10px; height: 10px; }
/* projection hint — the quiet chips under a dated editor field saying where it will surface
   (calendar / bell). Reuses .notes-chip; the two hosts need different top spacing. */
.proj-hint { display: flex; flex-wrap: wrap; gap: 8px; }
/* the hint chips read as soft outlined pills — a quiet affordance, not a control */
.proj-hint .notes-chip { padding: 3px 9px; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--card2); color: var(--ink2); }
.proj-hint .notes-chip i { font-size: 11px; color: var(--ink3); }
.form-row > .proj-hint { margin-top: 8px; }
.ent-attrs > .proj-hint { margin-top: -4px; }
/* the × on the editor's badge strip (the row chips fold into .w-linksum instead) */
.notes-linkx {
    border: 0;
    background: transparent;
    cursor: pointer;
    color: var(--ink3);
    display: inline-flex;
    align-items: center;
    padding: 3px 7px 3px 3px;
    font-size: 12px;
    line-height: 1;
}
.notes-linkx:hover, .notes-linkx:active { color: var(--due-ink); }
.notes-by { font-size: var(--fs-cap); color: var(--ink3); margin-top: 2px; }
.notes-by b { font-weight: 600; color: var(--ink2); }
.chore-undo { display: flex; align-items: center; gap: 8px; margin-top: 3px; }
.chore-undo .notes-by { margin-top: 0; }
#app .chore-undo-btn {
    border: 0; background: none; color: var(--pc-ink);
    font-family: var(--font-family); font-size: var(--fs-cap); font-weight: 600;
    cursor: pointer; padding: 2px 4px;
}
#app .chore-undo-btn:active { transform: scale(var(--button-click-scale)); }

/* FAB — solid ink. ONE full declaration for both: the split into "shared position, fin-only
   everything else" left the notes button a naked absolute <button> with no size, no circle and
   no ink — visibly broken on the notes surface. */
.notes-fab,
.fin-fab {
    position: absolute;
    right: 18px;
    bottom: 18px;
    z-index: 5;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    border: 0;
    background: var(--ink);
    color: var(--bg);
    cursor: pointer;
    box-shadow: var(--shadow);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 22px;
    transition: transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
/* the docked line is a sibling of the scroller, so the button has to step over it — its height
   is measured after render (--fin-dock-h) because it grows with the number of lines */
.fin-fab { bottom: calc(18px + var(--fin-dock-h, 0px)); }
.notes-fab:active,
.fin-fab:active { transform: scale(var(--button-click-scale)); }
.notes-fab svg,
.fin-fab svg { width: 24px; height: 24px; }

/* dashboard universal + and its "Neu" chooser sheet (rows: icon tile · title/sub · chevron) */
.dash-fab {
    position: absolute;
    right: 18px;
    bottom: 18px;
    z-index: 5;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    border: 0;
    background: var(--ink);
    color: var(--bg);
    cursor: pointer;
    box-shadow: var(--shadow);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    -webkit-tap-highlight-color: transparent;
    transition: transform var(--transition-fast);
}
.dash-fab:active { transform: scale(var(--button-click-scale)); }
.new-list { display: flex; flex-direction: column; }
.new-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    box-sizing: border-box;
    background: transparent;
    border: 0;
    border-bottom: 1px solid var(--line);   /* hairline divider between choices */
    padding: 12px 4px;
    font-family: var(--font-family);
    cursor: pointer;
    text-align: left;
    color: var(--ink);
    -webkit-tap-highlight-color: transparent;
    transition: background var(--transition-fast);
}
.new-row:last-child { border-bottom: 0; }
.new-row:active { background: var(--card2); }
.new-ic {
    width: 38px;
    height: 38px;
    flex-shrink: 0;
    border-radius: var(--r-ctl);
    background: var(--card2);
    border: 1px solid var(--line);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ink2);
    font-size: 16px;
}
.new-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.new-tx b { font-size: var(--fs-md); font-weight: 600; }
.new-tx span { font-size: var(--fs-cap); color: var(--ink3); }
.new-chev { color: var(--ink3); font-size: 13px; flex-shrink: 0; }

/* "Für dich" hero — a per-member agenda pager; recolored to the visible member via its
   pc-N class (--pc / --pc-soft / --pc-ink). Overdue items sit in a red zone at the top. */
.wg-you { position: relative; } /* flat like every other card — the accent bar is the hero cue */
.wg-you::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--pc, var(--ink)); z-index: 2; }
.wg-you > .w-head { padding-top: 13px; cursor: default; } /* aggregation, not a module — header doesn't navigate */
.fy-title { color: var(--pc-ink, var(--ink)); }
.fy-ava {
    width: 22px; height: 22px; border-radius: 50%; flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 10px; font-weight: 700;
    background: var(--pc-soft, var(--card2)); color: var(--pc-ink, var(--ink2));
}
.fy-pager { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
/* split widgets: the card follows the ACTIVE page's height (set per paint), tall neighbours clip */
.fy-pager.w-split { align-items: flex-start; overflow-y: hidden; transition: height var(--transition-base); }
.fy-pager::-webkit-scrollbar { display: none; }
.fy-page { flex: 0 0 100%; min-width: 0; scroll-snap-align: start; }
/* the overdue band whispers: no surface tint, just the 3px edge and the status-coloured
   sublines — red stays red, but it no longer floods the row */
.fy-due { position: relative; }
.fy-due::before { content: ""; position: absolute; top: 0; left: 0; bottom: 0; width: 3px; background: var(--due); }
.fy-row { display: flex; align-items: center; gap: 10px; padding: 10px 13px; border-top: 1px solid var(--line); }
.fy-due .fy-row:first-child { border-top: 0; }
.fy-tap { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.fy-time { font-size: var(--fs-cap); font-weight: 600; color: var(--ink2); width: 48px; flex-shrink: 0; font-variant-numeric: tabular-nums; }
.fy-time.due { color: var(--due-ink); }
.fy-time.q { color: var(--ink3); font-weight: 500; }
.fy-check.fy-check { margin-right: 31px; } /* 17px box + 31px = 48px — aligns with .fy-time */
.fy-due .fy-check { border-color: color-mix(in srgb, var(--due) 45%, transparent); }
.fy-body { flex: 1; min-width: 0; }
.fy-body b { display: block; font-size: var(--fs-body); font-weight: 500; }
.fy-sub { display: block; font-size: var(--fs-cap); color: var(--ink2); margin-top: 1px; }
.fy-sub:empty { display: none; }
.fy-sub.due { color: var(--due-ink); }
.fy-sub.pend { color: var(--pend-ink); }
.fy-sub.accent { color: var(--pc-ink, var(--ink2)); }
.fy-eta { flex-shrink: 0; align-self: center; font-size: var(--fs-cap); font-weight: 600; color: var(--ink);
  background: var(--card2); border: 1px solid var(--line); border-radius: var(--r-pill); padding: 3px 9px;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.fy-body .w-tags { margin-top: 4px; }
.fy-dots { display: flex; gap: 5px; justify-content: center; padding: 9px 0 11px; }
.fy-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--line2); transition: background 0.15s; }
.fy-dots i.on { background: var(--pc, var(--ink)); }

/* the shared household band — softer amber (--pend), never the personal red; a shared thing
   should not read as urgently as your own. Same whisper as the due band: 3px edge, no
   surface tint. Collapses behind a toggle when it grows long. */
.fy-shared { position: relative; border-top: 1px solid var(--line); }
.fy-shared::before { content: ""; position: absolute; top: 0; left: 0; bottom: 0; width: 3px; background: var(--pend); }
.fy-shared .fy-row:first-child { border-top: 0; }
.fy-shared .fy-check { border-color: color-mix(in srgb, var(--pend) 45%, transparent); }
.fy-shared-xtra { display: none; }
.fy-shared.open .fy-shared-xtra { display: flex; }
.fy-shared-foot {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    background: transparent;
    border: 0;
    border-top: 1px solid color-mix(in srgb, var(--pend) 12%, transparent);
    padding: 8px 13px;
    font-family: var(--font-family);
    font-size: var(--fs-cap);
    font-weight: 600;
    color: var(--pend-ink);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.fy-shared-foot i { font-size: 11px; transition: transform 250ms ease; }
.fy-shared.open .fy-shared-foot i { transform: rotate(180deg); }
.fy-shared.open .fy-shared-foot span { display: none; }

/* the personal due-today band folds the same way, but neutral — it is your own day, not the
   softer shared amber; rows keep the plain hairline separator */
.fy-rest-xtra { display: none; }
.fy-rest.open .fy-rest-xtra { display: flex; }
.fy-rest-foot {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    background: transparent;
    border: 0;
    border-top: 1px solid var(--line);
    padding: 8px 13px;
    font-family: var(--font-family);
    font-size: var(--fs-cap);
    font-weight: 600;
    color: var(--ink2);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.fy-rest-foot i { font-size: 11px; transition: transform 250ms ease; }
.fy-rest.open .fy-rest-foot i { transform: rotate(180deg); }
.fy-rest.open .fy-rest-foot span { display: none; }

/* ============================== baby ============================== */

/* a full-height pager: each baby is ONE page between header and the swipe dots */
#app .baby-wrap { position: relative; height: 100%; display: flex; flex-direction: column; }
#app .baby-today, #app .baby-growth { display: flex; flex-direction: column; gap: 14px; }

#app .baby-pager {
    flex: 1;
    min-height: 0;
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}
#app .baby-pager::-webkit-scrollbar { display: none; }
#app .baby-page {
    flex: 0 0 100%;
    min-width: 0;
    scroll-snap-align: start;
    box-sizing: border-box;
    padding: 12px var(--pad) 96px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
/* wide containers: status column (max ~360px) beside the tabs + section card */
@container (min-width: 600px) {
    #app .baby-page {
        display: grid;
        grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
        /* hero, then the tabs row (its own height) and the section row soaking up the rest:
           the tall status column spans rows 2+3, and without the 1fr the grid used to push
           its excess height INTO the tabs row, stretching the active tab on short sections */
        grid-template-rows: min-content min-content 1fr;
        grid-auto-rows: min-content;
        align-content: start;
        gap: 14px 12px;
    }
    #app .baby-page > .baby-hero-wrap { grid-column: 1 / -1; }
    #app .baby-page > .baby-status { grid-column: 1; grid-row: 2 / span 2; align-self: start; }
    #app .baby-page > .baby-tabs { grid-column: 2; grid-row: 2; margin: 0; }
    #app .baby-page > .tab-layer { grid-column: 2; grid-row: 3; }
}

/* swipe indicator — directly above the footer, always visible */
#app .baby-dots { flex: none; display: flex; justify-content: center; gap: 5px; padding: 8px 0 10px; }

#app .baby-fab {
    position: absolute;
    right: 18px;
    bottom: 18px;
    z-index: 5;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    border: 0;
    background: var(--ink);
    color: var(--bg);
    font-size: 24px;
    box-shadow: var(--shadow);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
#app .baby-fab:active { transform: scale(var(--button-click-scale)); }

/* hero: ringed avatar + name/age, today's counts right */
#app .baby-hero { display: flex; align-items: center; gap: 13px; padding: 2px 2px 0; flex-wrap: wrap; }
#app .baby-hero-glyph {
    width: 54px;
    height: 54px;
    box-sizing: border-box;
    border-radius: 50%;
    border: 2.5px solid var(--pc, var(--line2));
    flex: none;
    display: grid;
    place-items: center;
    font-size: 17px;
    font-weight: 600;
    background: var(--pc-soft, var(--card2));
    color: var(--pc-ink, var(--ink2));
    overflow: hidden;
}
#app .baby-hero-glyph img { width: 100%; height: 100%; object-fit: cover; }
#app .baby-hero-name { color: var(--ink); line-height: 1.2; } /* type comes from the display-serif rule at the end of the file */
#app .baby-hero-age { font-size: var(--fs-ui); color: var(--ink2); margin-top: 1px; }
#app .baby-hero-age i { font-size: 11px; color: var(--pc, var(--ink3)); }
#app .baby-hero-wrap { display: flex; flex-direction: column; gap: 10px; }
/* the head's edit pill (icon-only) on the right */
/* the head pencil joins the nav family — same tonal fill as ‹ Heute › */
#app .baby-head-edit { margin-left: auto; padding: 8px 12px; background: var(--nav-fill); border: 0; color: var(--ink); }
#app .baby-head-edit i { font-size: 14px; }
/* the avatar's edit pencil — a small ink disc pinned to the photo's corner */
#app .baby-hero-avatar { position: relative; flex: none; }
#app .baby-avatar-edit {
    position: absolute;
    right: -4px;
    bottom: -4px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 0;
    background: var(--ink);
    color: var(--bg);
    font-size: 10px;
    display: grid;
    place-items: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

/* the tab bar aligns with the page padding, like the calendar's switcher */
#app .baby-tabs { flex: none; margin: 0; border: 0; }
#app .baby-editable { cursor: pointer; -webkit-tap-highlight-color: transparent; }

/* status card — the module's one hero surface */
#app .baby-status {
    padding: 15px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: flex-start;
    --sleep-past: color-mix(in srgb, var(--pc) 45%, var(--card));
}
/* The arc's colour is the CHILD's people-&-things colour — the pc-N class this card also
   carries sets --pc/--pc-soft/--pc-ink. This is only the fallback for a child with no colour
   yet, and it sits in :where() so it has ZERO specificity: a pc-N class must always win.
   (The prototype's --jo does not exist in the app; reaching for it left --pc invalid, which
   silently painted the whole arc black.) */
:where(#app .baby-status) { --pc: var(--p5); --pc-soft: var(--p5-soft); --pc-ink: var(--p5-ink); }
/* dusty rosé turns muddy on a dark card unless the mix leans further to the colour */
[data-theme="dark"] #app .baby-status { --sleep-past: color-mix(in srgb, var(--pc) 58%, var(--card)); }

/* ── the week strip: the last fortnight as narrow 24h columns under the stat tiles.
   Sleep drawn where it lay (night = the child's colour, naps = the past-sleep tone the arc
   already uses), meals as ink dots, the viewed day framed. Reading is the point; the tap
   target is the whole column. */
#app .bweek { align-self: stretch; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
#app .bweek-avgs { color: var(--ink3); font-size: var(--fs-cap); margin-bottom: 8px; font-variant-numeric: tabular-nums; }
/* Columns stay NARROW whatever the day count — three days of data are three thin columns
   hugging today at the right, not three screen-wide slabs. They only ever SHRINK (14 on a
   small phone), never grow. */
#app .bweek-cols { display: flex; gap: 4px; justify-content: flex-end; }
#app .bweek-col {
    flex: 0 1 30px;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    background: none;
    border: none;
    padding: 2px;
    border-radius: 6px;
    cursor: pointer;
}
#app .bweek-col.sel { outline: 1.5px solid var(--ink); outline-offset: 1px; }
#app .bweek-track {
    position: relative;
    height: 72px;
    border-radius: 4px;
    background: var(--card2);
    overflow: hidden;
}
/* nobody recorded ≠ nothing happened: the gap track is dashed and hollow */
#app .bweek-track.gap { background: none; border: 1px dashed var(--line2); }
#app .bweek-track .bwn, #app .bweek-track .bwp {
    position: absolute;
    left: 15%;
    right: 15%;
    border-radius: 2px;
    background: var(--pc);
}
#app .bweek-track .bwp { background: var(--sleep-past); }
#app .bweek-track .bwm {
    position: absolute;
    left: 50%;
    width: 4px;
    height: 4px;
    margin-left: -2px;
    border-radius: 50%;
    background: var(--ink);
}
#app .bweek-lbl { color: var(--ink3); font-size: 9.5px; text-align: center; }
#app .bweek-col.today .bweek-lbl { color: var(--ink); font-weight: 600; }

/* a stepped-back day is unmistakable: the date wears a bordered pill where "Heute" is plain */
#app .baby-daynav-label.past {
    border: 0;
    background: var(--nav-fill);
    border-radius: var(--r-pill);
    padding: 4px 11px;
}

/* Day stepper (G2): ‹ [date] › centred above the arc, a "Heute" jump pinned right while a
   past day is shown; the arrows dim when there is no day to step to. */
#app .baby-daynav {
    align-self: stretch;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-height: 26px;
}
/* the same nav family as the calendar's ‹ Heute › — --nav-fill discs and pills */
#app .baby-daynav-arrow {
    width: 30px;
    height: 30px;
    border: 0;
    background: var(--nav-fill);
    border-radius: var(--r-pill);
    padding: 0;
    display: grid;
    place-items: center;
    color: var(--ink);
    cursor: pointer;
    font-size: 13px;
    transition: transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
#app .baby-daynav-arrow:active { transform: scale(var(--button-click-scale)); }
#app .baby-daynav-arrow:disabled { opacity: .28; cursor: default; }
#app .baby-daynav-label {
    font-size: var(--fs-body);
    font-weight: 600;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    min-width: 92px;
    text-align: center;
}
#app .baby-daynav-today {
    position: absolute;
    right: 0;
    border: 0;
    background: var(--nav-fill);
    border-radius: var(--r-pill);
    padding: 4px 11px;
    font-size: var(--fs-cap);
    font-weight: 600;
    color: var(--ink);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

/* ---- Tagesbogen (design/DESIGN.md Anhang "Baby-Tagesbogen") ---- */
#app .baby-status .ringWrap { position: relative; width: 100%; max-width: 330px; margin: 2px auto 0; }
#app .baby-status .ringWrap svg { display: block; width: 100%; height: auto; }
#app .baby-status .ringWrap .rHit { cursor: pointer; }
#app .baby-status .ringWrap.night svg { opacity: .55; transition: opacity .3s; }
#app .baby-pulse { animation: babyPulse 1.6s ease-in-out infinite; }
@keyframes babyPulse { 0%, 100% { opacity: .9 } 50% { opacity: .35 } }

/* Ring centre — over the SVG only, nudged down because CY 134 ≠ the box's own middle */
#app .ringCtr {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    pointer-events: none;
    transform: translateY(1.1%);
}
#app .ringCtr b { font-size: 24px; font-weight: 600; letter-spacing: -.01em; font-variant-numeric: tabular-nums; }
#app .ringCtr span { font-size: var(--fs-label); color: var(--ink2); margin-top: 5px; }
/* the centre tints every span; the button inside it is not centre TEXT and takes its label back */
#app .ringCtr .sleepBtn span { font-size: var(--fs-md); color: inherit; margin-top: 0; font-weight: 600; }
#app .ringCtr small { font-size: var(--fs-label); color: var(--pc-ink); margin-bottom: 3px; font-weight: 600; letter-spacing: .02em; }

/* The one inline action of the card: a running sleep is a TIMER, not a form */
/* lives INSIDE the ring-centre overlay now: the overlay is pointer-events:none so arc taps
   pass through, and the button opts back in */
#app .sleepBtn {
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: auto;
    gap: 7px;
    margin: 12px auto 0;
    border: 1px solid var(--ink);
    background: var(--ink);
    color: var(--bg);
    border-radius: var(--r-pill);
    padding: 10px 22px;
    font-family: var(--font-family);
    font-size: var(--fs-body);
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
#app .sleepBtn i { font-size: 15px; }
/* BOTH states wear the filled pill — Schlaf starten and Aufwecken are the same primary
 action at two moments, and the muted .on look read as disabled next to the widget's white */
#app .sleepBtn.on { background: var(--ink); color: var(--bg); border-color: var(--ink); }
#app .sleepUndo {
    display: none;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin: 8px auto 0;
    font-size: var(--fs-ui);
    font-weight: 500;
    color: var(--ink2);
}
#app .sleepUndo.on { display: flex; }
#app .sleepUndo button {
    border: 0; background: none; color: var(--pc-ink);
    font-family: var(--font-family); font-size: var(--fs-ui); font-weight: 600; cursor: pointer; padding: 2px 4px;
}

/* Callout — anchored at the tapped element, caret follows */
#app .ringPop {
    display: none;
    position: absolute;
    z-index: 6;
    width: 212px;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    padding: 10px 12px;
    font-size: var(--fs-ui);
    color: var(--ink);
    box-shadow: var(--shadow);
}
#app .ringPop.on { display: block; }
#app .ringPop::after {
    content: "";
    position: absolute;
    left: var(--cx, 50%);
    width: 10px; height: 10px;
    background: var(--card);
    border: 1px solid var(--line);
    transform: translateX(-50%) rotate(45deg);
}
#app .ringPop.up::after { bottom: -6px; border-top: 0; border-left: 0; }
#app .ringPop.dn::after { top: -6px; border-bottom: 0; border-right: 0; }
#app .riHead { display: flex; align-items: baseline; gap: 8px; }
#app .riHead b { font-size: var(--fs-hint); font-weight: 600; }
#app .riHead .riSub { font-size: var(--fs-label); color: var(--ink3); }
#app .riHead button { margin-left: auto; border: 0; background: transparent; color: var(--ink3); cursor: pointer; font-size: 15px; line-height: 1; padding: 0; }
#app .riRow { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-top: 1px solid var(--line); }
#app .riRow:first-of-type { margin-top: 8px; }
#app .riRow .riIc { width: 26px; height: 26px; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
#app .riRow .riT { font-size: var(--fs-cap); font-weight: 600; color: var(--ink2); width: 76px; flex-shrink: 0; font-variant-numeric: tabular-nums; }
#app .riRow .riL { font-size: var(--fs-ui); font-weight: 500; }
#app .baby-status-main { font-size: 20px; font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
/* awake: the duration leads big, "wach seit HH:MM" muted beside it */
#app .baby-status-main.baby-awake { display: flex; align-items: baseline; gap: 8px; }
#app .baby-status-main.baby-awake b { font-size: 24px; font-weight: 600; letter-spacing: -.01em; font-variant-numeric: tabular-nums; }
#app .baby-status-main.baby-awake span { font-size: var(--fs-ui); font-weight: 400; color: var(--ink2); }
/* the wake-window meter beneath it — fills in the baby's color toward the next nap */
#app .baby-meter {
    align-self: stretch;
    height: 5px;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    overflow: hidden;
}
#app .baby-meter i { display: block; height: 100%; background: var(--pc, var(--ink)); border-radius: var(--r-pill); }
#app .baby-status-sub { font-size: var(--fs-hint); color: var(--ink2); }
#app .baby-stop { align-self: stretch; }
/* the first-entry greeting centers itself in the section card WITHOUT overflowing it —
   width comes from the card, never from the blank's own margins (x-scrollbar trap) */
#app .baby-page .notes-blank { width: auto; max-width: 100%; box-sizing: border-box; margin: 6px 0 2px; }
/* the page never scrolls sideways */
#app .baby-page { overflow-x: hidden; }
/* the shared .tab-layer rule says flex:1 1 0% — basis 0 collapses the layer in THIS flex
   scroller and its card PAINTS past it, over the page's own 84px bottom padding (which is
   the intended footer gap). Basis auto keeps content height as the floor while short tabs
   still stretch to fill the page. */
#app .baby-page > .tab-layer { flex: 1 0 auto; }

/* ---- Meilensteine (design/DESIGN.md Anhang "MEILENSTEINE") — the memory timeline. The pc-soft
   rail IS the connection: no hairlines between rows, the icon chip is the timeline node. */
#app .msTl { position: relative; padding-left: 2px; }
#app .msTl::before { content: ""; position: absolute; left: 18px; top: 14px; bottom: 14px; width: 2px; background: var(--pc-soft); border-radius: var(--r-pill); }
#app .msRow { display: flex; gap: 12px; padding: 13px 0; position: relative; cursor: pointer; align-items: flex-start; }
#app .msIc { width: 34px; height: 34px; border-radius: 50%; background: var(--pc-soft); color: var(--pc-ink); display: flex; align-items: center; justify-content: center; flex-shrink: 0; position: relative; z-index: 1; box-shadow: 0 0 0 3px var(--card); }
#app .msIc i { font-size: 16px; }
#app .msBody { flex: 1; min-width: 0; }
#app .msBody > b { font-size: 14px; font-weight: 600; display: block; letter-spacing: -0.01em; }
#app .msAge { font-size: var(--fs-ui); font-weight: 600; color: var(--pc-ink); margin-top: 2.5px; display: block; }
#app .msAge small { font-size: var(--fs-label); font-weight: 500; color: var(--ink3); margin-left: 7px; }
#app .msNote { font-size: var(--fs-sub); color: var(--ink2); margin-top: 3px; display: block; line-height: 1.5; }
/* media band: wrapping 2-col grid breaking out of the text column; odd counts promote the
   first tile to a full-width hero so no row is half-empty (album collage rule) */
#app .msShots { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 10px 0 2px -46px; position: relative; z-index: 1; }
#app .msShot { aspect-ratio: 3/2; border-radius: var(--r-ctl); border: 1px solid var(--line); background: linear-gradient(135deg, var(--pc-soft), var(--card2)); display: flex; align-items: center; justify-content: center; color: var(--pc-ink); overflow: hidden; }
#app .msShot:only-child, #app .msShot:first-child:nth-last-child(odd) { grid-column: 1/-1; aspect-ratio: 21/9; }
#app .msShot img { width: 100%; height: 100%; object-fit: cover; }
#app .msShot i { font-size: 20px; opacity: .75; }
/* sheet: collapsible suggestion grid (tile catalog) + full symbol palette — ink states only */
.msSugHead { display: flex; align-items: center; gap: 7px; width: 100%; background: none; border: 0; padding: 2px 2px 8px; cursor: pointer; text-align: left; font-family: inherit; }
.msSugHead span { font-size: var(--fs-cap); font-weight: 600; color: var(--ink2); text-transform: uppercase; letter-spacing: .06em; }
.msSugHead i { font-size: 12px; color: var(--ink3); transition: transform .18s; }
.msSugHead[aria-expanded="false"] i { transform: rotate(-90deg); }
.msGrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; max-height: 264px; overflow-y: auto; padding: 2px; margin-bottom: 10px; }
/* display:grid would beat the hidden attribute — collapsed must WIN (initial state!) */
.msGrid[hidden] { display: none; }
.msTile { border: 1px solid var(--line); background: var(--card2); border-radius: var(--r-ctl); padding: 11px 6px 9px; display: flex; flex-direction: column; align-items: center; gap: 5px; cursor: pointer; text-align: center; font-family: inherit; color: var(--ink); }
.msTile i { font-size: 17px; }
.msTile b { font-size: var(--fs-label); font-weight: 600; line-height: 1.25; }
.msTile small { font-size: 9px; font-weight: 500; color: var(--ink3); font-variant-numeric: tabular-nums; }
.msTile.on { border-color: var(--ink); background: var(--card); box-shadow: 0 0 0 1px var(--ink) inset; }
.msIcons { display: flex; flex-wrap: wrap; gap: 8px; padding: 2px; margin-bottom: 10px; }
.msSym { width: 36px; height: 36px; border-radius: 50%; border: 1px solid var(--line2); background: var(--card); color: var(--ink2); display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; }
.msSym i { font-size: 15px; }
.msSym.on { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.msFieldLabel { font-size: var(--fs-cap); font-weight: 600; color: var(--ink2); text-transform: uppercase; letter-spacing: .06em; margin: 2px 2px 7px; }
.msAgeLine { font-size: var(--fs-sub); color: var(--ink2); margin: -2px 2px 10px; }
.msMedia { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; margin: 2px 0 10px; border: 1.5px dashed var(--line2); border-radius: var(--r-ctl); background: transparent; color: var(--ink2); font-weight: 600; font-size: var(--fs-hint); font-family: inherit; padding: 12px; cursor: pointer; }
.msMediaList { display: flex; flex-wrap: wrap; gap: 6px; margin: -4px 0 10px; }

/* today-at-a-glance stat blocks — inside the status card, full width */
/* Flat stats bar — three columns, hairline dividers, no boxes; numbers in ink, never in a
   category colour. The low-nappy warning lives HERE (count in due-ink + a dot before the
   label), not as a red box and not as a flag: it must be said exactly once. */
#app .baby-stats {
    display: flex;
    align-self: stretch;
    margin-top: 4px;
    padding-top: 12px;
    border-top: 1px solid var(--line);
}

#app .baby-stat {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    align-items: center;
    text-align: center;
}
#app .baby-stat + .baby-stat { border-left: 1px solid var(--line); }
#app .baby-stat-val { font-size: 15px; font-weight: 600; color: var(--ink); letter-spacing: -0.01em; white-space: nowrap; font-variant-numeric: tabular-nums; }
#app .baby-stat-lbl { font-size: 10px; color: var(--ink2); white-space: nowrap; display: inline-flex; align-items: center; gap: 5px; }
#app .baby-stat-lbl i { font-size: 10px; color: var(--ink3); }
#app .baby-stat-sub { font-size: 9.5px; color: var(--ink3); white-space: nowrap; }
#app .baby-stat.warn .baby-stat-val { color: var(--due-ink); }
#app .baby-stat.warn .baby-stat-lbl::before {
    content: "";
    width: 5px; height: 5px; border-radius: 50%;
    background: var(--due); flex: none;
}

/* quick-add grid — fills the card's width (the status card is a flex-start column) */
#app .baby-actions { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; align-self: stretch; }
#app .baby-action {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    padding: 10px 2px;
    color: var(--ink);
    font-family: var(--font-family);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
#app .baby-action i { font-size: 17px; }
#app .baby-action span { font-size: 10px; font-weight: 600; text-align: center; line-height: 1.15; }
#app .baby-action:active { transform: scale(0.96); }
/* the leading quick action (Schlaf) is the filled hero */
#app .baby-action.hero { background: var(--ink); border-color: var(--ink); color: var(--bg); }

/* timeline + event rows — hairline rows with soft round type chips */
#app .baby-ev {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 9px 2px;
    border-bottom: 1px solid var(--line);
}
#app .baby-ev:last-child { border-bottom: 0; }
#app .baby-ev-icon {
    width: 30px;
    height: 30px;
    box-sizing: border-box;
    border-radius: 10px;
    flex: none;
    display: grid;
    place-items: center;
    background: var(--card2);
    border: 1px solid var(--line);
    color: var(--ink2);
    font-size: var(--fs-body);
}
/* the universal date+time column: date on top, time (or window unit) muted beneath */
#app .baby-ev-time {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
    font-size: var(--fs-sub);
    font-weight: 600;
    color: var(--ink2);
    font-variant-numeric: tabular-nums;
    min-width: 64px;
    flex: none;
}
#app .baby-ev-time2 { font-size: var(--fs-label); font-weight: 400; color: var(--ink3); }
#app .baby-ev-desc { flex: 1; min-width: 0; font-size: var(--fs-body); font-weight: 500; color: var(--ink); }
#app .baby-ev-del { color: var(--ink3); }
/* two-line row body (title + meta) — the shared anatomy for vaccine and med rows */
#app .baby-ev-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
#app .baby-ev-meta { font-size: var(--fs-cap); color: var(--ink2); }
#app .baby-ev-meta.notes-overdue { color: var(--due-ink); font-weight: 600; }
#app .baby-ev-meta.notes-duetoday { color: var(--ink); font-weight: 600; }
/* vaccine state — ink means done, red means overdue (color is meaning) */
#app .baby-vx-ic-done { color: var(--ink); }
#app .baby-vx-ic-overdue { color: var(--due-ink); }

/* manual vaccine sheet: per dose a Geimpft|Fällig date pair under one legend */
#app .baby-dose-pair { display: flex; gap: 8px; flex: 1; min-width: 0; }
#app .baby-dose-pair > input { flex: 1; min-width: 0; }
#app .baby-dose-legend { display: flex; gap: 8px; margin: 4px 0 0; }
#app .baby-dose-legend span {
    flex: 1;
    font-size: var(--fs-cap);
    font-weight: 600;
    color: var(--ink3);
}

/* quiet sub-heading inside a baby section (e.g. "Weitere Impfungen" under the plan) */
#app .baby-subhead {
    margin: 18px 2px 4px;
    font-size: var(--fs-cap);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink3);
}

/* grouped vaccines: name + given/of pill, state line, one bar per dose */
#app .baby-vax {
    padding: 12px 2px;
    border-bottom: 1px solid var(--line);
}
#app .baby-vax:last-child { border-bottom: 0; }
#app .baby-vax-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
#app .baby-vax-top b { font-size: var(--fs-body); font-weight: 500; }
#app .baby-vax-count {
    font-size: var(--fs-cap);
    font-weight: 600;
    color: var(--ink2);
    background: var(--card2);
    border: 1px solid var(--line);
    padding: 3px 8px;
    border-radius: var(--r-pill);
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}
/* fully-dosed reads as a solid ink pill — the same "done = ink" language the dose bars use */
#app .baby-vax-count.done {
    background: var(--ink);
    border-color: transparent;
    color: var(--bg);
}
#app .baby-vax-meta { font-size: var(--fs-sub); color: var(--ink2); margin-top: 3px; }
#app .baby-vax-meta.notes-overdue { color: var(--due-ink); font-weight: 600; }
#app .baby-vax-meta.notes-duetoday { color: var(--ink); font-weight: 600; }
#app .baby-vax-doses { display: flex; gap: 4px; margin-top: 8px; }
#app .baby-vax-dose {
    flex: 1;
    height: 4px;
    border-radius: var(--r-pill);
    background: var(--card2);
    border: 1px solid var(--line);
    box-sizing: border-box;
    position: relative;
}
/* the 4px bar is a tap target (opens that dose) — pad its hit area invisibly */
#app .baby-vax-dose::after {
    content: '';
    position: absolute;
    inset: -12px -2px;
}
#app .baby-vax-dose.done { background: var(--ink); border-color: transparent; }
#app .baby-vax-dose.due { background: var(--due); border-color: transparent; }

/* section heads — quiet uppercase labels between row groups */
#app .baby-rec-h {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 6px 0 2px;
    padding: 4px 2px;
    font-size: var(--fs-ui);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink2);
}
#app .baby-guide { display: flex; flex-direction: column; }
/* each tab's section sits in its own card (the prototype's Heute/Impfungen cards),
   led by its head band */
#app .baby-page .tab-layer > div {
    background: var(--card);
    border-radius: var(--r-card);
    padding: 2px 14px;
}
#app .baby-sec-head { padding: 9px 2px 2px; cursor: default; }
/* type tiles: soft color per event type; sleep wears the baby's color */
#app .baby-ev-icon.tile-sleep { background: var(--pc-soft, var(--card2)); color: var(--pc-ink, var(--ink2)); border-color: transparent; }
#app .baby-ev-icon.tile-feed { background: var(--ok-soft); color: var(--ok-ink); border-color: transparent; }
#app .baby-ev-icon.tile-diaper { background: var(--pend-soft); color: var(--pend-ink); border-color: transparent; }
#app .baby-ev-icon.tile-measure { background: var(--p1-soft); color: var(--p1-ink); border-color: transparent; }
#app .baby-empty, #app .baby-empty-line { color: var(--ink2); }
#app .baby-empty { display: flex; flex-direction: column; gap: 10px; padding: 24px 16px; align-items: flex-start; }
#app .baby-empty-line { font-size: var(--fs-body); padding: 14px 2px; }
#app .baby-empty-hint { font-size: var(--fs-hint); color: var(--ink3); }

/* person-bound records surfaced in the baby module (meds + notes) */
#app .baby-records { display: flex; flex-direction: column; gap: 5px; }
#app .baby-rec-manage { margin-left: auto; background: none; border: 0; color: var(--ink2); font-size: var(--fs-cap); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; text-transform: none; letter-spacing: 0; }
#app .baby-rec-row { font-size: var(--fs-body); color: var(--ink); padding: 3px 2px; }
#app .baby-rec-row.baby-editable { display: flex; align-items: center; gap: 8px; }
#app .baby-rec-text { flex: 1; min-width: 0; }

/* dashboard widget bits — the flag/stats block sits hairline-free under the head */
#app .baby-w-flag { border-top: 0; padding: 8px 13px 0; }
#app .baby-w-flag .txt { font-size: var(--fs-hint); }
#app .baby-w-counts { border-top: 0; padding: 6px 13px 10px; gap: 13px; flex-wrap: wrap; }
#app .baby-w-counts span { font-size: var(--fs-sub); color: var(--ink2); white-space: nowrap; }
#app .baby-w-counts b { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
#app .baby-w-counts b.due { color: var(--due-ink); }
/* the quick-action row at the card foot — sleep (hero) · meal · diaper, one tap each */
#app .baby-w-quick-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    align-self: stretch;
    margin: 8px 13px 13px;
    margin-top: auto;
}

/* ============================== entity manager + settings ============================== */

#app .ent-tabs { margin: 2px 0 10px; }
#app .ent-row {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 12px 2px;
    border-bottom: 1px solid var(--line);
}
#app .ent-row:last-of-type { border-bottom: none; }
#app .ent-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ent-name-ro { font-size: var(--fs-md); font-weight: 500; color: var(--ink); word-break: break-word; }
#app .ent-sub {
    font-size: var(--fs-sub);
    color: var(--ink2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding: 0 1px;
}
#app .ent-edit,
#app .ent-del { flex-shrink: 0; }
#app .ent-del { font-size: 17px; }
/* row lead — persons get the ringed avatar circle, other types their glyph tile */
#app .ent-lead { flex-shrink: 0; }
#app .ent-lead.av {
    width: 38px;
    height: 38px;
    box-sizing: border-box;
    border: 2px solid var(--pc, var(--line));
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font: 600 14px var(--font-family);
    background: var(--pc-soft, var(--card2));
    color: var(--pc-ink, var(--ink2));
    overflow: hidden;
}
#app .ent-lead.av img { width: 100%; height: 100%; object-fit: cover; }
#app .ent-lead.tile {
    width: 38px;
    height: 38px;
    border-radius: var(--r-ctl);
    background: var(--card2);
    color: var(--ink2);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
}

/* the expand-in-place attribute form under a row — grouped fields on an inset surface */
#app .ent-attrs {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px;
    margin: 2px 0 10px;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: 14px;
}
/* inputs inside the inset group sit on card white */
#app .ent-attrs input,
#app .ent-attrs select,
#app .ent-attrs textarea { background: var(--card); }
#app .ent-attrs .mg-select-btn { background: var(--card); }
#app .ent-attr-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
#app .ent-attr-row span {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink3);
}
#app .ent-attrs .action-btn { align-self: flex-end; }

/* settings: email verification state + partner invite link */
#app .settings-email { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
#app .settings-email-addr { font-size: var(--fs-body); overflow-wrap: anywhere; }
#app .settings-email-state { font-size: var(--fs-cap); font-weight: 600; color: var(--ink2); }
#app .settings-invite { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
#app .settings-invite-create { display: flex; gap: 8px; width: 100%; }
#app #settings-invite-email { flex: 1; min-width: 0; }
#app #settings-invite-result { display: flex; gap: 8px; width: 100%; }
#app #settings-invite-link { flex: 1; min-width: 0; font-size: var(--fs-ui); }
#app #settings-invite-msg { font-size: var(--fs-cap); color: var(--ink2); }

/* attachments inside the attribute form */
#app .ent-files { display: flex; flex-direction: column; gap: 6px; }
#app .ent-files-head {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink3);
}
#app .ent-files-head i { margin-right: 4px; }
#app .ent-file-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
#app .ent-file-name {
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    text-align: left;
    font-family: var(--font-family);
    color: var(--ink);
    font-size: var(--fs-body);
    text-decoration: underline;
    text-underline-offset: 3px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1;
}
#app .ent-file-size { font-size: var(--fs-sub); color: var(--ink3); white-space: nowrap; }
#app .ent-file-del { font-size: 15px; }
#app .ent-file-menu { font-size: 15px; }
#app .ent-file-ren { font-size: var(--fs-ui); }
#app .ent-file-rename { flex: 1; min-width: 0; font-size: inherit; }
#app .ent-files .ent-file-add { align-self: flex-start; }
/* upload + pick-existing share one row (wraps on narrow sheets) */
#app .ent-file-btns { display: flex; gap: 8px; flex-wrap: wrap; align-self: flex-start; }
#app .ent-files-status { font-size: var(--fs-cap); color: var(--ink2); min-height: 0; }

/* ---- pick-existing sheet (pickExistingFiles): thumbnail grid, select mode ---- */
.fp-search { width: 100%; }
.fp-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 10px; max-height: 46vh; overflow-y: auto; }
@media (max-width: 420px) { .fp-grid { grid-template-columns: repeat(2, 1fr); } }
.fp-tile { position: relative; display: flex; flex-direction: column; padding: 0; border: 2px solid var(--line); border-radius: var(--r-ctl); overflow: hidden; background: var(--card2); cursor: pointer; text-align: left; }
.fp-tile.sel { border-color: var(--ink); }
.fp-tile.fp-here { opacity: 0.55; cursor: default; }
.fp-thumb { position: relative; aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center; font-size: 24px; color: var(--ink3); }
.fp-thumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.fp-badge { position: absolute; top: 6px; right: 6px; width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: var(--fs-cap); background: var(--card); color: var(--ink3); border: 1px solid var(--line); }
.fp-tile.sel .fp-badge { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.fp-tile.fp-here .fp-badge { width: auto; border-radius: 6px; padding: 1px 6px; }
.fp-heretag { font-size: 9px; font-weight: 700; white-space: nowrap; }
.fp-meta { padding: 5px 7px; font-size: var(--fs-cap); border-top: 1px solid var(--line); background: var(--card); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fp-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; }
.fp-count { font-size: var(--fs-sub); color: var(--ink2); }
.fp-note { font-size: var(--fs-cap); color: var(--ink3); margin: 8px 0 0; }
/* attachment category headings + the per-file category picker (compact select) */
.ent-file-cat {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink3);
    margin: 8px 2px 2px;
}
.ent-file-catsel { flex: none; max-width: 130px; }
.ent-file-catsel .mg-select-btn { padding: 4px 8px; font-size: var(--fs-cap); border-radius: var(--r-pill); }

/* related-entity / linked-note chips (the entity "hub") — link badges */
#app .ent-links { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
#app .ent-link-chip {
    display: inline-flex;
    align-items: center;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: 6px;
    font-size: var(--fs-label);
    font-weight: 600;
    color: var(--ink2);
    white-space: nowrap;
    flex-shrink: 0;
}
#app .ent-link-go {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: transparent;
    border: 0;
    color: inherit;
    cursor: pointer;
    font: inherit;
    padding: 3px 2px 3px 8px;
    white-space: nowrap;
}
#app .ent-link-x {
    display: inline-flex;
    align-items: center;
    background: transparent;
    border: 0;
    cursor: pointer;
    color: var(--ink3);
    padding: 3px 7px 3px 3px;
    font-size: var(--fs-ui);
}
#app .ent-link-x:hover, #app .ent-link-x:active { color: var(--due-ink); }

/* person-bound records (notes + medications) in the entity editor */
#app .ent-records { display: flex; flex-direction: column; gap: 6px; }
#app .ent-rec-list { display: flex; flex-direction: column; gap: 4px; }
#app .ent-rec-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
#app .ent-rec-txt { flex: 1; min-width: 0; font-size: var(--fs-body); color: var(--ink); overflow-wrap: anywhere; }
#app .ent-rec-off .ent-rec-txt { color: var(--ink3); text-decoration: line-through; }
/* the med active-checkbox must NOT ride the generic full-width popup input rule */
#app .ent-rec-active { flex: none; }
/* med row: bold name+dose with the schedule line under it, tap to edit */
#app .ent-med-txt {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
    background: none;
    border: 0;
    padding: 0;
    text-align: left;
    cursor: pointer;
    color: inherit;
    font: inherit;
}
#app .ent-med-txt b { font-size: var(--fs-body); font-weight: 600; }
#app .ent-med-sub { font-size: var(--fs-sub); color: var(--ink2); }
#app .ent-rec-off .ent-med-txt { color: var(--ink3); }
#app .ent-rec-off .ent-med-txt b { text-decoration: line-through; }
/* intake builder: one row per intake — slot/time picker · clock · per-intake dose · × */
#app .ent-med-intakes { display: flex; flex-direction: column; gap: 6px; flex: 1; min-width: 0; }
#app .ent-med-intake { display: flex; gap: 6px; align-items: center; min-width: 0; }
#app .ent-med-intake .mg-select { flex: 1.3; min-width: 0; }
#app .ent-med-intake .ent-med-time,
#app .ent-med-intake .ent-med-idose { flex: 1; min-width: 0; }
#app .ent-med-addintake { align-self: flex-start; }
#app .ent-rec-del { font-size: 14px; }
#app .ent-rec-add { display: flex; gap: 6px; }
#app .ent-rec-add input { flex: 1; min-width: 0; }
#app .ent-rec-edit { background: none; border: 0; padding: 0; text-align: left; cursor: pointer; text-decoration: underline; text-underline-offset: 3px; color: inherit; font: inherit; }
#app .ent-medform {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px;
    margin: 4px 0;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: 10px;
}
#app .ent-medform input { background: var(--card); }
#app .ent-medform-actions { display: flex; gap: 8px; justify-content: flex-end; }

/* the "add entity" row: type + name + button on one line */
#app .ent-add {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 10px;
    padding-top: 12px;
    border-top: 1px solid var(--line);
}
#app .popup-body .ent-add input { flex: 1; width: auto; min-width: 0; }
#app .ent-add .action-btn { flex-shrink: 0; }
#app .ent-empty {
    color: var(--ink3);
    font-size: var(--fs-hint);
    padding: 12px 0;
    text-align: center;
}
/* contract tab: the monthly-total line above the rows */
#app .ent-sum {
    color: var(--ink2);
    font-size: var(--fs-hint);
    padding: 4px 0 8px;
    border-bottom: 1px solid var(--line);
    margin-bottom: 6px;
}

/* unified Settings sheet — You | Group */
#app .settings-panel { display: flex; flex-direction: column; }
#app .settings-panel[hidden] { display: none; } /* beat display:flex so the inactive tab hides */
#app .settings-avatar { display: flex; align-items: center; gap: 12px; }
#app .settings-avatar-preview {
    width: 52px;
    height: 52px;
    flex: none;
    box-sizing: border-box;
    border-radius: 50%;
    overflow: hidden;
    background: var(--card2);
    border: 1px solid var(--line);
    display: grid;
    place-items: center;
    font-size: 24px;
    color: var(--ink3);
}
#app .settings-avatar-preview img { width: 100%; height: 100%; object-fit: cover; }
/* Avatar actions: three UNEQUAL things, so they no longer shout in three identical ink pills.
   The two ways to GET a picture share one line (upload = ink, choose = ghost); removing it is
   a destructive afterthought and drops beneath them in the red text voice. */
#app .settings-avatar-actions { display: flex; flex-wrap: wrap; gap: 6px; flex: 1; min-width: 0; }
#app .settings-avatar-actions .action-btn { flex: 1; min-width: 0; margin: 0; }
#app .settings-avatar-actions .delete-btn { flex-basis: 100%; text-align: left; padding-left: 0; }
#app .settings-lang { display: flex; gap: 6px; }
#app .settings-lang .lang-btn {
    background: var(--card);
    border: 1px solid var(--line2);
    border-radius: var(--r-pill);
    padding: 8px 16px;
    font-size: var(--fs-ui);
    font-weight: 600;
    cursor: pointer;
    color: var(--ink2);
    font-family: var(--font-family);
    transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}
#app .settings-lang .lang-btn.active { background: var(--ink); color: var(--bg); border-color: var(--ink); }

/* the "Personen & Dinge" row-link (prototype pdLink): quiet card row with a chevron */
#app .pd-link {
    display: flex;
    align-items: center;
    gap: 11px;
    width: 100%;
    box-sizing: border-box;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    padding: 12px 13px;
    font-family: var(--font-family);
    font-size: var(--fs-body);
    font-weight: 600;
    color: var(--ink);
    cursor: pointer;
    text-align: left;
    -webkit-tap-highlight-color: transparent;
}
#app .pd-link i:first-child { color: var(--ink2); font-size: 16px; }
#app .pd-link .chev { margin-left: auto; color: var(--ink3); font-size: 12px; }

/* weather places (Settings → Group): followed-location chips + geocoding search */
#app .settings-weather { display: flex; flex-direction: column; gap: 8px; }
#app #weather-current { display: flex; flex-wrap: wrap; gap: 5px; }
#app .weather-none { font-size: var(--fs-hint); color: var(--ink3); }
#app .weather-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: 3px 4px 3px 8px;
    font-size: var(--fs-label);
    font-weight: 600;
    color: var(--ink2);
    white-space: nowrap;
    flex-shrink: 0;
}
#app .weather-chip-x {
    border: 0;
    background: transparent;
    color: var(--ink3);
    cursor: pointer;
    font-size: var(--fs-ui);
    line-height: 1;
    padding: 0 4px;
    -webkit-tap-highlight-color: transparent;
}
#app .weather-chip-x:hover { color: var(--due-ink); }
#app .weather-search-row { display: flex; gap: 8px; }
#app .popup-body .weather-search-row input { flex: 1; width: auto; min-width: 0; }
#app .weather-search-row .action-btn { flex: none; }
#app #weather-results { display: flex; flex-direction: column; gap: 2px; font-size: var(--fs-ui); color: var(--ink3); }
#app .weather-result {
    text-align: left;
    border: 0;
    background: transparent;
    cursor: pointer;
    padding: 9px 10px;
    border-radius: 8px;
    font-family: var(--font-family);
    font-size: var(--fs-body);
    color: var(--ink);
    transition: background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
#app .weather-result:hover { background: var(--card2); }

/* tier usage ("82 / 100") — label + count, a thin bar below; over the limit = red */
#app .settings-usage { display: flex; flex-direction: column; gap: 12px; }
#app .usage-row { display: grid; grid-template-columns: 1fr auto; row-gap: 5px; align-items: baseline; }
#app .usage-label { font-size: var(--fs-hint); color: var(--ink); }
#app .usage-count { font-size: var(--fs-hint); color: var(--ink2); font-variant-numeric: tabular-nums; }
#app .usage-track {
    grid-column: 1 / -1;
    height: 4px;
    border-radius: var(--r-pill);
    background: var(--card2);
    border: 1px solid var(--line);
    overflow: hidden;
}
#app .usage-fill { display: block; height: 100%; border-radius: var(--r-pill); background: var(--ink); transition: width var(--transition-base); }
#app .usage-fill.over { background: var(--due); }

/* upload-in-flight bar (reuses .usage-track/.usage-fill) + its cancel button, laid out in one
   status line; shared by every upload surface */
#app .up-progress-wrap { display: flex; align-items: center; gap: 8px; margin: 6px 0; }
#app .up-progress { display: block; flex: 1; }
#app .up-cancel { flex: none; font-size: var(--fs-cap); color: var(--ink2); background: none; border: none; padding: 2px 4px; cursor: pointer; text-decoration: underline; }
#app .up-status { font-size: var(--fs-cap); color: var(--ink2); }

/* household member list (Render.openUsers) */
#app .user-row { display: flex; align-items: center; gap: 10px; padding: 12px 2px; border-bottom: 1px solid var(--line); }
#app .user-row:last-child { border-bottom: 0; }
/* the member's avatar disc — image when set, else the initial in the person color */
#app .user-row-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-cap);
    font-weight: 700;
    background: var(--pc-soft, var(--card2));
    color: var(--pc-ink, var(--ink2));
    overflow: hidden;
}
#app .user-row-avatar img { width: 100%; height: 100%; object-fit: cover; }
#app .user-row-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-md); font-weight: 500; }
#app .user-row-role {
    font-size: 10px;
    font-weight: 600;
    padding: 2.5px 8px;
    border-radius: var(--r-pill);
    background: var(--card2);
    border: 1px solid var(--line);
    color: var(--ink2);
}
#app .user-row-role.is-admin { background: var(--ink); border-color: transparent; color: var(--bg); }
#app .user-role-btn { flex-shrink: 0; }
#app .user-role-btn:disabled { opacity: 0.45; cursor: not-allowed; }
#app .confirm-sheet .confirm-message { margin: 0; padding: 6px 0 10px; font-size: var(--fs-md); line-height: 1.45; color: var(--ink); }
/* Optional toggle inside a confirm sheet (e.g. "delete the N entries too"). The label and the
   checkbox both have to shed the .popup-body form-field styling (uppercase label, width:100% input)
   so the text reads as a sentence and wraps inside the box instead of being pushed off the edge. */
#app .confirm-sheet .confirm-extra { display: flex; align-items: flex-start; gap: 10px; margin: 2px 0 8px; padding: 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--card2); cursor: pointer; text-align: left; font-size: var(--fs-md); font-weight: 400; letter-spacing: normal; text-transform: none; line-height: 1.4; color: var(--ink); }
#app .confirm-sheet .confirm-extra input { flex: none; margin: 1px 0 0; padding: 0; }
#app .confirm-sheet .confirm-extra span { flex: 1; min-width: 0; }
/* member area (design/prototype.html "Benutzer"): rows with a ⋮ kebab menu + an invite button */
#app .uList { display: flex; flex-direction: column; }
#app .uMem { display: flex; align-items: center; gap: 12px; padding: 14px 2px; border-top: 1px solid var(--line); }
#app .uMem:first-child { border-top: 0; }
#app .uMem .av { width: 40px; height: 40px; box-sizing: border-box; border: 2px solid var(--pc, var(--line)); border-radius: 50%; display: flex; align-items: center; justify-content: center; font: 600 15px var(--font-family); flex-shrink: 0; background: var(--pc-soft, var(--card2)); color: var(--pc-ink, var(--ink2)); overflow: hidden; }
#app .uMem .av img { width: 100%; height: 100%; object-fit: cover; }
#app .uMem .info { flex: 1; min-width: 0; }
#app .uMem .nm { font-size: 14px; font-weight: 600; display: flex; align-items: center; gap: 7px; }
#app .uMem .nm .you { font-size: var(--fs-label); font-weight: 600; color: var(--ink3); }
#app .uMem .rl { font-size: var(--fs-ui); color: var(--ink2); margin-top: 2px; display: flex; align-items: center; gap: 6px; }
#app .uMem .rl .rdot { width: 5px; height: 5px; border-radius: 50%; background: var(--ink3); flex-shrink: 0; }
#app .uMem .uLastActive { font-size: var(--fs-cap); color: var(--ink3); margin-top: 1px; }

/* support-access consent (Settings → Du) + the operator's read-only view banner */
#app .settings-support { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: var(--fs-body); }
#app .settings-support + .settings-support { margin-top: 6px; }
#app .settings-support[hidden] { display: none; } /* beat display:flex — the device rows hide where push cannot work */
#app .settings-support input { flex: none; }
#app .settings-support-info { font-size: var(--fs-sub); color: var(--ink3); line-height: 1.5; margin-top: 6px; }
/* lives on <body>, above everything — never scoped under #app. Fixed HEIGHT so the app
   can make exact room below it (body.support-view shifts #app down instead of being
   covered). */
body.support-view { --support-banner-h: 28px; }
.support-banner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 9999;
    height: var(--support-banner-h, 28px);
    box-sizing: border-box;
    background: var(--pend-soft);
    color: var(--pend-ink);
    border-bottom: 1px solid color-mix(in srgb, var(--pend) 30%, transparent);
    font-size: var(--fs-ui);
    font-weight: 600;
    line-height: 16px;
    text-align: center;
    padding: 6px 10px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
body.support-view #app {
    top: var(--support-banner-h);
    height: calc(100% - var(--support-banner-h));
}
#app .uMem .rl.admin .rdot { background: var(--ink); }
#app .uMem .rl.blocked { color: var(--due-ink); }
#app .uMem .rl.blocked .rdot { background: var(--due); }
#app .menuWrap { position: relative; flex-shrink: 0; }
#app .uKebab { width: 34px; height: 34px; border-radius: 10px; border: 1px solid var(--line2); background: var(--card2); color: var(--ink2); display: flex; align-items: center; justify-content: center; cursor: pointer; }
#app .uKebab svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
#app .uMenu { position: absolute; top: 40px; right: 0; background: var(--card); border: 1px solid var(--line); border-radius: var(--r-ctl); box-shadow: var(--shadow); padding: 5px; min-width: 210px; z-index: 60; display: none; }
#app .uMenu.on { display: block; }
#app .uMenu.up { top: auto; bottom: 40px; }
#app .uMenu button { display: flex; align-items: center; gap: 9px; width: 100%; border: 0; background: transparent; color: var(--ink); font: 500 13px var(--font-family); text-align: left; padding: 9px 10px; border-radius: 8px; cursor: pointer; }
#app .uMenu button:hover { background: var(--card2); }
#app .uMenu button:disabled { opacity: 0.4; cursor: not-allowed; }
#app .uMenu button svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; color: var(--ink2); }
#app .uMenu button.danger { color: var(--due-ink); }
#app .uMenu button.danger svg { color: var(--due); }
#app .uMenu .mDiv { height: 1px; background: var(--line); margin: 4px 6px; }
#app .uInvite { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; margin-top: 14px; border: 1.5px dashed var(--line2); border-radius: var(--r-ctl); background: transparent; color: var(--ink2); font: 600 13px var(--font-family); padding: 13px; cursor: pointer; }
#app .uInvite svg { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* the changelog sheet (drawer → Changelog): the newest release as a prominent card ("Neu"),
   older ones collapsed behind their date. Item dots carry the kind: feat = ink, fix = ok. */
#app .clLatest { background: var(--card2); border: 1px solid var(--line); border-radius: 14px; padding: 15px 16px; margin-top: 2px; }
#app .clEmpty { font-size: var(--fs-body); line-height: 1.5; color: var(--ink3); margin: 2px 0 0; }
#app .clLatestTop { display: flex; align-items: center; gap: 8px; margin-bottom: 11px; }
#app .clNew { font: 700 9.5px var(--font-family); letter-spacing: .05em; text-transform: uppercase; background: var(--ink); color: var(--bg); border-radius: var(--r-pill); padding: 2px 8px; }
#app .clDate { font-size: var(--fs-sub); color: var(--ink3); margin-left: auto; font-variant-numeric: tabular-nums; }
#app .clItems { list-style: none; display: flex; flex-direction: column; gap: 8px; padding-left: 2px; margin: 0; }
#app .clItems li { display: flex; gap: 9px; font-size: var(--fs-body); color: var(--ink); line-height: 1.45; }
#app .clItems li::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--line2); margin-top: 6px; flex-shrink: 0; }
#app .clItems li.feat::before { background: var(--ink); }
#app .clItems li.fix::before { background: var(--ink3); }
#app .clRow { border-top: 1px solid var(--line); }
#app .clLatest + .clRow { border-top: 0; margin-top: 14px; }
#app .clRowHd { display: flex; align-items: center; gap: 9px; width: 100%; padding: 13px 2px; border: 0; background: transparent; color: var(--ink); font: 600 13.5px var(--font-family); cursor: pointer; text-align: left; }
#app .clRowDate { font-variant-numeric: tabular-nums; }
#app .clRowChev { margin-left: auto; color: var(--ink3); transition: transform .18s; }
#app .clRow.open .clRowChev { transform: rotate(90deg); }
#app .clRowBody { display: none; padding: 0 2px 13px; }
#app .clRow.open .clRowBody { display: block; }

/* the tariff sheet (drawer → Tarif): active plan + usage, beta note, cycle toggle,
   plan cards with Vormerken, add-ons (design: sh-tarif in design/prototype.html) */
#app .plan-now { background: var(--card2); border: 1px solid var(--line); border-radius: 14px; padding: 15px 16px; }
#app .plan-now-top { display: flex; align-items: center; gap: 9px; margin-bottom: 4px; }
#app .plan-now-top b { font-size: 19px; font-weight: 600; }
#app .plan-now > p { font-size: var(--fs-ui); color: var(--ink2); line-height: 1.5; }
#app .plan-now .form-row { margin-top: 10px; }
#app .plan-chip {
    font-size: 9.5px;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    background: var(--ink);
    color: var(--bg);
    border-radius: var(--r-pill);
    padding: 2px 8px;
}
#app .plan-beta {
    display: flex;
    gap: 10px;
    background: var(--pend-soft);
    border: 1px solid color-mix(in srgb, var(--pend) 28%, transparent);
    border-radius: 14px;
    padding: 12px 13px;
    margin-top: 14px;
}
#app .plan-beta i { color: var(--pend-ink); font-size: 14px; margin-top: 2px; flex-shrink: 0; }
#app .plan-beta p { font-size: var(--fs-ui); color: var(--pend-ink); line-height: 1.5; }
#app .plan-cycle { display: flex; background: var(--card2); border: 1px solid var(--line); border-radius: var(--r-ctl); padding: 3px; margin: 16px 0 4px; }
#app .plan-cycle button {
    flex: 1;
    border: 0;
    background: transparent;
    color: var(--ink2);
    font-family: inherit;
    font-size: var(--fs-ui);
    font-weight: 600;
    padding: 8px;
    border-radius: 9px;
    cursor: pointer;
}
#app .plan-cycle button.on { background: var(--ink); color: var(--bg); }
#app .plan-cycle-save { font-size: 10px; opacity: 0.7; margin-left: 4px; }
#app .plan-card { border: 1px solid var(--line); border-radius: 14px; padding: 15px 16px; margin-top: 10px; background: var(--card2); }
#app .plan-card.cur { border-color: color-mix(in srgb, var(--ink) 40%, transparent); background: var(--card); }
#app .plan-top { display: flex; align-items: baseline; gap: 8px; }
#app .plan-top b { font-size: 16px; font-weight: 600; }
#app .plan-price { margin-left: auto; font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; }
#app .plan-price small { font-size: var(--fs-cap); font-weight: 500; color: var(--ink3); }
#app .plan-meta { font-size: var(--fs-sub); color: var(--ink2); margin-top: 5px; line-height: 1.5; }
#app .plan-feat { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
#app .plan-feat li { display: flex; gap: 8px; font-size: var(--fs-hint); color: var(--ink); line-height: 1.4; }
#app .plan-feat li::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--line2); margin-top: 6px; flex-shrink: 0; }
#app .plan-btn {
    width: 100%;
    margin-top: 13px;
    border-radius: var(--r-ctl);
    padding: 11px;
    font-family: inherit;
    font-size: var(--fs-hint);
    font-weight: 600;
    cursor: pointer;
    border: 1px solid var(--line2);
    background: var(--card);
    color: var(--ink);
}
#app .plan-btn.done { background: transparent; border-style: dashed; color: var(--ink3); cursor: default; }
#app .plan-btn.marked { border-color: color-mix(in srgb, var(--ink) 45%, transparent); color: var(--ink); background: var(--card2); }
#app .plan-btn:disabled:not(.done) { opacity: 0.55; cursor: default; }
#app .plan-sec-lbl {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink3);
    margin: 20px 2px 6px;
}
#app .addon-row { display: flex; align-items: center; gap: 10px; padding: 11px 2px; border-top: 1px solid var(--line); font-size: var(--fs-hint); }
#app .plan-sec-lbl + .addon-row { border-top: 0; }
#app .addon-sub { color: var(--ink3); font-size: var(--fs-cap); }
#app .addon-price { margin-left: auto; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
#app .plan-foot { font-size: var(--fs-cap); color: var(--ink3); line-height: 1.5; margin-top: 14px; }

/* calendar import (⋮ → Kalender importieren): provider pick → file → checkbox preview */
#app .cal-imp-intro { font-size: var(--fs-hint); color: var(--ink2); line-height: 1.5; margin-bottom: 10px; }
#app .cal-imp-provider {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    text-align: left;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    padding: 13px 14px;
    margin-top: 8px;
    font-family: inherit;
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--ink);
    cursor: pointer;
}
#app .cal-imp-provider span { flex: 1; min-width: 0; }
#app .cal-imp-provider i { color: var(--ink3); font-size: 11px; }
#app .cal-imp-source { font-size: 15px; font-weight: 600; margin-bottom: 6px; }
#app .cal-imp-how { font-size: var(--fs-hint); color: var(--ink2); line-height: 1.55; }
#app .cal-imp-err { font-size: var(--fs-hint); color: var(--due-ink); margin-top: 10px; }
#app .cal-imp-file { display: none; }
#app .cal-imp-head { font-size: var(--fs-ui); color: var(--ink2); line-height: 1.5; }
#app .cal-imp-cap { font-size: var(--fs-sub); color: var(--ink3); margin-top: 4px; }
#app .cal-imp-cap.over { color: var(--due-ink); font-weight: 600; }
#app .cal-imp-all {
    background: none;
    border: 0;
    padding: 8px 0 4px;
    font-family: inherit;
    font-size: var(--fs-ui);
    font-weight: 600;
    color: var(--ink2);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
}
#app .cal-imp-all:disabled { opacity: 0.5; cursor: default; }
#app .cal-imp-list { display: flex; flex-direction: column; }
#app .cal-imp-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 2px;
    border-top: 1px solid var(--line);
    cursor: pointer;
    min-width: 0;
}
#app .cal-imp-row:first-child { border-top: 0; }
#app .cal-imp-row input[type="checkbox"] { flex: none; }
#app .cal-imp-same { opacity: 0.55; }
#app .cal-imp-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
#app .cal-imp-txt b { font-size: var(--fs-body); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#app .cal-imp-sub { font-size: var(--fs-sub); color: var(--ink2); }
#app .cal-imp-chips { display: flex; flex-direction: column; gap: 3px; align-items: flex-end; flex: none; }
#app .cal-imp-chip {
    font-size: 9.5px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-radius: var(--r-pill);
    padding: 2px 7px;
    background: var(--card2);
    border: 1px solid var(--line);
    color: var(--ink2);
    white-space: nowrap;
}
#app .cal-imp-chip.st-new { background: var(--ink); border-color: transparent; color: var(--bg); }
#app .cal-imp-chip.st-update { background: var(--pend-soft); border-color: transparent; color: var(--pend-ink); }
/* baby export selection sheet: one checkbox row per section / document */
#app .exp-row { display: flex; align-items: center; gap: 10px; padding: 9px 2px; cursor: pointer; font-size: var(--fs-body); }
#app .exp-row input[type="checkbox"] { flex: none; }
#app .exp-hint { font-size: var(--fs-sub); color: var(--ink3); margin: 4px 0 0; line-height: 1.5; }

#app .cal-imp-done { font-size: 14px; font-weight: 600; }
#app .cal-imp-hint { font-size: var(--fs-ui); color: var(--ink2); margin-top: 6px; line-height: 1.5; }

/* the in-app manual (drawer → Handbuch): collapsible handbook sections, FAQ-style */
#app .manual-sec { border-bottom: 1px solid var(--line); }
#app .manual-sec:last-child { border-bottom: 0; }
#app .manual-head {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 8px;
    background: transparent;
    border: 0;
    padding: 13px 2px;
    cursor: pointer;
    font: inherit;
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--ink);
    text-align: left;
    -webkit-tap-highlight-color: transparent;
}
#app .manual-head i:last-child { margin-left: auto; font-size: 12px; color: var(--ink3); transition: transform 250ms ease; flex-shrink: 0; }
#app .manual-sec.open .manual-head i:last-child { transform: rotate(180deg); }
/* leading section icon — the collapsed list doubles as a table of contents */
#app .manual-head .manual-ico { margin-right: 10px; font-size: 15px; color: var(--ink2); flex-shrink: 0; }

/* the birthday bridge under the event title: a quiet offer, never a block */
.cal-bday-hint {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    margin: 2px 0 10px;
    padding: 10px 12px;
    background: var(--card2);
    border: 1px solid var(--line2);
    border-radius: var(--r-ctl);
    font-size: var(--fs-ui);
    color: var(--ink2);
    line-height: 1.45;
}
.cal-bday-go:active { transform: scale(var(--button-click-scale)); }
#app .manual-body { display: none; padding: 0 2px 13px; }
#app .manual-sec.open .manual-body { display: block; }
#app .manual-body p { margin: 0 0 9px; font-size: var(--fs-ui); line-height: 1.55; color: var(--ink2); }
#app .manual-body p:last-child { margin-bottom: 0; }

/* ============================== system indicators ============================== */


/* the failure toasts: a centred column above the footer, oldest at the top. Several failures
   can be on screen at once — a dead-lettered write must not be swallowed by a failed export a
   second later. Each pill leaves on its own deadline; the empty stack is removed with the last.
   The 20px here is the LOGIN screen's floor (no tab bar yet); once the bar exists, render/kit.js
   toast() measures it and lifts the column clear — one source for the bar's height, not two. */
.write-error-stack {
    position: fixed;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    max-width: calc(100% - 32px);
    z-index: 1000;
    /* Nothing here is tappable, and on the login screen the column still sits low. One pill
       already swallowed taps there; a stack of them would swallow a lot more. */
    pointer-events: none;
}

/* one message: a write that exhausted its retries, a failed export, an ended session */
.write-error-toast {
    font-size: var(--fs-ui);
    font-weight: 600;
    color: var(--badge-fg);
    background: var(--due);
    padding: 8px 15px;
    border-radius: var(--r-pill);
    box-shadow: var(--shadow);
    text-align: center;
}

/* ============================== files manager (drawer → Dateien) ============================== */

/* the manager keeps room for the filter popover even when few files exist */
#files-popup-overlay .popup-body { min-height: 420px; }

/* search row: live-filter input + the square filter/pencil buttons */
.fm-row { display: flex; gap: 8px; align-items: center; margin-top: 10px; }
.fm-row .fm-search {
    flex: 1;
    min-width: 0;
    border: 1px solid var(--line);
    background: var(--card2);
    border-radius: var(--r-ctl);
    padding: 11px 13px;
    font-family: var(--font-family);
    font-size: var(--fs-md);
    color: var(--ink);
    outline: none;
}
.fm-row .fm-search::placeholder { color: var(--ink3); }
.fm-flt {
    width: 42px;
    height: 42px;
    border-radius: var(--r-ctl);
    border: 1px solid var(--line);
    background: var(--card2);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ink2);
    cursor: pointer;
    flex: none;
    font-size: 15px;
    -webkit-tap-highlight-color: transparent;
}
.fm-flt-wrap { position: relative; flex: none; }

/* the filter popover reuses the header-menu anatomy, anchored to the funnel button */
.fm-pop {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 950;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-ctl);
    box-shadow: var(--shadow);
    padding: 5px;
    display: flex;
    flex-direction: column;
    min-width: 220px;
    max-height: 300px;
    overflow-y: auto;
    scrollbar-width: thin;
}

/* category pills ride the shared pill row inside the sheet (no screen-edge margin) */
.fm-cats { flex: 1; min-width: 0; margin: 0; padding: 0; }

/* active subject-filter chips (label ×) */
.fm-chips { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }
.fm-chips:empty { display: none; }
.fm-selchip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: var(--ink);
    color: var(--bg);
    border: 0;
    border-radius: var(--r-pill);
    padding: 6px 11px;
    font: 600 11.5px var(--font-family);
    cursor: pointer;
}
.fm-selchip i { font-size: 11px; opacity: 0.65; }

/* one file per row: mime tile, name + meta + carrier chips, actions */
/* ---- files: the three derived views (gallery / docs / all) ---- */
.fm-views { margin-bottom: 2px; }
/* Group headings speak ONE voice app-wide — the Notes feed's (fs-ui/700/ink, no tracking, no
   shouting). Only the TYPE is shared; each keeps the layout its own row needs (here: the count
   pushed to the right edge). */
.fg-month { display: flex; justify-content: space-between; align-items: baseline; margin: 16px 2px 8px; font-size: var(--fs-ui); font-weight: 700; color: var(--ink); }
.fg-month:first-child { margin-top: 2px; }
.fg-month small { font-size: var(--fs-cap); font-weight: 600; color: var(--ink3); }
.fg-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.fg-tile { display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: 9px; overflow: hidden; background: var(--card2); padding: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; font-family: inherit; }
.fg-thumb { position: relative; aspect-ratio: 1 / 1; display: block; }
.fg-thumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.fg-thumb.fg-vid { display: flex; align-items: center; justify-content: center; color: var(--ink3); font-size: 20px; }
.fg-badges { position: absolute; bottom: 5px; left: 6px; display: flex; gap: 3px; }
.fg-dot { width: 17px; height: 17px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 700; background: var(--card); color: var(--ink2); border: 1px solid var(--line); }
.fg-glyph i { font-size: 8px; }
.fg-name { padding: 3px 6px; font-size: var(--fs-cap); color: var(--ink2); background: var(--card); border-top: 1px solid var(--line); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; }
/* Same voice for the documents cabinet's category heads — they are the sibling of the gallery's
   month heads in the same drawer, and the household's OWN category names stop being shouted. */
.fd-head { display: flex; align-items: center; gap: 7px; margin: 16px 2px 8px; font-size: var(--fs-ui); font-weight: 700; color: var(--ink); }
.fd-head:first-child { margin-top: 2px; }
.fd-head small { font-size: var(--fs-cap); font-weight: 600; color: var(--ink3); }
/* pdf.js fallback viewer (browsers without a built-in one): stacked page canvases, capped to
   the body height so a long document scrolls inside the sheet */
.fv-pdf { display: flex; flex-direction: column; gap: 8px; align-items: center; width: 100%; max-height: 100%; overflow-y: auto; }
.fv-page { max-width: 100%; height: auto; background: var(--pdf-paper); border-radius: 4px; box-shadow: var(--page-shadow); }
.fm-list { margin-top: 4px; }
.fm-file { display: flex; align-items: center; gap: 9px; padding: 12px 2px; border-bottom: 1px solid var(--line); cursor: pointer; }
.fm-file:last-child { border-bottom: 0; }

/* file viewer — full-screen lightbox above popups; media centers on a strong scrim */
#file-viewer-overlay {
    position: fixed;
    inset: 0;
    z-index: 1100;
    background: var(--scrim-strong);
    display: flex;
    flex-direction: column;
}
#file-viewer-overlay .fv-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: calc(var(--safe-top, 0px) + 10px) 14px 10px;
    background: var(--card);
    border-bottom: 1px solid var(--line);
}
#file-viewer-overlay .fv-name {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
#file-viewer-overlay .fv-btn { color: var(--ink); font-size: 17px; }
#file-viewer-overlay .fv-body {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 14px;
    overflow: hidden; /* tall content never paints over the head */
}
#file-viewer-overlay .fv-media { max-width: 100%; max-height: 100%; border-radius: var(--r-ctl); }
#file-viewer-overlay .fv-audio { width: min(100%, 420px); }
#file-viewer-overlay .fv-text {
    width: 100%;
    height: 100%;
    overflow: auto;
    background: var(--card);
    color: var(--ink);
    border-radius: var(--r-ctl);
    padding: 14px;
    font-size: var(--fs-body);
    white-space: pre-wrap;
    word-break: break-word;
}
#file-viewer-overlay .fv-none {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    background: var(--card);
    color: var(--ink);
    border-radius: var(--r-card);
    padding: 26px 30px;
    text-align: center;
}
#file-viewer-overlay .fv-none i { font-size: 44px; color: var(--ink2); }
#file-viewer-overlay .fv-none p { color: var(--ink2); font-size: var(--fs-md); }
.file-ic {
    width: 34px;
    height: 34px;
    border-radius: 10px;
    background: var(--card2);
    border: 1px solid var(--line);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ink2);
    flex: none;
    font-size: 16px;
}
.fm-tx { flex: 1; min-width: 0; }
.fm-tx > b { display: block; font-size: var(--fs-md); font-weight: 500; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fm-tx > span { display: block; font-size: var(--fs-sub); color: var(--ink2); margin-top: 1px; }
.fm-act { display: flex; flex: none; }

/* carrier / link chips (entity initials circle or kind glyph + label, optional ×) */
.fm-tags { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.fm-chiplink {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--card2);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    padding: 4px 10px 4px 5px;
    font: 600 11px var(--font-family);
    color: var(--ink2);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.fm-chiplink .m {
    width: 19px;
    height: 19px;
    border-radius: 50%;
    font-size: 8.5px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    background: var(--pc-soft, var(--card2));
    color: var(--pc-ink, var(--ink2));
}
.fm-chiplink > i { font-size: 12px; padding-left: 4px; }
.fm-chip-x { border: 0; background: transparent; color: var(--ink3); cursor: pointer; padding: 0 2px; font-size: var(--fs-cap); }
.fm-link-hint { font-size: var(--fs-sub); color: var(--ink3); }

/* upload button + inline status line */
.fm-add { width: 100%; margin-top: 12px; border-radius: var(--r-ctl); padding: 12px; }
.fm-status { color: var(--due-ink); font-size: var(--fs-cap); margin-top: 8px; min-height: 1em; text-align: center; }

/* file editor: preview panel + meta line */
.fm-prev {
    height: 120px;
    border-radius: 14px;
    background: var(--card2);
    border: 1px solid var(--line);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ink3);
    margin: 6px 0 4px;
    font-size: 28px;
    overflow: hidden;
}
.fm-prev img { width: 100%; height: 100%; object-fit: contain; }
.fm-meta { font-size: var(--fs-cap); color: var(--ink3); margin-top: 12px; line-height: 1.6; }
.fm-meta b { font-weight: 600; color: var(--ink2); }

/* category manager: inline rename input + OK */
.fm-cat-rename {
    flex: 1;
    min-width: 0;
    border: 1px solid var(--line);
    background: var(--card2);
    border-radius: var(--r-ctl);
    padding: 8px 10px;
    font-family: var(--font-family);
    font-size: var(--fs-body);
    color: var(--ink);
    outline: none;
}
.fm-cat-new {
    flex: 1;
    min-width: 0;
    border: 1px solid var(--line);
    background: var(--card2);
    border-radius: var(--r-ctl);
    padding: 11px 13px;
    font-family: var(--font-family);
    font-size: var(--fs-md);
    color: var(--ink);
    outline: none;
}

/* the files sheet header back arrow (sub-sheets) */
.popup-header .popup-back {
    background: transparent;
    border: 0;
    color: var(--ink);
    cursor: pointer;
    font-size: 15px;
    padding: 6px 8px 6px 0;
}

/* a field whose value is INHERITED from an entity: readable, obviously not yours to type */
.popup-body input.is-inherited,
.popup-body .is-inherited .mg-select-btn { opacity: 0.6; }

/* a money attribute on an entity: amount · currency · since, on one line */
.ent-money { display: flex; gap: 6px; align-items: center; width: 100%; }
.ent-money .ent-money-amt { flex: 1 1 auto; min-width: 0; font-variant-numeric: tabular-nums; }
.ent-money .ent-money-cur { flex: 0 0 84px; }
.ent-money .ent-money-since { flex: 0 0 132px; }
.ent-money .date-wrap { flex: 0 0 168px; }
@media (max-width: 380px) {
    .ent-money { flex-wrap: wrap; }
    .ent-money .ent-money-since, .ent-money .date-wrap { flex: 1 0 100%; }
}

/* the finance card's first row: the month total, without a checkbox column */
/* the finance cards speak the module's own voice: a hero amount, then aligned money.
   The widget card gives NO padding of its own — every row carries the house 13px itself
   (.w-head/.w-row do the same); content at 0 runs straight into the card edge. */
.fin-w-hero { display: flex; flex-direction: column; gap: 1px; padding: 2px 13px 10px; }
.fin-w-hero b { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ink); }
.fin-w-hero span { font-size: var(--fs-label); color: var(--ink3); }
.fin-w-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 13px;
    border-top: 1px solid var(--line);
    cursor: pointer;
}
.fin-w-name { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.fin-w-name b { font-size: var(--fs-sub); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fin-w-name span { font-size: var(--fs-label); color: var(--ink3); }
.fin-w-amount { font-size: var(--fs-sub); font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.fin-w-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 2px 13px 13px; }
.fin-w-tile {
    background: var(--nav-fill);
    border-radius: var(--r-card);
    padding: 9px 8px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    align-items: center;
    text-align: center;
    cursor: pointer;
}
.fin-w-tile b { font-size: var(--fs-md); font-weight: 700; font-variant-numeric: tabular-nums; }
.fin-w-tile span { font-size: var(--fs-label); color: var(--ink3); }
.fin-w-tile.is-bad b { color: var(--due); }

/* ── Finanzen ─────────────────────────────────────────────────────────────────
   The Aufstellung: what runs every month and whether it has been debited. The row is the
   notes card's geometry (24px glyph · content · right rail) because it IS the same kind of
   object to the eye; only the right rail differs — a tick and an amount instead of avatars.
   Red appears in exactly one place: a debit whose day has passed unconfirmed. */
/* The module wrapper HOLDS, the tab layer SCROLLS — the notes anatomy. When the wrapper was
   the scroller as well, the FAB's `position:absolute` resolved against the scrolled content and
   the button drifted up the list; and a docked summary had nowhere to dock. */
.module-finances {
    display: flex;
    flex-direction: column;
    height: 100%;
    position: relative;
    min-height: 0;
}
/* the headline block insets to the screen edge like every other module's */
.module-finances .pageTitle { margin: 10px var(--pad) 0; }
.module-finances .tab-layer {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 90px; /* the FAB must never sit on the last row */
}
.fin-tabs { margin: 2px var(--pad) 10px; }
/* what a tab wants to say at all times, docked above the footer instead of scrolling away
   under it: the month's balance, and whatever a future tab needs there */
/* the docked answer — a floating card, not a bar glued to the footer: who pays whom is the
   page's one sentence, and it deserves the same card voice as everything else */
.fin-dock {
    flex: none;
    margin: 8px var(--pad) calc(8px + env(safe-area-inset-bottom, 0px));
    padding: 10px 13px;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-card);
    box-shadow: var(--shadow);
    font-variant-numeric: tabular-nums;
}
.fin-dock .fin-balance-line {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    font-size: var(--fs-md);
}
.fin-dock .fin-balance-line .who { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fin-dock .fin-balance-line .who i { font-style: normal; color: var(--ink3); padding: 0 2px; }
.fin-dock .fin-balance-line .amt { font-weight: 700; white-space: nowrap; }
.fin-dock .fin-balance-line .amt small { font-weight: 500; color: var(--ink3); font-size: var(--fs-label); margin-left: 4px; }
.fin-dock .fin-balance-line + .fin-balance-line { margin-top: 6px; }
.fin-dock .fin-settle-btn { margin-top: 10px; }
.fin-nav {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px var(--pad) 10px;
}
.fin-nav-label { flex: 1; text-align: center; min-width: 0; }
.fin-nav-label b { display: block; font-size: var(--fs-md); font-weight: 600; }
.fin-nav-label small { display: block; font-size: var(--fs-sub); color: var(--ink2); }
.fin-warn {
    margin: 0 var(--pad) 10px;
    padding: 10px 12px;
    border-radius: var(--r-ctl);
    background: var(--due-soft);
    color: var(--due-ink);
    font-size: var(--fs-hint);
    font-weight: 600;
}
.fin-feed { padding: 0 var(--pad) 16px; }
/* ── the ONE section heading (Module.sectionHead) ────────────────────────────────────────────
   Finanzen, Kalender and Notizen each had their own; this is the shape they share now. The
   label is quiet on purpose — it names a section without competing with the rows under it. */
.sec-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 14px 2px 6px;
    font-size: var(--fs-label);
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--ink3);
}
.sec-head:first-child { padding-top: 2px; }
.sec-head-sub {
    font-weight: 600;
    letter-spacing: 0.06em;
    color: var(--ink3);
    opacity: .75;
    font-variant-numeric: tabular-nums;
}
/* the right side carries numbers — a sum, a forecast — so it drops the upper case */
.sec-head-meta {
    margin-left: auto;
    text-transform: none;
    letter-spacing: 0;
    font-size: var(--fs-sub);
    font-weight: 600;
    color: var(--ink2);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
/* the calendar's hairline disc, kept because it was the nicest of the three */
.sec-head-add {
    margin-left: auto;
    flex: none;
    width: 28px;
    height: 28px;
    box-sizing: border-box;
    border-radius: 50%;
    border: 1px solid var(--line2);
    background: transparent;
    color: var(--ink2);
    cursor: pointer;
    font-size: 13px;
    line-height: 1;
    display: grid;
    place-items: center;
    transition: transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}
.sec-head-meta + .sec-head-add { margin-left: 8px; }
.sec-head-add:active { transform: scale(var(--button-click-scale)); }

.fin-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
    padding: 14px 2px 6px;
    font-size: var(--fs-label);
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--ink3);
}
.fin-head-sum {
    font-variant-numeric: tabular-nums;
    letter-spacing: 0;
    text-transform: none;
    font-size: var(--fs-body);
    color: var(--ink2);
}
.fin-item {
    background: var(--card);
    border-radius: var(--r-card);
    padding: 12px 14px;
    margin-bottom: 8px;
    display: grid;
    grid-template-columns: 24px minmax(0, 1fr) auto;
    gap: 2px 10px;
    align-items: start;
    cursor: pointer;
}
.fin-ki { grid-row: 1; color: var(--ink3); display: flex; justify-content: center; padding-top: 1px; font-size: 14px; }
.fin-body { grid-row: 1; min-width: 0; }
.fin-title { font-size: var(--fs-md); font-weight: 600; line-height: 1.4; word-break: break-word; }
.fin-meta {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 3px;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    font-size: var(--fs-sub);
    color: var(--ink2);
}
.fin-by + .fin-by::before { content: "· "; color: var(--ink3); }
.fin-right { grid-row: 1; display: flex; align-items: center; gap: 8px; padding-top: 1px; }
.fin-val { font-size: var(--fs-md); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.fin-val.muted { color: var(--ink2); font-weight: 500; }
.fin-val.overdue { color: var(--due-ink); }
.fin-chip {
    display: inline-flex;
    align-items: center;
    padding: 1px 7px;
    border-radius: var(--r-pill);
    font-size: var(--fs-cap);
    font-weight: 600;
    background: var(--card2);
    color: var(--ink2);
    border: 1px solid var(--line);
    white-space: nowrap;
}
.fin-chip.done { background: var(--nav-fill); color: var(--ink); border-color: transparent; }
.fin-chip.due { background: var(--due-soft); color: var(--due-ink); border-color: transparent; }
.fin-chip.wait { background: var(--card2); color: var(--ink3); }
.fin-balance-line + .fin-balance-line { margin-top: 4px; }
.fin-balance {
    margin-top: 12px;
    padding: 11px 14px;
    border-radius: var(--r-ctl);
    background: var(--nav-fill);
    font-size: var(--fs-body);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
/* Status: the chart, the three tiles, the one warning.
   Built like the weather graph (.wxg): a 0-100 viewBox stretched to the card with non-scaling
   strokes, labels as HTML pinned to the same percent space so type never scales with the SVG. */
/* Colours here are --ink / --ink2 / --ink3, like everywhere else. Eight declarations in this
   block used to say --text and --text-soft, which no token file ever defined: an undefined
   var() with no fallback makes the whole declaration invalid, so those elements silently
   inherited their parent's colour instead of stepping back. The colour gate did not catch it
   — it checks that a colour IS a token, not that the token exists. */
/* The chart runs nearly edge to edge: it is the widest thing on the page and the one that
   loses the most to a gutter. 6px of air instead of the page padding, and a money column
   just wide enough for a six-figure label. */
.fin-chart { padding: 4px 6px 0; --fin-gut: 42px; }
.fin-chart-head { display: flex; justify-content: flex-end; padding-bottom: 6px; }
/* the how-far-ahead pick: a small dropdown, because it is touched twice a year */
.fin-range { width: auto; min-width: 116px; }
/* a gutter on the left for the money axis; the plot itself starts after it */
.fin-plot { position: relative; height: 150px; padding-left: var(--fin-gut); }
/* ONE box for everything that is drawn. A percentage `left` resolves against the PADDING box, so
   a dot at left:0 inside .fin-plot landed in the gutter — before the curve, not on it. The svg and
   the marks that belong ON it share this box instead, which makes 0% the first data point and
   100% the last by construction. The money labels stay outside it, in the gutter. */
.fin-canvas { position: absolute; inset: 0 0 0 var(--fin-gut); }
.fin-canvas svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.fin-area { fill: var(--ink); fill-opacity: 0.10; }
.fin-line { fill: none; stroke: var(--ink); stroke-width: 1.8px; stroke-linecap: round;
    stroke-linejoin: round; stroke-dasharray: 4 3; vector-effect: non-scaling-stroke; }
/* the scale's hairlines, and the one that means nothing left */
.fin-grid { fill: none; stroke: var(--line2); stroke-width: 1px; opacity: .5;
    vector-effect: non-scaling-stroke; }
.fin-zero { fill: none; stroke: var(--due); stroke-width: 1px; opacity: .6;
    vector-effect: non-scaling-stroke; }
/* A percentage `left` resolves against the PADDING box, so left:0 already sits in the gutter —
   the negative margin on top of it pushed every label off the screen. */
.fin-ytick {
    position: absolute;
    width: 38px;
    text-align: right;
    transform: translateY(-50%);
    font-size: var(--fs-label);
    color: var(--ink3);
    font-variant-numeric: tabular-nums;
}
/* NAMES MATTER: .fin-val is the amount on every finance ROW. Reusing it here made the chart's
   `position:absolute` apply to every row amount in the module and shove them off screen. */
.fin-plot-dot { position: absolute; width: 6px; height: 6px; border-radius: 50%; background: var(--ink);
    transform: translate(-50%, -50%); }
.fin-plot-val {
    position: absolute;
    font-size: var(--fs-sub);
    font-weight: 700;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.fin-plot-val.start { transform: translate(0, calc(-100% - 8px)); }
.fin-plot-val.end { transform: translate(-100%, calc(-100% - 8px)); }
/* The month names sit under the SAME box the curve is drawn in. They used to carry another
   var(--pad) on each side on top of .fin-chart's own, so every name stood a padding to the right
   of the point it names. */
.fin-axis { position: relative; height: 16px; margin: 2px 0 0 var(--fin-gut); }
.fin-axis span {
    position: absolute;
    transform: translateX(-50%);
    font-size: var(--fs-label);
    color: var(--ink3);
    white-space: nowrap;
}
.fin-axis span:first-child { transform: none; }
.fin-axis span:last-child { transform: translateX(-100%); }
/* the forecast's one adjustable assumption, said quietly under the tiles it feeds */
.fin-varline {
    display: block;
    margin: 6px var(--pad) 0;
    padding: 0;
    background: none;
    border: none;
    font-family: var(--font-family);
    font-size: var(--fs-label);
    color: var(--ink3);
    text-align: left;
    cursor: pointer;
    font-variant-numeric: tabular-nums;
    -webkit-tap-highlight-color: transparent;
}
.fin-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; padding: 10px var(--pad) 0; }
.fin-tile {
    background: var(--nav-fill);
    border-radius: var(--r-card);
    padding: 10px 8px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    align-items: center;
    text-align: center;
}
.fin-tile b { font-size: var(--fs-md); font-weight: 700; font-variant-numeric: tabular-nums; }
.fin-tile span { font-size: var(--fs-label); color: var(--ink3); }
.fin-tile.is-bad b { color: var(--due); }
.fin-horizons { font-weight: 500; }
.fin-warn {
    margin: 10px var(--pad) 0;
    padding: 10px 14px;
    border-radius: var(--r-ctl);
    background: var(--nav-fill);
    color: var(--due);
    font-size: var(--fs-md);
    font-weight: 600;
}
.fin-why { margin: 12px var(--pad) 0; width: calc(100% - 2 * var(--pad)); }
/* Privat: what you have, in one line the eye lands on first */
.fin-hero { padding: 14px var(--pad) 4px; display: flex; flex-direction: column; gap: 2px; }
.fin-hero b { font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ink); }
.fin-hero span { font-size: var(--fs-sub); color: var(--ink3); }
.fin-hero-more { font-variant-numeric: tabular-nums; }
/* the breakdown of the big number: quieter than it, because it explains it */
/* what a holding was worth before — a record, so it steps back from the form above it */
.fin-hist { display: flex; flex-direction: column; gap: 3px; padding: 0 var(--pad) 4px; }
.fin-hist b { font-size: var(--fs-label); color: var(--ink3); text-transform: uppercase; letter-spacing: .04em; }
.fin-hist span { font-size: var(--fs-sub); color: var(--ink2); font-variant-numeric: tabular-nums; }
.fin-hero-avail {
    font-size: var(--fs-label);
    color: var(--ink3);
    font-variant-numeric: tabular-nums;
}
/* a value nobody refreshed in three months looks its age instead of counting silently */
.is-stale .fin-val { opacity: .55; }
/* a section that can grow carries its own + */
.fin-head-add { margin-left: 8px; }
/* the Aufteilung rows: who · the typed value · the euro it lands on, right-aligned */
.fin-shares { display: flex; flex-direction: column; gap: 6px; margin: 2px 0 4px; }
.fin-share-row { display: grid; grid-template-columns: 1fr 84px auto; align-items: center; gap: 8px; }
.fin-share-who { font-size: var(--fs-md); color: var(--ink); }
.fin-share-val { width: 100%; text-align: right; font-variant-numeric: tabular-nums; }
.fin-share-out {
    min-width: 76px;
    text-align: right;
    font-size: var(--fs-sub);
    font-variant-numeric: tabular-nums;
    color: var(--ink3);
}
.fin-share-hint.is-bad { color: var(--due); }
/* settling: the button sits inside the balance box, under what it will pay off */
.fin-settle-btn { margin-top: 10px; width: 100%; }
/* a settled entry stays readable but steps back — it is history, not a claim */
.is-settled .fin-title,
.is-settled .fin-val { opacity: .55; }
/* amount and its currency share one row: the currency is the one thing that can be wrong
   without anybody noticing, so it stands where the number is */
.popup-body .form-row.fin-amount-row { display: grid; grid-template-columns: 1fr 96px; gap: 8px; align-items: end; }
.popup-body .form-row.fin-amount-row label { grid-column: 1 / -1; margin-bottom: 0; }
.fin-cur { min-width: 0; }
/* the tick: the app's checkbox, ink when set (same shape the notes lines wear) */
.fin-check {
    appearance: none;
    -webkit-appearance: none;
    width: 17px;
    height: 17px;
    border-radius: 5px;
    border: 1.5px solid var(--line2);
    background: var(--card2);
    position: relative;
    cursor: pointer;
    flex: none;
    margin: 0;
}
.fin-check:checked { background: var(--ink); border-color: var(--ink); }
.fin-check:checked::after {
    content: "";
    position: absolute;
    left: 5px;
    top: 1.5px;
    width: 4.5px;
    height: 9px;
    border: solid var(--bg);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}
/* A labelled switch in a sheet: label left, box right. Born in the finance sheet, now also the
   pass's "is this being taken" — same row, same rules, one place to change. */
.popup-body .form-row.fin-check-row,
.popup-body .form-row.form-row-check {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}
.popup-body .form-row.fin-check-row label,
.popup-body .form-row.form-row-check label { margin-bottom: 0; flex: 1; }
/* the inset-input rule is width:100% — a checkbox is not an input field, and inheriting
   that turns it into a full-width bar with the label squeezed beside it */
.popup-body .form-row.fin-check-row .fin-check,
.popup-body .form-row.form-row-check .form-check { width: 17px; height: 17px; flex: none; }
.form-hint { font-size: var(--fs-hint); color: var(--ink3); margin: 4px 0 0; }

/* ── Module headings: the display serif ────────────────────────────────────────
   The ONLY place a second font appears (design/DESIGN.md §4): the four module
   headings (dashboard greeting, calendar view title, Notizen page title, baby's
   name) plus two sanctioned hero moments — the dashboard empty-state title and
   the recipe overlay title. This selector list IS the authoritative inventory;
   nothing else gets the serif. Size/weight/letter-spacing come with it — the
   serif carries 700 and one shared 30px. Deliberately last in the file: several
   of these elements are styled via `#app …` further up, so this rule needs equal
   specificity AND later source order to win. */
#app .pageTitle h2,
#app .cal-title,
#app .baby-hero-name,
#app .dash-empty-title,
#recipe-view-overlay .rv-title {
    font-family: var(--disp), var(--font-family), serif;
    font-optical-sizing: auto;
    font-weight: 700;
    font-size: 30px;
    letter-spacing: -0.015em;
}

/* A past calendar entry is a record, not a task — see _eventRow, which exempts overdue
   todos and chore turns so they keep their full weight. */
#app .cal-event.cal-past { opacity: 0.55; }

/* a required field the module refused to save on — flagged when Save is tapped, cleared on
   the next keystroke; red is state, and an empty mandatory field IS the error state */
#app .field-missing {
    border-color: var(--due);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--due) 22%, transparent);
}

/* Neuigkeiten — the operator's announcement card at the top of the dashboard (newsCard).
   The rosé wordmark dot marks the sender: josephine itself, not the household. */
#app .news-card {
    position: relative;
    grid-column: 1 / -1;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-card);
    padding: 13px 38px 13px 14px;
}
#app .news-head {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: var(--fs-ui);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink2);
}
#app .news-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--wm-dot);
}
#app .news-card p {
    margin: 7px 0 0;
    font-size: var(--fs-body);
    color: var(--ink);
    line-height: 1.5;
}
#app .news-card p + p {
    margin-top: 9px;
    padding-top: 9px;
    border-top: 1px solid var(--line);
}
#app .news-x {
    position: absolute;
    right: 8px;
    top: 7px;
    color: var(--ink3);
}

/* Feedback sheet: success is green (the base .fm-status is the error tone), and the segmented
   kind picker aligns full-width with the textarea with balanced room around the label. */
#app .fm-status.ok { color: var(--ok-ink); }
#feedback-popup-overlay .seg-tabs.seg-track { margin: 4px 0 0; }
#feedback-popup-overlay .popup-body .form-row { margin-top: 16px; }

/* Health (P31) — a subject's record across four tabs (Notfall · Protokoll · Vorsorge · Pass),
   built like Baby (hero + subject) on the Finanzen shell (holder + scrolling tab-layer + FAB).
   Red is the STATE of a severe allergy or an overdue thing (tokens.css: red is only for states),
   never a person. Everything else speaks the module's own ink. */
#app .module-health { display: flex; flex-direction: column; height: 100%; position: relative; min-height: 0; }
#app .module-health .tab-layer { overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 0 var(--pad) 90px; }
#app .hl-tabs { margin: 12px var(--pad) 8px; }
#app .module-health .hl-consent { margin: 12px var(--pad); }
#app .module-health .subject-filter { padding-top: 12px; }
/* each subject chip is led by its avatar circle (photo when set, else the initial in the person
   colour) — the badge is a real circle, not a bare letter flush against the name */
#app .module-health .subject-chip { display: inline-flex; align-items: center; gap: 7px; }
#app .subject-chip .m {
    width: 20px; height: 20px; border-radius: 50%; flex: none; overflow: hidden;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 9px; font-weight: 700;
    background: var(--pc-soft, var(--card2)); color: var(--pc-ink, var(--ink2));
}
/* the hero — subject colour ring, serif name, a sub-line of age · gender · privacy scope */
#app .hl-hero { display: flex; align-items: center; gap: 13px; padding: 10px var(--pad) 0; }
#app .hl-hero-glyph {
    width: 54px; height: 54px; box-sizing: border-box; border-radius: 50%; overflow: hidden;
    border: 2.5px solid var(--pc, var(--line2)); flex: none; display: grid; place-items: center;
    font-size: 17px; font-weight: 600; background: var(--pc-soft, var(--card2)); color: var(--pc-ink, var(--ink2));
}
#app .subject-chip .m img, #app .hl-hero-glyph img { width: 100%; height: 100%; object-fit: cover; display: block; }
#app .hl-hero-tx { min-width: 0; }
#app .hl-hero-name { color: var(--ink); line-height: 1.2; } /* serif comes from the display rule at the end of the file */
#app .hl-hero-age { font-size: var(--fs-ui); color: var(--ink2); margin-top: 2px; }
#app .hl-hero-age i { font-size: 11px; color: var(--pc, var(--ink3)); }
#app .hl-head-edit { margin-left: auto; padding: 8px 12px; background: var(--nav-fill); border: 0; color: var(--ink); }
#app .hl-head-edit i { font-size: 14px; }
/* the module's FAB — same corner as every sibling's */
#app .hl-fab {
    position: absolute; right: 18px; bottom: 18px; z-index: 5; width: 60px; height: 60px;
    border-radius: 50%; border: 0; background: var(--ink); color: var(--bg); cursor: pointer;
    box-shadow: var(--shadow); display: flex; align-items: center; justify-content: center;
    font-size: 22px; transition: transform var(--transition-fast); -webkit-tap-highlight-color: transparent;
}
#app .hl-fab:active { transform: scale(var(--button-click-scale)); }
/* a phone value dials from its row; the row's own tap still edits (tapToEdit ignores anchors) */
#app .hl-right { margin-left: auto; flex: none; }
#app a.hl-tel { display: inline-flex; align-items: center; gap: 6px; color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
#app a.hl-tel i { font-size: 12px; color: var(--ink3); }
/* the running-illness head on the Notfall tab */
#app .hl-run { padding: 4px 0 10px; border-bottom: 1px solid var(--line); margin-bottom: 8px; }
#app .hl-run-head .hl-meta .hl-by:first-child { color: var(--ink); font-weight: 600; }
#app .hl-run-lines { display: grid; gap: 4px; padding: 4px 2px 0; }
#app .hl-run-line { display: grid; grid-template-columns: minmax(96px, 34%) 1fr; gap: 8px; font-size: var(--fs-sub); line-height: 1.45; }
#app .hl-run-k { color: var(--ink3); }
#app .hl-run-foot { margin-top: 10px; }
#app .hl-run-foot .action-btn { margin: 0; }
#app .hl-card { background: var(--nav-fill); border-radius: var(--r-card); padding: 14px 16px; margin: 0 0 8px; }
#app .hl-card-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
#app .hl-card-head .w-title { color: var(--ink2); }
#app .hl-blood { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; border: 1px solid var(--ink); border-radius: 999px; padding: 2px 10px; }
#app .hl-card-lines { margin-top: 10px; display: grid; gap: 6px; }
#app .hl-card-line { display: grid; grid-template-columns: minmax(96px, 34%) 1fr; gap: 8px; font-size: var(--fs-sub); line-height: 1.45; }
#app .hl-card-k { color: var(--ink3); }
#app .hl-card-v { word-break: break-word; }
#app .hl-card-line.hl-severe .hl-card-v { color: var(--due-ink); font-weight: 600; }
#app .hl-card-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
#app .hl-section { display: flex; flex-direction: column; }
#app .hl-item { display: flex; align-items: center; gap: 10px; padding: 10px 2px; border-bottom: 1px solid var(--line); cursor: pointer; }
#app .hl-item:last-child { border-bottom: 0; }
#app .hl-body { flex: 1; min-width: 0; }
#app .hl-title { font-size: var(--fs-md); font-weight: 600; line-height: 1.4; word-break: break-word; }
#app .hl-scalar .hl-title { font-weight: 500; }
#app .hl-meta { font-size: var(--fs-sub); color: var(--ink3); line-height: 1.4; }
#app .hl-by + .hl-by::before { content: " · "; color: var(--ink3); }
#app .hl-item.hl-severe .hl-title::after { content: " !"; color: var(--due-ink); }
#app .hl-empty { color: var(--ink3); font-size: var(--fs-sub); padding: 8px 2px 12px; cursor: pointer; }
#app .hl-consent { background: var(--nav-fill); border-radius: var(--r-card); padding: 18px 16px; }
#app .hl-consent h3 { margin: 0 0 8px; }
#app .hl-consent p { margin: 0 0 10px; line-height: 1.5; }
#app .hl-consent-fine { color: var(--ink3); font-size: var(--fs-sub); }
#app .hl-w-row { display: flex; gap: 8px; align-items: baseline; }
#app .hl-w-meta { color: var(--ink3); font-size: var(--fs-sub); margin-left: auto; text-align: right; }
#app .hl-source { color: var(--ink3); font-size: var(--fs-sub); padding: 4px 2px 12px; line-height: 1.4; }
#app .hl-item.hl-due .hl-meta .hl-by:first-child { color: var(--ink); font-weight: 600; }
#app .hl-item.hl-overdue .hl-meta .hl-by:first-child { color: var(--due-ink); font-weight: 600; }
#app .hl-rec-head { margin-top: 14px; }
#app .hl-rec { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--line); font-size: var(--fs-sub); }
#app .hl-rec:last-child { border-bottom: 0; }
#app .hl-rec-del { margin-left: auto; border: 0; background: none; color: var(--ink3); font-size: 18px; line-height: 1; cursor: pointer; padding: 0 6px; }
#app .hl-rec-from { margin-left: auto; color: var(--ink3); }
/* Stage 3 — illness cards with their log, the log's entry rows, the chip row that adds to a
   running illness, and the "what to log?" list. The running illness reads bold in its first
   meta chip (ink, never red — an illness is a state of the day, not a fault). */
#app .hl-ep { padding: 4px 0 8px; border-bottom: 1px solid var(--line); }
#app .hl-ep:last-child { border-bottom: 0; }
#app .hl-ep .hl-item { border-bottom: 0; }
#app .hl-ep.hl-running .hl-meta .hl-by:first-child { color: var(--ink); font-weight: 600; }
#app .hl-ep-body { display: grid; gap: 2px; padding: 0 2px 4px; }
#app .hl-ev { display: flex; align-items: center; gap: 10px; padding: 6px 0; font-size: var(--fs-sub); cursor: pointer; }
#app .hl-ev i { width: 18px; text-align: center; color: var(--ink3); flex: none; }
#app .hl-ev-txt { flex: 1; min-width: 0; word-break: break-word; }
#app .hl-ev-when { color: var(--ink3); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* the two voices under an open illness / value card: one ink pill, one Bearbeiten pill */
#app .hl-ep-foot { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 8px; padding: 0 2px; }
#app .hl-ep-foot .action-btn { margin: 0; }
#app .hl-ep-loose .hl-ep-head { padding: 8px 2px 4px; }
/* the empty-log greeting sits like the notes/finances blank, sized for the scrolling layer */
#app .module-health .tab-layer .notes-blank { margin-top: 40px; }
/* Stage 4 — value cards: the last reading in the head, the course (a shape, not a scale — ink
   for the first line, the quieter ink for a pair's second) and the readings behind a tap; the
   picker's switches. */
#app .hl-val { padding: 4px 0 8px; border-bottom: 1px solid var(--line); }
#app .hl-val:last-child { border-bottom: 0; }
#app .hl-val .hl-item { border-bottom: 0; }
#app .hl-val-body { display: grid; gap: 2px; padding: 0 2px 4px; }
#app .hl-spark { width: 100%; height: 48px; display: block; margin: 2px 0 6px; }
#app .hl-spark polyline { fill: none; stroke: var(--ink); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
#app .hl-spark polyline + polyline { stroke: var(--ink3); }
/* A switch row is a <label> inside the sheet body — it must NOT read as a field caption
   (the generic .popup-body label is small caps, muted, block). */
#app .popup-body label.hl-opt { display: flex; align-items: center; gap: 12px; padding: 10px 4px; margin: 0; border-bottom: 1px solid var(--line); cursor: pointer; text-transform: none; letter-spacing: 0; font-weight: 400; font-size: var(--fs-body); color: var(--ink); }
#app .popup-body label.hl-opt:last-child { border-bottom: 0; }
/* a switch row whose value needs a word (INR, Peak-Flow) stacks the name over a quiet hint */
#app .hl-opt-tx { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
#app .hl-opt-tx .form-hint { margin: 0; }
/* a description that LEADS a sheet breathes before the first field */
#app .hl-sheet-desc { margin: 0 0 12px; }
