/* Federico — colour, from design_handoff_palette/.

   One rule: colour means something or it isn't used. Hue is the domain — green
   is feeding, clay is nappies, sand is medicines, everywhere and without
   exception. The step within a hue is the entry type. Weight is prominence,
   not category: solid evergreen belongs to the topbar and the active tab, a
   tint means an action you can take, white plus a rule means secondary.
   Everything else is neutral and numbers are ink, which is what lets the two
   accents register at a glance in a dark room.

   Ink is declared per surface, never globally: the darker the tile, the darker
   its mark. That is the only way the deep steps clear 4.5:1. */

:root {
  /* neutrals — structure */
  --paper:      #F4F1EA;   /* page ground */
  --card:       #FFFFFF;   /* cards, sheets */
  --line:       #E7E3D8;   /* borders */
  --rule:       #EFECE3;   /* row dividers inside a card */
  --ink:        #1E211C;   /* headings, numbers, row labels */
  --ink-soft:   #6B6F66;   /* meta, body, edit links */
  --ink-muted:  #8E9289;   /* stat-card labels, inline marks */

  /* feeding — green */
  --evergreen:   #1F4D3A;  /* topbar, active tab, brand mark */
  --sage:        #DCE6D8;  /* feeding action fill, breast tile */
  --sage-deep:   #C2D4BB;  /* pressed, borders on sage */
  --bottle:      #B9CFB4;  /* bottle tile */
  --solid:       #96B491;  /* solid tile — the deepest of the three */
  --on-sage:     #143025;  /* ink on --sage       11.06:1 */
  --on-bottle:   #122A1F;  /* ink on --bottle      9.19:1 */
  --on-solid:    #0E2318;  /* ink on --solid       7.26:1 */
  --sub-on-sage: #3C5A48;  /* sub-labels on a sage fill */
  /* The deep step of the green family, for charts only. The handoff stops at
     --solid and then jumps to --evergreen, and a chart of two series needs a
     third step between them: --solid against --bottle is one tint apart and
     reads as one bar in two printings, while --evergreen is the topbar's and
     spending it on half the columns makes a chart of feeding minutes the
     heaviest thing on the screen. Same hue family, a third of the way up from
     evergreen. */
  --moss:        #4A7A57;  /* charts: the deeper half of a pair */

  /* changes — clay */
  --clay:         #A0664B; /* the one meaningful accent: overdue */
  --clay-tint:    #F0E2D8; /* change action fill, pee tile */
  --clay-deep:    #E2C7B5; /* pressed, borders, poo tile */
  --clay-both:    #CFA88C; /* pee + poo tile */
  --on-clay:      #5A3520; /* ink on --clay-tint    8.44:1 */
  --on-clay-deep: #4E2D1A; /* ink on --clay-deep    7.62:1 */
  --on-clay-both: #3D2113; /* ink on --clay-both    6.76:1 */

  /* the post-feed countdown — a third family the handoff does not carry, kept
     on purpose: the quarter hour after a feed is neither a feed nor a change,
     and at 4am it has to be told apart from both at a glance. */
  --rose:      #F8D7D2;    /* pale red */
  --rose-line: #EFC3BB;
  --rose-ink:  #7C3B2C;    /* on --rose             6.21:1 */
  --rose-soft: #8A4E3E;    /* on --rose             4.83:1 */

  /* medicines — sand */
  --sand:    #E3DDC9;      /* meds tile */
  --on-sand: #4A472A;      /* ink on --sand         6.94:1 */

  /* on the evergreen bar — full-strength ink, never alpha-muted */
  --cream:        #FDFCF8;               /* text and icons on evergreen 9.1:1 */
  --on-dark-fill: rgba(253,252,248,.10); /* card wash inside the bar */
  --on-dark-line: rgba(253,252,248,.18); /* its border */
  --on-dark-pill: rgba(253,252,248,.14); /* age pill, icon button */
  --on-dark-sage: #C2D4BB;               /* "LAST FEED" eyebrow */
  --on-dark-clay: #E2C7B5;               /* "LAST CHANGE" eyebrow */

  /* structure, not colour */
  --radius:    16px;
  --shadow:    0 1px 2px rgba(31, 77, 58, .08), 0 6px 18px rgba(31, 77, 58, .07);
  --safe-top:    env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  /* The tab bar only has to clear the home indicator, not the whole inset iOS
     reserves below it — padded by the full amount the bar towered over the
     page once the app runs standalone from the home screen. */
  --nav-inset:   max(6px, calc(var(--safe-bottom) - 12px));
  --nav-height:  54px;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html { -webkit-text-size-adjust: 100%; }

/* No rubber-band at the top: that bounce is the one thing that would compete
   with the pull-to-refresh gesture for the same finger movement. Only where the
   app owns the gesture — in a browser tab the bounce is the browser's own pull
   to refresh, and containing it would leave the page with no way to reload. */
html.standalone { overscroll-behavior-y: contain; }

body {
  margin: 0;
  font: 16px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  color: var(--ink);
  background: var(--paper);
  padding: 0 0 var(--safe-bottom);
}
/* Every page fills the screen even when it has little on it. Medicines with
   nothing scheduled was the one page short enough not to scroll, and a page
   that cannot scroll keeps Safari's toolbar expanded, which lifts the fixed tab
   bar higher than it sits everywhere else. dvh, so the height follows the
   toolbar rather than fighting it; vh first for anything that lacks it. */
body.has-nav {
  padding-bottom: calc(var(--nav-height) + var(--nav-inset) + 14px);
  min-height: 100vh;
  min-height: 100dvh;
}

img { max-width: 100%; }
[hidden] { display: none !important; }
a { color: var(--evergreen); }
a:hover { color: var(--on-sage); }

/* ------------------------------------------------------------------ chrome */

.topbar {
  background: var(--evergreen); color: var(--cream);
  padding: calc(14px + var(--safe-top)) 16px 16px;
  border-radius: 0 0 22px 22px;
}
.topbar-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.topbar-name { display: flex; align-items: baseline; gap: 10px; min-width: 0; flex-wrap: wrap; }
.topbar h1 { margin: 0; font-size: 21px; font-weight: 650; letter-spacing: .2px; }
.topbar .sub { margin: 4px 0 0; font-size: 13px; color: var(--sage); }
.badge {
  font-size: 11.5px; font-weight: 600; color: var(--cream); background: var(--on-dark-pill);
  padding: 3px 9px; border-radius: 999px; white-space: nowrap;
}

/* Which log is open, above the heading rather than beside it: on a screen whose
   heading is already the baby's name it would read twice on one line, and the
   question it answers — am I in the right log? — is asked before the screen is
   read, not after. Only drawn for an account with more than one baby. */
.baby-switch {
  display: inline-flex; align-items: center; gap: 7px; margin: 0 0 10px;
  padding: 5px 11px 5px 9px; border-radius: 999px;
  background: var(--on-dark-pill); color: var(--cream);
  font-size: 12.5px; font-weight: 600; text-decoration: none; max-width: 100%;
}
.baby-switch:hover { color: var(--cream); }
.baby-switch-label { color: var(--on-dark-sage); font-weight: 600; letter-spacing: .04em; text-transform: uppercase; font-size: 10.5px; }
.baby-switch-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.baby-switch svg { flex: none; opacity: .75; }

/* The two things you open the app to find out. */
.chips { display: flex; gap: 8px; margin-top: 13px; }
.chip {
  flex: 1; min-width: 0; background: var(--on-dark-fill); border: 1px solid var(--on-dark-line);
  border-radius: 13px; padding: 9px 11px;
}
/* The hue rule carried onto the dark ground: the feed chip's eyebrow and its
   sub-line are green, the change chip's are clay, so a glance at the top of
   the screen reads the same way as a glance at the list below it. */
.chip-label {
  display: block; font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--on-dark-sage); font-weight: 600;
}
.chip-value { display: block; font-size: 16px; font-weight: 650; margin-top: 2px; color: var(--cream); }
.chip-sub   { display: block; font-size: 11.5px; color: var(--sage); margin-top: 1px;
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chip.change .chip-label { color: var(--on-dark-clay); }
.chip.change .chip-sub   { color: var(--clay-tint); }
.icon-link {
  color: var(--cream); text-decoration: none; line-height: 1;
  width: 40px; height: 40px; display: grid; place-items: center;
  border-radius: 50%; background: var(--on-dark-pill);
}
.icon-link svg { display: block; }

.wrap { padding: 16px; max-width: 760px; margin: 0 auto; }

.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  display: flex; background: rgba(253,252,248,.93); backdrop-filter: blur(10px);
  border-top: 1px solid var(--line);
  padding-bottom: var(--nav-inset);
}

