/* A slate-green ground, blue for one parent and green for the other, chosen so
   that neither reads as the default or the favored one. Both themes are token
   driven.

   The two parent colors are matched in lightness on purpose, and that is a
   constraint rather than a preference: the darker of two colors reads as the
   more important parent, every day, without anybody deciding it. The teal and
   ochre carried here from the prototype were retired on 25 August 2026 for
   failing a contrast bar nobody had measured. See `docs/next-steps.md` section
   7, and `tests/test_palette.py`, which is what now holds all of this. */
@font-face{font-family:Fraunces;src:url(/static/fonts/fraunces.woff2) format('woff2');
  font-weight:600 700;font-display:swap}
@font-face{font-family:PublicSans;src:url(/static/fonts/publicsans.woff2) format('woff2');
  font-weight:400 700;font-display:swap}
@font-face{font-family:RobotoMono;src:url(/static/fonts/robotomono.woff2) format('woff2');
  font-weight:400 600;font-display:swap}

:root{
  color-scheme:light;
  --ground:#eff3f2; --surface:#fff; --sunken:#dee5e3; --surface-2:#e5ebe9;
  --ink:#101d19; --ink-2:#465852; --ink-3:#566a65; --line:#d2dbd8; --line-2:#c0ccc8;
  --a:#1e65c9; --a-tint:#ecf1f8; --b:#177917; --b-tint:#e5f5e5;
  --ex:#7854b9; --ex-tint:#f2eff8; --bd:#ba365d; --wn:#915d02;
  --sc:#5b6b67; --sc-tint:#eef1f1;
  --on-accent:#fff;
}
@media (prefers-color-scheme:dark){:root{
  color-scheme:dark;
  --ground:#0c1311; --surface:#141e1b; --sunken:#101917; --surface-2:#1b2724;
  --ink:#e6eeeb; --ink-2:#9fb1ab; --ink-3:#7a908b; --line:#25332f; --line-2:#31423d;
  --a:#3589ff; --a-tint:#172436; --b:#379f37; --b-tint:#112911;
  --ex:#9e75ea; --ex-tint:#2a1c42; --bd:#f44d7f; --wn:#c37c00;
  --sc:#808f8b; --sc-tint:#202523;
  --on-accent:#0c1311;
}}

*{box-sizing:border-box}
/* `hidden` has to actually hide, and until 26 August it did not.
   -------------------------------------------------------------
   The attribute is implemented in the browser's own stylesheet as
   `[hidden]{display:none}`, and **any author rule setting `display` on the
   same element beats it, whatever the specificity**, because author styles
   outrank the user agent's. This file sets `display` on `label` and on `.btn`,
   so `hidden` did nothing on either, and three separate features quietly
   depended on it:

     * both print buttons ship with `hidden` so that a browser with the script
       switched off is not offered a control that cannot work. They were
       visible and inert the whole time, which is the exact failure the comment
       beside them says the attribute is there to prevent
     * the setup forms mark the fields that do not apply to the current
       selection. Four of them stayed on the holiday form
     * the care form marks the dose field on an appointment. It stayed too

   `!important` because the point of this rule is to beat every `display` in
   the file, including ones not written yet. The suite cannot catch this: it
   reads HTML, and every one of those elements had `hidden` correctly set on
   it. Only something rendering the page can see it, which is how it survived
   an accessibility pass and a full phone sweep. */
[hidden]{display:none !important}
body{margin:0;background:var(--ground);color:var(--ink);
  font:15px/1.5 PublicSans,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  -webkit-font-smoothing:antialiased}
body.centred{display:grid;place-items:center;min-height:100vh;padding:20px}
a{color:inherit}
.wrap{max-width:1120px;margin:0 auto;padding:22px 18px 60px}

.bar{display:flex;gap:16px;align-items:center;padding:12px 20px;background:var(--surface);
  border-bottom:1px solid var(--line);flex-wrap:wrap}
.bar strong{font-family:Fraunces,Georgia,serif;font-weight:600;font-size:17px;
  display:inline-flex;align-items:center;min-height:24px}
/* Section 7, answers 10 and 17 to 19. Three destinations across the top and
   five behind More, and on a phone the whole thing moves to a bottom bar.
   What was here before was not a design: eight links in a flex row set to
   wrap, which wrapped to two lines the moment Children was added and looked
   deliberate right up to the edge.

   One markup, two presentations. Home is in the nav on every page and hidden
   at desk widths, where the brand is the way home. It is a real item on the
   phone because a brand in a top corner is a poor tap target, and one markup
   that CSS presents two ways beats two markups that have to agree. */
.bar nav{display:flex;gap:14px;font-size:13.5px;align-items:center}
.bar nav a{color:var(--ink-3);text-decoration:none;font-weight:600;
  display:inline-flex;align-items:center;min-height:24px}
.bar nav a:hover{color:var(--ink)}
.bar nav .home{display:none}

/* More is a `<details>`, so the browser opens and closes it and nothing here
   needs scripting. The marker goes because the panel's position says which
   way it opens, and because the triangle sits oddly next to eight words that
   do not have one. */
.more{position:relative}
.more>summary{color:var(--ink-3);font-weight:600;cursor:pointer;list-style:none;
  min-height:24px;display:inline-flex;align-items:center;padding:0}
.more>summary::-webkit-details-marker{display:none}
.more>summary::marker{content:""}
.more>summary:hover,.more[open]>summary{color:var(--ink)}
.more-panel{position:absolute;top:calc(100% + 10px);left:-8px;z-index:40;
  display:flex;flex-direction:column;min-width:158px;padding:6px;
  background:var(--surface);border:1px solid var(--line-2);border-radius:10px}
.more-panel a{padding:7px 10px;border-radius:6px;min-height:24px}
.more-panel a:hover{background:var(--surface-2);color:var(--ink)}
.bar .who{margin-left:auto;color:var(--ink-3);font-size:13px}
button.link{background:none;border:0;color:var(--ink-3);font:inherit;cursor:pointer;
  padding:0;display:inline-flex;align-items:center;min-height:24px}

.card{background:var(--surface);border:1px solid var(--line);border-radius:12px;
  padding:16px;margin-bottom:16px}
.card.narrow{width:min(380px,100%)}
.card.cal{padding:0;overflow:hidden}
h1{font-family:Fraunces,Georgia,serif;font-weight:600;margin:0 0 4px;font-size:24px}
h2{margin:0 0 10px;font-size:11px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-3)}
.sub{color:var(--ink-3);font-size:12.5px;margin:0 0 12px}
.sub.warn{color:var(--wn);font-weight:600}

.cols{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:16px;align-items:start}
@media (max-width:900px){.cols{grid-template-columns:minmax(0,1fr)}}

/* The phone, answers 11, 17 and 19.

   720 rather than 560, and chosen rather than inherited. 560 was whichever
   screen first needed a breakpoint and it has been the number for everything
   since. The question this one answers is where five items across the bottom
   beat five items across the top, and that is true well before a phone: a
   tablet held in portrait wants the thumb bar too. The calendar has its own
   number below, at 440, because seven columns run out of room long after a
   nav does and the two should not be forced to share a breakpoint.

   The nav leaves the flow of the bar and fixes to the bottom. The brand, the
   name and Sign out stay at the top, which is where a title belongs and where
   a destructive-adjacent control is out of thumb reach on purpose. */
@media (max-width:720px){
  .bar{padding:10px 14px;gap:10px}
  .bar strong{font-size:16px}
  .bar nav{position:fixed;left:0;right:0;bottom:0;z-index:40;
    justify-content:space-around;gap:0;font-size:11px;
    background:var(--surface);border-top:1px solid var(--line);
    padding:6px 4px calc(6px + env(safe-area-inset-bottom, 0px))}
  .bar nav .home{display:inline-flex}
  .bar nav a,.more>summary{justify-content:center;gap:5px;min-height:44px;
    min-width:56px;padding:4px 6px;border-radius:8px;text-align:center}
  /* Opens upward, because there is nothing below it to open into. */
  .more-panel{top:auto;bottom:calc(100% + 10px);left:auto;right:6px;
    font-size:13.5px}
  /* `.bar nav a` above outranks a bare `.more-panel a`, so the panel's rows
     were centering themselves like bottom bar items. */
  .bar nav .more-panel a{justify-content:flex-start;min-width:0;text-align:left;
    min-height:38px;padding:8px 12px}
  /* Room for the bar, so the last thing on a page is not under it. */
  .wrap{padding-bottom:calc(74px + env(safe-area-inset-bottom, 0px))}
  /* WCAG 2.4.11. A fixed bar is the thing that hides the element you just
     tabbed to, and this app had no fixed anything until this rule.

     On the elements themselves rather than on `:focus-visible`. Scroll margin
     is read when the browser scrolls something into view, and hanging that on
     a state that has to be matched first is a race worth not having. It has
     no effect until something scrolls, so there is nothing to pay for it. */
  a,button,input,select,textarea,summary,[tabindex],main{scroll-margin-bottom:96px}
}

