/* app.css — the app's one stylesheet (design: design/prototype.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: rgba(20, 18, 14, 0.4);        /* drawer / popup / sheet backdrop */
    --scrim-strong: rgba(20, 18, 14, 0.82); /* file-viewer lightbox backdrop */
    --scroll-shadow: rgba(0, 0, 0, 0.07);  /* edge shadow on scrollable strips */
    /* 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-body: 13px;             /* row titles */
    --fs-md: 13.5px;             /* event titles, menu items, inputs */
}
[data-theme="dark"] {
    --scrim: rgba(0, 0, 0, 0.55);
    --scrim-strong: rgba(0, 0, 0, 0.85);
    --scroll-shadow: rgba(255, 255, 255, 0.09);
}

/* focus */
*:focus {
    outline: none;
}

/* 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;
}
#install-prompt .install-go {
    border: 0;
    border-radius: var(--r-pill);
    background: var(--ink);
    color: var(--bg);
    font-family: var(--font-family);
    font-size: var(--fs-ui);
    font-weight: 600;
    padding: 7px 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;
}

#app form .formSubmit button {
    border: 0;
    border-radius: var(--r-pill);
    background: var(--ink);
    color: var(--bg);
    font-family: var(--font-family);
    font-size: 14px;
    font-weight: 600;
    padding: 12px 30px;
    cursor: pointer;
    transition: transform var(--transition-fast);
}

#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: 12px;
    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: 12.5px;
    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: 12.5px;
    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: 12.5px;
    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: 12.5px;
    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 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: 13px;
    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);
    border-top: 1px solid var(--line);
    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.05em;
    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 initials circle in the person color */
.head-menu-item .fava {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    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.star.on { color: var(--ink); }
.icon-btn svg { width: 15px; height: 15px; }

/* action buttons — filled ink pill; cancel = ghost; delete = red text */
.action-btn.reusable {
    font-family: var(--font-family);
    font-size: 12.5px;
    font-weight: 600;
    padding: 10px 16px;
    background: var(--ink);
    color: var(--bg);
    border: 1px solid var(--ink);
    border-radius: var(--r-pill);
    cursor: pointer;
    white-space: nowrap;
    margin: 2px;
    transition: transform var(--transition-fast);
    -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;
    border: 1px solid var(--line);
    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;
    background: var(--card);
    border: 1px solid var(--line);
    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: 12.5px;
}
#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: 12.5px;
    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(--muted);
    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;
}

/* ── 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: 12px;
    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: 12px;
    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: 12px; }

/* the same tile with or without a photo — different heights per row would leave the
   recipe list fraying down the page */
.notes-thumb {
    width: 56px;
    height: 56px;
    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: 13px; flex: none; font-variant-numeric: tabular-nums; }

/* The list is the whole idea: every step stays readable, the current one is simply LARGER.
   Nothing is hidden, so reading ahead and jumping back cost nothing. */
.cook-steps { flex: 1; overflow-y: auto; padding: 8px var(--pad) 4px; }
/* a section heading is a LABEL, not a stop — it says what the next few steps belong to and
   stays legible while you work through them */
.cook-sec {
    padding: 16px 2px 4px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink3);
}
.cook-sec:first-child { padding-top: 4px; }
.cook-step {
    padding: 14px 2px;
    font-size: 16px;
    line-height: 1.5;
    color: var(--ink3);
    border-bottom: 1px solid var(--line);
    cursor: pointer;
    transition: color var(--transition-fast), font-size var(--transition-fast);
}
.cook-step:last-child { border-bottom: none; }
.cook-step.current {
    color: var(--ink);
    font-size: 22px;
    line-height: 1.45;
    font-weight: 500;
}
.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; }
.cook-ing-open { color: var(--due); font-size: 12px; flex: none; }
.cook-next {
    width: 100%;
    padding: 15px;
    border: none;
    border-radius: var(--r-ctl);
    background: var(--ink);
    color: var(--bg);
    font: inherit;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
}
.cook-next:active { transform: scale(var(--button-click-scale)); }
.pick-hint { color: var(--ink3); font-size: 12px; 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: 700; 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;
}
/* 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.05em;
    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 {
    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 { 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 scrolls with the widgets as the grid's first full-width row */
