/* OurHug -- blue and green, bright, phone first.
   Colour is load-bearing here: each person owns a hue, and every chip, dot and
   left edge in the app uses it, so you can read the board at a glance. */

:root {
  color-scheme: light;

  /* Brand ramp: sky -> teal -> emerald. */
  --sky: #0ea5e9;
  --teal: #14b8a6;
  --emerald: #10b981;
  --deep: #0f766e;
  --brand-grad: linear-gradient(135deg, #0ea5e9 0%, #14b8a6 55%, #10b981 100%);
  --brand-grad-soft: linear-gradient(135deg, #e0f2fe 0%, #ccfbf1 55%, #d1fae5 100%);

  --bg: #f2f9f8;
  --surface: #ffffff;
  --surface-2: #f7fbfb;
  --line: #dbeae8;
  --line-strong: #c3ddda;

  --ink: #0b2733;
  --ink-soft: #4a6b75;
  --ink-faint: #7d99a1;

  --accent: #f59e0b;
  --danger: #e11d48;
  --ok: #059669;

  --radius: 18px;
  --radius-sm: 12px;
  --shadow: 0 1px 2px rgba(9, 51, 61, .06), 0 8px 24px -12px rgba(9, 51, 61, .18);
  --shadow-lift: 0 2px 6px rgba(9, 51, 61, .08), 0 18px 40px -18px rgba(9, 51, 61, .32);

  --tap: 44px;
  --gutter: 16px;
  --header-h: 132px;
  --tabbar-h: 64px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #071319;
    --surface: #0f2129;
    --surface-2: #142b34;
    --line: #1e3a44;
    --line-strong: #2b4d59;
    --ink: #e7f4f4;
    --ink-soft: #9fbcc2;
    --ink-faint: #7794a0;
    --deep: #5eead4;
    --brand-grad: linear-gradient(135deg, #0369a1 0%, #0d7f77 55%, #047857 100%);
    --brand-grad-soft: linear-gradient(135deg, #10303f 0%, #10393a 55%, #0e3630 100%);
    --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -12px rgba(0, 0, 0, .6);
    --shadow-lift: 0 2px 6px rgba(0, 0, 0, .45), 0 18px 40px -18px rgba(0, 0, 0, .8);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #071319;
  --surface: #0f2129;
  --surface-2: #142b34;
  --line: #1e3a44;
  --line-strong: #2b4d59;
  --ink: #e7f4f4;
  --ink-soft: #9fbcc2;
  --ink-faint: #7794a0;
  --deep: #5eead4;
  --brand-grad: linear-gradient(135deg, #0369a1 0%, #0d7f77 55%, #047857 100%);
  --brand-grad-soft: linear-gradient(135deg, #10303f 0%, #10393a 55%, #0e3630 100%);
  --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px -12px rgba(0, 0, 0, .6);
  --shadow-lift: 0 2px 6px rgba(0, 0, 0, .45), 0 18px 40px -18px rgba(0, 0, 0, .8);
}

* { box-sizing: border-box; }

/* Any `display` declaration outranks the UA's [hidden] rule, and this file
   sets display on .field, .row2 and .view -- so toggling el.hidden silently
   did nothing. Make the attribute win everywhere. */
[hidden] { display: none !important; }

html, body {
  /* No double-tap-to-zoom, and no rubber-banding the whole page sideways.
     Anything that genuinely scrolls sideways -- a wide table, the Wrapped
     reel -- says so on its own container. */
  touch-action: pan-x pan-y;
  overflow-x: hidden;
  overscroll-behavior-x: none;
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans Thai",
        "Helvetica Neue", Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
}

/* The app is exactly one screen tall and does not scroll. The scrolling
   happens inside .scroll, which leaves the tab bar as an ordinary flex child
   at the bottom rather than something pinned over the top of the page. */
body {
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  position: relative;
}
.scroll {
  flex: 1 1 auto;
  overflow-y: auto;
  /* Pinned, and this is not belt-and-braces. A container with overflow-y:auto
     and nothing said about x computes overflow-x to auto as well -- so the
     app's one scrolling column was also a sideways-scrolling one, waiting for
     anything to be a pixel too wide, or for iOS to pan it while bringing a
     focused field above the keyboard. Nothing here is meant to move sideways;
     the few things that are (a wide table, the Wrapped reel) say so on their
     own container. */
  overflow-x: hidden;
  overscroll-behavior-y: contain;
  overscroll-behavior-x: none;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 8px;
}

h1, h2, h3 { margin: 0; line-height: 1.25; letter-spacing: -.01em; }
p { margin: 0; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--deep); }

/* ---------- header ---------------------------------------------------- */

.topbar {
  background: var(--brand-grad);
  color: #fff;
  padding: calc(env(safe-area-inset-top) + 18px) var(--gutter) 22px;
  border-radius: 0 0 26px 26px;
  box-shadow: var(--shadow);
  position: relative;
  overflow: hidden;
}
/* A soft light bloom so the gradient does not read as a flat slab. */
.topbar::after {
  content: "";
  position: absolute;
  inset: -60% -20% auto auto;
  width: 320px; height: 320px;
  background: radial-gradient(circle, rgba(255,255,255,.28), transparent 62%);
  pointer-events: none;
}
.topbar-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.greeting { font-size: 25px; font-weight: 700; }
.subtle { color: rgba(255,255,255,.86); font-size: 14px; margin-top: 3px; }

.topbar-tools { display: flex; gap: 8px; position: relative; z-index: 1; }

/* The same header, shrunk to the name of the screen you are on. The greeting
   is worth its height once a day on the Today screen; on the other five it is
   132px of nothing, above the thing you actually came to look at. */
.topbar.slim {
  --hue: var(--teal);
  padding: calc(env(safe-area-inset-top) + 14px) var(--gutter) 16px;
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--hue) 92%, #000 8%) 0%,
    var(--hue) 70%);
}
.topbar.slim #topGreeting, .topbar.slim .people { display: none; }
.top-title { font-size: 22px; font-weight: 700; letter-spacing: -.01em; }

.iconbtn {
  width: var(--tap); height: var(--tap);
  border-radius: 50%;
  border: 0;
  background: rgba(255,255,255,.18);
  color: #fff;
  font-size: 19px;
  cursor: pointer;
  display: grid; place-items: center;
  transition: background .15s ease, transform .1s ease;
}
.iconbtn:hover { background: rgba(255,255,255,.3); }
.iconbtn:active { transform: scale(.94); }

/* Person chips in the header. */
.people { display: flex; gap: 9px; margin-top: 16px; position: relative; z-index: 1; }
.person {
  flex: 1;
  min-width: 0;
  background: rgba(255,255,255,.17);
  border: 1px solid rgba(255,255,255,.24);
  border-radius: 14px;
  padding: 9px 10px;
  cursor: pointer;
  text-align: left;
  color: #fff;
  transition: background .15s ease, transform .1s ease;
}
.person:active { transform: scale(.97); }
.person[aria-pressed="true"] { background: rgba(255,255,255,.34); border-color: rgba(255,255,255,.6); }
.person-name { font-weight: 650; font-size: 14px; display: flex; align-items: center; gap: 6px; }
.person-meta { font-size: 12px; color: rgba(255,255,255,.85); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dot { width: 9px; height: 9px; border-radius: 50%; flex: none; background: var(--c, #fff);
  box-shadow: 0 0 0 2px rgba(255,255,255,.55); }

/* ---------- layout ---------------------------------------------------- */

main { padding: var(--gutter); display: grid; gap: 14px; max-width: 720px; margin: 0 auto; }
.view[hidden] { display: none; }
.view { display: grid; gap: 14px; animation: rise .22s ease both; }
@keyframes rise { from { opacity: 0; transform: translateY(6px); } }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.card-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 14px 16px 0;
}
.card-title { font-size: 13px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; color: var(--ink-faint); }
.card-body { padding: 12px 16px 16px; display: grid; gap: 10px; }

.pill {
  font-size: 12px; font-weight: 650; padding: 3px 9px; border-radius: 999px;
  background: var(--brand-grad-soft); color: var(--deep); border: 1px solid var(--line);
}
.pill.warn { background: #fff1f2; color: #be123c; border-color: #fecdd3; }
.pill.ok { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pill.warn { background: #3a1420; color: #fda4af; border-color: #6b2233; }
  :root:not([data-theme="light"]) .pill.ok { background: #0c2f26; color: #6ee7b7; border-color: #14503f; }
}
:root[data-theme="dark"] .pill.warn { background: #3a1420; color: #fda4af; border-color: #6b2233; }
:root[data-theme="dark"] .pill.ok { background: #0c2f26; color: #6ee7b7; border-color: #14503f; }

/* ---------- next up hero ---------------------------------------------- */

.hero {
  background: var(--brand-grad-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  display: flex; align-items: center; gap: 14px;
}
.hero-time {
  font-size: 27px; font-weight: 750; color: var(--deep);
  font-variant-numeric: tabular-nums; line-height: 1;
}
/* A word rather than a clock time needs to sit quieter and wrap sensibly. */
.hero-time.allday {
  font-size: 11px; letter-spacing: .06em; font-weight: 800;
  line-height: 1.25; max-width: 54px;
}
.hero-title { font-weight: 650; }
.hero-sub { font-size: 13px; color: var(--ink-soft); margin-top: 2px; }

/* ---------- quick actions --------------------------------------------- */

/* Three fixed buttons in fixed places. Muscle memory is the whole point, so
   these never reorder themselves by time of day or recent use. */
/* Four across, not three-and-a-lonely-one. A row that wraps leaves the last
   button sitting on its own line looking like a mistake, and on the narrowest
   phone in the house four still clear the 44px tap target. */
.quickbar { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.quick {
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 11px 4px 10px;
  display: grid; gap: 5px; justify-items: center;
  cursor: pointer; min-height: 76px;
  font-size: 11.5px; font-weight: 650; color: var(--ink);
  text-align: center; line-height: 1.15;
  transition: transform .1s ease, box-shadow .15s ease;
}
.quick:active { transform: scale(.96); }
.quick:hover { box-shadow: var(--shadow-lift); }
/* Each quick action wears its own colour rather than four mint circles in a
   row: the colour is how you find the one you want without reading, which is
   the entire point of a button you tap forty times a week. */
.quick .ico {
  line-height: 0;
  width: 44px; height: 44px; border-radius: 16px;
  display: grid; place-items: center;
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--c) 26%, var(--surface)),
    color-mix(in srgb, var(--c) 12%, var(--surface)));
  color: var(--c);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c) 22%, transparent);
}
.quick:active .ico { transform: scale(.93); }
.quick .ico { transition: transform .12s ease; }

/* ---------------- the More grid ---------------- */

/* Twelve doors. Centred, because a tile is a destination rather than a line
   in a list -- and the drawing is what you aim at, so it is the biggest thing
   on it. */
/* One person in "who is in this family": their colour, their name, and how
   they get in. Same shape as the account block above it. */
.fam-row {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 0;
}
.fam-row + .fam-row { border-top: 1px solid var(--line); }

/* The tiles sit straight on the page: no card around them, because a card
   holding cards is a border inside a border. */
.tile-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 11px; }
.tile {
  position: relative;
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--radius);
  /* Room along the bottom and right for the artwork to sit in. The height is
     whatever the words need -- a floor, not a fixed size. Two lines of state
     text land just under it; three push the row taller, and its neighbour
     stretches to match, which is what a grid row does. */
  padding: 13px 13px 11px;
  min-height: 84px;
  display: grid; align-content: start; justify-items: start; gap: 3px;
  text-align: left;
  cursor: pointer; color: var(--ink);
  overflow: hidden;
  transition: transform .1s ease, box-shadow .15s ease, border-color .15s ease;
}
.tile:hover { box-shadow: var(--shadow-lift); border-color: color-mix(in srgb, var(--c) 40%, var(--line)); }
.tile:active { transform: scale(.97); }
/* No backdrop: the symbol sits on the card itself, lower right, with the
   words upper left. A tinted lozenge behind every one of twelve tiles turns
   the grid into a sheet of buttons; this way the drawing is the thing you
   see, and the colour is carried by the drawing. */
.tile-icon {
  position: absolute; right: 11px; bottom: 9px;
  color: var(--c); line-height: 0;
  pointer-events: none;
}
/* Sized here rather than in the markup, so the wider tiers can give the
   drawing the room it was drawn for without re-rendering anything.
   40px on a phone: two tiles across is a compact tile, and the brief says so
   -- at 52px "notes, handouts, manuals" wrapped to three lines and ran into
   the box it was sitting next to. */
.tile-icon svg { width: 40px; height: 40px; }
/* In step with the rest of the app, not a size of its own.
 *
 * This was 17px/700 while the equivalent text on every other screen -- a row
 * title -- is the body size at 600. One step larger AND one step bolder made
 * the More grid read as a different app, which is what somebody noticed.
 * 650 rather than 600 because a tile label names a whole screen. */
.tile-label { font-size: 16px; font-weight: 650; line-height: 1.2; }
/* Kept clear of the artwork: a line of text running under the drawing is the
   one way this layout goes wrong. */
.tile-state { font-size: 12.5px; color: var(--ink-faint); line-height: 1.25; max-width: 68%; }

/* ---------- segmented control ------------------------------------------ */

/* Two ways to cut the same list. Deliberately not a card: it is a control
   sitting above the cards, not another thing to read. */
.seg {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 4px;
  padding: 4px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 999px;
}
.seg-btn {
  border: 0;
  background: transparent;
  border-radius: 999px;
  padding: 9px 10px;
  min-height: 38px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 650;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.seg-btn.on {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow);
}

/* A row of filters that scrolls sideways on purpose.
 *
 * Unlike .seg, which divides a fixed set of three or four between the full
 * width, this takes however many folders or categories a household happens to
 * have. It is one of the few things in the app that genuinely scrolls
 * horizontally, so it says so on its own container -- see the rule in .scroll.
 */
.chips {
  display: flex; gap: 7px;
  overflow-x: auto; overflow-y: hidden;
  padding: 2px 0 6px;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
}
.chips::-webkit-scrollbar { display: none; }
.chip {
  flex: none; scroll-snap-align: start;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-soft);
  border-radius: 999px;
  padding: 7px 13px;
  font: inherit; font-size: 13px; font-weight: 650;
  cursor: pointer; white-space: nowrap;
  display: flex; align-items: center; gap: 6px;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.chip:hover { border-color: var(--line-strong); }
.chip[aria-pressed="true"] {
  background: color-mix(in srgb, var(--c, var(--teal)) 16%, var(--surface));
  border-color: color-mix(in srgb, var(--c, var(--teal)) 55%, transparent);
  color: var(--ink);
}
.chip-count {
  font-size: 11.5px; font-weight: 700; color: var(--ink-faint);
}
.chip[aria-pressed="true"] .chip-count { color: inherit; opacity: .75; }

/* A card this person has switched off. Not `hidden`: the notes card hides
   itself when the fridge is bare, and "empty today" and "I never want this"
   are different states that must not fight over one attribute. */
/* A star that keeps a row at the top of its list.
 *
 * Outline when off, filled when on -- a control that is invisible until used
 * is not a control. Sized to the checkbox beside it so a row does not grow a
 * lump on the right. */
.star {
  flex: none; width: 34px; height: 34px; border: 0; border-radius: 999px;
  background: none; cursor: pointer; line-height: 1;
  font-size: 19px; color: var(--ink-faint);
  display: grid; place-items: center;
}
.star.on { color: #eab308; }
.star:active { transform: scale(.9); }

.card-off { display: none !important; }

/* A home-screen slot with nothing in it.
 *
 * The school, documents, dinner, pantry, occasions and trip cards are painted
 * into slots that stay in the DOM so the picker can order them. .view is a
 * grid with a gap, so an empty slot is invisible and still costs 14px -- six
 * of them would put 84px of nothing down the middle of the home screen. */
#view-today > div[data-card]:empty { display: none; }

/* One switchable row: a tick, the drawing, the name, and whatever the row
   needs on the right. Shared by "what Today shows" and "what this family
   uses" -- a column of identical words with a tick beside each is hard to
   read down, and the drawing is what the eye actually finds. */
.pick-row { display: flex; align-items: center; gap: 11px; padding: 8px 0; }
.pick-row + .pick-row { border-top: 1px solid var(--line); }
.pick-icon {
  flex: none; width: 38px; height: 38px; border-radius: 12px;
  display: grid; place-items: center; line-height: 0;
  color: var(--c);
  background: color-mix(in srgb, var(--c) 14%, var(--surface));
}
.pick-main { flex: 1; min-width: 0; }
.pick-label { font-weight: 600; line-height: 1.25; }
.pick-note { font-size: 12.5px; color: var(--ink-faint); margin-top: 1px; }
.pick-move { display: flex; gap: 6px; flex: none; }
.pick-move .pill { min-width: 38px; text-align: center; }
.pick-move .pill[disabled] { opacity: .35; cursor: not-allowed; }
/* A row switched off reads as switched off, rather than only its tick doing
   the work. */
.pick-row:has(.check[aria-checked="false"]) .pick-icon { opacity: .45; }
.pick-row:has(.check[aria-checked="false"]) .pick-label { color: var(--ink-faint); }

/* Picking an event's colour. A fixed palette, not a picker: these are tuned
   to be told apart at the size a calendar shows them. */
.swatches { display: flex; flex-wrap: wrap; gap: 8px; }
.swatch {
  width: 32px; height: 32px; border-radius: 50%;
  border: 2px solid transparent;
  background: var(--c, var(--surface-2));
  cursor: pointer; padding: 0;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08);
}
.swatch[aria-pressed="true"] {
  border-color: var(--ink);
  transform: scale(1.06);
}
/* "Whoever it belongs to" -- the absence of a choice, drawn as one. */
.swatch-auto {
  background: var(--surface-2);
  border: 2px dashed var(--line-strong);
  display: grid; place-items: center;
  font-size: 15px; color: var(--ink-faint);
}
.swatch-auto::after { content: "person"; font-size: 0; }
.swatch-auto::before { content: "\1F464"; font-size: 15px; }

/* ---------- list rows -------------------------------------------------- */

/* Member colours are tuned to be told apart as a 5px dot, which makes them too
   light to read as small text on white. Every place that prints text in a
   person's colour uses --c-text instead: the same hue, darkened for light mode
   and lightened for dark, so the palette stays intact and stays readable. */
.row, .score { --c-text: color-mix(in srgb, var(--c, var(--teal)) 72%, #04202a); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .row,
  :root:not([data-theme="light"]) .score { --c-text: color-mix(in srgb, var(--c, var(--teal)) 78%, #ffffff); }
}
:root[data-theme="dark"] .row,
:root[data-theme="dark"] .score { --c-text: color-mix(in srgb, var(--c, var(--teal)) 78%, #ffffff); }

.row {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 11px 12px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-left: 4px solid var(--c, var(--teal));
  border-radius: var(--radius-sm);
  min-height: var(--tap);
  cursor: pointer;
  transition: transform .1s ease, box-shadow .15s ease;
}
.row:active { transform: scale(.99); }
.row:hover { box-shadow: var(--shadow); }
.row-main { flex: 1; min-width: 0; }
.row-title { font-weight: 600; overflow-wrap: anywhere; }
.row-title.done { text-decoration: line-through; color: var(--ink-faint); font-weight: 500; }
.row-meta { font-size: 12.5px; color: var(--ink-soft); margin-top: 2px;
  display: flex; flex-wrap: wrap; gap: 4px 8px; }
.row-time {
  font-variant-numeric: tabular-nums; font-weight: 650; font-size: 14px;
  color: var(--c-text, var(--deep)); min-width: 46px;
}
.row-time.allday { font-size: 11px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-faint); font-weight: 700; }

.tag {
  font-size: 11px; font-weight: 650; padding: 2px 7px; border-radius: 6px;
  background: color-mix(in srgb, var(--c, var(--teal)) 16%, transparent);
  color: var(--c-text, var(--deep));
}

/* Round checkbox for tasks and shopping. */
.check {
  width: 26px; height: 26px; border-radius: 50%; flex: none; margin-top: 1px;
  border: 2px solid var(--line-strong); background: transparent;
  cursor: pointer; display: grid; place-items: center;
  color: transparent; font-size: 14px; font-weight: 800;
  transition: background .15s ease, border-color .15s ease, transform .1s ease;
}
.check:active { transform: scale(.88); }
.check[aria-checked="true"] {
  background: var(--c, var(--emerald)); border-color: var(--c, var(--emerald)); color: #04202a;
}

.empty { color: var(--ink-faint); font-size: 14px; text-align: center; padding: 18px 8px; }
.empty b { display: block; color: var(--ink-soft); font-size: 15px; margin-bottom: 3px; }
/* An empty screen that tells you what it is for should also let you do it.
   A link rather than a button: the screen already has a + in the corner, and
   two competing primary actions is worse than none. */
.empty-action {
  /* Block, not inline: the hint above it is a bare text node, so an
     inline-block link runs on from the end of the sentence and reads as part
     of it -- "the aircon man. Add the first number". */
  display: block; margin: 10px auto 0;
  border: 0; background: none; padding: 6px 4px;
  font: inherit; font-size: 14px; font-weight: 650;
  color: var(--deep); text-decoration: underline; cursor: pointer;
}

/* ---------- collapsible group ------------------------------------------ */

/* A whole aisle you have already walked can be folded away, so the list is
   what is left rather than what there was. FamilyWall does this and it is the
   difference between a list of forty and a list of the eleven still ahead. */
.fold-head {
  width: 100%; border: 0; background: none; cursor: pointer;
  display: flex; align-items: center; gap: 10px; text-align: left;
  padding: 12px 14px 10px; color: inherit; font: inherit;
}
.fold-head > .grow { flex: 1 1 auto; min-width: 0; }
.fold-chev {
  flex: none; color: var(--ink-faint); font-size: 13px; line-height: 1;
  transition: transform .18s ease;
}
.fold-head[aria-expanded="false"] .fold-chev { transform: rotate(-90deg); }
.fold-head[aria-expanded="false"] + .card-body { display: none; }
@media (prefers-reduced-motion: reduce) { .fold-chev { transition: none; } }

/* ---------- section hero ----------------------------------------------- */

/* A coloured band at the top of each More section: big title, the section's
   icon bleeding off the corner, a count on it. Borrowed wholesale from
   FamilyWall, where every screen announces itself instead of arriving as
   another grey list with a small heading.
   
   Each section sets --hue. The band is a gradient of it so the colour reads
   as deliberate rather than flat, and the text is white in both themes --
   which is why the hues are all mid-saturation: they have to hold white. */
/* main has a gutter; the band cancels it so the colour reaches all three
   edges rather than floating in a grey frame. */
.hero-band {
  --hue: var(--teal);
  position: relative; overflow: hidden;
  margin: calc(var(--gutter) * -1) calc(var(--gutter) * -1) 0;
  /* The band is the top of the page now -- the greeting header hides while a
     section is open -- so it has to clear the notch itself. */
  padding: calc(env(safe-area-inset-top) + 12px) var(--gutter) 18px;
  min-height: 132px;
  display: flex; flex-direction: column; justify-content: space-between;
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--hue) 92%, #000 8%) 0%,
    var(--hue) 70%);
  border-radius: 0 0 var(--radius) var(--radius);
  color: #fff;
}
.band-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.band-back {
  width: 38px; height: 38px; border-radius: 50%; border: 0; flex: none;
  background: rgba(255, 255, 255, .22); color: #fff;
  font-size: 19px; line-height: 1; cursor: pointer;
  display: grid; place-items: center;
  backdrop-filter: blur(6px);
}
.band-back:active { background: rgba(255, 255, 255, .34); }
.band-tools { display: flex; gap: 8px; }
/* Scoped to the band. .hero-title belongs to five older things -- the Today
   card, the PYP total, a trip, an occasion -- and restyling it here quietly
   made all of them 30px with a drop shadow. */
.band-title {
  font-size: 30px; font-weight: 800; letter-spacing: -.02em;
  margin: 0; position: relative; z-index: 1;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .16);
}
/* Oversized and half off the edge, the way an app that is pleased with itself
   does it. aria-hidden in the markup -- it is decoration, and the title
   already says which screen this is. */
.band-art {
  position: absolute; right: -14px; bottom: -18px;
  line-height: 0;
  opacity: .32; transform: rotate(-8deg);
  pointer-events: none; user-select: none;
}
.band-count {
  position: absolute; right: 26px; bottom: 26px;
  min-width: 34px; height: 34px; padding: 0 9px;
  border-radius: 999px; background: rgba(0, 0, 0, .42);
  color: #fff; font-size: 15px; font-weight: 750;
  display: grid; place-items: center;
  backdrop-filter: blur(4px);
}

/* The add button takes the section's colour, so the screen reads as one
   thing rather than a coloured header above somebody else's app. */
.fab.tinted { background: var(--hue); }

/* ---------- the account, at the top of settings ----------------------- */

.acct { display: flex; align-items: center; gap: 12px; padding: 2px 0 4px; }
.acct-avatar {
  width: 46px; height: 46px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--c); color: #fff; font-size: 19px; font-weight: 750;
}
.acct-who { display: grid; gap: 1px; min-width: 0; }
.acct-name { font-size: 16px; font-weight: 700; }
.acct-mail {
  font-size: 13px; color: var(--ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.acct-ok { font-size: 12px; font-weight: 650; color: var(--ok); }
.acct-warn { font-size: 12px; font-weight: 650; color: var(--accent); }

/* ---------- skeletons -------------------------------------------------- */

/* Shown while a screen is loading, instead of the word "Loading". It holds
   the shape the content will take, so the page does not jump when it lands
   and the wait does not read as a stall. */
.skeleton { display: grid; gap: 10px; padding: 4px 0; }
.skeleton-row {
  height: 58px; border-radius: var(--radius-sm);
  background: linear-gradient(90deg,
    var(--surface-2) 25%, color-mix(in srgb, var(--line) 60%, var(--surface-2)) 37%,
    var(--surface-2) 63%);
  background-size: 400% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
}
.skeleton-row:nth-child(2) { width: 88%; }
.skeleton-row:nth-child(3) { width: 74%; }
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }
@media (prefers-reduced-motion: reduce) {
  .skeleton-row { animation: none; }
}

/* ---------- calendar --------------------------------------------------- */

.cal-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 12px 6px; }
.cal-month { font-size: 17px; font-weight: 700; }
.cal-nav { display: flex; gap: 6px; }
.cal-nav button {
  width: 36px; height: 36px; border-radius: 10px; border: 1px solid var(--line);
  background: var(--surface-2); cursor: pointer; font-size: 15px;
}
.dow { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); padding: 4px 8px 0; }
.dow span { text-align: center; font-size: 11px; font-weight: 700; color: var(--ink-faint);
  text-transform: uppercase; letter-spacing: .05em; }
.grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 3px; padding: 6px 8px 12px; }
.day {
  aspect-ratio: 1 / 1.08;
  /* A grid item's automatic minimum is its MIN-CONTENT width, and Thai does
     not break on spaces -- so one imported school event called
     "สอบปลายภาค 1/2569 (รอบ 1) ม.1-ม.5" is a single unbreakable word about
     200px wide, and seven of those made the month 1400px wide inside a 900px
     card. The column floor above and this are the two halves of the fix. */
  min-width: 0;
  overflow: hidden;
  border: 1px solid transparent;
  border-radius: 11px;
  background: var(--surface-2);
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 5px 2px 4px;
  cursor: pointer; font-size: 13.5px; font-weight: 600;
  transition: transform .1s ease, border-color .15s ease;
}
.day:active { transform: scale(.94); }
.day.out { background: transparent; color: var(--ink-faint); font-weight: 400; opacity: .55; }
.day.today { background: var(--brand-grad); color: #fff; }
/* The selected day has to be obvious at a glance: it is the only feedback
   that a tap landed, and the list it controls may be further down the page. */
.day.sel {
  border-color: var(--deep);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--teal) 45%, transparent);
  font-weight: 750;
}
.day.sel:not(.today) { background: color-mix(in srgb, var(--teal) 14%, var(--surface-2)); }
.day-dots { display: flex; gap: 2.5px; flex-wrap: wrap; justify-content: center; min-height: 6px; }
.day-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--c); display: block; }
.day.today .day-dots i { box-shadow: 0 0 0 1px rgba(255,255,255,.7); }
/* Written-out days exist in the markup at every size and are shown only when
   there is room. One render, two readings -- rather than two code paths that
   drift. */