.cal-head{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:13px 14px;border-bottom:1px solid var(--line);flex-wrap:wrap}
.nav{display:flex;align-items:center;gap:8px}
/* Today and Print, grouped so that `space-between` puts them together on the
   right rather than spreading three things across the header. */
.cal-acts{display:flex;align-items:center;gap:6px}
.month{font-family:Fraunces,Georgia,serif;font-weight:600;font-size:19px;margin:0;min-width:9ch}
.btn{display:inline-block;padding:6px 12px;border:1px solid var(--line-2);border-radius:8px;
  font-size:13.5px;font-weight:600;text-decoration:none;background:var(--surface);
  color:var(--ink)}
.btn:hover{background:var(--surface-2)}
.btn.icon{padding:5px 11px;line-height:1.2}
.btn.ghost{border-color:transparent;color:var(--ink-2)}
.btn.icon.off{opacity:.3;cursor:default;background:var(--surface)}

.kidbar{display:flex;gap:6px;align-items:center;flex-wrap:wrap;padding:10px 14px 0;width:100%}
.kidbar .lbl{font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--ink-3);margin-right:2px}
.chip{padding:5px 12px;border:1px solid var(--line-2);border-radius:999px;font-size:12.5px;
  font-weight:600;text-decoration:none}
.chip.on{background:var(--ink);border-color:var(--ink);color:var(--ground)}

.dow{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px;padding:12px 12px 0}
.dow span{text-align:center;font-size:10px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--ink-3);padding-bottom:6px}
.grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px;padding:0 12px 12px}
.day{position:relative;display:flex;flex-direction:column;gap:2px;min-height:86px;
  padding:6px 6px 6px 10px;border-radius:8px;background:var(--sunken);text-decoration:none;
  border:1px solid transparent;min-width:0;overflow:hidden}
.day::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;border-radius:8px 0 0 8px}
.day:hover{filter:brightness(.97)}
@media (prefers-color-scheme:dark){.day:hover{filter:brightness(1.2)}}
.day.pa{background:var(--a-tint)} .day.pa::before{background:var(--a)}
.day.pb{background:var(--b-tint)} .day.pb::before{background:var(--b)}
/* Both of you there. Two tone rather than a third color, so it reads as the
   two of you together and not as some other person's day. */
.day.pboth{background:linear-gradient(135deg,var(--a-tint) 0 50%,var(--b-tint) 50% 100%)}
.day.pboth::before{background:linear-gradient(180deg,var(--a) 0 50%,var(--b) 50% 100%)}
.day.pboth .who{color:var(--ink-2)}
/* A day both of you had time with the children. The night parent keeps the
   cell and the color it has always had; the band along the top is the other
   parent's hours, sized to their share of them.

   A band rather than a second background, so it composes with .pa and .pb
   instead of replacing them, and so it reads as something added to the day
   rather than as a different kind of day. That distinction is the whole point:
   the night has not moved and the cell must not suggest it has. It is also
   deliberately not the .pboth diagonal, which means the two of you share the
   night and is a different statement. */
.day .dayband{position:absolute;left:0;right:0;top:0;border-radius:7px 7px 0 0;opacity:.55}
.day .dayband.ba{background:var(--a)}
.day .dayband.bb{background:var(--b)}
.day.unset::before{background:repeating-linear-gradient(135deg,var(--line-2) 0 3px,transparent 3px 6px)}
.day.out{opacity:.42}
.day.sel{border-color:var(--ink);box-shadow:0 0 0 1px var(--ink)}
.day.split::after{content:"";position:absolute;right:0;top:0;bottom:0;width:4px;
  border-radius:0 8px 8px 0;background:repeating-linear-gradient(135deg,var(--a) 0 5px,var(--b) 5px 10px)}
.num{font-family:RobotoMono,monospace;font-size:13px;font-weight:600;font-variant-numeric:tabular-nums}
.day.today .num{background:var(--ink);color:var(--ground);border-radius:5px;padding:0 5px;
  margin:0 -2px;align-self:flex-start}
.who{font-size:10.5px;font-weight:700;line-height:1.2;max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* One name, written twice, and the width decides which one is read. Both are
   in the markup because the server has no idea how wide the screen is, and
   `display:none` keeps the unread one away from a screen reader as well as
   from the page. */
.wshort{display:none}
.day.pa .who{color:var(--a)} .day.pb .who{color:var(--b)}
.day.unset .who{color:var(--ink-3);font-weight:400;font-style:italic}
.tag{font-size:9px;font-weight:700;border-radius:4px;padding:1px 4px;line-height:1.3;
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tag.rule{color:var(--ex);background:var(--ex-tint)}
.tag.school{color:var(--sc);background:var(--sc-tint)}
.tag.school.off{color:var(--on-accent);background:var(--sc)}
.tag.bday{color:var(--ink-2);background:transparent;box-shadow:inset 0 0 0 1px var(--line-2)}
.tag.split-tag{color:var(--on-accent);background:var(--ink-3)}
.foot{margin-top:auto;font-size:9.5px;font-weight:700;letter-spacing:.05em;color:var(--ink-3)}

.split-bar{display:flex;height:24px;border-radius:6px;overflow:hidden;background:var(--sunken)}
.split-bar span{display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;
  font-family:RobotoMono,monospace;color:var(--on-accent);min-width:0;overflow:hidden}
.split-bar .sa{background:var(--a)} .split-bar .sb{background:var(--b)}
.split-bar .sboth{flex:1;background:linear-gradient(90deg,var(--a) 0 50%,var(--b) 50% 100%)}
.split-bar .none{flex:1;color:var(--ink-3);background:var(--surface-2);font-weight:500}
.lead.pboth{background:linear-gradient(90deg,var(--a),var(--b));-webkit-background-clip:text;
  background-clip:text;color:transparent}

.lead{font-size:17px;font-weight:700;margin:0 0 2px}
.lead.pa{color:var(--a)} .lead.pb{color:var(--b)} .lead.pn{color:var(--ink-3)}
.kidsplit{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:12px}
.kidchip{font-size:11.5px;border:1px solid var(--line);border-radius:999px;padding:3px 9px}
.kidchip.pa{color:var(--a);border-color:var(--a);background:var(--a-tint)}
.kidchip.pb{color:var(--b);border-color:var(--b);background:var(--b-tint)}
.rows{display:grid;grid-template-columns:auto 1fr;gap:5px 12px;margin:0;font-size:12.5px}
.rows dt{font-weight:700;color:var(--ink-3);white-space:nowrap}
.rows dd{margin:0}

/* Ahead of eight nav items and Sign out on every page, which is what a
   keyboard user otherwise tabs through before reaching anything. Off
   screen rather than hidden: `display:none` is not focusable. */
/* Read aloud, never drawn. `display:none` and `visibility:hidden` are
   both skipped by screen readers, which is the opposite of the point. */
.offscreen{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;
  border:0}
.skip{position:absolute;left:-9999px;top:0;z-index:10;padding:10px 14px;
  background:var(--surface);color:var(--ink);border:1px solid var(--line-2);
  border-radius:0 0 8px 0;font-size:13px;font-weight:600;text-decoration:none}
.skip:focus{left:0}
main:focus{outline:none}

label{display:block;margin-bottom:12px;font-size:13px;font-weight:600}
input[type=checkbox],input[type=radio]{width:24px;height:24px;min-width:24px;
  margin-top:0;accent-color:var(--ink)}
input,select{width:100%;margin-top:5px;padding:9px 10px;border:1px solid var(--line);border-radius:8px;
  background:var(--sunken);color:var(--ink);font:inherit}
form button[type=submit]{padding:9px 16px;border:0;border-radius:8px;background:var(--ink);
  color:var(--ground);font:inherit;font-weight:600;cursor:pointer}
.err{color:var(--bd);font-size:13px;margin:0 0 12px}
.feed{display:block;padding:10px 12px;background:var(--sunken);border:1px solid var(--line);
  border-radius:8px;font-family:RobotoMono,monospace;font-size:11.5px;word-break:break-all;cursor:pointer}
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,
textarea:focus-visible,summary:focus-visible,[tabindex]:focus-visible{
  outline:2px solid var(--ink);outline-offset:2px}

/* ---- setup screens ---- */
.setup-head{margin-bottom:16px}
.setup-head h1{margin-bottom:2px}
.setup-head .kidbar{padding:6px 0 0}
.banner{padding:9px 13px;border-radius:9px;font-size:13px;font-weight:600;margin:0 0 14px;
  border:1px solid var(--line)}
.banner.ok{background:var(--surface-2);border-color:var(--line-2);color:var(--ink)}
/* Used where a screen is about to do something large: changing the rotation,
   taking a child off the calendar. Deliberately not the error color, because
   nothing has gone wrong and nothing has happened yet.
   That sentence was here before --wn existed and the rule it states was not
   kept: this used --bd, which is the error color, so the comment described an
   intention the code never honored. Section 7 answer 6 is what made it true. */
.banner.warn{background:var(--surface-2);border-color:var(--wn);color:var(--ink);
  font-weight:400;line-height:1.55}
.banner.warn b{color:var(--wn)}
.change-list{margin:-6px 0 14px;padding-left:18px;font-size:13px;color:var(--ink-2)}
.change-list li{margin:3px 0}
.change-list li.more{list-style:none;margin-left:-14px;color:var(--ink-3);font-size:12.5px}
/* The name and its Remove sit on one line while there is room for it, and the
   button stays with the name it removes when there is not. */
.kid-row{align-items:end}
.kid-remove{padding:0 0 12px}
.errs{background:var(--surface-2);border:1px solid var(--bd);border-radius:9px;
  padding:11px 14px;margin:0 0 14px;font-size:13px}
.errs p{margin:0 0 5px;font-weight:700;color:var(--bd)}
.errs ul{margin:0;padding-left:18px} .errs li{margin:2px 0}

.setup-form .row{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:0 12px}
.setup-form fieldset{border:1px solid var(--line);border-radius:10px;padding:13px 14px 2px;
  margin:0 0 14px;min-width:0}
.setup-form legend{font-size:10.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--ink-3);padding:0 6px}
.hint{display:block;font-weight:400;font-size:11.5px;color:var(--ink-3);margin-top:4px}
label.check{display:flex;gap:8px;align-items:flex-start;font-weight:600;margin-bottom:12px}
label.check input{width:auto;margin:2px 0 0;flex:none}
label.check.inline{display:inline-flex;margin-right:16px}
fieldset.pick{padding-bottom:10px}
.actions{display:flex;gap:12px;align-items:center;flex-wrap:wrap}
.actions .sub{margin:0}
.inline-form{display:inline}
/* Beats `form button[type=submit]`, which would otherwise make Remove the
   loudest thing on the row. A destructive action should be quiet and reachable,
   not the first thing the eye lands on. */
form button.link{padding:0;border:0;border-radius:0;background:none;color:var(--ink-3);
  font:inherit;font-size:12.5px;font-weight:600;cursor:pointer;text-decoration:underline;
  display:inline-flex;align-items:center;min-height:24px}
form button.link:hover{color:var(--ink)}
form button.link.danger{color:var(--bd)}
.btn.sm{padding:3px 9px;font-size:12px}
.unset-cell{color:var(--ink-3);font-style:italic;white-space:nowrap}

.scroll{overflow-x:auto;margin:0 -2px}
.tbl{width:100%;border-collapse:collapse;font-size:13px}
.tbl th{text-align:left;font-size:10px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--ink-3);padding:0 10px 7px 0;white-space:nowrap}
.tbl td{padding:9px 10px 9px 0;border-top:1px solid var(--line);vertical-align:top}
.tbl tr.past{opacity:.5}
.tbl .how{color:var(--ink-2);font-size:12.5px;min-width:210px}
.tbl .pa-cell{color:var(--a);font-weight:700;white-space:nowrap}
.tbl .pb-cell{color:var(--b);font-weight:700;white-space:nowrap}
.row-actions{white-space:nowrap;text-align:right;padding-right:0}
.row-actions .btn{margin-right:8px}
/* Two forms side by side had nothing between them, so Approved adults read
   "Withdraw my approvalRemove" as one word, at every width and since the
   screen was built. It is one gap rather than a redesign: `.btn` already had
   its margin and nothing had ever put two of these forms in one cell. Found
   by stacking that table on a phone, where the run-on is unmissable. */
