/* The household page's stylesheet (PERF-09, 2026-10-28). It was inline in base.html,
   17 KB on every page: two thirds of /notes once gzipped. Served from /static under a
   name that changes with its contents (web.asset), so a browser keeps it until a
   deploy changes it. All of it is here since the lanes met (Home's quick actions
   included, at the end, where they were last in the inline sheet, so they still win);
   a page's own <style> block comes after this file. */
:root {
  --bg:#f6f5f3; --card:#fff; --ink:#1c1b19; --dim:#6b6862; --line:#e3e0da;
  --accent:#7a5c3e; --ok:#3f7d4e; --warn:#a8452f; --radius:14px;
  /* Amber completes the red-amber-green run that priority and deadlines share.
     Sacha and Ivon get a hue each — blue and violet, far from the traffic
     lights, so "whose" never reads as "how urgent". */
  --amber:#9a6d15; --sacha:#3a6ea5; --ivon:#7a5490;
  /* Text ON the accent (a primary button). White on the light scheme's dark brown;
     the dark scheme's accent is light, and white on it was 2.33:1 (UXW-01). */
  --on-accent:#fff; --on-accent-dim:rgba(255,255,255,.8);
}
@media (prefers-color-scheme: dark) {
  :root { --bg:#161513; --card:#211f1d; --ink:#eeebe6; --dim:#9a958c;
          --line:#33302c; --accent:#c9a37a; --ok:#7fbf8f; --warn:#e0836c;
          --amber:#d9ab5a; --sacha:#84b0dd; --ivon:#b899d0;
          --on-accent:#161513; --on-accent-dim:rgba(0,0,0,.7); }
}
* { box-sizing:border-box; }
body {
  margin:0; background:var(--bg); color:var(--ink);
  font:16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  padding-bottom:env(safe-area-inset-bottom);
}
main { max-width:640px; margin:0 auto; padding:1rem 1rem 2.5rem; }
h1 { font-size:1.35rem; margin:.2rem 0 1rem; }
h2 { font-size:1rem; margin:1.6rem 0 .6rem; color:var(--dim);
     text-transform:uppercase; letter-spacing:.06em; font-weight:600; }
a { color:var(--accent); }
.card { background:var(--card); border:1px solid var(--line);
        border-radius:var(--radius); padding:.9rem; margin-bottom:.7rem; }
.row { display:flex; align-items:center; gap:.7rem; }
.row + .row { border-top:1px solid var(--line); padding-top:.6rem; margin-top:.6rem; }
.grow { flex:1; min-width:0; }
.dim { color:var(--dim); font-size:.85rem; }
.strike { text-decoration:line-through; color:var(--dim); }
/* Tap targets are 44px minimum — this is used one-handed, at night. */
button, .btn {
  min-height:44px; padding:.6rem 1rem; font-size:1rem; font-family:inherit;
  border:1px solid var(--line); border-radius:var(--radius);
  background:var(--card); color:var(--ink); cursor:pointer;
  display:inline-flex; align-items:center; justify-content:center; gap:.4rem;
  text-decoration:none;
}
button:active, .btn:active { transform:translateY(1px); }
.primary { background:var(--accent); border-color:var(--accent); color:var(--on-accent); }
/* Two a row, always: the page is phone-width even on a laptop, and a fixed
   grid keeps every tile the same size as the one beside it. */
.tiles { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:.5rem; }
.tiles button, .tiles .tile { flex-direction:column; min-height:62px; gap:.15rem;
                              line-height:1.2; width:100%; height:100%;
                              text-align:center; }
.tiles small { color:var(--dim); font-size:.75rem; }
/* A habit tile that is due gets the warning colour on its edge and says "due"
   in words — colour is never the only carrier. */
.tiles button.due { border-color:var(--warn); }
/* The money tiles: the edge says how long ago the statement went in. */
.tiles .up-fresh { border-color:var(--ok); }
.tiles .up-stale { border-color:var(--amber); }
.tiles .up-late, .tiles .up-never { border-color:var(--warn); }
.primary small { color:var(--on-accent-dim); }
input, select, textarea {
  min-height:44px; padding:.55rem .7rem; font-size:16px; font-family:inherit;
  border:1px solid var(--line); border-radius:var(--radius);
  background:var(--bg); color:var(--ink); width:100%;
}
/* Tall enough to write a page in, and monospaced because it is markdown:
   a list that lines up is a list you can see is a list before you save. */
textarea { min-height:22rem; line-height:1.45; resize:vertical;
           font-family:ui-monospace, SFMono-Regular, Menlo, monospace;
           font-size:15px; }
/* Rendered markdown. The defaults for h1/h2 above are page furniture — inside
   a document they would shout, so headings step down to something a recipe or
   a note can carry. */
.prose > :first-child { margin-top:0; }
.prose > :last-child { margin-bottom:0; }
.prose h1, .prose h2, .prose h3 {
  font-size:1.05rem; margin:1.1rem 0 .4rem; color:var(--ink);
  text-transform:none; letter-spacing:0; font-weight:600;
}
.prose ul, .prose ol { padding-left:1.2rem; margin:.4rem 0; }
.prose li { margin:.15rem 0; }
/* A row per box, the box pinned left. Positioned rather than flex, because a line can
   hold <strong> and the like, and flex would make each of those a column. */
.prose li.task { list-style:none; margin:0 0 0 -1.2rem; position:relative;
                 padding:.6rem 0 .6rem 2rem;
                 /* Holds the To-buy badge's float: a one-line row is shorter than the
                    44px badge, which hung into the row below (NOTE-05). */
                 display:flow-root; }
.prose li.task + li.task { border-top:1px solid var(--line); }
.prose li.task p { margin:0; }
/* The global input rule (full width, 44px tall) is for text fields, not boxes. */
.prose li.task input { position:absolute; left:0; top:calc(.6rem + .15em);
                       width:1.25rem; height:1.25rem; min-height:0; padding:0; margin:0;
                       accent-color:var(--ok); }
.prose li.task:has(input:enabled) { cursor:pointer; }
.prose li.task.done { color:var(--dim); }
.prose li .aside { display:block; color:var(--dim); font-size:.9em; }
/* To buy: filled while it still needs buying, a dashed outline once it does not. Right
   of the row, 44px tall like every button. */
.prose li .buy { float:right; margin:0 0 0 .6rem; padding:.3rem .75rem;
                 font-size:.75rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
                 border:1px dashed var(--line); background:none; color:var(--dim); }
.prose li .buy.on { background:var(--accent); border:1px solid var(--accent); color:var(--card); }
span.buy { display:inline-block; border-radius:8px; }
.prose blockquote { margin:.6rem 0; padding-left:.8rem;
                    border-left:3px solid var(--line); color:var(--dim); }
.prose code { font-family:ui-monospace, SFMono-Regular, Menlo, monospace;
              font-size:.9em; background:var(--bg); padding:.1rem .3rem;
              border-radius:4px; }
.prose pre { background:var(--bg); padding:.7rem; border-radius:var(--radius);
             overflow-x:auto; }
.prose pre code { background:none; padding:0; }
.prose hr { border:none; border-top:1px solid var(--line); margin:1rem 0; }
/* Tables scroll sideways inside their own box instead of widening the page. */
.prose .table-wrap { overflow-x:auto; margin:.6rem 0; }
.prose table { border-collapse:collapse; font-size:.9rem; }
.prose th, .prose td { border:1px solid var(--line); padding:.35rem .6rem;
                       text-align:left; vertical-align:top; }
.prose th { background:var(--bg); font-weight:600; white-space:nowrap; }
.prose s { color:var(--dim); }
.prose img { max-width:100%; height:auto; }
form.inline { display:flex; gap:.5rem; flex-wrap:wrap; }
/* 45%, so the field, a select and the + fit one line at 390 (the + wrapped alone). */
form.inline .grow { flex:1 1 45%; }
/* Sorting and filtering, on a labelled line each. They were three equal
   dropdowns in a row until 2026-09-18, which said they were three of a kind —
   and one of them decided the order while the other two decided what was left
   out. */
.controls { margin-bottom:.5rem; }
.controls .line { display:flex; gap:.4rem; align-items:center;
                  flex-wrap:wrap; margin-bottom:.4rem; }
.controls .key { font-size:.78rem; color:var(--dim); flex:0 0 auto; }
.controls select { flex:1 1 7rem; width:auto; min-width:0; }
.controls button { flex:0 0 auto; }
/* A form that stays folded until it is wanted: correcting a feed or a habit. Plain <details>, so there is no state to get out
   of sync and the page works with the scripting off. */
.fix > summary { list-style:none; cursor:pointer; font-size:.85rem;
                 color:var(--dim); padding:.5rem 0; display:inline-flex;
                 align-items:center; min-height:44px; }
.fix > summary::-webkit-details-marker { display:none; }
.fix label { display:block; font-size:.78rem; color:var(--dim); margin-top:.6rem; }
/* A list row's Edit opens on a line of its own under the row, the width of the card
   (LIST-03); closed, its summary lines up under the title. */
.row.item { flex-wrap:wrap; row-gap:0; }
.row.item > details.fix { flex:1 0 100%; }
.row.item > details.fix > summary { margin-left:calc(44px + .7rem); }
.row.item textarea { min-height:6rem; }
/* Home's feed strip: Earlier… (2026-10-28), folded the same way. The Started chips
   keep their line; Earlier… takes the one under them, lined up with the chips, and
   opens a time field and Save. Dashed like Other…, it is a way to more; filled, with
   the time in words, when the row's time is one it set. Every rule here outranks the
   chip rules it meets, so where Quick actions' own rules sit does not matter. */
.chiprow.started { flex-wrap:wrap; row-gap:.35rem; }
.chiprow.started > details.earlier { flex:1 0 100%; }
.earlier > summary { list-style:none; cursor:pointer; width:auto;
                     margin-left:calc(3.1rem + .35rem); }
.earlier > summary::-webkit-details-marker { display:none; }
.earlier > summary.set { border-style:solid; background:var(--accent);
                         border-color:var(--accent); color:var(--card); font-weight:600; }
.earlier > summary.set::before { content:"✓"; font-size:.75rem; line-height:1; }
.earlier > form { display:flex; flex-wrap:wrap; gap:.35rem; margin-top:.35rem; }
.earlier > form input { flex:1 1 11rem; width:auto; min-width:0; }
.earlier > form button { flex:0 0 auto; }
.remove { width:100%; margin-top:.9rem; color:var(--warn); }
/* Words for a screen reader that the eye gets from the row around them. */
.sr { position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%);
      white-space:nowrap; }