.day-items { display: none; }


/* ---------- forms and sheets ------------------------------------------- */

/* A password you can look at.
   Deliberately a reveal rather than a second "confirm" box: a confirm field
   mostly teaches people to paste, which defeats the point, and on a phone
   keyboard re-typing a long passphrase is where the typo happens twice. */
.peek { position: relative; display: block; }
.peek > .input { padding-right: 64px; }
.peek > button {
  position: absolute; top: 0; right: 0; height: 100%;
  padding: 0 12px; border: 0; background: none;
  font: inherit; font-size: 12.5px; font-weight: 650;
  color: var(--ink-soft); cursor: pointer;
}
.peek > button:hover { color: var(--ink); }

.field { display: grid; gap: 5px; }
.field > label { font-size: 12.5px; font-weight: 650; color: var(--ink-soft); }
.input, select, textarea {
  width: 100%;
  padding: 11px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: var(--surface-2);
  min-height: var(--tap);
  -webkit-appearance: none; appearance: none;
}
select { background-image: linear-gradient(45deg, transparent 50%, var(--ink-soft) 50%),
                          linear-gradient(135deg, var(--ink-soft) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; padding-right: 34px; }
textarea { min-height: 72px; resize: vertical; }
.input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--teal);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--teal) 22%, transparent);
}
.field-error { color: var(--danger); font-size: 12.5px; }
.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