.dash-grid > .pageTitle { grid-column: 1 / -1; }
/* "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: 12.5px;
    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 { font-size: 23px; font-weight: 600; letter-spacing: -0.02em; margin: 0; }
.pageTitle p { font-size: 12.5px; color: var(--ink2); margin: 2px 0 0; }
/* .fill is set by the dashboard AFTER layout, only when the content actually FITS the
   viewport: leftover space then distributes across the rows so widgets reach the footer.
   Overflowing dashboards never get the class — scrolling stays intact. */
.dash-grid.fill {
    grid-auto-rows: auto;
    align-content: stretch;
}
/* 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, hairline borders */
.widget {
    background: var(--card);
    border: 1px solid var(--line);
    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-count {
    font-size: var(--fs-cap);
    font-weight: 600;
    color: var(--ink3);
    font-variant-numeric: tabular-nums;
}
.w-count.hot { color: var(--due-ink); }
.w-spacer { flex: 1; }
/* the + — a quiet hairline disc in every widget head */
#app .w-add {
    width: 22px;
    height: 22px;
    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: 11px;
    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;
}
.w-check {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    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 { background: var(--ink); border-color: var(--ink); }
.w-check: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);
}
.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); }
.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-ui); 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 */
/* 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: 2px 13px 10px; }
.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 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 */
.wx-hour:first-child { background: var(--card2); border: 1px solid var(--line); }
.wx-hour .i { font-size: 12px; color: 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 ROWS: weekday · description · max° · min° (two columns when wide) */
.wx-days {
    padding: 4px 13px 11px;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    column-gap: 22px;
}
.wx-day {
    display: flex;
    align-items: center;
    padding: 5px 0;
    font-size: var(--fs-sub);
    min-width: 0;
}
.wx-day-name { width: 28px; flex-shrink: 0; font-weight: 600; color: var(--ink2); }
.wx-day-desc { flex: 1; min-width: 0; color: var(--ink3); font-size: var(--fs-label); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wx-day-max { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.wx-day-min { color: var(--ink3); font-variant-numeric: tabular-nums; margin-left: 7px; width: 26px; text-align: right; flex-shrink: 0; }
.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; }
.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.04em; }
/* 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-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 {
    font-size: 21px;
    font-weight: 600;
    letter-spacing: -0.02em;
    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; }
.cal-title { flex: 1; font-size: 22px; font-weight: 600; letter-spacing: -0.02em; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-nav {
    width: 30px;
    height: 30px;
    flex: none;
    border: 1px solid var(--line2);
    background: var(--card);
    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: 500;
    color: var(--ink);
    background: var(--card);
    border: 1px solid var(--line2);
    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);
    border: 1px solid var(--line);
    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); }
.cal-view-btn .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);
}
.cal-view-btn.active .seg-count { color: var(--bg); opacity: 0.65; }

/* month grid — one card */
.cal-grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 2px;
    margin: 3px var(--pad) 12px;
    padding: 13px 8px 8px;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-card);
    flex: none;
}
.cal-wd { text-align: center; font-size: 10px; font-weight: 600; color: var(--ink3); padding-bottom: 7px; }
.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: 12.5px;
    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 — capped like the prototype's calList on wide screens */
.cal-week, .cal-day, .cal-upcoming {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 6px var(--pad) 96px;
}
@container (min-width: 600px) {
    .cal-week .cal-week-day, .cal-day .cal-daylist, .cal-day .cal-agenda-label,
    .cal-upcoming .cal-daylist, .cal-upcoming .cal-up-month, .cal-upcoming .cal-up-day,
    .cal-week .cal-week-hd { max-width: 680px; }
}

