/* ============================================================
   eikori — calm design system
   Light is default; [data-theme="dark"] flips the tokens.
   ============================================================ */

:root,
[data-theme="light"] {
    --bg: #f7f4ee;
    --bg-tint: #efece3;
    --surface: #fffdf9;
    --surface-2: #f4f1ea;
    --ink: #2a2723;
    --ink-soft: #514c44;
    --muted: #837c70;
    --border: #e6e0d4;
    --border-strong: #d7d0c1;
    --primary: #3f6f63;
    --primary-hover: #335a50;
    --primary-ink: #ffffff;
    --primary-soft: #e6efe9;
    --accent: #c08a4a;
    --danger: #a8443a;
    --danger-soft: #f6e7e4;
    --success: #3f6f63;
    --shadow: 0 1px 2px rgba(42, 39, 35, .04), 0 8px 24px rgba(42, 39, 35, .06);
    --shadow-sm: 0 1px 2px rgba(42, 39, 35, .06);
    --radius: 16px;
    --radius-sm: 10px;
    --radius-pill: 999px;
}

[data-theme="dark"] {
    --bg: #1c1b19;
    --bg-tint: #232120;
    --surface: #26241f;
    --surface-2: #2f2c27;
    --ink: #f0ece4;
    --ink-soft: #d3cdc1;
    --muted: #a39c8e;
    --border: #3a3631;
    --border-strong: #4a453e;
    --primary: #7bb3a4;
    --primary-hover: #8cc2b3;
    --primary-ink: #15201c;
    --primary-soft: #2b3a35;
    --accent: #d6a468;
    --danger: #e08a80;
    --danger-soft: #3a2a28;
    --success: #7bb3a4;
    --shadow: 0 1px 2px rgba(0, 0, 0, .25), 0 10px 28px rgba(0, 0, 0, .35);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
    margin: 0;
    font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    background: var(--bg);
    color: var(--ink);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, .brand__name {
    font-family: 'Fraunces', Georgia, 'Times New Roman', serif;
    color: var(--ink);
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.01em;
}

a { color: var(--primary); text-decoration: none; }
a:hover { color: var(--primary-hover); text-decoration: underline; }

/* Headings receive programmatic focus on navigation (FocusOnNavigate) for
   screen readers — keep that, but don't draw a visible focus box on them. */
h1:focus, h2:focus, h3:focus,
h1:focus-visible, h2:focus-visible, h3:focus-visible { outline: none; }

p { color: var(--ink-soft); }

/* ---------- App shell ---------- */
.app-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.app-header {
    position: sticky;
    top: 0;
    z-index: 20;
    background: color-mix(in srgb, var(--bg) 86%, transparent);
    backdrop-filter: saturate(140%) blur(10px);
    border-bottom: 1px solid var(--border);
}

.app-header__inner {
    max-width: 1080px;
    margin: 0 auto;
    padding: .7rem 1.5rem;
    display: flex;
    align-items: center;
    gap: 1.25rem;
}

.brand { display: inline-flex; align-items: center; gap: .55rem; }
.brand:hover { text-decoration: none; }

.brand__mark { width: 30px; height: 30px; display: block; }

.brand__name { font-size: 1.4rem; color: var(--ink); }

.app-nav { display: flex; gap: .25rem; margin-left: .5rem; }

.app-nav__link {
    padding: .4rem .75rem;
    border-radius: var(--radius-sm);
    color: var(--ink-soft);
    font-weight: 500;
    font-size: .95rem;
}
.app-nav__link:hover { background: var(--surface-2); text-decoration: none; color: var(--ink); }
.app-nav__link.active { background: var(--primary-soft); color: var(--primary); }

.app-header__actions {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: .6rem;
}

.user-chip {
    max-width: 180px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--muted);
    font-size: .9rem;
}

.household-chip {
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--primary);
    background: var(--primary-soft);
    font-weight: 600;
    font-size: .9rem;
    padding: .35rem .85rem;
    border-radius: var(--radius-pill);
}
.household-chip:hover { color: var(--primary-hover); text-decoration: none; }

/* ---------- Header menus (avatar + always-available hamburger) ---------- */
/* The hamburger belongs to narrow screens. It used to be shown at every width on the theory that
   some people prefer a full menu — but beside the inline navigation it is the same sections twice,
   and a reader has to work out that the two are one thing. Ken, 2026-07-31. */
.nav-menu { display: none; }

.menu { position: relative; }
.menu > summary { list-style: none; cursor: pointer; outline: none; }
.menu > summary::-webkit-details-marker { display: none; }

.avatar {
    width: 36px; height: 36px; border-radius: 50%;
    background: var(--primary-soft); color: var(--primary);
    display: inline-flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: .85rem; border: 1px solid var(--border);
}
.menu[open] .avatar, .avatar:hover { box-shadow: 0 0 0 3px var(--primary-soft); }
.avatar { overflow: hidden; padding: 0; }

/* Resolved avatar (photo / preset / gravatar / initials). */
.ua {
    position: relative; display: inline-flex; align-items: center; justify-content: center;
    width: var(--ua-size, 36px); height: var(--ua-size, 36px);
    border-radius: 50%; overflow: hidden; flex: 0 0 auto;
    background: var(--primary-soft); color: var(--primary);
}
.ua__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ua__preset, .ua__preset svg { width: 100%; height: 100%; display: block; }
.ua__initials {
    display: none; width: 100%; height: 100%;
    align-items: center; justify-content: center;
    font-weight: 700; font-size: calc(var(--ua-size, 36px) * .4);
}
.ua__initials--show { display: flex; }
.ua--lg { --ua-size: 96px; }
.avatar-preset-grid { display: flex; flex-wrap: wrap; gap: .6rem; }
.avatar-preset-grid label { cursor: pointer; }
.avatar-preset-grid input { position: absolute; opacity: 0; width: 0; height: 0; }
.avatar-preset-grid .ua { box-shadow: 0 0 0 2px var(--border); }
.avatar-preset-grid input:checked + .ua { box-shadow: 0 0 0 3px var(--primary); }

/* A header button that is only an icon — currently the household feed, which earns a place of its
   own because people look in on it several times a day. Sized to match the hamburger beside it so
   the row reads as one set of controls rather than three unrelated shapes. */
.icon-btn {
    width: 40px; height: 36px; border-radius: var(--radius-sm);
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--surface-2); border: 1px solid var(--border);
    color: var(--ink-soft); flex: 0 0 auto;
}
.icon-btn:hover { background: var(--primary-soft); color: var(--primary); text-decoration: none; }
.icon-btn svg { width: 20px; height: 20px; display: block; }

.hamburger {
    width: 40px; height: 36px; border-radius: var(--radius-sm);
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--surface-2); border: 1px solid var(--border);
    color: var(--ink); font-size: 1.15rem;
}

.menu__panel {
    position: absolute; right: 0; top: calc(100% + .5rem); z-index: 50;
    min-width: 210px; background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); box-shadow: var(--shadow); padding: .4rem;
}
.menu__head {
    display: flex; flex-direction: column; gap: .1rem;
    padding: .5rem .6rem; border-bottom: 1px solid var(--border); margin-bottom: .3rem;
}
.menu__head strong { color: var(--ink); }
.menu__sub { color: var(--muted); font-size: .82rem; overflow: hidden; text-overflow: ellipsis; }
.menu__item {
    display: block; width: 100%; text-align: left; box-sizing: border-box;
    padding: .55rem .6rem; border-radius: var(--radius-sm);
    color: var(--ink-soft); font: inherit; background: transparent; border: 0;
    cursor: pointer; text-decoration: none;
}
.menu__item:hover { background: var(--surface-2); color: var(--ink); text-decoration: none; }
.menu__item--button { color: var(--danger); }
.menu__item--button:hover { background: var(--danger-soft); color: var(--danger); }