.row-actions .inline-form + .inline-form{margin-left:10px}
/* A quiet second line: under a name in a table row, or under the heading of a
   request. Metadata about something, never the thing itself.

   This was called `.note` until 25 August and `.note` was also the note card
   forty lines further down, which is declared later and therefore won. So
   every one of these rendered as a bordered box that looked like an empty
   input field: a caregiver's note on the approved adults tab, and all four
   machine-written lines on the requests screen. The visible cost was worse
   than untidy. On `/requests` the generated line "Declined by Alex, 20:07"
   got a hard border while the message the person actually typed got a soft
   fill, so the app shouted the timestamp and murmured the sentence.

   Renamed rather than reordered. Reordering fixes today and leaves the trap
   in place; `test_templates.py` now refuses any duplicated selector in this
   file, which is what actually stops it happening again. */
.subline{font-size:11.5px;color:var(--ink-3);font-weight:400;margin-top:2px}
.mono{font-family:RobotoMono,monospace;font-size:12px}
.tag.both{color:var(--on-accent);background:linear-gradient(90deg,var(--a) 50%,var(--b) 50%)}
.tag.kidsonly{color:var(--ink-2);background:var(--surface-2)}
.tag.ok{color:var(--ink);background:var(--surface-2)}
.tag.pending{color:var(--ink-2);background:var(--surface-2);
  box-shadow:inset 0 0 0 1px var(--line-2)}
.brk-head{display:flex;justify-content:space-between;align-items:baseline;gap:12px;
  flex-wrap:wrap;margin-bottom:12px}
.brk-head h2{margin:0}
.bday-row{align-items:end}
/* First run. Every child row keeps its own labels rather than hiding all but
   the first: the columns stack on a phone, where a single header row would be
   pointing at nothing, and a label per input is what a screen reader needs.
   The repetition is the honest cost of that. */
.kid-rows .row{gap:0 12px}
.kid-rows .row + .row{border-top:1px dashed var(--line);padding-top:12px}
textarea.mono{font-family:RobotoMono,monospace;font-size:12.5px;line-height:1.6}
.bday-row .check{align-self:center;padding-bottom:12px}
/* Change requests. The status color is carried on a left edge rather than a
   background, so a long list of settled requests stays readable and the two
   parent colors keep their meaning of who has the children. */
.pip{display:inline-block;min-width:17px;margin-left:5px;padding:0 5px;border-radius:999px;
  background:var(--wn);color:var(--on-accent);font-size:10.5px;font-weight:700;
  text-align:center;font-variant-numeric:tabular-nums}
.req{border-top:1px solid var(--line);padding:14px 0 4px}
.req:first-of-type{border-top:0;padding-top:0}
.req.accepted,.req.declined,.req.countered,.req.withdrawn{opacity:.72}
.req-head{display:flex;gap:9px;align-items:baseline;flex-wrap:wrap;margin-bottom:9px}
.req-head strong{font-size:13.5px}
.req-when{color:var(--ink-3);font-size:11.5px;margin-left:auto;
  font-family:RobotoMono,monospace}
.req-lines{margin:0 0 10px;padding-left:17px;font-size:13.5px}
.req-lines li{margin:3px 0}
.req-msg{margin:0 0 10px;padding:9px 12px;background:var(--sunken);border-radius:9px;
  font-size:13px;color:var(--ink-2)}
.req-msg cite{display:block;margin-top:4px;font-size:11px;font-style:normal;
  font-weight:700;color:var(--ink-3)}
.drift{border:1px solid var(--wn);border-radius:9px;padding:10px 13px;margin:0 0 11px;
  font-size:12.5px;background:var(--surface-2)}
.drift p{margin:0 0 5px;font-weight:700;color:var(--wn)}
.drift.flat p,.drift.flat{margin-bottom:11px}
.drift ul{margin:0;padding-left:17px} .drift li{margin:2px 0;color:var(--ink-2)}
/* The closing line is context, not a second alarm, so it opts back out of the
   color the heading uses. `.drift p` outranks `.hint` on its own. */
.drift p.hint{margin-top:6px;margin-bottom:0;font-weight:400;color:var(--ink-3)}
.req .answer{margin:0 0 4px}
.req .answer label{margin-bottom:9px}
.tag.no{color:var(--ink-3);background:var(--surface-2)}
.tag.agreed{color:var(--ex);background:var(--ex-tint)}
/* Every submit button in a form is filled dark by default, which would give
   Decline exactly as much weight as Accept. Only one action on this page moves
   the calendar, and it should be the only one that looks like it. */
form button[type=submit].btn{background:var(--surface);color:var(--ink);
  border:1px solid var(--line-2);font-weight:600}
