/* Paior — application styles.
   Monochrome by default; colour is reserved for meaning (event-type dots/legend).
   Mobile-first: baseline 375px wide, no horizontal scroll, tap targets >= 44px. */

:root {
    --ink: #111;
    --ink-soft: #444;
    --muted: #767676;
    --line: #e2e2e2;
    --line-strong: #cfcfcf;
    --bg: #fff;
    --bg-soft: #f7f7f7;
    --bg-active: #f0f0f0;
    --radius: 8px;
    --tap: 44px;
    --maxw: 960px;
    --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--font);
    font-size: 16px;
    line-height: 1.5;
    -webkit-text-size-adjust: 100%;
}

a { color: var(--ink); text-decoration: none; }
a:hover { text-decoration: underline; }
h1 { font-size: 1.5rem; margin: 0 0 .25rem; }
h2 { font-size: 1.125rem; margin: 0 0 .5rem; }
.muted { color: var(--muted); }
.hint { color: var(--muted); font-size: .85rem; margin: .25rem 0 0; }

/* ---- Top bar + nav (mobile-first: collapsible) ---- */
.topbar {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0 1rem; height: 56px;
    border-bottom: 1px solid var(--line);
    position: sticky; top: 0; background: var(--bg); z-index: 10;
}
.brand { font-weight: 700; letter-spacing: .02em; font-size: 1.2rem; }
.nav-toggle {
    width: var(--tap); height: var(--tap);
    border: 1px solid var(--line-strong); border-radius: var(--radius);
    background: var(--bg); font-size: 1.2rem; cursor: pointer;
}
.mainnav { display: none; flex-direction: column; border-bottom: 1px solid var(--line); }
body.nav-open .mainnav { display: flex; }
.mainnav a, .nav-logout button {
    display: flex; align-items: center; min-height: var(--tap);
    padding: 0 1rem; border-bottom: 1px solid var(--line);
    color: var(--ink); background: none; border-left: none; border-right: none; border-top: none;
    width: 100%; text-align: left; font: inherit; cursor: pointer;
}
.mainnav a.active { background: var(--bg-active); font-weight: 600; }
.nav-logout { margin: 0; }
.nav-logout button { color: var(--muted); }

/* ---- Content ---- */
.content { max-width: var(--maxw); margin: 0 auto; padding: 1rem; }
.page-head { margin-bottom: 1rem; }
.page-head p { margin: .25rem 0 0; }