/* Section dropdowns in the desktop nav (shorter, tree-like). */
.nav-section__summary {
    display: inline-flex; align-items: center; gap: .4rem;
    padding: .4rem .7rem; border-radius: var(--radius-pill);
    color: var(--ink-soft); font-size: .95rem; white-space: nowrap;
}
.nav-section__summary::after { content: "▾"; font-size: .7rem; color: var(--muted); }
.nav-section__summary:hover, .nav-section[open] > .nav-section__summary {
    background: var(--surface-2); color: var(--ink);
}
.nav-section__icon { display: inline-flex; align-items: center; color: var(--primary); }
.nav-section .menu__panel { left: 0; right: auto; }
.nav-item.menu__item { display: flex; align-items: center; gap: .5rem; }
.nav-item__icon { display: inline-flex; align-items: center; color: var(--primary); }
.nav-section__icon svg, .nav-item__icon svg { width: 1.1rem; height: 1.1rem; }
.menu__panel--sections { min-width: 252px; max-height: 78vh; overflow-y: auto; }
.menu__section-head {
    display: flex; align-items: center; gap: .4rem;
    padding: .55rem .6rem .25rem; margin-top: .2rem;
    font-size: .72rem; text-transform: uppercase; letter-spacing: .05em;
    color: var(--muted); font-weight: 700;
}

/* Two-level collapsible groups inside the always-available hamburger menu. */
.menu__group { border-radius: var(--radius-sm); }
.menu__group > summary {
    list-style: none; cursor: pointer;
    display: flex; align-items: center; gap: .45rem;
    padding: .5rem .6rem; border-radius: var(--radius-sm);
    font-weight: 600; color: var(--ink);
}
.menu__group > summary::-webkit-details-marker { display: none; }
.menu__group > summary::after {
    content: "▸"; margin-left: auto; color: var(--muted); font-size: .8rem;
    transition: transform .15s ease;
}
.menu__group[open] > summary::after { transform: rotate(90deg); }
.menu__group > summary:hover { background: var(--surface-2); }
.menu__group-items { padding-left: .65rem; margin-bottom: .15rem; }

@media (max-width: 760px) {
    .app-nav--desktop { display: none; }
    .nav-menu { display: inline-block; }
    .household-chip { max-width: 120px; }
}

.logout-form { margin: 0; }

.app-main {
    flex: 1 0 auto;
    width: 100%;
    max-width: 1080px;
    margin: 0 auto;
    padding: 2.5rem 1.5rem 3.5rem;
}

.app-main--wide {
    /* Admin is dense, tabular work: keys and values side by side, one row per record. The 1080px
       measure that keeps prose readable just makes those tables scroll sideways for no reason on a
       desktop, which is where this work is actually done. Ken, 2026-07-31. */
    max-width: 1440px;
}

.data-table {
    width: 100%;
    border-collapse: collapse;
}

.data-table th,
.data-table td {
    padding: .5rem .55rem;
    text-align: left;
    vertical-align: middle;
}

.data-table thead tr {
    border-bottom: 1px solid var(--border);
}

.data-table tbody tr + tr {
    border-top: 1px solid var(--border);
}

/* Wraps a table so a narrow window scrolls it instead of clipping the last column — which is what
   hid the "replace" button on the secrets page. */
.data-table-scroll {
    overflow-x: auto;
}

/* Delivery-status badges. Colour carries the meaning at a glance, but never alone — the word is
   always there too, because roughly one man in twelve cannot separate the green from the red. */
.badge {
    display: inline-block;
    padding: .16rem .55rem;
    border-radius: 999px;
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .01em;
    white-space: nowrap;
    color: #fff;
    background: var(--muted);
}

/* Ours. "submitted" is the neutral we-handed-it-over state; "not-sent" is red because mail
   disappearing into the log outbox is a fault, not a status. */