form button[type=submit].btn:hover{background:var(--surface-2)}
.btn.go,form button[type=submit].btn.go{background:var(--ink);border-color:var(--ink);
  color:var(--ground);font-weight:700}
.btn.go:hover,form button[type=submit].btn.go:hover{background:var(--ink-2);
  border-color:var(--ink-2)}
/* Answer 14, one shape. `.empty` was the old name and there is deliberately
   no rule for it any more, so a screen still using it stands out rather than
   quietly inheriting something close enough. The state half stays italic
   because it is the app describing itself; the next step is an instruction and
   is set upright, which is the only way the two halves read as two halves. */
.blank{color:var(--ink-3);font-size:13px;margin:0;font-style:italic}
/* The next step is an instruction rather than the app describing itself, and
   setting it upright is the only thing that makes the two halves read as two. */
.blank .blank-next{font-style:normal}
.blank .blank-next a{color:var(--ink-2)}
textarea{width:100%;margin-top:5px;padding:9px 10px;border:1px solid var(--line);
  border-radius:8px;background:var(--surface);color:var(--ink);font:inherit;
  font-size:14px;resize:vertical}

@media (max-width:720px){
  .row-actions{text-align:left}
  .setup-form .row{grid-template-columns:minmax(0,1fr)}
  .req-when{margin-left:0;width:100%}
}
/* Room at the edges on a narrow window, for every screen and not just the
   calendar. Separate from the calendar block below because it is answering a
   different question: this one is about a window, that one is about seven
   columns. */
@media (max-width:720px){
  .wrap{padding-top:16px;padding-left:10px;padding-right:10px}
}

/* The calendar on a phone, answers 12 and 13.

   440, and measured rather than picked. The number is where a tag stops being
   able to hold the word inside it: below about 440 a day cell has under 45
   pixels of usable width, and the tags this app writes are words like Hosmer
   and Thanksgiving. The old block shrank them to 8 pixels to make them fit,
   which is answer 13's argument in one line: that is not making them fit, it
   is making them decoration.

   So the tags go and the name stays, and the grid stays a grid. A rotation is
   a pattern and only a grid shows a pattern, which is answer 12 and is the
   whole reason this is not a list of days.

   The padding here is tight on purpose and every pixel of it was spent on the
   name. The measurements, at 360 which is the common cheap Android and the
   narrowest width worth designing for: the cell is 47 wide, the rail and the
   padding take 8, and the name gets the rest. */
@media (max-width:440px){
  /* The month and the arrows and Today, kept on one line. `.cal-head` wraps,
     and at 320 the serif month name was wide enough to push Today onto a
     second row and make the header taller than two weeks of the grid. */
  .cal-head{padding:11px 10px;gap:8px}
  .month{font-size:17px;min-width:0}
  .dow,.grid{padding-left:3px;padding-right:3px;gap:2px}
  .day{min-height:58px;padding:4px 1px 4px 6px}
  .day::before{width:3px}
  /* ---- a table that stops being a table, opt-in through `.stack` ----

     The phone check on 26 August found the Holidays tab hiding the answer.
     The table is 570 pixels wide inside a 325 pixel scroller, so 43 percent of
     it sat off to the right, and what sat off to the right was Even years and
     Odd years: the names, which are the whole question that screen exists to
     answer. It scrolled, so nothing was lost, but the widest column was the
     sentence and the answer was the part over the edge.

     So each row becomes a small block and the column headings move in front of
     the cells they belong to. `data-label` carries the heading, which is why
     the markup has it: CSS cannot reach a `<thead>` from a `<td>`.

     Not called `.stack`, which was the first name and is already taken by
     the child file's form. `.tbl.stack` would not in fact have collided,
     because the table scopes it, but a second meaning for one class name is
     how two screens end up sharing a rule neither of them knows about. The
     test that reads every rule outside the phone block is what found it.

     Opt-in on purpose. There are eight of these tables in setup and this rule
     changes the shape of any table it touches, so a table adopts it by adding
     the class and the labels rather than by being caught in a selector. The
     mechanism is general and the other seven can take it whenever somebody has
     looked at them on a phone; nothing here is specific to holidays. */
  .blocks,.blocks tbody,.blocks tr,.blocks td{display:block}
  .blocks thead{display:none}
  /* On `.blocks` rather than `.tbl.blocks`, which is what it said until the
     Time table wanted it. That table is a `table.tally` and shares none of
     `.tbl`'s classes, and the six rules here are about display order and know
     nothing about which table they are stacking. The class stays opt-in: what
     changed is that a table no longer has to be a `.tbl` to opt in. */
  .blocks td{border-top:none;padding:1px 0}
  /* The block, and its edge. A row needs to read as one thing now that it is
     five stacked lines, and the line between rows is the only thing saying
     where one holiday stops. */
  .blocks tr{border-top:1px solid var(--line);padding:11px 0}
  .blocks tr:first-child{border-top:none;padding-top:2px}
  /* The name of the holiday is the block's heading rather than a labeled
     field, so it is the one cell with no label in front of it. */
  /* The weight is here rather than in the markup because this cell is bold
     in every table but one. The commitments table on Notes writes its first
     column as plain text, at the desk as well, and that is its own choice; a
     `<b>` added for the phone's benefit would have changed the desk too. */
  .blocks .rowhead{font-size:14px;padding-bottom:4px;font-weight:600}
  .blocks td[data-label]::before{content:attr(data-label) ": ";
    color:var(--ink-3);font-weight:700;font-size:10px;letter-spacing:.09em;
    text-transform:uppercase}
  /* **The definition goes last, under the answer.** This is the whole point of
     the fix arriving somewhere it can be seen: in source order the sentence
     sits between the holiday and who has it, which on a phone is the same
     failure as before wearing a different shape. Only the cells move, and none
     of them is focusable, so nothing keyboard-reachable is reordered. */
  .blocks tr{display:flex;flex-direction:column}
  .blocks .how{order:2;min-width:0;padding-top:3px}
  .blocks .row-actions{order:3}
  /* The last line of a block is the one that gets acted on, so it gets the
     gap. On `td:last-child` rather than on `.row-actions`, because the
     rotations table ends in a cell that is a status pill with a Remove under
     it and is not a `.row-actions` at all: without this the link sat one
     pixel under the pill. */
  .blocks td:last-child{padding-top:7px}
  /* And inside that cell, when what follows the pills is a whole form rather
     than an inline one. The rotations table's Remove is a block form, so it
     landed hard against the bottom of the warning pill. Inline forms ignore a
     vertical margin, so this reaches the one case that needs it and none of
     the cells where Edit and Remove already sit on a line together. */
  .blocks td:last-child form{margin-top:6px}

  /* The clause table in the mediator report keeps its shape on a phone and
     gives its first column back. `min-width:9em` is right for the tables whose
     row header is a date range and wrong for the one whose row header is "4.2":
     113 pixels went to two characters while the clause itself got 142, which is
     four words to a line. The nights tables keep the minimum, which is what it
     was written for. */
  table.doc-table.wide:not(.nights) th[scope=row]{min-width:0}

  /* The Time table, which is the one two dimensional thing that got stacked.
     Its own rules are written for a grid of figures and each of them is wrong
     once a row is a block: numbers pushed to the right edge of the screen, a
     `nowrap` that no longer has anything to protect, and a vertical rule
     dividing halves that are no longer side by side.

     The labels this one carries are compound, "Nights, Alex" rather than
     "Alex", because its heading is two rows deep and either half alone is
     ambiguous. That is the header structure being folded into the label,
     which is the only honest way to flatten a table with a `colspan` in it. */
  table.tally.blocks th,table.tally.blocks td{text-align:left;
    white-space:normal;padding:1px 0}
  table.tally.blocks th:nth-child(5),table.tally.blocks td:nth-child(5){
    border-left:none}

  /* Print is a desk gesture, so it goes here rather than into the thumb bar.
     Measured rather than assumed: with the button in the header at 375, which
     is the common iPhone, every month name except October pushed Today and
     Print onto a second row and took the header from 57 pixels to 93. That is
     most of a grid row spent on a control nobody presses with a thumb, on the
     one screen both parents open daily. The phone loses nothing it had the day
     before: printing from a phone is the browser's own share menu, which is
     where it was already. */
  .cal-acts [data-print]{display:none}
  /* Answer 13. What is on a day is one tap away; whose night it is is not. */
  .day .tag,.day .foot{display:none}
  /* Not 9. That was the phone-only shrink answer 13 exists to undo, and the
     name is the one thing in the cell that has to survive the phone. */
  .who{font-size:11px}
  .num{font-size:12px}
  .wfull{display:none}
  .wshort{display:inline}
}

/* Recovery codes, shown once. Monospaced and selectable in one gesture,
   because what actually happens here is a drag and a paste into a password
   manager, and anything decorative gets in the way of that. */