/* ---- Flash ---- */
.flash { padding: .75rem 1rem; border-radius: var(--radius); margin-bottom: 1rem; border: 1px solid var(--line-strong); }
.flash-success { background: #f2f7f2; border-color: #cfe0cf; }
.flash-error { background: #fbf2f2; border-color: #e6cccc; }

/* ---- Panels ---- */
.panel {
    border: 1px solid var(--line); border-radius: var(--radius);
    padding: 1rem; margin-bottom: 1rem; background: var(--bg);
}
.panel legend { font-weight: 600; padding: 0 .35rem; }
.count { display: inline-block; min-width: 1.4em; padding: 0 .4em; margin-left: .25rem;
    font-size: .8rem; background: var(--ink); color: #fff; border-radius: 999px; text-align: center; }

/* ---- Stats ---- */
.stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: .75rem; margin-bottom: 1rem; }
.stat { display: flex; flex-direction: column; align-items: flex-start;
    border: 1px solid var(--line); border-radius: var(--radius); padding: .75rem 1rem; min-height: var(--tap); }
.stat:hover { text-decoration: none; background: var(--bg-soft); }
.stat-n { font-size: 1.6rem; font-weight: 700; line-height: 1; }
.stat-l { color: var(--muted); font-size: .85rem; margin-top: .25rem; }

.grid-2 { display: grid; grid-template-columns: 1fr; gap: 1rem; }

/* ---- Buttons ---- */
.btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: var(--tap); padding: 0 1rem;
    border: 1px solid var(--line-strong); border-radius: var(--radius);
    background: var(--bg); color: var(--ink); cursor: pointer; font: inherit;
}
.btn:hover { background: var(--bg-soft); text-decoration: none; }
.btn-primary { background: var(--ink); color: #fff; border-color: var(--ink); }
.btn-primary:hover { background: #000; }

/* ---- Forms ---- */
.stack { display: flex; flex-direction: column; gap: 1rem; }
label { display: block; font-weight: 500; }
input[type=text], input[type=email], input[type=password], input[type=date],
input[type=search], input[type=number], input[type=time], select, textarea {
    display: block; width: 100%; min-height: var(--tap);
    padding: .5rem .75rem; margin-top: .35rem;
    border: 1px solid var(--line-strong); border-radius: var(--radius);
    font: inherit; background: var(--bg); color: var(--ink);
}
textarea { min-height: 6rem; resize: vertical; }
/* A time is four characters wide. Full width it reads as a field someone forgot to
   fill in. Capped rather than fixed, so a browser that renders its own am/pm segment —
   or a larger system font — still has room for it. */
.w-time { width: auto; max-width: 100%; min-width: 9rem; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--ink); outline-offset: 1px; }
.form-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1rem; }
/* A checkbox beside its label, rather than stacked like a text field. */
.checkline { display: flex; align-items: center; gap: .5rem; min-height: var(--tap); font-weight: 500; }
.checkline input { width: auto; min-height: 0; margin: 0; }
.panel.danger { border-color: #e6cccc; }
.panel.danger h2 { color: #8a2b2b; }
.btn-danger { border-color: #c98c8c; color: #8a2b2b; }
.btn-danger:hover { background: #fbf2f2; }

/* ---- Lists (events, tasks, contacts) ---- */
.eventlist, .tasklist, .contactlist, .idlist, .mergelist, .mealweek, .shoplist, .meallib, .legend ul {
    list-style: none; margin: 0; padding: 0;
}
.eventlist li { display: flex; align-items: baseline; gap: .5rem; padding: .5rem 0; border-bottom: 1px solid var(--line); }
.eventlist li:last-child { border-bottom: none; }
.ev-time { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; font-size: .9rem; }
.ev-title { font-weight: 500; }

.tasklist li { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
    gap: .5rem; padding: .6rem 0; border-bottom: 1px solid var(--line); }
.tasklist li:last-child { border-bottom: none; }
.tasklist.done .task-title { color: var(--muted); text-decoration: line-through; }
.task-title { font-weight: 500; }
.task-meta { display: flex; align-items: center; gap: .5rem; color: var(--muted); font-size: .85rem; }
.due { white-space: nowrap; }

.contactlist li { display: flex; align-items: center; gap: .5rem; border-bottom: 1px solid var(--line); }
.contactlist a { display: flex; flex-direction: column; padding: .6rem 0; min-height: var(--tap); justify-content: center; }
.contactlist a:hover { text-decoration: none; }
.contactlist > li > a:not(.c-edit) { flex: 1 1 auto; min-width: 0; }
.c-name { font-weight: 500; }
.c-ids { color: var(--muted); font-size: .85rem; display: flex; gap: .75rem; flex-wrap: wrap; }
.star { color: #b8860b; } /* meaning: importance */

/* Row selection. The label is the tap target, padded out to 44px so a thumb can
   hit the checkbox without hitting the link beside it. */
.c-pick { display: flex; align-items: center; justify-content: center;
    width: var(--tap); min-height: var(--tap); flex: 0 0 auto; margin: 0; }
.c-pick input { width: 1.15rem; height: 1.15rem; margin: 0; }
.c-edit { flex: 0 0 auto; padding: 0 .6rem !important; min-height: var(--tap);
    color: var(--muted); font-size: .9rem; align-items: center; }
.c-block { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; padding: .6rem 0; }
.c-actions { display: flex; flex-wrap: wrap; gap: .4rem; flex: 0 0 auto; }
.c-actions form { margin: 0; }
.c-actions .btn { padding: 0 .7rem; }
.contactlist.archived li { flex-wrap: wrap; }

/* Bulk bar: sticky under the header so the action stays reachable on a long list. */
.bulkbar { display: flex; align-items: center; justify-content: space-between; gap: .5rem;
    position: sticky; top: 56px; z-index: 5; background: var(--bg);
    padding: .5rem 0; border-bottom: 1px solid var(--line); }
.bulk-all { display: flex; align-items: center; gap: .5rem; min-height: var(--tap);
    font-weight: 400; color: var(--muted); font-size: .9rem; }
.bulk-all input { width: 1.15rem; height: 1.15rem; margin: 0 0 0 calc((var(--tap) - 1.15rem) / 2); }
/* Nothing ticked: the button stays clickable (the server answers "Nothing
   selected"), but it recedes so it doesn't invite a stray tap. */
.bulkform:not(.has-selection) .bulkbar .btn-danger { opacity: .5; }

.searchbar { display: flex; gap: .5rem; margin-bottom: 1rem; }
.searchbar input { margin-top: 0; }
.searchbar .btn { flex: 0 0 auto; }

/* Identity editor rows: stacked on a phone, inline once there's width. */
.idrow { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
    padding: .6rem 0; border-bottom: 1px solid var(--line); }
.idrow:last-child { border-bottom: none; }
.idrow select { width: auto; margin-top: 0; flex: 0 0 auto; }
.idrow input[type=text] { margin-top: 0; flex: 1 1 12rem; min-width: 0; }
.idrow-opt { display: flex; align-items: center; gap: .35rem; min-height: var(--tap);
    font-weight: 400; color: var(--muted); font-size: .9rem; white-space: nowrap; }
.idrow-opt input { width: auto; min-height: 0; margin: 0; }

.idlist li, .meallib li, .shoplist li { padding: .5rem 0; border-bottom: 1px solid var(--line); }
.idlist li:last-child, .meallib li:last-child, .shoplist li:last-child { border-bottom: none; }

.kv { display: grid; grid-template-columns: max-content 1fr; gap: .35rem .75rem; margin: 0; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; }

/* ---- Badges / pills ---- */
.badge { display: inline-block; padding: .05rem .45rem; font-size: .72rem; text-transform: uppercase;
    letter-spacing: .03em; border: 1px solid var(--line-strong); border-radius: 999px; color: var(--ink-soft); }
.pill { display: inline-block; padding: .05rem .5rem; font-size: .72rem; border-radius: 999px; }
.pill-on { background: #eef4ee; color: #2b662b; border: 1px solid #cfe0cf; }
.pill-off { background: var(--bg-soft); color: var(--muted); border: 1px solid var(--line); }
/* Two more tones, for the SMS outbox. "Warn" is the state that wants a person to look —
   a message we cannot say went or didn't. "Bad" is a message that definitely did not go.
   Both carry their words too, so the colour is a second signal and never the only one. */
.pill-warn { background: #fdf5e8; color: #7a5410; border: 1px solid #ecd9b4; }
.pill-bad  { background: #fbf2f2; color: #8a2b2b; border: 1px solid #e6cccc; }

/* ---- SMS outbox ---- */
/* One message per block rather than a table: on a phone the body is the widest thing
   here and a table would either scroll sideways or squeeze it to two words a line. */
.outbox { list-style: none; margin: .5rem 0 0; padding: 0; }
.outbox li { padding: .6rem 0; border-bottom: 1px solid var(--line); }
.outbox li:last-child { border-bottom: none; }
.outbox-head { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem; }
/* Wraps rather than truncates: a message cut off at one line is exactly the thing you
   came to this page to read. */
.outbox-body { margin: .3rem 0 .1rem; white-space: pre-wrap; overflow-wrap: anywhere; }
.outbox-error { color: #8a2b2b; }

/* ---- Calendar ---- */
.cal-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem; }
.cal-controls { display: flex; flex-wrap: wrap; gap: .4rem; }
.cal-controls .btn { padding: 0 .7rem; }
.cal-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.calendar { width: 100%; min-width: 640px; border-collapse: collapse; table-layout: fixed; }
.calendar th { font-size: .75rem; color: var(--muted); text-transform: uppercase; padding: .35rem; border: 1px solid var(--line); }
.calendar td { vertical-align: top; height: 96px; padding: .25rem; border: 1px solid var(--line); }
.calendar td.other-month { background: var(--bg-soft); color: var(--muted); }
.calendar td.today { outline: 2px solid var(--ink); outline-offset: -2px; }
.daynum { font-size: .8rem; font-weight: 600; margin-bottom: .15rem; }
.cal-event { display: flex; align-items: center; gap: .25rem; font-size: .75rem; line-height: 1.3;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-time { color: var(--muted); font-variant-numeric: tabular-nums; }
.dot { display: inline-block; width: .6rem; height: .6rem; border-radius: 50%; flex: 0 0 auto; background: var(--ink); }

.legend ul { display: flex; flex-wrap: wrap; gap: .5rem 1rem; }
.legend li { display: flex; align-items: center; gap: .4rem; font-size: .9rem; }

/* ---- Meals ---- */
.mealweek li { display: flex; gap: .75rem; padding: .5rem 0; border-bottom: 1px solid var(--line); }
.mealweek li:last-child { border-bottom: none; }
.mw-day { width: 5.5rem; color: var(--muted); flex: 0 0 auto; }
.mw-meal { font-weight: 500; }
.tick { color: #2b662b; }
.ml-name { font-weight: 500; }
.ml-ing { display: block; font-size: .85rem; }
.ml-stat { display: block; font-size: .8rem; }
.meallib li { display: flex; align-items: center; gap: .5rem; }
.c-actions form { margin: 0; }

/* Week stepper. The arrows are the full tap target, not just the glyph. */
.weeknav { display: flex; align-items: center; gap: .5rem; margin-bottom: 1rem; }
.weeknav .btn { flex: 0 0 auto; padding: 0 .9rem; }
.weeknav-label { flex: 1 1 auto; text-align: center; font-weight: 600; }

/* One row per day: the day label stays fixed so the selects line up, and the select
   takes whatever is left. Below 380px the label sits above rather than squeezing it. */
.planlist li { padding: .4rem 0; border-bottom: 1px solid var(--line); }
.planlist li:last-child { border-bottom: none; }
.planrow { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.pr-day { width: 5.5rem; flex: 0 0 auto; font-weight: 500; }
.pr-name { display: block; }
.pr-date { display: block; font-size: .8rem; font-weight: 400; }
.planrow select { flex: 1 1 9rem; min-width: 0; margin-top: 0; }
.pr-gone { flex: 0 0 auto; font-size: .8rem; }

/* Who volunteered, and what the household made of it (phase D). Full basis so it wraps
   onto its own line beneath the dropdown rather than squeezing it — at 375px the select
   is already the narrowest thing on the row that still has to be usable. Indented to the
   width of .pr-day plus the gap, so it reads as belonging to the day above it. */
.pr-said { flex: 1 0 100%; margin-left: 6.1rem; font-size: .8rem; }

/* Head count, and the way through to the day. A bordered box rather than a link colour:
   it sits next to a select and a tick, and underlined blue text among those reads as an
   error. Fixed width so seven of them line up down the week — 2 and 12 must not shift
   the row. The "+" is the only sign that guests are coming, so it stays visible when the
   number is what you glance at. */
.pr-heads {
    flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
    min-width: var(--tap); min-height: var(--tap); padding: 0 .4rem;
    border: 1px solid var(--line-strong); border-radius: var(--radius);
    color: var(--ink); text-decoration: none; font-variant-numeric: tabular-nums;
}
.pr-heads:hover { background: var(--bg-soft); text-decoration: none; }
.pr-guests { color: var(--muted); }
.dayheads { font-size: 1.1rem; margin: 0; }

/* Guest rows. Same shape as the shopping editor: the name takes the room, the count is
   deliberately tiny, and the dietary note gets its own line on a phone rather than
   fighting the name for width. */
.guestrow { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
    padding: .35rem 0; border-bottom: 1px solid var(--line); }
.guestrow:last-of-type { border-bottom: none; }
.guestrow input[type=text] { flex: 1 1 8rem; min-width: 0; margin-top: 0; }
.guestrow .qty { flex: 0 0 4.5rem; margin-top: 0; }

/* Shopping list editor. Item name takes the room; quantity is deliberately small —
   it holds "2kg", not a sentence. */
.shopedit li { padding: .35rem 0; border-bottom: 1px solid var(--line); }
.shopedit li:last-child { border-bottom: none; }
.shoprow { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.shoprow input[type=text] { flex: 1 1 8rem; min-width: 0; margin-top: 0; }
.shoprow .qty { flex: 0 0 5.5rem; }
.inline-form { margin: 0; flex: 0 0 auto; }

/* ---- Merges ---- */
.merge-pair { display: flex; align-items: center; gap: .6rem; font-weight: 500; }
.merge-vs { color: var(--muted); }

/* ---- Settings ---- */
/* Tabs are links. On a phone the row scrolls sideways rather than wrapping into a
   ragged block; every tab keeps a full 44px tap target. */
.tabnav { display: flex; gap: .3rem; margin-bottom: 1rem; overflow-x: auto;
    -webkit-overflow-scrolling: touch; border-bottom: 1px solid var(--line); }
.tabnav .tab { display: inline-flex; align-items: center; flex: 0 0 auto;
    min-height: var(--tap); padding: 0 .9rem; color: var(--muted); text-decoration: none;
    white-space: nowrap; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.tabnav .tab:hover { color: var(--ink); }
.tabnav .tab-active { color: var(--ink); font-weight: 600; border-bottom-color: var(--ink); }

.setting-row { padding: .6rem 0; border-bottom: 1px solid var(--line); }
.setting-row:last-child { border-bottom: none; }
.clear-toggle { display: inline-flex; align-items: center; gap: .35rem; margin-top: .4rem; font-weight: 400; color: var(--muted); }
.clear-toggle input { width: auto; min-height: 0; }

/* A long URL beside a copy button. Stacks on a phone; the field stays selectable so
   the URL can still be copied by hand if the button isn't there. */
.copyrow { display: flex; flex-wrap: wrap; gap: .4rem; }
.copyrow input { flex: 1 1 14rem; min-width: 0; font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: .8rem; }
.copyrow .btn { flex: 0 0 auto; }

/* ---- Family view (the member role's one page) ---- */
/* Sign out sits in the top bar rather than a nav, because the family layout has no nav
   to put it in — every other destination is admin-only. */
.topbar-out { margin: 0; }
.topbar-out button {
    min-height: var(--tap); padding: 0 .75rem;
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--bg); color: var(--muted); font: inherit; cursor: pointer;
}
.week { list-style: none; margin: 0; padding: 0; }
.week-day {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem;
    min-height: var(--tap); padding: .6rem 0; border-bottom: 1px solid var(--line);
}
.week-day:last-child { border-bottom: none; }
.week-when { flex: 0 0 9.5rem; font-weight: 600; }
.week-meal { overflow-wrap: anywhere; }

/* ---- The children's week (phase D) ---- */
/* A card per night rather than a row, because a night now carries four things — meal,
   cook, tally, and up to five controls — and a flex row of that on a 375px screen wraps
   into something nobody can read. Stacked and separated stays legible at any width. */
.nights { display: flex; flex-direction: column; gap: .25rem; }
.night {
    display: flex; flex-direction: column; gap: .5rem;
    padding: .85rem 0; border-bottom: 1px solid var(--line);
}
.night:last-child { border-bottom: none; }
.night-when { font-weight: 600; }
.night-what { font-size: 1.05rem; overflow-wrap: anywhere; }
.night-cook { line-height: 1; }
.tally { font-size: .85rem; margin: 0; }

/* Three across at 375px: (343 − 2 gaps) / 3 ≈ 110px, which fits "Can't make it" at this
   size. Equal-width and fixed height so the row does not reflow as the labels change —
   a button that moves under a thumb between renders gets mis-tapped. */
.choices { display: grid; grid-template-columns: repeat(3, 1fr); gap: .4rem; margin: 0; }
.choice { padding: 0 .35rem; font-size: .85rem; text-align: center; line-height: 1.15; }

.claim { display: flex; gap: .4rem; align-items: stretch; margin: 0; }
.claim select { margin: 0; flex: 1 1 auto; min-width: 0; }
.claim .btn { flex: 0 0 auto; white-space: nowrap; }
.giveup { margin: 0; }
.giveup .btn { width: 100%; }

/* Visible to a screen reader, not to the eye. The dropdown has a visible day heading
   above it but no label of its own, and seven unlabelled selects on one page is unusable
   read aloud. */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- Auth card ---- */
/* The password form, folded away under the link form. Nobody in this house types a
   password today; the box is kept because that will change. */
.alt-signin { margin-top: 1.5rem; border-top: 1px solid var(--line); padding-top: .75rem; }
.alt-signin summary { min-height: var(--tap); display: flex; align-items: center; color: var(--muted); cursor: pointer; }
.alt-signin .stack { margin-top: .5rem; }

body.centered { display: flex; min-height: 100vh; align-items: center; justify-content: center; background: var(--bg-soft); padding: 1rem; }
.card { width: 100%; max-width: 360px; background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.5rem; }
.card-brand { font-weight: 700; font-size: 1.3rem; text-align: center; margin-bottom: 1rem; }
.heartbeat { font-size: .85rem; margin-top: 1.5rem; }

/* ---- Wider screens ---- */
@media (min-width: 720px) {
    .nav-toggle { display: none; }
    .mainnav { display: flex; flex-direction: row; align-items: center; gap: .25rem;
        max-width: var(--maxw); margin: 0 auto; padding: 0 1rem; border-bottom: 1px solid var(--line); }
    .mainnav a { min-height: 48px; padding: 0 .9rem; border: none; border-bottom: 2px solid transparent; width: auto; }
    .mainnav a.active { background: none; border-bottom-color: var(--ink); }
    .nav-logout { margin-left: auto; }
    .nav-logout button { border: none; width: auto; }
    .stats { grid-template-columns: repeat(4, 1fr); }
    .grid-2 { grid-template-columns: 1fr 1fr; }
}