.badge--submitted { background: #4a6d8f; }
.badge--notsent   { background: #b23c3c; }
.badge--failed    { background: #b23c3c; }

.badge--queued    { background: #b9873a; }
.badge--sent      { background: #2b6cb0; }
.badge--delivered { background: #2b6cb0; }
.badge--open      { background: #4a8f6d; }
.badge--click     { background: #2f7d52; }
.badge--unsub     { background: #b23c3c; }
.badge--blocked   { background: #a85422; }
.badge--spam      { background: #a34a6a; }
.badge--bounce    { background: #7a4bb5; }
.badge--deferred  { background: #7c4a2a; }

/* Narrow screens: a table that scrolls sideways is a table nobody reads on a phone. Each row
   becomes its own card, and every cell carries its column name from data-label — which is why the
   markup sets that attribute even though wide screens never show it. */
@media (max-width: 760px) {
    .data-table,
    .data-table thead,
    .data-table tbody,
    .data-table tr,
    .data-table th,
    .data-table td {
        display: block;
    }

    .data-table thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }

    .data-table tbody tr {
        border: 1px solid var(--border);
        border-radius: var(--radius-sm);
        padding: .75rem .9rem;
        margin-bottom: .75rem;
        background: var(--surface);
    }

    .data-table tbody tr + tr { border-top: 1px solid var(--border); }

    .data-table td {
        padding: .22rem 0;
        display: flex;
        gap: .75rem;
        align-items: baseline;
        justify-content: space-between;
    }

    .data-table td::before {
        content: attr(data-label);
        color: var(--muted);
        font-size: .82rem;
        flex: 0 0 auto;
    }

    /* A cell with no label is a full-width one — an action button, or the expandable history. */
    .data-table td[data-label=""]::before { content: none; }
    .data-table td[data-label=""] { display: block; }

    .data-table-scroll { overflow-x: visible; }
}

.admin-filters {
    display: flex;
    gap: .75rem;
    flex-wrap: wrap;
    align-items: flex-end;
    margin-bottom: .75rem;
}
.admin-filters .nb-input { min-width: 12rem; }

.data-table__sub td { padding-top: 0; }
.data-table__sub summary { cursor: pointer; color: var(--muted); font-size: .88rem; }
.mail-history { list-style: none; margin: .5rem 0 .25rem; padding: 0; display: grid; gap: .35rem; }
.mail-history li { display: flex; gap: .6rem; align-items: baseline; flex-wrap: wrap; }

.nowrap { white-space: nowrap; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.cell-actions { text-align: right; white-space: nowrap; }
@media (max-width: 760px) { .cell-actions { text-align: left; } }

/* Dialogs. The fleet rule: a row action that needs input answers where the reader is looking, not
   in a form rendered below the list where the button appears dead. */
.dialog-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .55);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    z-index: 100;
}

/* Fixed and self-centring, not merely centred by the backdrop's flexbox. The backdrop-centred
   version only works when the dialog is nested inside it, and writing them as siblings — which
   looks equally reasonable — put the dialog in normal flow at the very bottom of the page: the
   screen dimmed and the content was somewhere below the fold. It failed silently, on a screen an
   administrator uses to give money away. Now it lands in front of the reader either way. */
.dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 101;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.6rem;
    width: calc(100% - 2rem);
    max-width: 34rem;
    max-height: min(85vh, 100dvh - 3rem);
    overflow-y: auto;
}

.dialog__title { margin: 0 0 .35rem; font-size: 1.25rem; word-break: break-all; }
.dialog__actions { display: flex; gap: .6rem; justify-content: flex-end; margin-top: 1.25rem; }

/* Full screen on a phone. A dialog you have to pinch at is worse than no dialog. */
@media (max-width: 600px) {
    .dialog-backdrop { padding: 0; align-items: stretch; }
    .dialog {
        max-width: none;
        max-height: none;
        min-height: 100dvh;
        border: 0;
        border-radius: 0;
    }
    .dialog__actions { flex-direction: column-reverse; }
    .dialog__actions .nb-btn { width: 100%; }
}

/* A field with a button beside it — the button sizes to its text, the field takes the rest. */
.input-with-action { display: flex; gap: .5rem; align-items: stretch; }
.input-with-action .field-input { flex: 1 1 auto; min-width: 0; }
.input-with-action .nb-btn { flex: 0 0 auto; }

.admin-toolbar {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: .75rem;
}
.admin-toolbar h2 { margin: 0; }

/* Says which hat you are wearing, and keeps saying it. Deliberately not hidden on narrow screens
   the way the household chip's name is truncated — on a phone the admin navigation disappears into
   the menu button, so this becomes the only thing on screen that answers "where am I". */
.admin-chip {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .2rem .6rem;
    border-radius: 999px;
    border: 1px solid var(--accent);
    color: var(--accent);
    background: transparent;
    font-size: .8rem;
    font-weight: 600;
    letter-spacing: .02em;
    text-decoration: none;
    white-space: nowrap;
}

.admin-chip:hover { background: color-mix(in srgb, var(--accent) 14%, transparent); }

/* The browser's own file button is a bare grey system control that ignores the theme entirely —
   the same "looks unfinished" that Ken has now pointed at twice. Style the part we are allowed to. */
input[type="file"].field-input {
    padding: .45rem;
    cursor: pointer;
}

input[type="file"].field-input::file-selector-button {
    margin-right: .75rem;
    padding: .35rem .8rem;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--surface-2, var(--surface));
    color: var(--ink);
    font: inherit;
    font-size: .9rem;
    cursor: pointer;
}

input[type="file"].field-input::file-selector-button:hover {
    border-color: var(--accent);
}

/* A second section inside a card must look like a second section.
   "Pending invitations" sat flush against the Send button above it and read as part of that form —
   Ken has seen the same collision in several places, so this is a rule rather than a patch on the
   one page. A heading that is not the first thing in a card gets room and a hairline above it; the
   line does the separating so the heading does not have to carry it alone. */
.card-surface > h2:not(:first-child),
.card-surface > h3:not(:first-child) {
    margin-top: 2rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--border);
}

/* Where a divider is already drawn by hand, do not draw a second one. */
.card-surface > hr + h2,
.card-surface > hr + h3 {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}

.app-footer__version {
    color: var(--muted);
    font-size: .78rem;
    opacity: .7;
}

.app-footer {
    border-top: 1px solid var(--border);
    color: var(--muted);
    font-style: italic;
    text-align: center;
    padding: 1.25rem;
    font-size: .9rem;
}

/* ---------- Appearance toggle ---------- */
.theme-toggle {
    display: inline-flex;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    padding: 2px;
}
.theme-toggle__btn {
    border: 0;
    background: transparent;
    color: var(--muted);
    padding: .5rem .9rem;
    border-radius: var(--radius-pill);
    cursor: pointer;
    font-size: .9rem;
    font-weight: 600;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    justify-content: center;
}
.theme-toggle__btn:hover { color: var(--ink); }
html[data-theme-mode="light"] .theme-toggle__btn[data-mode="light"],
html[data-theme-mode="dark"] .theme-toggle__btn[data-mode="dark"],
html[data-theme-mode="system"] .theme-toggle__btn[data-mode="system"] {
    background: var(--surface);
    color: var(--primary);
    box-shadow: var(--shadow-sm);
}

/* ---------- Buttons (bespoke, nb- prefix to avoid Bootstrap clash) ---------- */
.nb-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    font: inherit;
    font-weight: 600;
    padding: .7rem 1.25rem;
    border-radius: var(--radius-pill);
    border: 1px solid transparent;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease, transform .05s ease;
    text-decoration: none;
    line-height: 1.2;
}
.nb-btn:hover { text-decoration: none; }
.nb-btn:active { transform: translateY(1px); }
.nb-btn--sm { padding: .45rem .9rem; font-size: .9rem; }
.nb-btn--lg { padding: .85rem 1.6rem; font-size: 1.05rem; }
.nb-btn--primary { background: var(--primary); color: var(--primary-ink); }
.nb-btn--primary:hover { background: var(--primary-hover); color: var(--primary-ink); }
.nb-btn--ghost { background: transparent; color: var(--ink-soft); border-color: var(--border-strong); }
.nb-btn--ghost:hover { background: var(--surface-2); color: var(--ink); }
.nb-btn--block { width: 100%; }
.nb-btn--danger { background: var(--danger); color: #fff; }
.nb-btn--danger:hover { background: color-mix(in srgb, var(--danger) 85%, black); color: #fff; }

/* Two-step remove (ConfirmRemove.razor). The summary looks like the old one-tap button; opening it
   reveals the actual submit beside it. Closing the details again is the cancel. */
.confirm-remove { display: inline-flex; align-items: center; gap: .4rem; }
.confirm-remove > summary { list-style: none; cursor: pointer; }
.confirm-remove > summary::-webkit-details-marker { display: none; }
.confirm-remove__ask { display: inline-flex; align-items: center; gap: .4rem; }

/* Password-style field with an eye toggle (vault secret value). */
.reveal-wrap { position: relative; display: block; }
.reveal-wrap .field-input { padding-right: 2.6rem; }
.reveal-toggle {
    position: absolute; right: .35rem; top: 50%; transform: translateY(-50%);
    background: transparent; border: 0; cursor: pointer; font-size: 1rem;
    color: var(--muted); padding: .3rem .45rem; border-radius: var(--radius-sm);
}
.reveal-toggle:hover { background: var(--surface-2); color: var(--ink); }

.comment__time { display: block; color: var(--muted); font-size: .72rem; margin-top: .15rem; }
.comment__editwrap { margin-top: .2rem; }
.comment__editwrap > summary {
    list-style: none; cursor: pointer; color: var(--primary);
    font-size: .78rem; display: inline-block;
}
.comment__editwrap > summary::-webkit-details-marker { display: none; }
.comment__editwrap .comment-add { margin-top: .35rem; }

/* Filter box that sits above a long <select> (PickerFilter.razor). */
.picker-filter { margin-bottom: .35rem; font-size: .9rem; }

/* ---------- Cards ---------- */
.card-surface {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.75rem;
}

.section-lead { color: var(--muted); max-width: 60ch; }

/* ---------- Add disclosures (tuck add-forms away) ---------- */
.add-disclosure { margin-top: 1rem; border-top: 1px solid var(--border); padding-top: 1rem; }
.add-disclosure > summary {
    cursor: pointer; color: var(--primary); font-weight: 600; font-size: .95rem;
    list-style: none; display: inline-block;
}
.add-disclosure > summary::-webkit-details-marker { display: none; }
.add-disclosure[open] > summary { margin-bottom: .9rem; }

/* ---------- Inventory items + photos ---------- */
.inv-item { list-style: none; padding: .8rem 0; border-bottom: 1px solid var(--border); }
.inv-item:last-child { border-bottom: 0; }
.photos-disclosure { margin-top: .5rem; }
.photos-disclosure > summary {
    cursor: pointer; color: var(--muted); font-weight: 600; font-size: .82rem;
    list-style: none; display: inline-block;
}
.photos-disclosure > summary::-webkit-details-marker { display: none; }
.photos-disclosure[open] > summary { color: var(--primary); }
.photo-grid { display: flex; flex-wrap: wrap; gap: .6rem; margin: .6rem 0; }
.photo-thumb { display: flex; flex-direction: column; align-items: center; gap: .25rem; }
.photo-thumb img {
    width: 88px; height: 88px; object-fit: cover;
    border-radius: var(--radius-sm); border: 1px solid var(--border); display: block;
}

/* ---------- Household members / invites ---------- */
.member-list { list-style: none; padding: 0; margin: 0; }
.member-row, .invite-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
    padding: .75rem 0;
    border-bottom: 1px solid var(--border);
}
.member-row:last-child, .invite-row:last-child { border-bottom: 0; }
/* ---------- Document list / preview ---------- */
.doc-item { padding: .75rem 0; border-bottom: 1px solid var(--border); list-style: none; }
.doc-item:last-child { border-bottom: 0; }
.doc-preview { margin-top: .6rem; }
.doc-preview > summary {
    cursor: pointer; color: var(--primary); font-size: .9rem; font-weight: 600;
    list-style: none; display: inline-block; padding: .2rem 0;
}
.doc-preview > summary::-webkit-details-marker { display: none; }
.doc-preview img { max-width: 100%; border-radius: var(--radius-sm); border: 1px solid var(--border); margin-top: .5rem; }
.doc-preview iframe { width: 100%; height: 460px; border: 1px solid var(--border); border-radius: var(--radius-sm); margin-top: .5rem; background: #fff; }

.role-badge {
    font-size: .8rem;
    font-weight: 600;
    color: var(--primary);
    background: var(--primary-soft);
    padding: .25rem .6rem;
    border-radius: var(--radius-pill);
    white-space: nowrap;
}

/* ---------- Hero / landing ---------- */
.hero__eyebrow {
    color: var(--primary);
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    font-size: .78rem;
}
.hero__lead { font-size: 1.18rem; color: var(--ink-soft); max-width: 46ch; }
.hero__actions { display: flex; align-items: center; gap: .9rem; flex-wrap: wrap; margin-top: 2rem; }
.hero__signin { color: var(--muted); font-size: .95rem; }

/* Clip the bleed of the absolutely-positioned aurora (inset -40px each side) so it
   never pushes a horizontal scrollbar on the page (beta F1). */
.landing { position: relative; overflow-x: clip; }

/* Warm "aurora" glow behind the hero — lively but soft. */
.landing__aurora {
    position: absolute;
    inset: -120px -40px auto -40px;
    height: 460px;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(closest-side at 18% 30%, color-mix(in srgb, var(--primary) 30%, transparent), transparent),
        radial-gradient(closest-side at 78% 18%, color-mix(in srgb, var(--accent) 34%, transparent), transparent),
        radial-gradient(closest-side at 55% 70%, color-mix(in srgb, var(--primary) 18%, transparent), transparent);
    filter: blur(28px);
    opacity: .8;
}

.landing__hero {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: 1.1fr .9fr;
    gap: 2.5rem;
    align-items: center;
    padding: 1.5rem 0 1rem;
}
.landing__copy { max-width: 600px; }
.landing__title {
    font-size: clamp(2.4rem, 5vw, 3.7rem);
    line-height: 1.04;
    margin: .6rem 0 1.1rem;
}
.text-gradient {
    background: linear-gradient(105deg, var(--primary), var(--accent) 90%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    display: inline;
}

/* Floating "memory cards" composition. */
.landing__visual {
    position: relative;
    min-height: 320px;
}
.memory-card {
    position: absolute;
    display: flex;
    flex-direction: column;
    gap: .5rem;
    width: 168px;
    padding: 1.1rem 1.2rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    animation: nb-float 7s ease-in-out infinite;
}
.memory-card__icon { font-size: 1.6rem; }
.memory-card__label { font-weight: 600; color: var(--ink); font-size: .98rem; }
.memory-card--1 { top: 8%;  left: 4%;  transform: rotate(-5deg); animation-delay: 0s; }
.memory-card--2 { top: 0;   right: 6%; transform: rotate(4deg);  animation-delay: .8s; }
.memory-card--3 { bottom: 6%; left: 16%; transform: rotate(3deg); animation-delay: 1.6s; }
.memory-card--4 { bottom: 12%; right: 2%; transform: rotate(-3deg); animation-delay: 2.4s;
    border-color: var(--primary); box-shadow: 0 10px 30px color-mix(in srgb, var(--primary) 30%, transparent); }
.memory-card--4 .memory-card__label { color: var(--primary); }

@keyframes nb-float {
    0%, 100% { translate: 0 0; }
    50% { translate: 0 -10px; }
}

/* Feature row below the hero. */
.feature-row {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.1rem;
    margin-top: 3rem;
}
.feature {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.5rem;
    box-shadow: var(--shadow-sm);
    transition: transform .15s ease, box-shadow .15s ease;
}
.feature:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.feature h3 { margin: .9rem 0 .35rem; font-size: 1.2rem; }
.feature p { margin: 0; font-size: .96rem; }
.feature__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px; height: 44px;
    border-radius: 14px;
    font-size: 1.25rem;
    color: var(--primary-ink);
    background: linear-gradient(140deg, var(--primary), var(--primary-hover));
}
.feature__badge--share { background: linear-gradient(140deg, #c8607a, #a8443a); }
.feature__badge--keep { background: linear-gradient(140deg, var(--accent), #a06a2e); }

@media (prefers-reduced-motion: reduce) {
    .memory-card { animation: none; }
}

@media (max-width: 860px) {
    .landing__hero { grid-template-columns: 1fr; gap: 1rem; }
    .landing__visual { min-height: 280px; order: 2; margin-top: 1rem; }
    .feature-row { grid-template-columns: 1fr; }
    .landing__aurora { height: 360px; }
}

/* ---------- Dashboard ---------- */
.dash-greeting { font-size: 1.05rem; color: var(--muted); margin-bottom: .25rem; }
.empty-state {
    background: linear-gradient(180deg, var(--surface), var(--surface-2));
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 2.5rem 2rem;
    box-shadow: var(--shadow);
}
.empty-state h2 { font-size: 1.65rem; margin: 0 0 .5rem; }
.card-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); margin-top: 1.75rem; }
/* Uniform row heights ONLY where there are actual columns. grid-auto-rows: 1fr means every row
   matches the tallest row — the rule that keeps side-by-side cards equal (Ken's requirement).
   Unqualified, it also applied to the single-column phone layout, where each card has its own row
   and every row inherited the tallest card's height: 842px of dead space between "Steder" and the
   add-thing form on /belongings, 986px on a manual's page. Found by Ken on his phone, 2026-08-03. */
@media (min-width: 640px) {
    .card-grid { grid-auto-rows: 1fr; }
}
.suggestion-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.5rem;
    box-shadow: var(--shadow-sm);
    display: flex;
    flex-direction: column;
    gap: .5rem;
}
.suggestion-card__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.6rem;
    height: 2.6rem;
    border-radius: var(--radius);
    background: var(--primary-soft);
    color: var(--primary);
}
.suggestion-card__icon svg { width: 1.4rem; height: 1.4rem; }
.suggestion-card h3 { font-size: 1.15rem; margin: 0; }
.suggestion-card p { margin: 0; font-size: .95rem; flex: 1; }
.suggestion-card .nb-btn { align-self: flex-start; margin-top: .5rem; }
.suggestion-card__actions { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-top: .5rem; }
.suggestion-card__actions .nb-btn { margin-top: 0; }
.suggestion-card__actions form { margin: 0; }
.card-mini-action {
    background: none;
    border: 0;
    color: var(--muted);
    font: inherit;
    font-size: .85rem;
    cursor: pointer;
    padding: .3rem .45rem;
    border-radius: var(--radius-sm);
}
.card-mini-action:hover { color: var(--ink); background: var(--surface-2); }
.card-snooze { position: relative; }
.card-snooze > summary { list-style: none; }
.card-snooze > summary::-webkit-details-marker { display: none; }
.card-snooze__menu {
    position: absolute;
    z-index: 25;
    top: calc(100% + .25rem);
    left: 0;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    padding: .25rem;
    display: flex;
    flex-direction: column;
    gap: .1rem;
    width: max-content;
}

/* ---------- Memory entries ---------- */
.memory-entry {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1rem 1.1rem;
    margin: 0 0 .85rem;
    background: var(--surface);
}
.memory-entry__by { font-size: .85rem; color: var(--muted); margin-bottom: .35rem; }
.memory-entry__body { margin: .35rem 0; white-space: pre-wrap; }
.memory-entry__photo { max-width: 100%; border-radius: var(--radius); margin-top: .5rem; display: block; }
.memory-entry__actions { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin-top: .6rem; }
/* Social-style image gallery: one image fills the width; several tile responsively. */
.memory-gallery { display: grid; gap: .4rem; margin-top: .5rem; grid-template-columns: 1fr; }
.memory-gallery:has(> img:nth-child(2)) { grid-template-columns: repeat(2, 1fr); }
.memory-gallery > .memory-entry__photo { margin-top: 0; object-fit: cover; width: 100%; aspect-ratio: 4 / 3; }
.memory-gallery:has(> img:only-child) > .memory-entry__photo { aspect-ratio: auto; }
.radio-row { display: flex; gap: .6rem; align-items: flex-start; margin-bottom: .6rem; cursor: pointer; }
.radio-row input { margin-top: .25rem; }

/* ---------- Memories: social composer + feed ---------- */
.memory-main { display: flex; flex-direction: column; gap: 1rem; }

.composer {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1rem 1.1rem 1.1rem;
    box-shadow: 0 1px 2px rgba(0,0,0,.04);
}
.composer--identity { padding: 1.25rem; }
.composer__head { display: flex; align-items: center; gap: .65rem; margin-bottom: .75rem; }
.composer__who { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem; }
.composer__as { font-weight: 600; color: var(--ink); }

/* The writing area: borderless, large, grows with the text. */
.composer__text {
    width: 100%; border: 0; background: transparent; resize: none;
    font-size: 1.18rem; line-height: 1.5; color: var(--ink);
    padding: .15rem 0; min-height: 2.6em; font-family: inherit;
}
.composer__text:focus { outline: none; }
.composer__text::placeholder { color: var(--muted); }

/* Optional title + milestone stay hidden until tapped from the toolbar. */
.composer__extra { display: none; margin: .35rem 0 .5rem; }
.composer__extra.is-open { display: block; }
.composer__title {
    width: 100%; border: 0; border-bottom: 1px solid var(--border); background: transparent;
    font-size: 1.05rem; font-weight: 600; color: var(--ink); padding: .35rem 0; font-family: inherit;
}
.composer__title:focus { outline: none; border-bottom-color: var(--primary); }
.composer__milestone {
    width: 100%; padding: .5rem .6rem; border: 1px solid var(--border);
    border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); font-family: inherit;
}

/* Inline image thumbnails with a remove button — the social "photos appear" feel. */
.composer__previews { display: flex; flex-wrap: wrap; gap: .5rem; margin: .35rem 0 .25rem; }
.composer__previews.is-empty { display: none; }
.composer__thumb { position: relative; width: 88px; height: 88px; border-radius: var(--radius-sm); overflow: hidden; }
.composer__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.composer__thumb-x {
    position: absolute; top: 3px; right: 3px; width: 22px; height: 22px; line-height: 20px;
    border: 0; border-radius: var(--radius-pill); background: rgba(0,0,0,.6); color: #fff;
    font-size: 16px; cursor: pointer; padding: 0; display: flex; align-items: center; justify-content: center;
}
.composer__thumb-x:hover { background: rgba(0,0,0,.8); }

.composer__bar {
    display: flex; align-items: center; justify-content: space-between; gap: .6rem;
    margin-top: .65rem; padding-top: .65rem; border-top: 1px solid var(--border);
}
.composer__tools { display: flex; align-items: center; gap: .25rem; }
.composer__tool {
    display: inline-flex; align-items: center; gap: .35rem; border: 0; background: transparent;
    color: var(--muted); cursor: pointer; padding: .45rem .55rem; border-radius: var(--radius-sm);
    font: inherit; font-size: .92rem;
}
.composer__tool:hover { background: var(--surface-2); color: var(--ink); }
.composer__tool.is-active { color: var(--primary); background: var(--primary-soft); }
.composer__tool-label { font-weight: 500; }
.composer__share { white-space: nowrap; }
.composer__change-panel { margin: -.25rem 0 .25rem; }
.composer__change-panel > summary { font-size: .85rem; color: var(--muted); }
@media (max-width: 480px) {
    .composer__tool-label { display: none; }
}

/* Feed posts: avatar + name + date header, like a memory wall. */
.post { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); padding: 1rem 1.1rem; }
.post__head { display: flex; align-items: center; gap: .6rem; margin-bottom: .5rem; }
.post__avatar {
    flex: 0 0 auto; width: 40px; height: 40px; border-radius: var(--radius-pill);
    background: var(--primary-soft); color: var(--primary); font-weight: 600; font-size: 1.05rem;
    display: flex; align-items: center; justify-content: center;
}
.post__meta { display: flex; flex-direction: column; line-height: 1.25; }
.post__author { font-weight: 600; color: var(--ink); display: inline-flex; align-items: center; flex-wrap: wrap; gap: .35rem; }
.post__date { font-size: .82rem; color: var(--muted); }

/* Tagging people (shared books): a wrap of selectable name chips. */
.people-picker { display: flex; flex-wrap: wrap; gap: .4rem; }
.people-chip {
    display: inline-flex; align-items: center; gap: .35rem; cursor: pointer;
    border: 1px solid var(--border); border-radius: var(--radius-pill);
    padding: .25rem .6rem .25rem .45rem; font-size: .9rem; background: var(--surface);
}
.people-chip:has(input:checked) { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }
.people-chip input { margin: 0; }
.post__mentions { margin: .35rem 0 0; font-size: .9rem; color: var(--muted); }

/* "Add to feed" checkbox shown on module create forms. */
.feed-check { display: flex; align-items: center; gap: .5rem; margin: .25rem 0 .9rem; cursor: pointer; color: var(--ink-soft); font-size: .92rem; }
.feed-check input { margin: 0; }

/* Activity posts (generated from module actions): subtle, with a link. */
.post__activity { display: flex; align-items: center; gap: .45rem; margin: .25rem 0; color: var(--ink-soft); }
.post__activity-icon { color: var(--accent); flex: 0 0 auto; }
.post__activity a { margin-left: .25rem; white-space: nowrap; }

/* Reaction bar: emoji buttons, the chosen one highlighted, counts inline. */
.post__reactions { display: flex; flex-wrap: wrap; gap: .3rem; margin: .6rem 0 .2rem; padding-top: .5rem; border-top: 1px solid var(--border); }
.react-btn {
    display: inline-flex; align-items: center; gap: .25rem; cursor: pointer;
    border: 1px solid transparent; border-radius: var(--radius-pill);
    background: transparent; padding: .2rem .5rem; font-size: 1.05rem; line-height: 1; color: var(--ink);
}
.react-btn:hover { background: var(--surface-2); }
.react-btn.has-count { border-color: var(--border); }
.react-btn.is-picked { border-color: var(--primary); background: var(--primary-soft); }
.react-count { font-size: .82rem; color: var(--muted); font-weight: 600; }
.react-btn.is-picked .react-count { color: var(--primary); }

/* Comments: small avatar bubble + text, an inline add box. */
.post__comments { margin-top: .5rem; display: flex; flex-direction: column; gap: .45rem; }
.comment { display: flex; align-items: flex-start; gap: .5rem; }
.comment__avatar {
    flex: 0 0 auto; width: 28px; height: 28px; border-radius: var(--radius-pill);
    background: var(--surface-2); color: var(--muted); font-size: .8rem; font-weight: 600;
    display: flex; align-items: center; justify-content: center;
}
.comment__bubble { background: var(--surface-2); border-radius: var(--radius-sm); padding: .35rem .6rem; }
.comment__bubble strong { display: block; font-size: .85rem; }
.comment__body { white-space: pre-wrap; }
.comment__del { border: 0; background: transparent; color: var(--muted); cursor: pointer; font-size: 1rem; line-height: 1; padding: .2rem .35rem; }
.comment__del:hover { color: var(--danger); }
.comment-add { display: flex; gap: .4rem; align-items: center; margin-top: .15rem; }
.comment-add .field-input { flex: 1; padding: .4rem .6rem; }

/* Inline post editor: a calm mini-composer, not a labelled form stack. */
.post__edit { width: 100%; }
.composer--edit { box-shadow: none; padding: .85rem; margin-top: .5rem; background: var(--surface-2); }
.composer--edit .composer__title { margin-bottom: .25rem; }
.composer--edit .composer__text { background: transparent; min-height: 3em; }
.composer__editmeta { display: flex; flex-wrap: wrap; gap: .9rem; margin: .5rem 0 .65rem; }
.inline-field { display: inline-flex; align-items: center; gap: .4rem; font-size: .85rem; color: var(--muted); }
.inline-field input, .inline-field select {
    border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface);
    color: var(--ink); padding: .35rem .5rem; font: inherit; font-size: .9rem;
}

/* Owner tag management */
.tag-list { list-style: none; padding: 0; margin: .25rem 0 .5rem; display: flex; flex-direction: column; gap: .35rem; }
.tag-row { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.tag-add { display: flex; gap: .5rem; align-items: center; }
.tag-add .field-input { flex: 1; }

/* ---------- Auth (centred card) ---------- */
.auth-wrap {
    min-height: 60vh;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: 1rem;
}
.auth-card {
    width: 100%;
    max-width: 440px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 2rem;
}
.auth-card h1 { font-size: 1.7rem; margin: 0 0 .25rem; }
.auth-card__lead { color: var(--muted); margin: 0 0 1.5rem; }
.auth-alt { margin-top: 1.5rem; text-align: center; color: var(--muted); font-size: .95rem; }
.auth-meta { margin-top: .75rem; text-align: center; font-size: .92rem; }

/* ---------- Bespoke form fields ---------- */
.field { margin-bottom: 1.1rem; }
.field > label { display: block; font-weight: 500; font-size: .92rem; margin-bottom: .35rem; color: var(--ink-soft); }
.field-hint { color: var(--muted); font-size: .82rem; margin-top: .3rem; }
.field-input,
.field select {
    width: 100%;
    padding: .7rem .85rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--bg-tint);
    color: var(--ink);
    font: inherit;
}
.field-input:focus,
.field select:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-soft);
    background: var(--surface);
}
.field-error { color: var(--danger); font-size: .85rem; margin-top: .3rem; display: block; }

/* Welcoming first-run empty state: large soft area graphic above the invite. */
.empty-state--welcome { text-align: center; }
.empty-state--welcome .empty-state-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 4.5rem;
    height: 4.5rem;
    border-radius: var(--radius);
    background: var(--primary-soft);
    color: var(--primary);
    margin-bottom: 1rem;
}
.empty-state--welcome .empty-state-icon svg { width: 2.4rem; height: 2.4rem; }
.empty-state--welcome .empty-state-body { margin: 1.25rem auto 0; text-align: left; }

/* Module page header: soft tinted area icon + title + lead. */
.page-header { display: flex; align-items: flex-start; gap: 1rem; margin: 0 0 .25rem; }
.page-header-icon {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    border-radius: var(--radius);
    background: var(--primary-soft);
    color: var(--primary);
    margin-top: .15rem;
}
.page-header-icon svg { width: 1.6rem; height: 1.6rem; }
.page-header-text { min-width: 0; }
.page-header-text h1 { margin: 0; display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; }
.page-header-text .section-lead { margin-top: .35rem; }
@media (max-width: 520px) {
    .page-header-icon { width: 2.5rem; height: 2.5rem; }
    .page-header-icon svg { width: 1.35rem; height: 1.35rem; }
}

/* Info affordance: click the (i) to reveal explanatory text as a floating popover. */
.info-hint { display: inline-block; position: relative; vertical-align: middle; }
.info-hint > summary.info-hint-trigger {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.4rem;
    height: 1.4rem;
    border-radius: var(--radius-pill);
    color: var(--muted);
    transition: color .15s ease, background-color .15s ease;
}
.info-hint > summary.info-hint-trigger::-webkit-details-marker { display: none; }
.info-hint > summary.info-hint-trigger:hover,
.info-hint[open] > summary.info-hint-trigger {
    color: var(--primary);
    background: var(--primary-soft);
}
.page-header-titlerow { display: inline-flex; align-items: center; gap: .45rem; }
.page-header-titlerow h1 { margin: 0; display: inline; }

.info-hint-body {
    position: absolute;
    z-index: 30;
    top: calc(100% + .4rem);
    left: 0;
    width: max-content;
    max-width: 19rem;
    background: var(--surface);
    color: var(--ink-soft);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    padding: .7rem .8rem;
    font-size: .85rem;
    line-height: 1.4;
    font-weight: 400;
}
.info-hint-body .info-hint-title { display: block; color: var(--ink); margin-bottom: .25rem; }
/* If the hint sits near the right edge, let callers flip it leftward. */
.info-hint.info-hint-end .info-hint-body { left: auto; right: 0; }
/* On a phone the hint used to open from its trigger and run 144px past the right edge — the
   explanation was simply unreadable. Fixed to the viewport's width instead: same content, same
   toggle, but the box spans the screen minus a margin, under the header. */
@media (max-width: 640px) {
    .info-hint-body {
        position: fixed;
        left: 1rem; right: 1rem; top: 4.2rem;
        width: auto; max-width: none;
    }
}

/* Profile: personal menu configuration (reorder sections, toggle items). */
.nav-cfg-section { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: .5rem .65rem; margin-bottom: .55rem; }
.nav-cfg-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: .25rem; }
.nav-cfg-ord { display: inline-flex; gap: .15rem; }
.nav-cfg-ord button[disabled] { opacity: .3; cursor: default; }
.nav-cfg-item { display: flex; align-items: center; gap: .5rem; padding: .25rem 0; cursor: pointer; }

/* Dashboard quick-link hub (visible once the household is set up). */
/* Norwegian compounds are long: "Bruksanvisninger", "Beredskapslager",
   "Gjenopprettingskart". At 160px two columns fit on a phone and the words did not, and a flex
   child defaults to min-width:auto — so instead of wrapping, the label ran out past the card edge.
   180px gives the narrowest phones a single column; the label rules below are what actually stop
   text escaping, at any width. */
.quick-links { display: grid; gap: .75rem; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); grid-auto-rows: 1fr; }
/* Cards in columns stay a grid, not a staircase (Ken, 2026-08-01). Grid already equalises height
   *within* a row; grid-auto-rows makes every row match the tallest, so one three-line label does
   not leave the card beside it looking clipped short. The trade is deliberate: uniform tiles cost
   some whitespace, and text we cannot control has to be allowed to be any length. Grids whose
   children are genuinely different things — a document panel next to a longer one — opt out with
   align-items: start, and those are not tiles. */

.quick-link__label {
    min-width: 0;
    overflow-wrap: anywhere;
    hyphens: auto;
}
.quick-link {
    display: flex;
    align-items: center;
    gap: .65rem;
    padding: .85rem 1rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    color: var(--ink);
    text-decoration: none;
    font-weight: 500;
    transition: border-color .15s ease, transform .1s ease;
}
.quick-link:hover { border-color: var(--primary); transform: translateY(-1px); }
.quick-link__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.2rem;
    height: 2.2rem;
    flex: 0 0 auto;
    border-radius: var(--radius-sm);
    background: var(--primary-soft);
    color: var(--primary);
}
.quick-link__icon svg { width: 1.2rem; height: 1.2rem; }