.tabbar a {
  flex: 1; text-align: center; padding: 9px 4px 8px; text-decoration: none;
  color: var(--ink-soft); font-size: 11px; line-height: 1; letter-spacing: .3px;
  text-transform: uppercase;
  display: flex; flex-direction: column; gap: 4px; align-items: center;
}
/* An SVG needs a box, not a type size. `display: block` on the svg kills the
   inline descender gap that would otherwise push the label off centre. */
.tabbar a .ico { display: block; width: 17px; height: 17px; vertical-align: middle; }
.tabbar a .ico svg { display: block; }
.tabbar a.on { color: var(--evergreen); font-weight: 700; }

/* ------------------------------------------------------ pull to refresh */

/* The mark rides above everything and takes no taps: the gesture moves it, the
   page underneath never shifts. Parked off-screen until a pull starts. */
.ptr {
  position: fixed; top: calc(var(--safe-top) - 34px); left: 50%; z-index: 40;
  width: 34px; height: 34px; margin-left: -17px; border-radius: 50%;
  background: #FFFFFFF2; box-shadow: var(--shadow);
  display: grid; place-items: center;
  opacity: 0; pointer-events: none;
}
.ptr i {
  display: block; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid var(--sage-deep); border-top-color: var(--evergreen);
}
/* Only while springing back or spinning — during the pull the mark tracks the
   finger, and a transition there would lag behind it. */
.ptr.ease { transition: transform .22s ease, opacity .22s ease; }
.ptr.spin i { animation: ptr-spin .7s linear infinite; }
@keyframes ptr-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .ptr.spin i { animation-duration: 1.6s; }
}