.btn {
  border: 0; border-radius: var(--radius-sm); padding: 12px 16px;
  font-weight: 650; cursor: pointer; min-height: var(--tap);
  background: var(--surface-2); color: var(--ink); border: 1px solid var(--line-strong);
  transition: transform .1s ease, filter .15s ease;
}
.btn:active { transform: scale(.98); }
.btn-primary { background: var(--brand-grad); color: #fff; border: 0; }
.btn-primary:hover { filter: brightness(1.06); }
.btn-danger { background: transparent; color: var(--danger); border-color: transparent; }
/* The loud one, for the single action in the app that cannot be undone. Every
   other delete stays quiet -- if they all shouted, none of them would. */
.btn-destroy {
  background: var(--danger); color: #fff; border-color: var(--danger);
  font-weight: 700;
}
.btn-destroy:hover { filter: brightness(1.06); }
.btn-destroy:active { filter: brightness(.94); }
.btn-row { display: flex; gap: 10px; }
.btn-row .btn { flex: 1; }

/* Segmented control, used for filters. */
.seg { display: flex; gap: 4px; background: var(--surface-2); padding: 4px;
  border-radius: 12px; border: 1px solid var(--line); }
.seg button {
  flex: 1; border: 0; background: transparent; border-radius: 9px; padding: 8px 6px;
  font-size: 13px; font-weight: 650; color: var(--ink-soft); cursor: pointer; min-height: 36px;
}
.seg button[aria-pressed="true"] { background: var(--surface); color: var(--ink); box-shadow: var(--shadow); }

/* Bottom sheet dialog. */
dialog {
  border: 0; padding: 0; background: transparent; max-width: 560px; width: 100%;
  margin: auto auto 0; color: var(--ink);
}
dialog::backdrop { background: rgba(4, 28, 34, .5); backdrop-filter: blur(2px); }
.sheet {
  background: var(--surface);
  border-radius: 22px 22px 0 0;
  padding: 8px var(--gutter) calc(var(--gutter) + env(safe-area-inset-bottom));
  /* dvh, not vh: vh on iPhone is the height with Safari's toolbars hidden, so
     a sheet sized in vh is taller than the screen while they are showing. The
     vh line stays first as the fallback for anything that lacks dvh. */
  max-height: 88vh;
  max-height: 88dvh;
  overflow-y: auto;
  /* Same reason as .scroll: a sheet is a column, and the keyboard opening on
     a field inside it must not leave it panned half off the screen. */
  overflow-x: hidden;
  overscroll-behavior-x: none;
  display: grid; gap: 12px;
  animation: slideup .24s cubic-bezier(.2, .9, .3, 1) both;
}
@keyframes slideup { from { transform: translateY(28px); opacity: .6; } }
.grabber { width: 40px; height: 4px; border-radius: 4px; background: var(--line-strong);
  margin: 6px auto 2px; }
.sheet h2 { font-size: 19px; }

@media (min-width: 620px) {
  dialog { margin: auto; }
  .sheet { border-radius: 22px; }
}

/* ---------- tab bar ---------------------------------------------------- */

.tabbar {
  /* Not fixed. See the comment in index.html: a fixed bar is anchored to the
     layout viewport and strands itself mid-page as soon as somebody pinches. */
  flex: none; z-index: 30;
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
}
.tabbar button {
  position: relative;
  border: 0; background: transparent; cursor: pointer;
  padding: 9px 4px 7px; display: grid; gap: 3px; justify-items: center;
  color: var(--ink-faint); font-size: 10px; font-weight: 650; min-height: var(--tabbar-h);
}
.tabbar button span.ico {
  display: grid; place-items: center; line-height: 0;
  /* The tinted lozenge behind the icon is what actually marks the current tab;
     colour alone was too quiet to read at a glance on a phone. */
  padding: 4px 13px; border-radius: 999px;
  transition: background .18s ease;
}
.tabbar button[aria-current="page"] { color: var(--deep); font-weight: 750; }
.tabbar button[aria-current="page"] span.ico {
  background: color-mix(in srgb, var(--teal) 20%, transparent);
}

/* In a browser tab, iOS puts its own bar along the bottom -- and on iOS 26 it
   floats over the page. Give ours room to sit clear of it. Added to the Home
   Screen there is no such bar, and this rule does not apply. */
@media (display-mode: browser) {
  .tabbar { padding-bottom: calc(env(safe-area-inset-bottom) + 12px); }
}
.tab-badge {
  position: absolute; top: 4px; left: 50%; transform: translateX(8px);
  background: var(--accent); color: #3a2400; font-size: 10px; font-weight: 800;
  border-radius: 999px; padding: 1px 5px; min-width: 16px; line-height: 1.4;
  box-shadow: 0 0 0 2px var(--surface);
}

/* Floating add button. */
.fab {
  /* Absolute against the body, which is exactly one screen tall and never
     scrolls -- so this behaves like the old fixed positioning without
     borrowing its habit of wandering off when the page is zoomed. */
  position: absolute; right: 18px;
  bottom: calc(var(--tabbar-h) + 16px + env(safe-area-inset-bottom));
  width: 56px; height: 56px; border-radius: 50%; border: 0; z-index: 25;
  background: var(--brand-grad); color: #fff; font-size: 27px; line-height: 1;
  box-shadow: var(--shadow-lift); cursor: pointer;
  transition: transform .12s ease;
}
.fab:active { transform: scale(.92); }

/* ---------- misc ------------------------------------------------------- */

.toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--tabbar-h) + 22px + env(safe-area-inset-bottom));
  background: #08313a; color: #fff; padding: 11px 16px; border-radius: 12px;
  font-size: 14px; box-shadow: var(--shadow-lift); z-index: 60; max-width: 90vw;
  animation: rise .2s ease both;
}
.toast.bad { background: var(--danger); }
.toast.has-undo { display: flex; align-items: center; gap: 14px; padding-right: 8px; }
.toast-undo {
  border: 0; background: rgba(255, 255, 255, .16); color: #fff;
  border-radius: 9px; padding: 7px 13px; min-height: 34px;
  font: inherit; font-size: 13.5px; font-weight: 700; cursor: pointer;
  flex: none;
}
.toast-undo:active { background: rgba(255, 255, 255, .3); }