/* Inline take-out / add stock controls on a supply row. */
.stock-ops { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.stock-ops form { display: flex; gap: .3rem; align-items: center; }
.stock-ops .field-input { width: 4.5rem; }

/* Symbol+text choice buttons for a small set of options (radio under the hood). */
.choice-group { display: flex; flex-wrap: wrap; gap: .5rem; }
.choice-group > label { display: inline-flex; cursor: pointer; }
.choice-group input { position: absolute; opacity: 0; width: 0; height: 0; }
.choice-chip {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .5rem .85rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-pill);
    font-size: .9rem;
    color: var(--ink-soft);
    transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.choice-group label:hover .choice-chip { border-color: var(--primary); }
.choice-group input:checked + .choice-chip { background: var(--primary-soft); border-color: var(--primary); color: var(--primary); }
.choice-group input:focus-visible + .choice-chip { outline: 2px solid var(--primary); outline-offset: 2px; }

/* Selects shouldn't look identical to text inputs — add a caret affordance. */
select.field-input {
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23837c70' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
    background-repeat: no-repeat;
    background-position: right .75rem center;
    padding-right: 2.25rem;
    cursor: pointer;
}

.alert-note {
    border-radius: var(--radius-sm);
    padding: .75rem 1rem;
    margin-bottom: 1.25rem;
    font-size: .92rem;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--ink-soft);
}
.alert-note--ok { background: var(--primary-soft); border-color: var(--primary); color: var(--primary); }
.alert-note--error { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }

/* ============================================================
   Calm restyle of Bootstrap (used by secondary Identity pages)
   ============================================================ */
.btn { border-radius: var(--radius-pill); font-weight: 600; }
.btn-primary {
    --bs-btn-bg: var(--primary);
    --bs-btn-border-color: var(--primary);
    --bs-btn-hover-bg: var(--primary-hover);
    --bs-btn-hover-border-color: var(--primary-hover);
    --bs-btn-active-bg: var(--primary-hover);
    --bs-btn-active-border-color: var(--primary-hover);
    --bs-btn-color: var(--primary-ink);
    --bs-btn-hover-color: var(--primary-ink);
}
.btn-link { --bs-btn-link-color: var(--primary); --bs-btn-link-hover-color: var(--primary-hover); }
.form-control, .form-select {
    background: var(--bg-tint);
    border-color: var(--border-strong);
    color: var(--ink);
    border-radius: var(--radius-sm);
}
.form-control:focus, .form-select:focus {
    background: var(--surface);
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-soft);
    color: var(--ink);
}
.form-floating > label { color: var(--muted); }
.form-label { color: var(--ink-soft); font-weight: 500; }
h1 { font-size: 1.9rem; }

/* Identity pages render bare under our shell; give them breathing room. */
.app-main > h1:first-child { margin-bottom: 1rem; }