.flash {
  position: fixed; top: calc(10px + var(--safe-top)); left: 12px; right: 12px; z-index: 50;
  background: var(--evergreen); color: var(--cream); padding: 12px 16px; border-radius: 12px;
  box-shadow: var(--shadow); font-size: 14px; animation: fade 4s forwards;
}
@keyframes fade { 0%,80% { opacity: 1 } 100% { opacity: 0; visibility: hidden } }

/* ------------------------------------------------------------------- cards */

.card {
  background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 16px; margin: 0 0 14px;
}
.card h2 {
  margin: 0 0 12px; font-size: 13px; text-transform: uppercase; letter-spacing: .09em;
  color: var(--ink-soft); font-weight: 700;
}
/* A feed in progress is the feeding domain at its most prominent, so it takes
   the sage fill rather than the solid evergreen it used to wear — evergreen
   belongs to the topbar and the active tab. Ink and sub-ink are the ones
   declared for a sage ground; nothing here is muted with alpha. */
.card.timer { background: var(--sage); color: var(--on-sage); text-align: center; }
.card.timer h2 { color: var(--sub-on-sage); }
.clock { font-size: 46px; font-weight: 300; font-variant-numeric: tabular-nums; letter-spacing: 1px; margin: 4px 0 2px; }
.card.timer .meta { color: var(--sub-on-sage); font-size: 13px; margin-bottom: 14px; }
/* Three actions share this card and each has to be read at a glance, so none
   of them may wear the card's own fill: white saves, the deeper green of the
   same family switches side, and the outline discards. Discarding is the one
   that throws work away, so it takes the ink the app already spends on that
   and nothing else — 5.28:1 on this ground. */