.fix .pair { display:flex; gap:.5rem; }
.fix .pair label { flex:1; }
/* What a to-do carries, as separate things you can find by their shape. Real
   columns were asked for; at 390px that is four unreadable ones or a sideways
   scroll, and the sort and the filter give the same grip on the same page. */
.chips { display:flex; flex-wrap:wrap; gap:.3rem; margin-top:.25rem; }
.chip { font-size:.75rem; padding:.1rem .45rem; border-radius:999px;
        border:1px solid var(--line); color:var(--dim); white-space:nowrap; }
/* A chip that is a link (a note hung under a to-do) is a 24px pill and a 44px target:
   the target reaches past the pill, above and below (UXW-05). */
a.chip { position:relative; }
a.chip::after { content:""; position:absolute; inset:-11px 0; }
/* Priority and nearness both run red-amber-green, which is the point: they are
   both answers to "how soon", and a glance should not have to learn two
   vocabularies. Colour is never the only carrier — the word and the date are
   in the label, so this still reads without seeing the difference. */
.chip.prio-high,   .chip.due-now   { color:var(--warn); border-color:var(--warn);
                                     font-weight:600; }
.chip.prio-medium, .chip.due-soon  { color:var(--amber); border-color:var(--amber); }
.chip.prio-low,    .chip.due-later { color:var(--ok); border-color:var(--ok); }
/* And the two of them, so a list answers "whose is this" before you read it. */
.chip.who-sacha { color:var(--sacha); border-color:var(--sacha); }
.chip.who-ivon  { color:var(--ivon);  border-color:var(--ivon); }
/* A recipe's two questions: which kitchen, and what is it built on. Two colours
   and not one per kitchen — a palette that grows every time the household cooks
   something new is a palette that runs out of distinguishable colours. */