/* ---------- Blazor error UI ---------- */
#blazor-error-ui {
    color: var(--ink);
    background: var(--surface);
    border-top: 1px solid var(--border);
    bottom: 0;
    box-shadow: 0 -1px 8px rgba(0,0,0,.1);
    display: none;
    left: 0;
    padding: .8rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}
#blazor-error-ui .dismiss { cursor: pointer; position: absolute; right: 1rem; top: .6rem; }

.blazor-error-boundary {
    background: var(--danger-soft);
    padding: 1rem;
    border-radius: var(--radius-sm);
    color: var(--danger);
}

@media (max-width: 640px) {
    .app-header__inner { flex-wrap: wrap; gap: .75rem; padding: .6rem 1rem; }
    .app-nav { order: 3; width: 100%; }
    .user-chip { display: none; }
    .app-main { padding: 1.75rem 1rem 2.5rem; }
}

/* ---------- Print: clean printout (e.g. the emergency binder) ---------- */
/* Shown only when printing (e.g. a clean shopping list). */
.print-only { display: none; }

@media print {
    .app-header,
    .app-footer,
    .add-disclosure,
    .nb-btn,
    .theme-toggle,
    .no-print { display: none !important; }

    .print-only { display: block !important; }
    .app-main { padding: 0 !important; }
    .card-surface,
    .memory-entry { border-color: #ccc !important; box-shadow: none !important; break-inside: avoid; }
    .card-grid { display: block !important; }
    .card-grid > * { margin-bottom: 1rem; }
    a { color: inherit; text-decoration: none; }
    body { background: #fff !important; }
}

/* 404 / not-found */
.notfound { text-align: center; max-width: 460px; margin: 2rem auto; }
.notfound__art { margin: 0 auto .5rem; max-width: 240px; }
.notfound__code { font-family: var(--font-serif, "Fraunces", serif); font-size: 3.25rem; font-weight: 600; letter-spacing: .04em; margin: .25rem 0 0; color: var(--brand-green, #466559); line-height: 1; }
.notfound h1 { margin: .25rem 0 .5rem; }
.notfound .nb-btn { margin-top: 1rem; }

/* Footer legal links (privacy / cookies / terms) */
.app-footer__legal { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; margin-top: .4rem; font-style: normal; font-size: .85rem; }
.app-footer__legal a { color: var(--muted); text-decoration: none; }
.app-footer__legal a:hover { text-decoration: underline; }

/* Storage page. The bars are relative to the largest area, not to a quota — there is no quota
   yet, and a bar against an invented denominator would be a claim rather than a picture. */
.storage-total {
    font-size: 2.25rem;
    font-weight: 600;
    margin: 0;
    letter-spacing: -0.02em;
}

.storage-areas {
    list-style: none;
    margin: 1.75rem 0 0;
    padding: 0;
}

.storage-areas > li + li { margin-top: 1.25rem; }

.storage-area-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}

.storage-area-name {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
}

.storage-area-name svg { width: 1.05em; height: 1.05em; }

.storage-area-size {
    font-variant-numeric: tabular-nums;
    color: var(--muted);
}

.storage-bar {
    height: 6px;
    border-radius: 3px;
    background: var(--accent, currentColor);
    opacity: .55;
    margin: .4rem 0 .15rem;
    min-width: 2px;
}

/* Admin: the tab strip on a detail page. It scrolls sideways and never wraps — a tab row on two
   lines pushes the content off the screen, which is the original complaint in a new costume
   (admin-screens.md §8). */
.tabs {
    display: flex;
    gap: .25rem;
    margin: 1rem 0 1.25rem;
    overflow-x: auto;
    scrollbar-width: none;
    border-bottom: 1px solid var(--border);
}

.tabs::-webkit-scrollbar { display: none; }

.tabs__tab {
    flex: 0 0 auto;
    white-space: nowrap;
    padding: .6rem .9rem;
    color: var(--muted);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

.tabs__tab--on {
    color: var(--ink);
    border-bottom-color: var(--primary);
    font-weight: 600;
}

/* A list row whose whole width is the way in. The anchor is stretched over the row rather than the
   row being given a click handler, so it stays a real link — middle-click, copy address, and
   keyboard focus all keep working. */
.row-link { position: relative; }
.row-link:hover { background: var(--primary-soft); }
.row-link__a { text-decoration: none; color: var(--ink); font-weight: 600; }
.row-link__a::after { content: ""; position: absolute; inset: 0; }

/* Label/value pairs on a detail page. Two columns with room to breathe, one column on a phone. */
.facts { display: grid; grid-template-columns: max-content 1fr; gap: .5rem 1.25rem; margin: 0; }
.facts dt { color: var(--muted); }
.facts dd { margin: 0; }

@media (max-width: 520px) {
    .facts { grid-template-columns: 1fr; gap: .15rem; }
    .facts dd { margin-bottom: .6rem; }
}

/* A confirmation anchored to the viewport, not to the document.

   Named .save-note rather than .toast on purpose: Bootstrap is loaded here and owns .toast, where
   `.toast:not(.show) { display: none }` means a plain .toast is invisible. I wrote one and it never
   appeared — a generic class name in a page that loads a framework collides silently, and the
   symptom is identical to the bug this element exists to fix.
   admin-screens.md §7 says something must change inside the visible viewport without scrolling.
   Putting the message next to the button was not enough: the re-render after saving reset the
   scroll position, so both button and message ended up below the fold — the same failure as the
   sibling dialog, arrived at a different way. Fixed to the viewport, it cannot be scrolled away. */
.save-note {
    position: fixed;
    left: 50%;
    bottom: 1.25rem;
    transform: translateX(-50%);
    z-index: 200;
    max-width: min(32rem, calc(100% - 2rem));
    padding: .75rem 1.1rem;
    border-radius: var(--radius);
    background: var(--surface);
    border: 1px solid var(--primary);
    box-shadow: var(--shadow);
    color: var(--ink);
    text-align: center;
}

/* ----- reconnect dialog (Components/Layout/ReconnectModal.razor) -----
   Wired in on purpose (fleet broadcast 2026-08-05): without the component in the markup the
   framework injects its own inline-styled white div that no CSS reaches — white-on-white in dark
   mode, shown to someone who has already lost their connection. Colors ride the theme tokens, so
   both modes are right by construction. The class dance below is the framework's own contract. */
.components-reconnect-first-attempt-visible,
.components-reconnect-repeated-attempt-visible,
.components-reconnect-failed-visible,
.components-pause-visible,
.components-resume-failed-visible,
.components-rejoining-animation {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible,
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation,
#components-reconnect-modal.components-reconnect-paused .components-pause-visible,
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible,
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible,
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation,
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible {
    display: block;
}

#components-reconnect-modal.components-reconnect-failed #components-reconnect-button,
#components-reconnect-modal.components-reconnect-paused #components-resume-button,
#components-reconnect-modal.components-reconnect-resume-failed #components-resume-button {
    display: inline-block;
}

#components-reconnect-modal {
    background-color: var(--surface);
    color: var(--ink);
    width: min(20rem, calc(100vw - 2rem));
    margin: 20vh auto;
    padding: 1.5rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}

#components-reconnect-modal::backdrop {
    background-color: rgba(0, 0, 0, .4);
}

#components-reconnect-modal p {
    margin: 0;
    text-align: center;
}

.components-reconnect-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

/* The template's two-ring spinner, on our primary color. */
.components-rejoining-animation {
    position: relative;
    width: 60px;
    height: 60px;
}

.components-rejoining-animation div {
    position: absolute;
    border: 3px solid var(--primary);
    opacity: 1;
    border-radius: 50%;
    animation: components-rejoining-animation 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}

.components-rejoining-animation div:nth-child(2) {
    animation-delay: -0.75s;
}

@keyframes components-rejoining-animation {
    0% {
        top: 50%;
        left: 50%;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        opacity: 0;
    }
}

/* ----- favorites: the star, and the front-page chips -----
   The star toggles from the thing itself (a page header, a room); the chips are the same things
   on the front page. Per user — see UserFavorite. */
.fav-form { display: inline-flex; }

.fav-star {
    background: none;
    border: 0;
    cursor: pointer;
    font-size: 1.15rem;
    line-height: 1;
    padding: .2rem .3rem;
    color: var(--muted);
    border-radius: var(--radius-sm);
}

.fav-star:hover { color: var(--accent); background: var(--surface-2); }
.fav-star--on { color: var(--accent); }

.quick-links--favs { margin-bottom: 1rem; }

.fav-chip { display: inline-flex; align-items: stretch; }

.fav-chip__link { border-top-right-radius: 0; border-bottom-right-radius: 0; }

.fav-chip__remove { display: flex; }

.fav-chip__x {
    border: 1px solid var(--border);
    border-left: 0;
    border-top-right-radius: var(--radius);
    border-bottom-right-radius: var(--radius);
    background: var(--surface);
    color: var(--muted);
    cursor: pointer;
    padding: 0 .5rem;
    font-size: 1rem;
    line-height: 1;
}

.fav-chip__x:hover { color: var(--danger); background: var(--danger-soft); }

.guide-close {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    margin-top: 1rem;
}