.codes{font:13.5px/1.9 RobotoMono,ui-monospace,Menlo,monospace;background:var(--surface-2);
  border:1px solid var(--line);border-radius:9px;padding:12px 14px;margin:0 0 12px;
  letter-spacing:.04em;overflow-x:auto;user-select:all}

/* ---- hours and nights ----
   Two rules hold the tone of this screen. Neither parent's color leads: they
   are always in slot order and always the same weight. And the three kinds of
   time that belong to neither of you get full-strength treatment rather than a
   thin gray sliver, because the whole point of the screen is that school is
   large and the reason the split looks uneven. */
.rangeform{display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;margin:12px 0 2px}
.rangeform label{margin:0;font-size:11px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-3)}
.rangeform input{width:auto;min-width:150px}
.rangeform button{margin-bottom:1px}

.card.range h2{margin-bottom:2px;font-size:17px}
.card.range .sub{margin:0}

.measure{margin-bottom:22px}
.measure:last-child{margin-bottom:0}
.measure h3{margin:0 0 10px;font-size:11px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--ink-3)}
.measure h3 .of{font-weight:400;letter-spacing:0;text-transform:none;font-size:12px}
.figures{display:flex;gap:10px;margin-bottom:8px}
.fig{flex:1 1 0;min-width:0;padding:9px 12px;border-radius:9px;background:var(--surface-2)}
.fig .lbl{display:block;font-size:11.5px;font-weight:600;color:var(--ink-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fig strong{font:600 20px/1.25 Fraunces,Georgia,serif;display:block;margin-top:1px}
.fig.pa{background:var(--a-tint)} .fig.pa strong,.fig.pa .lbl{color:var(--a)}
.fig.pb{background:var(--b-tint)} .fig.pb strong,.fig.pb .lbl{color:var(--b)}
.aside{margin:7px 0 0;font-size:12px;line-height:1.55}

.wherebar{display:flex;height:30px;border-radius:7px;overflow:hidden;
  background:var(--sunken);margin-bottom:12px}
/* A bucket holding a few hours across a school year rounds to 0% and would
   otherwise be a key entry with no bar behind it. */
.wherebar .seg{min-width:3px}
.wherekey{list-style:none;margin:0;padding:0;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(275px,1fr));gap:2px 22px}
.wherekey li{display:flex;align-items:center;gap:8px;font-size:12.5px;padding:3px 0}
.wherekey .key{flex:none;width:11px;height:11px;border-radius:3px}
.wherekey .nm{color:var(--ink-2);white-space:nowrap}
.wherekey .val{margin-left:auto;white-space:nowrap;font-variant-numeric:tabular-nums}
.wherekey .pc{width:38px;text-align:right;font-weight:700;
  font-variant-numeric:tabular-nums}
.k-A .key,.wherebar .seg.k-A{background:var(--a)}
.k-B .key,.wherebar .seg.k-B{background:var(--b)}
.k-both .key,.wherebar .seg.k-both{background:linear-gradient(135deg,var(--a) 0 50%,var(--b) 50% 100%)}
.k-school .key,.wherebar .seg.k-school{background:var(--sc)}
.k-care .key,.wherebar .seg.k-care{background:var(--ex)}
/* The same hatch the calendar uses for a night nobody holds, so "not
   scheduled" looks like itself in both places. */
.k-none .key,.wherebar .seg.k-none{
  background:repeating-linear-gradient(135deg,var(--line-2) 0 4px,transparent 4px 8px)}

.scroller{overflow-x:auto}
table.tally{width:100%;border-collapse:collapse;font-size:13px;
  font-variant-numeric:tabular-nums}
table.tally th,table.tally td{padding:7px 10px;text-align:right;white-space:nowrap}
table.tally th[scope=row]{text-align:left;font-weight:600}
table.tally thead th{font-size:10.5px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--ink-3);text-align:center}
table.tally thead tr:first-child th{border-bottom:1px solid var(--line)}
table.tally thead tr.sub-head th{text-align:right;font-size:10px}
table.tally tbody tr{border-top:1px solid var(--line)}
table.tally td.pct{color:var(--ink-3)}
/* The two halves of the table are the two measures, and without this they read
   as one run of six numbers. */
table.tally th:nth-child(5),table.tally td:nth-child(5){
  border-left:1px solid var(--line)}

.defs .rows{font-size:12.5px;gap:7px 14px}
.defs .rows dt{color:var(--ink)}
.defs .rows dd{color:var(--ink-2)}

@media (max-width:720px){
  .figures{flex-direction:column;gap:7px}
  .rangeform input{min-width:0;width:100%}
  .rangeform label{flex:1 1 130px}
  .wherekey{grid-template-columns:minmax(0,1fr)}
}
table.tally .nil{color:var(--ink-3)}

/* ---- notes and standing items ----
   A note looks like a message and a standing item looks like a setting,
   because that is what each one is. If they ever look alike, somebody writes a
   message into a setting or expects a setting to be a record. */
.note{border:1px solid var(--line);border-radius:10px;padding:11px 13px;margin:0 0 10px;
  background:var(--surface)}
.note.mine{background:var(--surface-2)}
.note-head{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;margin-bottom:5px}
.note-head strong{font-size:13px}
.note-when{font-size:11.5px;color:var(--ink-3)}
.note-day{margin:0 0 5px;font-size:11px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-3)}
.note-body{margin:0;font-size:14px;line-height:1.55;white-space:pre-wrap}
.note-note{margin:7px 0 0;font-size:12px;color:var(--ink-3);font-style:italic}
.note-actions{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:9px 0 0}
/* Withdrawn and replaced both stay readable. They are part of the record, so
   they are muted rather than hidden, and never struck through: the words were
   said and pretending otherwise is the thing this table exists to prevent. */
.note.gone,.note.old{opacity:.72;background:transparent;border-style:dashed}
.seen{margin-left:auto;font-size:11px;color:var(--ink-3);white-space:nowrap}
.seen.on{color:var(--ink-2);font-weight:700}

.standing-row{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 10px}
.standing{font-size:11.5px;border:1px solid var(--line);border-radius:999px;
  padding:3px 10px;color:var(--ink-2);background:var(--sunken)}
.standing b{color:var(--ink);font-weight:700}

.daygroup{padding:0 0 4px;margin:0 0 14px;border-left:2px solid var(--line);
  padding-left:13px}
.daygroup:last-child{margin-bottom:0}
/* Today, which is not one of the parents. It was --a, which made the current
   day on the notes screen wear one parent's color. The calendar already marks
   today in --ink, so this now agrees with it. */
.daygroup.now{border-left-color:var(--ink)}
.daygroup h3{margin:0 0 8px;font-size:11px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--ink-3)}
.daygroup.now h3{color:var(--ink)}

@media (max-width:720px){
  .seen{margin-left:0;width:100%}
  .note-actions{gap:8px}
}

/* ---------------------------------------------------------- the child file */

/* The list screen. A card per child, and what it carries is the urgent facts
   themselves rather than a count of them: "3 things" is nothing anybody can
   act on, and the argument for this screen is that a peanut allergy should be
   readable without a second click. */
.kidcard-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.kidcard-head h2{margin:0}
.kidcard-head h2 a{text-decoration:none}
.kidcard-head h2 a:hover{color:var(--ink)}
.kidcard .count{font-size:11.5px;color:var(--ink-3);white-space:nowrap}

.urgentlist{list-style:none;margin:10px 0 0;padding:0;display:grid;gap:7px}
.urgentlist li{font-size:13.5px;line-height:1.45;color:var(--ink-2)}
.urgentlist b{color:var(--ink);font-weight:700}

/* The kind, as a word rather than a color alone: the three that appear here
   are the ones somebody may be reading out to a nurse, and a legend you have
   to have learned is no use at that moment. */
.pill{display:inline-block;margin-right:5px;padding:1px 7px;border-radius:999px;
  font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  vertical-align:1px;background:var(--sunken);color:var(--ink-3)}
/* There is no --bd-tint, and inventing one for this would put a color outside
   the token set, so the color is carried as a ring instead of a fill.
   This stays --bd where the birthday tag no longer does. An allergy is the one
   place in this app where something can actually go wrong for a child, which is
   what --bd is now reserved for. Section 7, answers 5 and 6. */
.pill.allergy{background:transparent;color:var(--bd);box-shadow:inset 0 0 0 1px var(--bd)}
.pill.condition{background:var(--sc-tint);color:var(--sc)}
.pill.medication{background:var(--ex-tint);color:var(--ex)}

/* The file itself. */
.crumb{font-size:11.5px;color:var(--ink-3);margin:0 0 8px}
.factgroup{background:var(--surface);border:1px solid var(--line);border-radius:12px;
  padding:16px;margin-bottom:16px}