.chip.kitchen { color:var(--accent); border-color:var(--accent); }
.chip.base    { color:var(--ok);     border-color:var(--ok); }
.icon { background:none; border:none; min-height:44px; min-width:44px;
        font-size:1.1rem; color:var(--dim); padding:0;
        /* Also worn by an <a> (the link to an item's page), which needs the
           centring and the underline off that a <button> gets for free. */
        display:inline-flex; align-items:center; justify-content:center;
        text-decoration:none; }
/* The menu: off-canvas on a phone, a fixed column on anything wider.
   No JavaScript — a hidden checkbox and a <label> for the ☰.

   A <details> did this until 2026-09-18 and could not keep doing it. The panel
   has to be permanently OPEN above 900px, and there is no reliable way to say
   that in CSS: browsers hide a closed <details>'s contents through the UA
   shadow slot, which `display:block` on the child does not undo everywhere. A
   checkbox has no such opinion, so "always open" is one media query. It also
   fails in the right direction: with no CSS at all the links are simply
   visible, where a <details> would leave them shut. */
/* One pixel, not the 100% every input gets: wider than the page, the hidden box made
   every signed-in page scroll sideways (394px on a 390px phone, 244px under the side
   menu at 1280; the UX review, 2026-10-28). */
.menu-toggle { position:absolute; opacity:0; pointer-events:none;
               width:1px; height:1px; min-height:0; padding:0; margin:0; }