.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px;
  word-break: break-all; background: var(--surface-2); padding: 9px 11px;
  border-radius: 10px; border: 1px solid var(--line); }

.help { font-size: 13px; color: var(--ink-soft); }
.help ol { margin: 8px 0 0; padding-left: 20px; display: grid; gap: 5px; }

.scoreboard { display: flex; gap: 9px; }
.score { flex: 1; text-align: center; padding: 11px 6px; border-radius: 13px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-top: 3px solid var(--c); }
.score b { display: block; font-size: 21px; color: var(--c-text); font-variant-numeric: tabular-nums; }
.score span { font-size: 11.5px; color: var(--ink-soft); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ---------- budget dials ----------------------------------------------- */

/* A ring per category, filling clockwise as its month is spent. Round because
   a budget is a whole thing being used up, and because a ring fills the tile
   evenly -- the jar this replaced left a hole above it and squeezed the name
   into an ellipsis. */

.budget-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }

.budget-tile {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  padding: 12px 10px 13px;
  display: grid; gap: 8px; justify-items: center;
  text-align: center;
  /* Tiles are buttons -- tapping the thing you are looking at should open it */
  width: 100%; font: inherit; color: inherit; cursor: pointer;
  transition: transform .1s ease, box-shadow .15s ease;
}
button.budget-tile:active { transform: scale(.97); }
button.budget-tile:hover { box-shadow: var(--shadow); }
.budget-tile.wide {
  grid-column: 1 / -1;
  justify-items: stretch; text-align: left;
  gap: 9px;
}