/* day headers — name · date · forecast right · + (outside the day card) */
.cal-agenda-label, .cal-up-day, .cal-week-hd {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 4px 2px 8px;
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--ink);
}
.cal-week-name { font-size: var(--fs-md); font-weight: 600; color: var(--ink); }
.cal-week-date { font-size: var(--fs-ui); font-weight: 400; color: var(--ink2); font-variant-numeric: tabular-nums; }
/* 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: 22px;
    height: 22px;
    box-sizing: border-box;
    border-radius: 50%;
    border: 1px solid var(--line2);
    background: transparent;
    color: var(--ink2);
    cursor: pointer;
    font-size: 11px;
    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 */
.cal-daylist {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-card);
    overflow: hidden;
    margin-bottom: 16px;
    padding-bottom: 0;
}
.cal-week-day {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-card);
    overflow: hidden;
    margin-bottom: 16px;
}
.cal-week-day .cal-week-hd { margin: 0; padding: 11px 14px 9px; border-bottom: 1px solid var(--line); }
.cal-week-day.cal-todaycell .cal-week-name { text-decoration: underline; text-underline-offset: 3px; }
/* the week card holds its own day list — no double frame */
.cal-week-day .cal-daylist { border: 0; border-radius: 0; margin-bottom: 0; }

/* 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: 12.5px; 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; }
.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; }
/* 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: 52px;
    height: 52px;
    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: 22px;
    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: 22px; height: 22px; }

/* editor sheet extras */
.cal-hidden { display: none !important; }
.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;
    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; }

/* scrolling layer with swipe feedback: while dragging horizontally the layer follows
   the finger via --notes-drag (CSSOM — CSP-safe); releasing below the threshold
   springs back; `touch-action: pan-y` keeps vertical scrolling native */
.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;
    transform: translateX(var(--notes-drag, 0px));
    transition: transform var(--transition-base);
}
/* 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; }
.notes-layer.dragging { transition: none; } /* 1:1 finger follow while dragging */
/* directional slide when switching type layers (tap or swipe commit) */
@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; } }
.notes-layer.slide-from-right { animation: notesSlideFromRight var(--transition-base); }
.notes-layer.slide-from-left  { animation: notesSlideFromLeft  var(--transition-base); }
@media (prefers-reduced-motion: reduce) {
    .notes-layer.slide-from-right, .notes-layer.slide-from-left { animation: none; }
    .notes-layer { transition: none; }
}

/* list-group headers — quiet titles between cards */
.notes-group-label {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 14px 2px 8px;
    color: var(--ink);
    font-size: var(--fs-md);
    font-weight: 600;
    letter-spacing: -0.01em;
}
.notes-group-label:first-child { margin-top: 0; }
/* jump target of the list-card tap — keep clear of the header when scrolled to */
.notes-group-label { scroll-margin-top: 76px; }
.notes-empty {
    color: var(--ink3);
    font-size: 12.5px;
    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 {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 0 20px 28px;
}
.notes-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 {
    font-size: 14.5px;
    font-weight: 600;
    color: var(--ink);
}
.notes-blank p {
    font-size: 12.5px;
    color: var(--ink2);
    margin-top: 5px;
    line-height: 1.55;
    max-width: 250px;
}
.notes-blank .action-btn { margin-top: 15px; }

/* item card — checkbox/glyph + title + status + chips + authorship */
.notes-item {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-card);
    padding: 14px;
    margin-bottom: 10px;
    min-height: 44px; /* tick rows stay a comfortable touch target even with one short line */
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 10px;
    align-items: start;
    position: relative;
    overflow: hidden;
}
.notes-item.pinned::before {
    content: "";
    position: absolute;
    left: 0;
    top: 14px;
    bottom: 14px;
    width: 3px;
    background: var(--ink);
    border-radius: 0 2px 2px 0;
}

/* leading control: custom checkbox / kind glyph */
.notes-lead { padding-top: 2px; }
.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);
}
/* the 18px box answers taps in a 44px halo — the store-view tick target (::after is taken
   by the check mark; the box is position:relative, so the halo centers on it). Scoped to
   the LIST cards: dashboard widget rows are whole-row tap targets where a halo would turn
   an open-the-editor tap into a state write */