/* Absolute, so the ☰ scrolls away with the page instead of sitting over the tick
   column of a long list (UXW-04); open, it is fixed, as the ✕ over the panel. */
.bars { position:absolute; top:.8rem; left:.8rem; z-index:3;
        min-height:44px; min-width:44px; display:inline-flex;
        align-items:center; justify-content:center; font-size:1.25rem;
        cursor:pointer; border-radius:var(--radius);
        border:1px solid var(--line); background:var(--card); }
.bars::after { content:"☰"; }
/* Open, the same button becomes the ✕ over the panel, which is why the panel
   needs no close button of its own. */
.menu-toggle:checked ~ .bars::after { content:"✕"; }
.menu-toggle:checked ~ .bars { position:fixed; }
/* The checkbox takes the focus, so the ☰ shows it. */
.menu-toggle:focus-visible ~ .bars { outline:2px solid var(--accent); outline-offset:2px; }
.scrim { position:fixed; inset:0; background:rgba(0,0,0,.4); z-index:1;
         display:none; }
.menu-toggle:checked ~ .scrim { display:block; }
nav.sheet { position:fixed; top:0; left:0; bottom:0; z-index:2;
            width:min(78vw,300px); background:var(--card);
            border-right:1px solid var(--line); overflow-y:auto;
            transform:translateX(-100%); transition:transform .18s ease-out, visibility .18s;
            padding:4.2rem .7rem calc(1rem + env(safe-area-inset-bottom));
            /* Closed is hidden, not only moved off screen: its links were in the tab
               order and read out while nobody could see them (UXW-04). */
            visibility:hidden; }
.menu-toggle:checked ~ nav.sheet { transform:none; visibility:visible; }
@media (prefers-reduced-motion: reduce) { nav.sheet { transition:none; } }
/* Wide enough for the panel to simply live there: the ☰ goes, the scrim goes,
   and the page moves over. A laptop should not have to open a menu to find out
   what the site contains. */
@media (min-width: 900px) {
  .bars, .scrim { display:none; }
  nav.sheet { transform:none; width:240px; padding-top:1rem; visibility:visible; }
  /* On the body, so `main` keeps centring itself — in the space that is left
     rather than in the window the panel is covering a fifth of. */
  body { padding-left:240px; }
}
nav.sheet a { display:flex; align-items:center; gap:.75rem; min-height:48px;
              padding:.3rem .6rem; border-radius:var(--radius);
              color:var(--ink); text-decoration:none; }
nav.sheet a.on { background:var(--bg); color:var(--accent); font-weight:600; }
nav.sheet b { font-size:1.2rem; font-weight:400; width:1.5rem; text-align:center; }
nav.sheet hr { border:none; border-top:1px solid var(--line); margin:.5rem .6rem; }
.who { display:flex; gap:.4rem; align-items:center; margin-bottom:.5rem;
       /* Room for the ☰, which is fixed in the corner this strip starts in. */
       padding-left:3rem; }
.who button, .who .btn { min-height:44px; padding:.2rem .8rem; font-size:.85rem; }
/* A list row that is one link (notes, recipes, memos): the whole row is the target,
   in the ink colour, with its name in the link colour so it still reads as one. */
a.rowlink { color:var(--ink); text-decoration:none; min-height:44px; }
/* A to-do's title on Home is the way into its Edit: a 44px target that does not make the
   row taller, the padding taken back by the margin. */
a.titlelink { display:inline-block; padding:12px 0; margin:-12px 0; }
a.grow.rowlink { display:flex; align-items:center; flex-wrap:wrap; gap:0 .3rem; }
a.rowlink .t { color:var(--accent); text-decoration:underline; }
a.rowlink .preview { color:var(--dim); font-size:.9rem; margin-top:.15rem;
                     overflow-wrap:anywhere; }
/* "← Notes" and its kind above a page: a link, 44px tall like a button (UXW-05). */
a.up { display:inline-flex; align-items:center; min-height:44px; }
@media (min-width: 900px) { .who { padding-left:0; } }
table { width:100%; border-collapse:collapse; font-variant-numeric:tabular-nums; }
td, th { padding:.45rem .3rem; text-align:right; border-bottom:1px solid var(--line); }
th:first-child, td:first-child { text-align:left; }
th { color:var(--dim); font-weight:600; font-size:.8rem; }
.neg { color:var(--warn); } .pos { color:var(--ok); }
.bar { height:5px; border-radius:3px; background:var(--line); overflow:hidden; margin-top:.3rem; }
.bar span { display:block; height:100%; background:var(--ok); }
.bar span.over { background:var(--warn); }
.empty { color:var(--dim); padding:.6rem 0; }
/* What a refused save says, above the list it was refused on. */
.notice { border:1px solid var(--warn); border-radius:var(--radius);
          background:var(--card); padding:.6rem .8rem; margin:0 0 .7rem; }