.budget-head { display: flex; align-items: center; gap: 7px; width: 100%; }
.budget-icon {
  font-size: 16px; line-height: 1;
  width: 28px; height: 28px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--brand-grad-soft);
}
/* Wraps rather than truncating: "Food delivery" is not a useful thing to
   shorten to "Food deli...". */
.budget-name {
  font-weight: 650; font-size: 12.5px; color: var(--ink);
  line-height: 1.25; text-align: left; min-width: 0;
}

.budget-dial { width: 100%; max-width: 108px; display: block; }
.budget-dial-track { fill: none; stroke: var(--line); stroke-width: 11; }
.budget-dial-fill {
  fill: none; stroke-width: 11; stroke-linecap: round;
  transition: stroke-dasharray .5s cubic-bezier(.2, .8, .3, 1);
}
/* Where the ring would have reached if the month were spent evenly. */
.budget-dial-pace { stroke: var(--ink-faint); stroke-width: 2.5; opacity: .75; }
.budget-dial-pct { font-size: 21px; font-weight: 750; }
.budget-dial-sub { font-size: 8.5px; fill: var(--ink-faint); font-weight: 600;
  letter-spacing: .04em; }

.budget-left { font-size: 14.5px; font-weight: 750; line-height: 1.2; }
.budget-of { font-size: 11.5px; color: var(--ink-faint); line-height: 1.3; }