.card.timer .btn.white     { border-color: transparent; }
.card.timer .btn.tone-feed { background: var(--sage-deep); border-color: var(--sage-deep); color: var(--on-sage); }
.card.timer .btn.ghost     { background: transparent; color: #8F4636; border-color: #8F4636; }

/* ------------------------------------------------------------------ inputs */

/* White plus a rule is the secondary button, and it is the default: an action
   with no domain behind it does not get to borrow a hue. Peers in a row share
   one fill — four ways to start a feed are four of the same kind of action, so
   colouring Breast, Bottle and Solid differently implied a difference in kind
   that was not there. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px;
  font-size: 15px; font-weight: 600;
  background: var(--card); color: var(--ink); text-decoration: none; cursor: pointer;
  font-family: inherit; min-height: 48px; width: 100%;
}
.btn:active { transform: scale(.985); }
.btn small   { color: var(--ink-soft); }
/* A button that logs an entry wears that entry's own colour rather than a fill
   shared with its peers: what you tap is what you will later read in the log,
   and the hue still says which domain it belongs to. No pressed-state fill
   here — a Pee button deepening to clay-deep would flash as a Poo button — so
   the press is carried by .btn:active's scale alone. */
.btn.tone-feed, .btn.tone-bottle, .btn.tone-solid,
.btn.tone-pee,  .btn.tone-poo,   .btn.tone-peepoo {
  background: var(--tile); color: var(--on-tile); border-color: transparent;
}
/* Sub-labels take the ink declared for their own ground: --sub-on-sage is a
   sage pairing, and on the deeper bottle green it would sit at 4.6:1. */
.btn.tone-feed small   { color: var(--sub-on-sage); }
.btn.tone-bottle small { color: var(--on-bottle); }
.btn.tone-solid small  { color: var(--on-solid); }
/* Saving a form belongs to no domain, so the emphatic button is the darkest
   neutral. Solid evergreen is not available here, and spending a hue on it
   would leave that hue meaning nothing. */
.btn.dark    { background: var(--ink); border-color: var(--ink); color: var(--paper); }
/* Evergreen is the topbar's and the active tab's, and nothing else in the app
   may wear it — except here, where the whole screen is already evergreen and
   the brand is the subject. Signing in is the one action on the page, so it
   takes the ground's own colour and the neutral .dark would look like a
   stranger on it. */
.btn.brand   { background: var(--evergreen); border-color: var(--evergreen); color: var(--cream); }
.btn.dark small { color: var(--line); }
.btn.ghost   { background: transparent; color: var(--ink-soft); border: 1px solid var(--line); }
.btn.white   { background: var(--card); color: var(--evergreen); border-color: var(--line); }
/* Outside the palette: it holds no destructive hue, and clay would have to
   stop meaning "a change" for this to borrow it. */
.btn.danger  { background: var(--card); color: #8F4636; border: 1px solid #E3CCC5; }
/* Removing a medicine is the last thing on its own, not the first thing on the
   card that follows it. */
.danger-zone { display: block; margin: 0 0 22px; }
.btn.sm      { padding: 9px 12px; font-size: 13px; min-height: 38px; width: auto; border-radius: 10px; }

.grid   { display: grid; gap: 10px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { display: grid; gap: 10px; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid form, .grid-3 form { display: flex; }
.grid .btn, .grid-3 .btn {
  flex-direction: column; gap: 2px; padding: 13px 6px; height: 100%;
  overflow-wrap: anywhere;   /* long labels wrap instead of stretching their column */
}
.grid .btn small, .grid-3 .btn small { font-weight: 500; font-size: 11px; }

label { display: block; font-size: 13px; font-weight: 600; color: var(--ink-soft); margin: 0 0 5px; }
.field { margin-bottom: 12px; }
input[type=text], input[type=password], input[type=email], input[type=number],
input[type=datetime-local], input[type=date], select, textarea {
  width: 100%; padding: 12px; font-size: 16px; font-family: inherit; color: var(--ink);
  border: 1px solid var(--line); border-radius: 11px; background: var(--paper); min-height: 48px;
}
/* iOS sizes date and time fields to their own content and lets them spill past
   the box they sit in, so the birth field came out a different width from every
   other input and clipped its own value. Dropping the native appearance makes
   them ordinary boxes that fill the field; the picker still opens on tap. */
input[type=email], input[type=datetime-local], input[type=date], input[type=time] {
  -webkit-appearance: none; appearance: none;
  display: block; max-width: 100%; min-width: 0;
  text-align: left;
}

/* A number with its unit beside it, so "minutes" need not crowd the label. */
.suffixed { display: flex; align-items: center; gap: 10px; }
.suffixed input { width: 6.5em; flex: none; }
.suffixed span { font-size: 14px; color: var(--ink-soft); }

textarea { min-height: 70px; resize: vertical; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--evergreen); outline-offset: 1px; border-color: transparent; }
.row { display: flex; gap: 10px; }
.row > * { flex: 1; }

details.adder { background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow); margin-bottom: 14px; }
details.adder > summary {
  list-style: none; cursor: pointer; padding: 15px 16px; font-weight: 650; font-size: 14px; color: var(--evergreen);
}
details.adder > summary::-webkit-details-marker { display: none; }
details.adder > summary::after { content: '+'; float: right; font-size: 20px; line-height: 1; color: var(--ink-soft); }
details.adder[open] > summary::after { content: '–'; }
details.adder .body { padding: 0 16px 16px; }

/* ------------------------------------------------------------------- lists */

.list { list-style: none; margin: 0; padding: 0; }
.list li {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 0; border-top: 1px solid var(--rule);
}
.list li:first-child { border-top: 0; }
/* One declaration per entry type, read by the tile in the log and by the button
   that creates the entry alike, so a Poo button and a Poo row cannot drift
   apart. Each step deepens with how much the entry represents, which is why
   Pee + Poo is the darkest clay, and each carries its own ink: the darker the
   ground, the darker the mark. */
.tone-feed   { --tile: var(--sage);      --on-tile: var(--on-sage); }
.tone-bottle { --tile: var(--bottle);    --on-tile: var(--on-bottle); }
.tone-solid  { --tile: var(--solid);     --on-tile: var(--on-solid); }
.tone-pee    { --tile: var(--clay-tint); --on-tile: var(--on-clay); }
.tone-poo    { --tile: var(--clay-deep); --on-tile: var(--on-clay-deep); }
.tone-peepoo { --tile: var(--clay-both); --on-tile: var(--on-clay-both); }
.tone-med    { --tile: var(--sand);      --on-tile: var(--on-sand); }
/* A measurement is neither a feed, a change nor a medicine, and the palette
   carries no fourth hue to spend on it — so it takes the neutral tile. */
.tone-growth { --tile: var(--line);      --on-tile: var(--ink); }

/* Untyped, the tile is neutral: a medicine no longer being given has no domain
   left to declare. */
.dot {
  width: 38px; height: 38px; border-radius: 12px; flex: 0 0 38px;
  display: grid; place-items: center; font-size: 15px;
  background: var(--tile, var(--rule)); color: var(--on-tile, var(--ink-muted));
}
/* The tile keeps its ground; the icon is currentColor on top of it, so it is
   never given a colour of its own. The font size stays for the few tiles that
   still hold a character, not an icon.

   One step per type, deepening with how much the entry represents — which is
   why Pee + Poo is the darkest clay. A change never sits on a green tile: a
   Pee row on sage made green mean both "feed" and "pee", leaving the hue
   carrying no information at all. */
.dot svg { display: block; }
.li-main   { flex: 1; min-width: 0; }
.li-title  { font-weight: 600; font-size: 15px; }
.li-sub    { font-size: 12.5px; color: var(--ink-soft); }
/* Block, where the title and the times deliberately run on together: what was
   written by hand is worth its own line, and wrapping it under them keeps the
   row scannable when the note is a long one. */
.li-note   { display: block; font-size: 12.5px; color: var(--ink-soft); margin-top: 1px; }
.li-side   { text-align: right; font-size: 12.5px; color: var(--ink-soft); white-space: nowrap; }
/* Wet and dirty together: both marks beside the row, never both in one tile. */
.li-marks      { display: inline-flex; gap: 4px; vertical-align: -4px; margin-right: 6px; color: var(--ink-muted); }
.li-marks svg  { display: block; }
.li-side b { display: block; font-size: 15px; color: var(--ink); font-weight: 600; }

/* A row opens. Everything the collapsed line has no room for — when the entry
   started, when it ended, how long the pause between two sides ran — is one tap
   away instead of crowded into 12.5px of grey. <details> carries it, so the
   whole thing works with no script: a phone that never finishes loading still
   opens its rows.

   The flex that was on the row itself moves to the summary, since the li is now
   a block holding the panel underneath. .list li stays flex for the hand-built
   rows elsewhere — the week of doses on Meds is not an event row. */
.list li.ev { display: block; padding: 0; }
.ev > details > summary {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 0; cursor: pointer; list-style: none;
}
.ev > details > summary::-webkit-details-marker { display: none; }
.ev > details > summary::marker { content: ''; }
/* Held open by the finger: the only feedback a tap on a whole row can give,
   since the row itself must not move. */
.ev > details > summary:active { opacity: .62; }
.ev .chev {
  flex: 0 0 auto; display: grid; place-items: center; color: var(--ink-muted);
  transition: transform .18s ease;
}
.ev > details[open] > summary .chev { transform: rotate(90deg); }

/* Indented past the tile and its gap, so the facts start where the title does
   and the panel reads as that row's, not as a new one. */
.ev-more { padding: 0 0 13px 50px; }
.ev-facts { margin: 0; display: grid; gap: 5px; }
.ev-facts > div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
}
.ev-facts dt {
  flex: 0 0 auto; font-size: 11px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-muted);
}
.ev-facts dd {
  margin: 0; min-width: 0; font-size: 13px; color: var(--ink);
  text-align: right; font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}