.notes-item .notes-check::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
}
.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;
    width: 4.5px;
    height: 9px;
    border: solid var(--card);
    border-width: 0 1.8px 1.8px 0;
    transform: rotate(43deg);
}
.notes-glyph {
    width: 26px;
    height: 26px;
    box-sizing: border-box;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    background: var(--card2);
    border: 1px solid var(--line);
    color: var(--ink2);
    flex: none;
}

/* body: title + status + meta */
.notes-body { min-width: 0; }
.notes-title {
    font-size: 14.5px;
    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: 12.5px; }
/* a note's body under its title — own block, keeps typed line breaks */
.notes-text { color: var(--ink2); font-size: 12.5px; line-height: 1.5; white-space: pre-line; word-break: break-word; margin-top: 2px; }
/* 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; }
.notes-meta {
    display: flex;
    align-items: center;
    gap: 5px 6px;
    flex-wrap: wrap;
    margin-top: 8px;
}
/* list-card preview: a quiet window into the list — open entries first, done ones struck */
.notes-list-preview { display: flex; flex-direction: column; gap: 3px; margin-top: 6px; }
.nlp-row { display: flex; align-items: center; gap: 7px; min-width: 0; font-size: var(--fs-sub); color: var(--ink2); }
.nlp-box { width: 11px; height: 11px; box-sizing: border-box; border: 1.4px solid var(--line2); border-radius: 3.5px; flex: none; }
.nlp-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nlp-row.done { color: var(--ink3); }
.nlp-row.done .nlp-text { text-decoration: line-through; }
.nlp-row.done .nlp-box { background: var(--line2); border-color: var(--line2); }
.nlp-row { cursor: pointer; }
/* 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; }
}
/* progress beside the list name — muted, never bold */
.nlp-count { margin-left: 7px; font-size: 12px; font-weight: 400; color: var(--ink3); font-variant-numeric: tabular-nums; }
/* the expander strip inside the list card body — from the 4th entry on (dashboard pattern) */
.nlp-row.nlp-xtra { display: none; }
.notes-body.open .nlp-row.nlp-xtra { display: flex; }
.notes-body .w-foot { justify-content: flex-start; padding: 4px 0 0; }
.notes-body.open .w-foot i { transform: rotate(180deg); }
.notes-body.open .w-foot span { display: none; }
/* person chip — soft pill with a name */
.notes-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: var(--fs-label);
    font-weight: 600;
    padding: 2.5px 8px;
    border-radius: var(--r-pill);
    background: var(--card2);
    border: 1px solid var(--line);
    color: var(--ink2);
    white-space: nowrap;
}
.notes-chip svg { width: 10px; height: 10px; }
/* 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); }

/* trailing icon actions */
.notes-acts { display: flex; gap: 2px; align-self: start; }

/* FAB — solid ink */
.notes-fab {
    position: absolute;
    right: 18px;
    bottom: 18px;
    z-index: 5;
    width: 52px;
    height: 52px;
    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;
}
.notes-fab:active { transform: scale(var(--button-click-scale)); }
.notes-fab svg { width: 22px; height: 22px; }

/* 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: 52px;
    height: 52px;
    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;
    -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: 11px;
    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; box-shadow: var(--shadow); }
.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; }
.fy-due { position: relative; background: var(--due-soft); border-bottom: 1px solid color-mix(in srgb, var(--due) 16%, transparent); }
.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 { border-top: 1px solid color-mix(in srgb, var(--due) 12%, transparent); }
.fy-due .fy-row:first-child { border-top: 0; }
.fy-tap { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.fy-time { font-size: 11px; font-weight: 600; color: var(--ink2); width: 48px; flex-shrink: 0; font-variant-numeric: tabular-nums; }
.fy-time.due { color: var(--due-ink); }
.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-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; background: var(--pc, var(--ink)); }
.fy-body { flex: 1; min-width: 0; }
.fy-body b { display: block; font-size: 13px; font-weight: 500; }
.fy-sub { display: block; font-size: 11px; 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-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. Collapses behind a toggle when it grows long. */
.fy-shared { position: relative; background: var(--pend-soft); border-top: 1px solid color-mix(in srgb, var(--pend) 16%, transparent); }
.fy-shared::before { content: ""; position: absolute; top: 0; left: 0; bottom: 0; width: 3px; background: var(--pend); }
.fy-shared .fy-row { border-top: 1px solid color-mix(in srgb, var(--pend) 12%, transparent); }
.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; }