.budget-total-bar {
  position: relative; height: 12px; border-radius: 6px;
  background: var(--line); overflow: hidden;
}
.budget-total-fill { height: 100%; border-radius: 6px; transition: width .45s ease; }
.budget-total-pace { position: absolute; top: -2px; bottom: -2px; width: 2px; opacity: .5; }

/* ---------- moments ----------------------------------------------------- */

/* An album, so the picture leads and the words follow: a photograph is what
   you recognise a day by. Two across on a phone, more as the screen allows. */

/* Two across whatever the phone's width, then more as there is room.
   auto-fill alone collapsed to a single full-width column on a narrow screen
   -- an iPhone with Display Zoom on has about 256px here, and two 140px
   columns plus the gap need 290. A photograph filling the screen is not a
   thumbnail. */
.moment-grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 520px) {
  .moment-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
}

/* A month is a heading, not a label: it reads as words rather than shouting. */
.card-title.plain {
  text-transform: none; letter-spacing: -.01em;
  font-size: 15.5px; color: var(--ink);
}

.moment-tile {
  display: grid; gap: 6px;
  padding: 0; border: 0; background: none; font: inherit; color: inherit;
  text-align: left; cursor: pointer;
  transition: transform .1s ease;
}
.moment-tile:active { transform: scale(.97); }