/* The sides of a folded feeding, one line each: a combo row is two entries and
   opening it is the only place that says so in full. */
.ev-parts {
  list-style: none; margin: 9px 0 0; padding: 9px 0 0;
  border-top: 1px solid var(--rule); font-size: 13px;
}
.ev-parts li {
  display: flex; align-items: baseline; gap: 8px;
  padding: 3px 0; border-top: 0; color: var(--ink-soft);
}
.ev-part-side {
  flex: 0 0 18px; font-weight: 700; color: var(--evergreen);
  font-size: 12px; letter-spacing: .04em;
}
.ev-parts a, .ev-acts a { margin-left: auto; font-weight: 600; }
.ev-acts { margin: 11px 0 0; font-size: 13px; display: flex; }

.day-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin: 18px 2px 8px; font-size: 13px; font-weight: 700; color: var(--evergreen);
  text-transform: uppercase; letter-spacing: .06em;
}
.day-head span { font-weight: 500; color: var(--ink-soft); text-transform: none; letter-spacing: 0; }
.day-head svg  { display: inline-block; vertical-align: -3px; margin-left: 1px; }

/* An icon is never the only carrier of meaning: where one heads a column, the
   word goes with it, out of sight but in the accessibility tree. */
.vh {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.empty { text-align: center; color: var(--ink-soft); padding: 26px 10px; font-size: 14px; }

/* ------------------------------------------------------------------- stats */

.tiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-bottom: 14px; }
/* No accent borders by default. Four of them on four cards encoded nothing;
   one accent survives and it now means something, which is why it is spelled
   .overdue and not a colour name. */
.tile {
  background: var(--card); border-radius: var(--radius); padding: 14px; box-shadow: var(--shadow);
}
.tile .k { font-size: 11.5px; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-muted); font-weight: 600; }
.tile .v { font-size: 25px; font-weight: 650; line-height: 1.15; margin-top: 3px; color: var(--ink); font-variant-numeric: tabular-nums; }
.tile .u { font-size: 12px; color: var(--ink-soft); }
.tile.overdue    { box-shadow: var(--shadow), inset 3px 0 0 var(--clay); }
.tile.overdue .u { color: var(--clay); }

/* A day inside the medicines week: the date, and what became of it. Sits
   between lists rather than above cards, so it is quieter than .day-head. */
.dose-day {
  display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
  margin: 14px 0 2px; font-size: 12px; font-weight: 700; color: var(--evergreen);
  text-transform: uppercase; letter-spacing: .06em;
}
.dose-day:first-of-type { margin-top: 0; }
.dose-day span + span {
  font-weight: 500; color: var(--ink-soft); text-transform: none; letter-spacing: 0;
}
/* A dose that was due and never ticked off keeps the neutral tile — sand means
   a medicine was given, and this one was not. */
.dose-day + .list li:first-child { border-top: 0; }

.segmented { display: flex; gap: 6px; background: var(--line); padding: 4px; border-radius: 12px; margin-bottom: 14px; }
.segmented a {
  flex: 1; text-align: center; padding: 9px 4px; border-radius: 9px; text-decoration: none;
  font-size: 13px; font-weight: 600; color: var(--ink-soft);
}
.segmented a.on { background: var(--card); color: var(--evergreen); box-shadow: var(--shadow); }