/* The urgent three carry a left edge and nothing louder. This screen is read by
   somebody already worried, and a red panel would add to that without telling
   them anything they did not come here knowing. */
.factgroup.urgent{border-left:3px solid var(--bd)}

.fact{padding:11px 0;border-top:1px solid var(--line)}
.fact:first-of-type{border-top:0;padding-top:2px}
.fact.pinned .fact-value{font-weight:600}
.fact-head{display:flex;gap:8px;flex-wrap:wrap;align-items:baseline}
.fact-head strong{font-size:13.5px;font-weight:700;min-width:7ch}
.fact-value{font-size:14.5px;color:var(--ink)}
.fact-detail{margin:5px 0 0;font-size:13px;line-height:1.5;color:var(--ink-2)}
.fact-foot{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;margin:7px 0 0}
/* Small, last, never a heading. The useful part is whether the dose you are
   reading was written down two years ago or corrected last week. It must not
   read as a ledger of who touched what. */
.fact-who{font-size:11px;color:var(--ink-3)}
.fact-actions{display:flex;gap:12px;align-items:baseline;margin-left:auto}
/* The weight is set on both and not left to inherit. Change is an anchor and
   Remove is a button, and a button picks up 600 from elsewhere in this file, so
   the destructive one was rendering as the heavier of the two. */
/* Both axes, and the second one arrived late. The accessibility pass on
   26 August raised these to 24 tall and stopped there, because the browser
   sweep behind it had measured heights: everything it found was too short and
   nothing it looked at was too narrow. "Edit" is four characters at 12px and
   comes out 22 wide, which is the one label in the app short enough for the
   other axis to bind. It conformed anyway, through 2.5.8's spacing exception,
   which is why it took a second look on a phone to notice.

   `justify-content` because the box is now wider than its text and the
   underline should sit under the word rather than off to one side. */
.fact-actions .link{font-size:12px;font-weight:400;color:var(--ink-3);
  text-decoration:underline;display:inline-flex;align-items:center;
  justify-content:center;min-height:24px;min-width:24px}
.fact-actions .link:hover{color:var(--ink)}
button.link.quiet{font-size:12px;font-weight:400;color:var(--ink-3);
  text-decoration:underline}
/* 2.5.8 again. A fold is a control, and all three of these were 17px tall. */
summary{min-height:24px;padding:3px 0}

.stack{display:grid;gap:12px}
.stack label{display:grid;gap:4px;font-size:12px;font-weight:600;color:var(--ink-2)}
.stack input[type=text],.stack select,.stack textarea{width:100%;padding:8px 10px;
  border:1px solid var(--line-2);border-radius:8px;background:var(--surface);
  color:var(--ink);font:inherit;font-size:14px}
.stack textarea{resize:vertical;line-height:1.5}
/* Clearly a suggestion rather than a filled-in value. These examples are
   full sentences, and at the default weight the form reads as already
   answered. */
.stack ::placeholder{color:var(--ink-3);opacity:.75}
.stack label.check{display:flex;gap:8px;align-items:flex-start;font-weight:400}
.stack .hint{display:block;font-weight:400;color:var(--ink-3);font-size:11.5px}

@media (max-width:720px){
  .fact-actions{margin-left:0}
  .fact-head strong{min-width:0}
}

/* ----------------------------------------------------------- the care log */

/* The headline. Read at 2am, half asleep, so it is the largest text on the
   page after the child's name, and it states without advising: how long ago,
   never whether another one is due. See care_render.py. */
.doselist{list-style:none;margin:0;padding:0;display:grid;gap:10px}
.doselist.tight{gap:6px}
/* A dose GIVEN is not a standing fact about the child, and on the card the two
   lists sit one under the other. The heading is what keeps them apart; spacing
   alone was not enough and read as one list. */
.given{margin:12px 0 0;padding:10px 0 0;border-top:1px solid var(--line)}
.given h3{margin:0 0 7px;font-size:10px;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--ink-3)}
.dose{display:grid;gap:1px}
.dose-line{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 10px}
.dose-what{font-size:16px;font-weight:600;color:var(--ink)}
.doselist.tight .dose-what{font-size:14px}
.dose-since{font-size:15px;font-weight:700;color:var(--ink);
  font-variant-numeric:tabular-nums}
.doselist.tight .dose-since{font-size:13px}
/* Its own line, always. Deliberately quiet and deliberately present: the exact
   clock time is what somebody reads out to a nurse, and the "4 hours ago" above
   it is what they need first. Neither is a judgement about the other. On one
   line these wrapped for the long entries and not the short ones. */
.dose-when{font-size:12px;color:var(--ink-3)}
.doses .sub{margin:14px 0 0}
.empty-doses .blank{margin:0}

.daylog h2{margin-bottom:12px}
.entry{padding:11px 0;border-top:1px solid var(--line)}
.entry:first-of-type{border-top:0;padding-top:2px}
.entry-head{display:flex;gap:8px;align-items:baseline}
.entry-when{font-family:RobotoMono,monospace;font-size:12.5px;font-weight:600;
  color:var(--ink-2);font-variant-numeric:tabular-nums}
.entry-kind{font-size:9.5px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--ink-3);margin-left:auto}
.entry.medication .entry-kind{color:var(--ex)}
.entry-what{margin:3px 0 0;font-size:14.5px}
.entry-detail{margin:4px 0 0;font-size:13px;line-height:1.5;color:var(--ink-2)}
.entry-foot{display:flex;gap:10px;flex-wrap:wrap;margin:6px 0 0}
.entry-by,.entry-late{font-size:11px;color:var(--ink-3)}
/* Said only when the two timestamps are hours apart, and worth its own color
   when it is: it is the difference between a log you can trust and one you
   cannot. */
.entry-late{color:var(--ink-2);font-weight:600}
.entry-actions{margin:6px 0 0}
.entry-note{margin:6px 0 0;font-size:11.5px;line-height:1.5;color:var(--ink-3)}
/* Withdrawn stays readable and is never struck through, exactly like a
   withdrawn note. It was logged, and pretending otherwise is the thing an
   append-only table exists to prevent. */
.entry.gone{opacity:.72}
.entry.gone .entry-what{text-decoration:none;color:var(--ink-2)}

/* The days you both mean to be there. A tag, never a change to the day's
   color: the flag marks the day and does not move custody, and recoloring
   the cell would say that it had. */
.tag.both-tag{color:var(--on-accent);
  background:linear-gradient(90deg,var(--a) 0 50%,var(--b) 50% 100%)}
.both-note{color:var(--ink-2);font-weight:600}

/* ---- the document register ----
   A clause and the rule implementing it are two objects, and this stylesheet's
   job is to keep them looking like two. The clause is the plan's words and is
   set in prose; the rule underneath it is the engine's words and is set small
   and gray. A row where the two ran together would hide the one sentence this
   screen exists to say, which is that they have stopped matching. */
.split-bar.cov span{font-size:11px}
.split-bar .cov-ok{background:var(--ink-2);color:var(--ground)}
.split-bar .cov-warn{background:var(--wn);color:var(--on-accent)}
.split-bar .cov-todo{background:var(--surface-2);color:var(--ink-2)}
/* A divergence is settled, so it sits with the filled part of the bar rather
   than the empty part, and takes its own color because it is settled by
   agreement rather than by the app doing anything. */
.split-bar .cov-agreed{background:var(--ex);color:var(--on-accent)}
.clause{margin-top:3px;font-size:13px;line-height:1.5;color:var(--ink-2);
  max-width:52ch;white-space:pre-wrap}
/* Named rule-line rather than note. `.note` is defined twice in this file, and
   the second definition, a bordered box for the notes screen, is the one that
   wins. Reusing it here would put a card around one line of gray text. */
.rule-line{font-size:11.5px;color:var(--ink-3);margin-top:2px;max-width:46ch}
.rule-line b{color:var(--ink-2)}
.rule-line.warn{color:var(--ink-2);border-left:2px solid var(--wn);
  padding-left:8px;margin-top:5px}
/* The two readings nobody typed. A left edge rather than a fill: the row still
   has to be read, and a red row reads as an error in the app rather than as a
   question for the person looking at it. It was a red row until section 7
   answer 6; the argument in this comment is what that answer generalized. */
tr.attention td:first-child{box-shadow:inset 2px 0 0 var(--wn)}
/* A superseded document stays legible. It is the document that explains what
   happened while it was in force, and dimming it to unreadable would answer
   the question people open the register to ask. */
.card.dim{opacity:.78;border-style:dashed}
/* The link controls. Only the rows asking a question get an open one: a select
   on every row turns the register into a form, and the two rows that need
   somebody stop standing out from the twenty that do not. */