/* ============================== 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) 84px;
    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);
        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: 52px;
    height: 52px;
    border-radius: 50%;
    border: 0;
    background: var(--ink);
    color: var(--bg);
    font-size: 20px;
    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 { font-size: 22px; font-weight: 600; letter-spacing: -0.02em; color: var(--ink); line-height: 1.2; }
#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 */
#app .baby-head-edit { margin-left: auto; padding: 8px 12px; }
#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; }
#app .baby-editable { cursor: pointer; -webkit-tap-highlight-color: transparent; }

/* status card — the module's one hero surface */
#app .baby-status {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r-card);
    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: 11px; 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: 1px solid var(--line2);
    background: var(--card2);
    border-radius: 999px;
    padding: 3px 10px;
}

/* 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;
}
#app .baby-daynav-arrow {
    border: 0;
    background: none;
    padding: 4px;
    color: var(--ink2);
    cursor: pointer;
    font-size: 13px;
    -webkit-tap-highlight-color: transparent;
}
#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: 1px solid var(--line2);
    background: var(--card2);
    border-radius: var(--r-pill);
    padding: 3px 10px;
    font-size: var(--fs-cap);
    font-weight: 600;
    color: var(--ink);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

/* ---- Tagesbogen (design/BRIEF-BABY-TAGESBOGEN.md) ---- */
#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: 10.5px; 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: 13.5px; color: inherit; margin-top: 0; font-weight: 600; }
#app .ringCtr small { font-size: 10.5px; 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: 13px;
    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: 12px;
    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: 12px; 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: 13px;
    padding: 10px 12px;
    font-size: 12px;
    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: 12.5px; font-weight: 600; }
#app .riHead .riSub { font-size: 10.5px; 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: 11px; font-weight: 600; color: var(--ink2); width: 76px; flex-shrink: 0; font-variant-numeric: tabular-nums; }
#app .riRow .riL { font-size: 12px; 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: 25px; font-weight: 600; 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: 12.5px; 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 "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: 99px; }
#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: 12px; font-weight: 600; color: var(--pc-ink); margin-top: 2.5px; display: block; }
#app .msAge small { font-size: 10.5px; font-weight: 500; color: var(--ink3); margin-left: 7px; }
#app .msNote { font-size: 11.5px; 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: 13px; 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: 11px; 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: 12px; 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: 10.5px; 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: 11px; 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: 12px; background: transparent; color: var(--ink2); font-weight: 600; font-size: 12.5px; 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: 13px;
    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: 13px;
}
/* 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); }
#app .baby-ev-edit { margin: -8px -8px -8px auto; flex: none; align-self: center; 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.05em;
    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(--card);
}
#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: 1px solid var(--line);
    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-ui); 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: 12.5px; }
#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 one-tap sleep button — a padded block button at the card's bottom */
#app .baby-w-quick {
    align-self: stretch;
    margin: 8px 13px 13px;
    margin-top: auto;
    border-radius: 11px;
    padding: 11px;
    font-size: var(--fs-body);
}