/* Bar charts: a y axis with gridlines, so bar heights can be read as numbers. */
.chart { display: flex; align-items: flex-start; gap: 7px; margin: 10px 0 2px; }
.chart .y {
  position: relative; flex: 0 0 auto; min-width: 20px; height: 140px;
  font-size: 9.5px; color: var(--ink-soft); font-variant-numeric: tabular-nums;
}
.chart .y span { position: absolute; right: 0; transform: translateY(50%); line-height: 1; white-space: nowrap; }
.chart .plot { flex: 1; min-width: 0; }
.chart .area { position: relative; height: 140px; }
.chart .area > i { position: absolute; left: 0; right: 0; height: 1px; background: var(--line); }
.chart .area > i:first-child { background: var(--sage-deep); }
.chart .cols,
.chart .xlabels { display: flex; gap: var(--gap, 4px); }
.chart .cols { position: absolute; inset: 0; align-items: flex-end; }
.chart .col { flex: 1; min-width: 0; height: 100%; display: flex; align-items: flex-end; gap: 2px; }
.chart .stack { flex: 1; min-width: 0; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; gap: 2px; }
.chart .stack.stacked { gap: 1px; }
.chart .stack.stacked .bar { border-radius: 0; }
.chart .stack.stacked .bar:first-of-type { border-radius: 4px 4px 0 0; }
/* Every chart here measures feeding, so every bar is a step of the one green
   family, and the three steps are spaced far enough apart to be told apart in
   one glance at a chart of paired columns: pale by default, --solid where a
   second series has to separate from it, --moss for the heavier half of a
   pair. A clay series would have made minutes of feeding read as a nappy.

   The pair used to be --bottle against --evergreen, which failed at both ends:
   --bottle is a hair off the default bar, so "Right" looked like every other
   chart's only series, and --evergreen is the topbar's own colour, so half the
   columns of an ordinary chart came out heavier than the page around them. */
.chart .bar { background: var(--sage-deep); border-radius: 4px 4px 0 0; }
.chart .bar.mid  { background: var(--solid); }
.chart .bar.dark { background: var(--moss); }
/* Nappies are the one thing charted here that is not a feed, so they are the
   one thing charted in clay — and the wet step sits above the dirty one, the
   same way round as their tiles in the log. A series of changes of every kind
   takes the Pee + Poo step, which is what it is: both of them together. */
.chart .bar.wet   { background: var(--clay-deep); }
.chart .bar.dirty { background: var(--clay-both); }
.chart .bar.nappy { background: var(--clay-both); }
.chart .val { font-size: 9.5px; text-align: center; color: var(--ink-soft); font-variant-numeric: tabular-nums; line-height: 1; margin-bottom: 2px; }
.chart .lab { flex: 1; min-width: 0; font-size: 9.5px; text-align: center; color: var(--ink-soft); padding-top: 5px; }

/* A growth curve. Bars pile up from a baseline; a measurement does not, so this
   chart is a line on a band that starts where the readings do. It borrows the
   bar chart's axis and gridlines so the two read as one family. Both curves
   wear --moss: they never share a plot, so a second hue would only imply a
   contrast that isn't being drawn. */
.chart.line .area { overflow: visible; }
.chart.line svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.chart.line polyline { fill: none; stroke: var(--moss); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
/* The dot is 9px; the thing you can hit is 22px, because a fingertip is not a
   cursor. The ring is the card behind it, so a dot stays a dot where it lands
   on the line. */
.chart.line .pt {
  position: absolute; width: 22px; height: 22px; margin: 0 0 -11px -11px;
  display: grid; place-items: center;
}
.chart.line .pt i { width: 9px; height: 9px; border-radius: 50%; background: var(--moss); box-shadow: 0 0 0 2px var(--card); }
.chart.line .end {
  position: absolute; right: 0; margin-bottom: 12px; font-size: 11px; font-weight: 600;
  color: var(--ink-soft); font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap;
}
.chart.line .end.mid { right: auto; left: 50%; transform: translateX(-50%); }
.chart.line .ends {
  display: flex; justify-content: space-between; gap: 8px;
  font-size: 9.5px; color: var(--ink-soft); padding-top: 7px;
}
.chart.line .ends.one { justify-content: center; }

.legend { display: flex; gap: 14px; font-size: 12px; color: var(--ink-soft); margin-top: 10px; }
.legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; margin-right: 5px; background: var(--sage-deep); }
.legend i.mid   { background: var(--solid); }
.legend i.dark  { background: var(--moss); }
.legend i.wet   { background: var(--clay-deep); }
.legend i.dirty { background: var(--clay-both); }
.legend i.nappy { background: var(--clay-both); }

/* Medicine banner: loud enough to catch the eye, quiet enough to live above
   the timer card without shouting. */
.banner {
  display: flex; align-items: center; gap: 12px;
  background: var(--sand); color: var(--on-sand);
  border-radius: var(--radius); padding: 13px 15px; margin: 0 0 12px;
  box-shadow: var(--shadow);
}
/* Sand says "medicine" whether the dose is coming up or already late. What
   changes is the one accent the palette keeps for overdue — the same rule a
   stat card wears, in the same place, meaning the same thing. */
.banner.now { box-shadow: var(--shadow), inset 3px 0 0 var(--clay); }
.banner-main  { flex: 1; min-width: 0; }
.banner-title { font-weight: 650; font-size: 15px; }
.banner-mark  { font-weight: 400; }
.banner-mark svg { display: inline-block; vertical-align: -2px; }
.banner-sub   { font-size: 12.5px; margin-top: 2px; }
.banner .btn  { width: auto; white-space: nowrap; }

/* Pale red, and the one card in the app that is neither green nor clay nor
   sand. White plus a rule put it in the same register as an ordinary card,
   which is not what a running clock wants at 4am. */