.actions.tight{gap:14px;margin-top:5px}
.linkform{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:4px}
.linkform select{max-width:min(340px,100%);font-size:12px;padding:4px 6px}
.linkfold{margin-top:4px}
.linkfold summary{font-size:11.5px;color:var(--ink-3);cursor:pointer;
  list-style-position:outside}
.linkfold summary:hover{color:var(--ink-2)}

/* The line on the calendar saying the other parent produced a report. On this
   screen because it is the one both parents open daily, and dismissible
   because a banner that never goes away is a banner nobody reads. It is a
   statement and not a question: there is nothing here to approve, since either
   parent may produce one whenever they like. */
.notice{display:flex;gap:12px;align-items:center;flex-wrap:wrap;
  background:var(--surface);border:1px solid var(--line-2);border-left:3px solid var(--ex);
  border-radius:10px;padding:11px 14px;margin:0 0 16px;font-size:13px;line-height:1.55}
.notice p{margin:0;flex:1 1 260px}
.notice form{margin:0}

/* ---- the mediator report ---- */
/* Two things live here. A few classes for the picker screen, and then the
   document itself, which is the only page in this app written for somebody who
   is not one of the two parents and has never seen it before.

   The document's rule: no color carries meaning. It gets printed, photocopied
   and faxed, and a colored cell that means one parent is a gray cell that means
   nothing two machines later. Every distinction is made in words. */
.plain{list-style:none;margin:0 0 12px;padding:0;font-size:13px;line-height:1.55}
.plain li{padding:4px 0 4px 15px;position:relative;color:var(--ink-2)}
.plain li:before{content:"";position:absolute;left:2px;top:12px;width:5px;height:5px;
  border-radius:50%;background:var(--line-2)}
.plain.log li{color:var(--ink);border-top:1px solid var(--line);padding-left:0}
.plain.log li:first-child{border-top:0}
.plain.log li:before{display:none}
.plain.log .sub{display:inline;margin-left:6px}
.card h3{margin:16px 0 6px;font-size:13px}

.doc{max-width:760px;margin:0 auto}
.doc-controls{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:0 0 18px}
.doc-controls .sub{margin:0;flex:1 1 220px}
.doc-head{border-bottom:2px solid var(--ink);padding-bottom:14px;margin-bottom:22px}
.doc-kind{margin:0;font-size:10.5px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink-3)}
.doc-head h1{margin:4px 0 14px;font-size:26px}
.doc-meta{display:grid;grid-template-columns:auto 1fr;gap:4px 16px;margin:0;font-size:13px}
.doc-meta dt{font-weight:700;color:var(--ink-3);white-space:nowrap}
.doc-meta dd{margin:0}
.doc-sec{margin:0 0 26px}
.doc-sec h2{font-size:17px;margin:0 0 8px;padding-bottom:5px;
  border-bottom:1px solid var(--line);text-transform:none;letter-spacing:normal;
  color:var(--ink)}