/* "Attach a note…" until Edit opens it into the picker: a link, 44px like a button. */
a.attach { display:inline-flex; align-items:center; min-height:44px; margin-top:.4rem; }
/* The strip under a list: what left it lately; your own last ten minutes with ↶. */
.closed h2 { margin:0 0 .3rem; }
/* The briefing is a whole page written elsewhere, so it gets the screen: a
   frame that fills what is left under the header and scrolls inside itself. It
   is sandboxed — see web.briefing_raw. It grew by the height of the tab bar
   when the bar went. */
/* White under it in both schemes, as a browser's own page is: a briefing that sets no
   background of its own is black text, and on the dark card it read at about 1.2:1 (the
   UX review, 2026-10-28). The briefings' own heads set both colours, and cover this. */
.frame { width:100%; height:calc(100dvh - 200px); min-height:360px; display:block;
         border:1px solid var(--line); border-radius:var(--radius);
         background:#fff; }
/* The household's short message on the home page: the routine's own line
   breaks kept, nothing else interpreted. */
.brief-message { white-space:pre-line; margin:.5rem 0; }
.dates { columns:2; font-size:.9rem; margin:.4rem 0 0; padding:0; list-style:none; }
.dates li { padding:.2rem 0; }
/* Home */
/* A save that was refused, said at the top of the page it came back to: the
   warning colour on its edge, and the words say it too. */
.notice { border-color:var(--warn); border-left-width:4px; }
/* Quick actions: rows you act in, each target 44px or more, nothing that only
   navigates. The strips under a row appear right after your own write. */
.qa > * + * { margin-top:.6rem; }
.qa .feed { width:100%; flex-direction:column; min-height:64px; font-size:1.15rem;
            gap:.1rem; line-height:1.2; }
.qa .feed small { font-size:.85rem; }
.facts { margin:.35rem 0 0; font-size:.85rem; color:var(--dim); }
.facts.warn { color:var(--warn); font-weight:600; }
.strip { border:1px solid var(--line); border-radius:var(--radius); padding:.6rem;
         background:var(--bg); }
.strip-head { gap:.5rem; }
.chiprow { display:flex; align-items:center; gap:.35rem; margin-top:.45rem; }
.chiprow > form, .chiprow > a { flex:1 1 0; min-width:44px; display:flex; }
.chiprow .key { flex:0 0 3.1rem; font-size:.78rem; color:var(--dim); }
.chipbtn { width:100%; min-height:44px; padding:.3rem .35rem; font-size:.88rem;
           line-height:1.15; border-radius:12px; text-align:center;
           display:flex; flex-direction:column; align-items:center; justify-content:center;
           text-decoration:none; white-space:nowrap; }
.chipbtn small { font-size:.7rem; opacity:.85; }
/* Pressed says so in words too: a tick before the label, not only the fill. The
   text takes the card colour, which is dark on the light accent of dark mode. */
.chipbtn[aria-pressed="true"] { background:var(--accent); border-color:var(--accent);
                                color:var(--card); font-weight:600; }
.chipbtn[aria-pressed="true"]::before { content:"✓"; font-size:.75rem; line-height:1; }
.chipbtn.more { color:var(--accent); border:1px dashed var(--accent); background:none; }
.qa .add input { width:100%; }
.pair2 { display:grid; grid-template-columns:1fr 1fr; gap:.5rem; margin-top:.5rem; }
.pair2 button { width:100%; }
.strip.twin { border-color:var(--warn); }
.strip.twin p { margin:0 0 .5rem; }
.strip.twin .btn { width:100%; }
main > .strip.twin { margin-bottom:.7rem; }
.note-row { min-height:44px; color:var(--ink); text-decoration:none; }
.note-row .grow { color:var(--accent); text-decoration:underline; }
main > .strip.removed { margin-bottom:.7rem; }
/* The daybook's and the habits' "correct": a target like every other. */
.fix > summary { min-height:44px; }
/* The search on the transactions page, folded away on the To file tab so the lines come
   first on a phone (2026-10-28, UXW-09); open, its summary is not needed. */
.search-fold > summary { min-height:44px; display:flex; align-items:center; cursor:pointer;
                         color:var(--dim); }
.search-fold[open] > summary { display:none; }