.card.countdown {
  background: var(--rose); border: 1px solid var(--rose-line);
  color: var(--rose-ink); text-align: center;
}
.card.countdown h2 { color: var(--rose-soft); }
.card.countdown .clock { color: var(--rose-ink); }
.card.countdown .clock.done { font-size: 30px; font-weight: 600; }
.card.countdown .meta { color: var(--rose-soft); font-size: 13px; margin-bottom: 14px; }
.card.countdown .btn.white { border: 1px solid var(--rose-line); color: var(--rose-ink); }

.balance { display: flex; height: 10px; border-radius: 5px; overflow: hidden; margin-top: 16px; background: var(--line); }
/* The same two greens as the chart above it, or the bar would recolour the two
   sides a line after naming them. */
.balance .seg.l { background: var(--moss); }
.balance .seg.r { background: var(--solid); }

.table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.table th, .table td { padding: 9px 6px; text-align: right; border-top: 1px solid var(--rule); font-variant-numeric: tabular-nums; }
.table th { color: var(--ink-soft); font-size: 11px; text-transform: uppercase; letter-spacing: .05em; border-top: 0; }
.table td:first-child, .table th:first-child { text-align: left; }
.table th svg { display: inline-block; vertical-align: -4px; }
.scroll-x { overflow-x: auto; }

/* Choosing a log is the whole point of that card, so each row is the button —
   a name with a tap target the width of the screen, rather than a row with a
   small link parked at one end. The one you are reading wears the feeding
   tint and says Open instead of pointing onward, because it is already open. */
.list.picker li { padding: 0; }
.list.picker form { width: 100%; }
.pick {
  display: flex; align-items: center; gap: 12px; width: 100%;
  background: none; border: 0; padding: 13px 2px; cursor: pointer;
  font: inherit; color: var(--ink); text-align: left;
}
.pick .li-main { flex: 1; min-width: 0; }
.pick .pick-mark { flex: none; color: var(--ink-muted); font-size: 12.5px; font-weight: 700; display: flex; align-items: center; }
.pick.on { background: var(--sage); color: var(--on-sage); border-radius: 12px; padding-inline: 12px; }
.pick.on .li-sub { color: var(--sub-on-sage); }
.pick.on .pick-mark { color: var(--sub-on-sage); }

/* A choice that is on or off, written as a line you can read rather than a
   label beside a box: the heading is the thing being turned on, the small line
   under it is when it will actually reach you. The whole row is the target —
   at 4am nobody is aiming at a 16px square. */
.check {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 2px; border-top: 1px solid var(--rule); cursor: pointer;
  font-weight: 400; font-size: 14px; color: var(--ink); margin: 0;
}
.check:first-of-type { border-top: 0; }
.check input { flex: none; width: 20px; height: 20px; margin: 1px 0 0; accent-color: var(--evergreen); min-height: 0; }
.check span { display: block; min-width: 0; }
.check strong { display: block; font-weight: 600; }
.check small { display: block; font-size: 12.5px; color: var(--ink-soft); margin-top: 2px; line-height: 1.4; }
.check + .btn { margin-top: 14px; }

/* The delivery log, shown as what it is: fixed pitch, because the status code
   and the endpoint line up down the left and that alignment is the whole point
   of reading it. It scrolls sideways rather than wrapping — a wrapped log line
   is worse than a clipped one. */
pre.log {
  margin: 0; padding: 11px 12px; background: var(--paper); border-radius: 11px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; line-height: 1.6; color: var(--ink-soft);
  white-space: pre; min-width: max-content;
}

.hint { font-size: 12.5px; color: var(--ink-soft); margin: 8px 2px 0; }
/* A hint that stands on its own between blocks, like the averages note above
   the charts, otherwise sits flush against whatever follows it. It closes the
   block above, so the air belongs after it, not before. */
.hint + .card,
.hint + .tiles { margin-top: 24px; }
/* And one that explains the chart above it has to clear the x-labels, whether
   or not the chart carries a legend in between. */
.chart + .hint, .legend + .hint { margin-top: 14px; }

/* -------------------------------------------------------------- auth pages */

/* Sign-in and setup are the only screens with no topbar above them, which is
   why they used to read as an empty beige field. So they wear the brand colour
   themselves: the card lands in light on a deep evergreen ground, lit from
   where the topbar would have been and falling away at the foot. The status
   bar is already themed evergreen, so on a phone the two meet with no seam.
   min-height rather than a fixed attachment, which iOS scales wrongly. The
   glow stops at .42 because that is where the lightest pixel of the ground
   still holds the subtitle at 4.65:1. */
/* The discs are the same ground one step lighter, not a second colour: hard
   edged so they read as shapes rather than as a blotchy gradient, and low
   enough in contrast that the card, the mark and the subtitle are still the
   three things the eye lands on. They sit under the glow, which is what keeps
   the pair at the top from cutting across the wordmark. */