.doc-sec h3,.doc-doc h3{font-size:14px;margin:16px 0 4px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.doc-note{margin:0 0 10px;font-size:12.5px;line-height:1.6;color:var(--ink-2)}
.doc-warn{margin:0 0 20px;padding:10px 13px;border:1px solid var(--ink-3);
  border-radius:8px;font-size:12.5px;line-height:1.6}
.doc-quote{margin:5px 0 0;padding-left:11px;border-left:2px solid var(--line-2);
  font-size:12.5px;line-height:1.55;color:var(--ink-2)}
.doc-cite{display:block;margin-top:3px;font-size:11.5px;color:var(--ink-3)}
.doc-list{margin:0;padding-left:20px;font-size:13px}
.doc-req{margin:0 0 14px}
.doc-req .plain{margin:0 0 4px}
/* No dot on these. The request is already numbered by the list it sits in, and
   two markers on one line reads as a nesting that is not there. */
.doc-req .plain li{padding:2px 0}
.doc-req .plain li:before{display:none}
.doc-doc{margin:0 0 20px}
.doc-foot{border-top:1px solid var(--line);padding-top:12px;margin-top:30px;
  font-size:11.5px;color:var(--ink-3)}
.doc-foot p{margin:0}
table.doc-table{width:100%;border-collapse:collapse;font-size:12.5px;margin:0 0 6px}
table.doc-table th,table.doc-table td{padding:7px 10px;text-align:right;
  vertical-align:top;border-top:1px solid var(--line)}
table.doc-table thead th{border-top:0;border-bottom:1px solid var(--ink-3);
  font-size:10px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  color:var(--ink-3)}
table.doc-table th[scope=row]{text-align:left;font-weight:600;white-space:nowrap}
/* The prose tables. Nothing in them is a figure, so right alignment would be
   wrong and nowrap would push a clause off the side of the paper. */
table.doc-table.wide th,table.doc-table.wide td{text-align:left}
table.doc-table.wide th[scope=row]{white-space:normal;min-width:9em}
/* Column two is a count of nights, so it is right aligned and never wrapped.
   On `.nights` and not on every wide table, which is what it used to say and
   was a bug at every width. "Agreements on file" is also a wide table and its
   second column is the text of a clause, so `nowrap` set one parenting plan
   provision on a single 687 pixel line and took the table to 887 inside a 760
   pixel document. It ran off the side of the mediator report, which is the one
   thing this app produces to be handed to somebody outside the family, and a
   sheet of paper is about 700 pixels wide, so it ran off that too.

   The selector names what the column means rather than where it sits. A wide
   table added later wraps by default, which is the safe way round. */
table.doc-table.nights td:nth-child(2){text-align:right;white-space:nowrap}

@media print{
  /* The app's only print stylesheet, and it exists for one page. Everything
     that belongs to the application rather than to the document goes away, and
     the ground becomes paper: the dark theme prints as a black rectangle
     otherwise, and it will be printed in whichever theme the browser is in. */
  :root{color-scheme:light;--ground:#fff;--surface:#fff;--surface-2:#fff;--sunken:#fff;
    --ink:#000;--ink-2:#333;--ink-3:#555;--line:#bbb;--line-2:#999}
  .skip,.bar,.no-print{display:none !important}
  body{background:#fff;color:#000;font-size:11pt}
  .wrap{max-width:none;padding:0}
  .doc{max-width:none}
  .doc-head h1{font-size:20pt}
  .doc-sec h2{font-size:13pt}
  /* Keep a heading with what it introduces, and never split a run of nights or
     a clause across two sheets. A table that breaks mid-row is the one thing
     guaranteed to be quoted back wrongly.

     Deliberately not `break-inside:avoid` on the sections themselves. A period
     with forty change requests in it makes that section longer than a sheet of
     paper, and a block that cannot fit on a page it may not be broken across
     either overflows or leaves most of a page blank. Rows and clauses are the
     units small enough for the promise to be keepable. */
  .doc-sec{margin-bottom:20pt}
  .doc-sec h2,.doc-sec h3{break-after:avoid-page}
  .doc-req,.doc-doc,tr{break-inside:avoid}
  thead{display:table-header-group}
  a{text-decoration:none}

  /* ------------------------------------------------ the month, answer 16 */

  /* A page of paper is about 700 css pixels wide, which is under the 720 the
     nav uses and over the 440 the calendar uses. So the phone nav rules apply
     to a printed page and the phone calendar rules do not, and both of those
     are accidents of arithmetic rather than decisions. The nav is hidden here
     anyway; the calendar's are put back explicitly so that a narrower sheet,
     or a browser that scales, cannot silently print the short names. */
  .wfull{display:inline}
  .wshort{display:none}
  .day .tag,.day .foot{display:inline-block}

  .cols{display:block}
  /* The controls are the application. The month is the document. */
  .cal-head .btn{display:none}
  .cal-head{border-bottom:none;padding:0 0 10pt}
  .month{font-size:17pt}

  /* The filter becomes a statement. Without this a sheet showing one child is
     indistinguishable from a sheet showing the family, which is the kind of
     ambiguity that only ever shows up after somebody has acted on it. */
  .kidbar{padding:0 0 8pt}
  .kidbar .chip:not(.on){display:none}
  .kidbar .chip.on{background:none;border:none;color:#000;padding:0;
    font-weight:700}

  /* **The night count does not print, and that is a decision.** A printed
     month is the sheet that ends up on a fridge or in somebody else's hand,
     and "16 nights with Alex, 14 with Blake" on it turns a calendar into a
     scoreboard. The mediator report is the document built to be read by
     someone outside this family and it carries no score on purpose; a sheet
     that leaves by the same door should not carry one either. The day panel
     goes with it because it is a screen, not a page. */
  .side{display:none}

  .card.cal{border:none;padding:0}
  /* **The name in the cell is what carries whose night it is on paper.** A
     browser does not print backgrounds unless the person asks it to, so the
     tints and the color rail are usually simply absent, and forcing them on
     would not rescue anything: the two parent tints are within two percent of
     each other in lightness by design, so a mono printer renders them as the
     same gray. The tint rules are left alone rather than overridden, so that
     somebody who does turn background graphics on gets a better sheet and
     nobody who does not gets a worse one. Either way the cell has a border
     and a name in it, which is the whole of what the sheet has to say.

     The rail goes, because a rail nobody can tell apart from the other
     parent's is decoration pretending to be information. */
  .day{border:1px solid #bbb;min-height:76pt;break-inside:avoid}
  .day::before,.day::after,.day .dayband{display:none}
  .day.out{opacity:1;color:#777}
  .day.out .who,.day.out .num{color:#777}
  .day.today .num{background:none;color:#000;text-decoration:underline}
  .day.sel{border-color:#bbb;box-shadow:none}
  .who{font-size:9.5pt}
  .grid,.dow{padding:0;gap:3pt}
  .dow span{font-size:8pt}
  .grid{break-inside:avoid}
}

@page{margin:14mm}

/* A night decided against a school year the app is projecting rather than one
   it has. Deliberately a plain outline rather than a color: it is not a
   warning and nothing is wrong, it is a statement about how much the app
   knows, and coloring it would make three years of ordinary nights look like
   a problem. */
.tag.est{color:var(--ink-3);background:transparent;box-shadow:inset 0 0 0 1px var(--line-2)}
.est-note{color:var(--ink-2);line-height:1.55}
@media print{.tag.est{box-shadow:inset 0 0 0 1px #999}}

/* Recording what actually happened at a handoff. It sits inside the day panel
   under the handoff row rather than on a screen of its own, because the day
   panel is where a handoff is read and a second screen would be a navigation
   for a two field edit.

   Closed by default and opened by `<details>`, which needs no JavaScript. The
   panel's job is answering "who has them tonight" in one glance, and a form
   sitting open under every changeover would push the school and birthday rows
   below the fold on a phone for the sake of a field most days do not use. */
.handoff-edit{margin:2px 0 0}
.handoff-said{color:var(--ink-2);margin:0 0 6px}
.handoff-form summary{font-size:11.5px;color:var(--ink-3);cursor:pointer;
  list-style-position:outside}
.handoff-form summary:hover{color:var(--ink-2)}
.handoff-form form{margin-top:8px}
.handoff-form label{display:block;font-size:11.5px;font-weight:700;
  letter-spacing:.02em;color:var(--ink-2);margin-bottom:8px}
.handoff-form input,.handoff-form select{width:100%;max-width:100%}
.handoff-form .hint{margin:-4px 0 10px}
.handoff-form .actions{margin-top:2px}
.handoff-edit .errs{margin-bottom:10px}
.handoff-edit .ok{color:var(--ink);font-weight:600;margin:0 0 6px}
/* Why the form is not here at all, on days that have settled. A rule worth
   stating on the screen it applies to: silence would read as the app having
   forgotten how to edit older days. */
.locked-note{color:var(--ink-3);line-height:1.55;margin:0}

/* What the children have on, under the day panel. The rows themselves reuse
   `.rows`, so a drive reads like a handoff or a birthday rather than like a
   different kind of thing, which is the point: it is one more fact about the
   day.

   The fold and its summary copy `.handoff-form` deliberately rather than
   sharing a class with it. They are the same gesture on the same screen and
   they are two features, and the last time two screens shared a rule here the
   change one of them wanted broke the other one quietly.

   Nothing here sizes or colors by who is driving. A drive that is not the
   parent with the children is somebody's deliberate answer, so the panel
   states it in the same weight as everything else. See section 17. */
.act{padding:10px 0;border-top:1px solid var(--line)}
.act:first-of-type{padding-top:2px;border-top:0}
.act p{margin:0 0 4px}
.act .rows{margin-top:6px}
/* Called off, and still on the calendar. Struck through rather than removed,
   because a date that vanishes reads as one nobody ever entered and sends
   somebody to an empty field. */
.act.off b{text-decoration:line-through}
.act.off{color:var(--ink-3)}
.act .fold{margin-top:6px}
.act .fold summary{font-size:11.5px;color:var(--ink-3);cursor:pointer;
  list-style-position:outside}
.act .fold summary:hover{color:var(--ink-2)}
.act .fold form{margin-top:8px}
.act .fold label{display:block;font-size:11.5px;font-weight:700;
  letter-spacing:.02em;color:var(--ink-2);margin-bottom:8px}
.act .fold input,.act .fold select{width:100%;max-width:100%}
/* The two rules above are more specific than `label.check`, so the tick box
   inherited the full width of a text field and floated in the middle of its
   own label. Restated rather than loosened: the fields in this fold do want
   the full width, and a checkbox is the one thing in it that never does. */
.act .fold label.check{display:flex;gap:8px;align-items:flex-start}
.act .fold label.check input{width:auto;margin:2px 0 0;flex:none}
.act .fold .hint{margin:-4px 0 10px}

/* ---- Home, the first screen ----
   One column of cards in priority order, and a section with nothing in it is
   not rendered at all. Held to a readable width rather than stretched across a
   monitor: this is a page you read top to bottom, not a surface to fill. The
   argument for the shape is in docs/next-steps.md section 18, and there is a
   drawing of both options linked from it. */
.home{max-width:640px;margin:0 auto}

/* What to do first, for a family that has entered nothing. It disappears for
   good once there is a rotation and one holiday, so it is never a nag. */
.steps{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
.step{display:grid;grid-template-columns:auto 1fr;gap:10px;align-items:baseline}
/* 2.5.8: the four things a new family has to do were the last targets
   under 24px, and they are the four a phone is most likely to tap. */
.step a{font-weight:700;color:var(--ink);text-decoration:none;
  display:inline-flex;align-items:center;min-height:24px}
.step a:hover{text-decoration:underline}
.step .sub{display:block;margin:1px 0 0}
.step.done a{color:var(--ink-3);font-weight:600}
.stepmark{font-size:9px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  border-radius:4px;padding:2px 6px;white-space:nowrap}
/* --ink-3 on --surface-2 is 2.90 to 1 and was the first thing tried here. */
.stepmark.todo{background:var(--ink);color:var(--ground)}
.stepmark.done{background:var(--surface-2);color:var(--ink-2)}

/* A note from the other parent that has not been read. Showing the words here
   is what marks it seen, so it shows the words.
   The edge was --b, which is one of the parents rather than either of them: a
   note Hannah had not read was flagged in her own color, not in the color of
   whoever wrote it. */
.unread{border-left:3px solid var(--ink);padding-left:11px;margin-bottom:10px}
.unread:last-child{margin-bottom:0}
.unread p{margin:0}
.unread .sub{margin:0 0 3px}

.on-today{margin:6px 0 0;font-size:13px;color:var(--ink-2)}

/* One line per drive, and per thing coming up. A date in tabular figures on
   the left so the column reads as a column. */
.drive-row{display:grid;grid-template-columns:58px 1fr;gap:10px;align-items:baseline;
  padding:6px 0;border-top:1px solid var(--line);font-size:13px}
.drive-row:first-of-type{border-top:0;padding-top:0}
.drive-row .d{font-family:RobotoMono,monospace;font-size:11px;color:var(--ink-3);
  font-variant-numeric:tabular-nums;white-space:nowrap}

.wk{display:flex;flex-direction:column}
.wk-row{display:grid;grid-template-columns:58px 1fr;gap:10px;align-items:baseline;
  padding:6px 0;border-top:1px solid var(--line);font-size:13px}
.wk-row:first-child{border-top:0;padding-top:0}
.wk-row .d{font-family:RobotoMono,monospace;font-size:11px;color:var(--ink-3);
  font-variant-numeric:tabular-nums;white-space:nowrap}
/* Behind you, and still here because yesterday is the last day either parent
   can correct a night alone. Dimmed rather than dropped. */
.wk-row.past{opacity:.55}
.wk-row.now{font-weight:600}
.wk-row.now .d{color:var(--ink)}
.wk-row b.pa{color:var(--a)} .wk-row b.pb{color:var(--b)} .wk-row b.pn{color:var(--ink-3)}

/* A day with nothing asking for anything. It says so rather than showing an
   empty panel or nothing at all, because silence reads as a page that failed
   to load and a page that is only ever demands is one both parents stop
   opening. */
.quiet-day h2{color:var(--ink-2)}

/* The app name is the way home, which is what keeps Home from needing a
   navigation item of its own. */
.bar .brand{color:inherit;text-decoration:none}
.bar .brand:hover{opacity:.75}