/* ============================== 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: 12px;
    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-ren { font-size: 12px; }
#app .ent-file-rename { flex: 1; min-width: 0; font-size: inherit; }
#app .ent-files .ent-file-add { align-self: flex-start; }
#app .ent-files-status { font-size: var(--fs-cap); color: var(--ink2); min-height: 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: 12px;
}
#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 { width: 16px; height: 16px; flex: none; accent-color: var(--ink); }
/* 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: 12.5px;
    padding: 12px 0;
    text-align: center;
}

/* 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; }
#app .settings-avatar-actions { display: flex; flex-direction: column; gap: 6px; flex: 1; min-width: 0; }
#app .settings-avatar-actions .action-btn { width: 100%; }
#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-ui); 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: 12px;
    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: 12.5px; color: var(--ink); }
#app .usage-count { font-size: 12.5px; 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); }

/* 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: 11px;
    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(--card); }
#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); }
/* 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: 14.5px; font-weight: 600; display: flex; align-items: center; gap: 7px; }
#app .uMem .nm .you { font-size: 10.5px; font-weight: 600; color: var(--ink3); }
#app .uMem .rl { font-size: 12px; 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: 11px; 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 input { width: 16px; height: 16px; flex: none; accent-color: var(--ink); }
#app .settings-support-info { font-size: 11.5px; 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: 12px;
    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: 9px; border: 1px solid var(--line); 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: 12px; 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: 12px; 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: 13px; 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(--card); border-radius: 99px; padding: 2px 8px; }
#app .clDate { font-size: 11.5px; 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: 13px; 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: 12px; 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(--card);
    border-radius: 99px;
    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: 12px;
    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: 12px; color: var(--pend-ink); line-height: 1.5; }
#app .plan-cycle { display: flex; background: var(--card2); border: 1px solid var(--line); border-radius: 99px; padding: 3px; margin: 16px 0 4px; }
#app .plan-cycle button {
    flex: 1;
    border: 0;
    background: transparent;
    color: var(--ink2);
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    padding: 8px;
    border-radius: 99px;
    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: 11px; font-weight: 500; color: var(--ink3); }
#app .plan-meta { font-size: 11.5px; 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: 12.5px; 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: 11px;
    padding: 11px;
    font-family: inherit;
    font-size: 12.5px;
    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: 10px;
    font-weight: 600;
    letter-spacing: 0.07em;
    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: 12.5px; }
#app .plan-sec-lbl + .addon-row { border-top: 0; }
#app .addon-sub { color: var(--ink3); font-size: 11px; }
#app .addon-price { margin-left: auto; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
#app .plan-foot { font-size: 11px; 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: 12.5px; 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: 12px;
    padding: 13px 14px;
    margin-top: 8px;
    font-family: inherit;
    font-size: 13.5px;
    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: 12.5px; color: var(--ink2); line-height: 1.55; }
#app .cal-imp-err { font-size: 12.5px; color: var(--due-ink); margin-top: 10px; }
#app .cal-imp-file { display: none; }
#app .cal-imp-head { font-size: 12px; color: var(--ink2); line-height: 1.5; }
#app .cal-imp-cap { font-size: 11.5px; 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: 12px;
    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"] { width: 16px; height: 16px; flex: none; accent-color: var(--ink); }
#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: 99px;
    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(--card); }
#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"] { width: 16px; height: 16px; flex: none; accent-color: var(--ink); }
#app .exp-hint { font-size: 11.5px; 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: 12px; 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 {
    border: 0;
    border-radius: var(--r-pill);
    background: var(--ink);
    color: var(--bg);
    font-family: var(--font-family);
    font-size: var(--fs-ui);
    font-weight: 600;
    padding: 7px 14px;
    cursor: pointer;
    transition: transform var(--transition-fast);
}
.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 12px;
    font-family: var(--font-family);
    font-size: 13px;
    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 */
.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: 14.5px;
    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;
}
#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-frame { width: 100%; height: 100%; border: 0; border-radius: var(--r-ctl); background: var(--card); }
#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: 13px;
    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: 13.5px; font-weight: 500; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fm-tx > span { display: block; font-size: 11.5px; 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: 11px; }
.fm-link-hint { font-size: 11.5px; 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: 11px; 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: 13px;
    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 12px;
    font-family: var(--font-family);
    font-size: 13px;
    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;
}

/* ── Module headings: the display serif ────────────────────────────────────────
   The ONLY place a second font appears (design/DESIGN.md §3): the dashboard
   greeting, the calendar's view title, Notizen's page title and the baby's name.
   Size/weight/letter-spacing come with it — the serif carries 700 and one shared
   24px, not the 600 and per-element sizes the sans headings had. 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 {
    font-family: var(--disp), var(--font-family), serif;
    font-optical-sizing: auto;
    font-weight: 700;
    font-size: 24px;
    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);
}