body.plain {
  min-height: 100svh;
  background:
    radial-gradient(circle 118px at 17% 7%,  rgba(253, 252, 248, .050) 99%, rgba(253, 252, 248, 0) 100%),
    radial-gradient(circle 32px  at 20% 6%,  rgba(253, 252, 248, .075) 99%, rgba(253, 252, 248, 0) 100%),
    radial-gradient(circle 188px at 97% 33%, rgba(253, 252, 248, .045) 99%, rgba(253, 252, 248, 0) 100%),
    radial-gradient(circle 74px  at 2%  54%, rgba(253, 252, 248, .040) 99%, rgba(253, 252, 248, 0) 100%),
    radial-gradient(circle 24px  at 23% 95%, rgba(253, 252, 248, .065) 99%, rgba(253, 252, 248, 0) 100%),
    radial-gradient(circle 150px at 4%  99%, rgba(253, 252, 248, .035) 99%, rgba(253, 252, 248, 0) 100%),
    radial-gradient(88% 52% at 50% 4%, rgba(74, 122, 87, .42), rgba(74, 122, 87, 0) 68%),
    radial-gradient(125% 78% at 50% 118%, rgba(9, 32, 23, .60), rgba(9, 32, 23, 0) 72%),
    var(--evergreen);
  background-repeat: no-repeat;
}

.auth { min-height: 100svh; display: flex; align-items: center; justify-content: center; padding: 24px 18px; }
.auth .box { width: 100%; max-width: 380px; }
.auth .logo { text-align: center; margin-bottom: 22px; }
.auth .logo .mark { color: var(--cream); display: flex; justify-content: center; }
.auth .logo .mark svg { display: block; }
/* The horizontal lockup — the only permitted one. Mark then wordmark, never
   the wordmark stacked underneath. Mark is the text's cap height plus ~40%. */
.auth .logo .brand {
  display: flex; align-items: center; justify-content: center; gap: 16px;
  color: var(--cream); margin-bottom: 8px;
}
.auth .logo .brand span { font-weight: 700; font-size: 26px; letter-spacing: -.025em; }
.auth .logo .brand svg { display: block; }
.auth .logo h1 { margin: 10px 0 4px; font-size: 30px; letter-spacing: -.02em; color: var(--cream); }
.auth .logo p { margin: 0; color: var(--on-dark-sage); font-size: 15px; }
/* The page shadow is a green tint meant for paper and vanishes on the dark
   ground, so the card carries a deeper one of its own to lift off it. */
.auth .card {
  box-shadow: 0 2px 6px rgba(9, 32, 23, .20), 0 20px 44px rgba(9, 32, 23, .30);
  border-radius: 20px; padding: 24px 22px; margin-bottom: 0;
}
/* The one h2 in the app that is a greeting rather than a section label, so it
   drops the uppercase eyebrow treatment the cards elsewhere wear: on a screen
   holding a single card there is no other section to be told apart from. */
.auth .card h2 {
  font-size: 22px; text-transform: none; letter-spacing: -.015em;
  color: var(--ink); margin: 0 0 18px;
}
.auth .card .lede { margin: -10px 0 18px; font-size: 14px; color: var(--ink-soft); line-height: 1.45; }
/* Uppercase here and nowhere else: these labels sit above the only boxes in the
   app you fill in before you are signed in, and the small caps hold them apart
   from the white box without another rule or a second weight of ink. */
.auth .field label {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .085em;
  font-weight: 700; color: var(--ink-muted); margin: 0 0 5px;
}
.auth .field { margin-bottom: 16px; }
/* The label's gap moves to the head when there is one, so a field with a Show
   beside its label sits the same distance off its box as one without. */
.auth .field-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin: 0 0 5px; }
.auth .field-head label { margin: 0; }
/* A text button, not a box: it is a switch on the field's own label line, and a
   bordered control there would compete with the box underneath it. Ink is the
   body ink so it is legible, underlined so it reads as something to tap, and
   the tap target is padded out to the full label line. */
.auth .reveal {
  background: none; border: 0; padding: 2px 0; margin: -2px 0;
  font: inherit; font-size: 13px; font-weight: 600; color: var(--ink-soft);
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.auth .reveal:hover { color: var(--ink); }
/* White boxes on a white card: on this screen the card is the only surface, so
   a paper fill would read as a second one. The rule is what holds the shape. */
.auth input[type=text], .auth input[type=password], .auth input[type=email],
.auth input[type=datetime-local], .auth input[type=date], .auth input[type=number], .auth select {
  background: var(--card); border-color: var(--line); border-radius: 12px; padding: 14px 13px;
}
.auth .hint { margin: 7px 2px 0; }
.auth .btn { border-radius: 12px; min-height: 54px; font-size: 16px; margin-top: 8px; }
.auth-alt { margin: 22px 0 0; text-align: center; font-size: 14.5px; color: var(--on-dark-sage); }
.auth-alt a { color: var(--cream); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }

/* The refusal is a line of prose with its mark beside it, not a banner: it
   holds the same clay family the app already spends on nappies, one step paler
   than a tile so it never reads as something you can tap. */
.err {
  display: flex; align-items: flex-start; gap: 10px;
  background: #F2E4DF; color: #8F4636; padding: 12px 14px; border-radius: 12px;
  font-size: 14px; line-height: 1.4; margin: 0 0 16px;
}
.err svg { flex: none; margin-top: 1px; }

@media (min-width: 620px) {
  .tiles { grid-template-columns: repeat(4, 1fr); }
  .grid  { grid-template-columns: repeat(4, 1fr); }
}