.moment-cover { position: relative; }
.moment-cover img, .moment-cover video {
  display: block; width: 100%; aspect-ratio: 1; object-fit: cover;
  border-radius: var(--radius-sm); border: 1px solid var(--line);
  background: var(--surface-2);
}
/* A day with no picture still gets a tile: an album that hides the days
   nobody photographed is telling half the story. */
.moment-cover-empty {
  width: 100%; aspect-ratio: 1; display: grid; place-items: center;
  font-size: 28px;
  border-radius: var(--radius-sm); border: 1px dashed var(--line-strong);
  background: var(--brand-grad-soft);
}
.moment-count, .moment-clip {
  position: absolute; bottom: 7px;
  background: rgba(4, 28, 34, .72); color: #fff;
  font-size: 11px; font-weight: 700; line-height: 1;
  padding: 4px 7px; border-radius: 999px;
  backdrop-filter: blur(4px);
}
.moment-count { right: 7px; }
.moment-clip { left: 7px; }

.moment-name {
  font-weight: 650; font-size: 13px; line-height: 1.25; color: var(--ink);
  /* Two lines, then trail off -- and always two lines' worth of room, so a
     short title next to a long one does not leave the dates out of step. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(2em * 1.25);
}
.moment-when {
  display: flex; gap: 7px; flex-wrap: wrap;
  font-size: 11.5px; color: var(--ink-faint);
}

/* ---------- the wrapped player ----------------------------------------- */

.reel {
  position: relative; width: 100%; aspect-ratio: 4 / 5;
  border-radius: var(--radius); overflow: hidden;
  background: #05131a;
}
.reel img, .reel video {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: contain;
}
/* A still that sits perfectly still for four seconds feels like a stuck
   page. A slow drift across it reads as a film instead. */
.reel img { animation: drift 7s ease-out both; }
@keyframes drift {
  from { transform: scale(1.08) translate3d(1.5%, 1.5%, 0); }
  to   { transform: scale(1) translate3d(0, 0, 0); }
}
.reel-frame { animation: fadein .45s ease both; }
@keyframes fadein { from { opacity: 0; } }

/* Story-style segments: how many there are, and how far through. */
.reel-bars {
  position: absolute; top: 8px; left: 8px; right: 8px; z-index: 2;
  display: flex; gap: 3px;
}
.reel-bar {
  flex: 1; height: 3px; border-radius: 2px;
  background: rgba(255, 255, 255, .3); overflow: hidden;
}
.reel-bar i { display: block; height: 100%; width: 0; background: #fff; border-radius: 2px; }
.reel-bar.done i { width: 100%; }
.reel-bar.now i { animation: fill var(--hold, 4s) linear both; }
@keyframes fill { from { width: 0; } to { width: 100%; } }

.reel-caption {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 34px 14px 14px;
  background: linear-gradient(to top, rgba(4, 18, 24, .82), transparent);
  color: #fff;
}
.reel-title { font-size: 17px; font-weight: 750; line-height: 1.2; }
.reel-when { font-size: 12.5px; opacity: .85; margin-top: 2px; }

/* Real buttons, because an invisible half of a picture is not a control
   anybody can find. */
.reel-controls { display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center; }
.reel-step {
  width: 46px; height: 46px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--surface);
  font-size: 17px; cursor: pointer; display: grid; place-items: center;
}
.reel-step:disabled { opacity: .35; cursor: default; }
.reel-play {
  height: 46px; border-radius: 999px; border: 0; cursor: pointer;
  background: var(--brand-grad); color: #fff;
  font-weight: 750; font-size: 14.5px;
}

/* ---------------- search ---------------- */

.search-field { position: relative; }
.search-field .input { padding-right: 40px; }
/* The browser draws its own clear button on a search input, and two crosses
   side by side is one too many. Ours stays: it is the one that also puts the
   cursor back in the box. */
.search-field .input::-webkit-search-cancel-button { display: none; }
.search-clear {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 30px; height: 30px; border: 0; border-radius: 50%;
  background: transparent; color: var(--ink-faint);
  font-size: 17px; cursor: pointer; display: grid; place-items: center;
}
.search-clear:hover { background: var(--surface-2); color: var(--ink); }

.search-results {
  display: grid; gap: 14px; max-height: 56vh;
  overflow-y: auto; overflow-x: hidden;
}
.search-group-head {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-faint); margin-bottom: 6px;
}
.search-hit {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px 12px; border: 0; border-radius: 12px;
  background: var(--surface-2); color: var(--ink);
  font: inherit; text-align: left; cursor: pointer;
}
.search-hit + .search-hit { margin-top: 6px; }
.search-hit:hover { filter: brightness(1.04); }
.search-hit-main { min-width: 0; flex: 1; }
.search-hit-title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-hit-meta { font-size: 12.5px; color: var(--ink-faint); margin-top: 2px; }
.search-hit mark { background: transparent; color: var(--teal); font-weight: 700; }
.search-hit-go { color: var(--ink-faint); font-size: 15px; }

/* ---------- rewards ----------/* ---------- rewards ------------------------------------------------------
 *
 * A shelf, not a list. The point of the screen is to be looked at by a child
 * deciding what to save for, so the cost is the biggest thing on the tile and
 * the tiles sit side by side where they can be compared.
 */
.prize-grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}
.prize {
  position: relative; display: grid; gap: 4px; align-content: start;
  min-height: 104px; padding: 12px 13px 11px; text-align: left;
  border: 1px solid var(--line); border-radius: 16px;
  background: var(--surface); color: inherit; font: inherit; cursor: pointer;
  border-left: 3px solid var(--c);
}
.prize:active { transform: scale(.985); }
.prize-cost {
  font-size: 22px; font-weight: 750; line-height: 1.1; color: var(--c);
  font-variant-numeric: tabular-nums;
}
.prize-name { font-size: 14px; font-weight: 650; line-height: 1.3; }
.prize-foot { font-size: 11.5px; color: var(--ink-faint); margin-top: auto; }
/* Asked for: the tile says so without needing a second look. */
.prize-asked { border-color: var(--c); box-shadow: inset 0 0 0 1px var(--c); }
.prize-gone { opacity: .5; }

/* Yes and no sit together on a request, so the affirmative has to be the one
   that looks like the answer. */
.pill-yes { background: var(--emerald); border-color: var(--emerald); color: #fff; }

/* ---------- growth -------------------------------------------------------
 *
 * A chart with nothing behind the line. There is no reference band and no
 * shaded region because there is nothing here to compare against: the app
 * draws a family's own numbers and stops, and the reading of them belongs to
 * the clinic. See lib/growth.mjs.
 */
.growth-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}
.growth-age { font-size: 20px; font-weight: 750; line-height: 1.2; }
.growth-born {
  background: none; border: 0; padding: 2px 0; margin: 0;
  font: inherit; font-size: 12.5px; color: var(--ink-faint);
  text-decoration: underline; cursor: pointer;
}
.growth-last { display: flex; gap: 14px; flex-wrap: wrap; justify-content: flex-end; }
.growth-last-one { text-align: right; }
.growth-last-v {
  font-size: 19px; font-weight: 750; line-height: 1.15;
  font-variant-numeric: tabular-nums; display: block;
}
.growth-last-u { font-size: 11.5px; color: var(--ink-faint); }

/* Its own scroll container, so a long series never pushes the page sideways. */
.growth-chart-wrap { overflow-x: auto; }
.growth-chart { width: 100%; min-width: 280px; display: block; }
.growth-line { fill: none; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.growth-dot { stroke: var(--surface); stroke-width: 1.6; }
.growth-grid { stroke: var(--line); stroke-width: 1; }
.growth-tick, .growth-axis {
  fill: var(--ink-faint); font-size: 10.5px; font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* ---------- bigger screens ---------------------------------------------
 *
 * One tier, not a rebuild. The app stays a single column -- that is what it
 * is -- and the extra width goes into the two places it actually buys
 * something: reading the month instead of tapping through it, and seeing
 * more than two doors at a time.
 */
@media (min-width: 700px) {
  /* The header's contents line up with the cards below rather than floating
     out to the left edge while the cards sit centred. */
  .topbar > * { max-width: 688px; margin-inline: auto; }

  /* A month you can read. The dots were a phone compromise. */
  .day {
    aspect-ratio: 1 / .8;
    align-items: stretch;
    padding: 6px 6px 5px;
    gap: 4px;
  }
  .day-num { text-align: center; flex: none; }
  .day-dots { display: none; }
  /* Exactly two rows, and the box is exactly two rows TALL.
     A third row would begin past the bottom edge and so is clipped whole
     rather than sliced down the middle -- which is what a day carrying a
     holiday and the sports week looked like: a line of Thai cut in half
     horizontally, legible as neither text nor decoration. Height and row
     height are tied together here so they cannot drift apart. */
  .day-items {
    --day-row: 15px;
    display: grid; gap: 2px; align-content: start;
    grid-auto-rows: var(--day-row);
    height: calc(var(--day-row) * 2 + 2px);
    overflow: hidden; min-height: 0;
  }
  .day-item, .day-more {
    font-size: 10.5px; font-weight: 600; line-height: var(--day-row);
    text-align: left; padding: 0 4px; border-radius: 4px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .day-item { background: color-mix(in srgb, var(--c) 20%, transparent); }
  .day-more { color: var(--ink-faint); font-weight: 500; }
  .day.today .day-item { background: rgba(255, 255, 255, .3); }
  .day.today .day-more { color: rgba(255, 255, 255, .85); }
  /* A day from the month either side is context, not content. */
  .day.out .day-items { display: none; }

  /* Columns by the room there is for them, not by the width of the window.
     The content column is capped at 720px on every screen, so asking for four
     columns on a desktop made each tile NARROWER than the same tile on a
     phone -- the count went up and the space did not. A minimum tile width
     works it out instead, and stops at three because that is what fits. */
  .tile-grid { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
  .tile { min-height: 104px; padding: 15px 15px 13px; }
  .tile-icon { right: 14px; bottom: 11px; }
  .tile-icon svg { width: 52px; height: 52px; }

  /* The tab bar stops being a strip pinned across a wide screen and becomes
     a bar the width of a hand, where the thumb -- or the pointer -- already
     is. */
  .tabbar {
    /* width AND max-width: an auto inline margin on a flex item cancels the
       cross-axis stretch, so without this the bar shrinks to fit its five
       labels instead of filling the 560 it is allowed. */
    width: 100%;
    max-width: 560px;
    margin: 0 auto calc(env(safe-area-inset-bottom) + 12px);
    border: 1px solid var(--line);
    border-radius: 999px;
    padding-bottom: 0;
    box-shadow: var(--shadow-lift);
    overflow: hidden;
  }
}
