/* ============================================================================
   Life OS — the one stylesheet
   ----------------------------------------------------------------------------
   Themes: <html data-palette="tideline|graphite|forest|midnight|ember|mono"
                 data-appearance="auto|light|dark">
   Every colour below comes from a token. Palette tokens were contrast-checked
   (docs/research/palette-tools: WCAG 2.x) in light and dark. Day-status colours
   are the same in every palette so a year always reads the same way (the
   validated Blueprint set); the dark and automatic-dark blocks are identical.
   When you change CSS, bump ASSET_VER in includes/bootstrap.php.
   ========================================================================= */

/* ---- Theme tokens (from the validated palette table, docs/research/palette-tools) ---- */
:root{ --canvas:#F7F4F1; --surface:#FFFEFD; --surface-2:#EEECE8; --raised:#FFFFFF; --line:#E1DEDA; --line-strong:#87837F; --ink:#1F1D1B; --ink-soft:#4E4B47; --muted:#6B6763; --accent:#026468; --accent-ink:#FFFFFF; --focus:#026468; --ok:#35693D; --warn:#955621; --danger:#AE3539; --st-none:var(--surface-2); --scrim:rgba(20,18,16,.34); --tint:18%; --shadow-float:0 1px 2px rgba(20,18,16,.06), 0 10px 28px rgba(20,18,16,.12); --shadow-sheet:0 -12px 40px rgba(20,18,16,.16); color-scheme:light; }
:root[data-palette="tideline"]{ --canvas:#F7F4F1; --surface:#FFFEFD; --surface-2:#EEECE8; --raised:#FFFFFF; --line:#E1DEDA; --line-strong:#87837F; --ink:#1F1D1B; --ink-soft:#4E4B47; --muted:#6B6763; --accent:#026468; --accent-ink:#FFFFFF; --focus:#026468; --ok:#35693D; --warn:#955621; --danger:#AE3539; }
:root[data-palette="graphite"]{ --canvas:#F3F4F6; --surface:#FFFFFF; --surface-2:#E8EAEE; --raised:#FFFFFF; --line:#DCDFE4; --line-strong:#7B818B; --ink:#15171B; --ink-soft:#434852; --muted:#5F6570; --accent:#2A55C6; --accent-ink:#FFFFFF; --focus:#2A55C6; --ok:#35693D; --warn:#955621; --danger:#AE3539; }
:root[data-palette="forest"]{ --canvas:#F2F4EF; --surface:#FEFFFC; --surface-2:#E6EAE2; --raised:#FFFFFF; --line:#D9DED4; --line-strong:#7C8578; --ink:#191D18; --ink-soft:#434A40; --muted:#5F675B; --accent:#2E6A48; --accent-ink:#FFFFFF; --focus:#2E6A48; --ok:#35693D; --warn:#955621; --danger:#AE3539; }
:root[data-palette="midnight"]{ --canvas:#F2F4F8; --surface:#FFFFFF; --surface-2:#E6E9F0; --raised:#FFFFFF; --line:#D9DEE7; --line-strong:#767F8E; --ink:#121826; --ink-soft:#3D4658; --muted:#596377; --accent:#86600F; --accent-ink:#FFFFFF; --focus:#86600F; --ok:#35693D; --warn:#955621; --danger:#AE3539; }
:root[data-palette="ember"]{ --canvas:#F6F2EE; --surface:#FFFDFB; --surface-2:#ECE5DF; --raised:#FFFFFF; --line:#E0D8D1; --line-strong:#88807A; --ink:#221C18; --ink-soft:#50473F; --muted:#6D645C; --accent:#9A4B1C; --accent-ink:#FFFFFF; --focus:#9A4B1C; --ok:#35693D; --warn:#955621; --danger:#AE3539; }
:root[data-palette="mono"]{ --canvas:#F5F5F5; --surface:#FFFFFF; --surface-2:#EBEBEB; --raised:#FFFFFF; --line:#DEDEDE; --line-strong:#808080; --ink:#141414; --ink-soft:#454545; --muted:#636363; --accent:#141414; --accent-ink:#FFFFFF; --focus:#141414; --ok:#35693D; --warn:#955621; --danger:#AE3539; }
:root[data-appearance="dark"]{ --st-none:var(--surface-2); --scrim:rgba(0,0,0,.55); --tint:30%; --shadow-float:0 0 0 1px rgba(255,255,255,.06), 0 12px 32px rgba(0,0,0,.55); --shadow-sheet:0 -12px 40px rgba(0,0,0,.6); color-scheme:dark; }
:root[data-appearance="dark"][data-palette="tideline"]{ --canvas:#141210; --surface:#1D1B1A; --surface-2:#2D2B28; --raised:#252321; --line:#393634; --line-strong:#797572; --ink:#F0EDEB; --ink-soft:#C3C0BD; --muted:#9E9B97; --accent:#75C6C7; --accent-ink:#151D1D; --focus:#75C6C7; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
:root[data-appearance="dark"][data-palette="graphite"]{ --canvas:#0E1014; --surface:#16191E; --surface-2:#242830; --raised:#1D2127; --line:#2E333B; --line-strong:#6E7580; --ink:#ECEEF2; --ink-soft:#BFC4CD; --muted:#959CA7; --accent:#8EAEFF; --accent-ink:#0D1530; --focus:#8EAEFF; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
:root[data-appearance="dark"][data-palette="forest"]{ --canvas:#0F120E; --surface:#171B16; --surface-2:#252A23; --raised:#1E231D; --line:#30372E; --line-strong:#727B6E; --ink:#ECF0E9; --ink-soft:#C1C8BC; --muted:#98A093; --accent:#92CDA3; --accent-ink:#0E1C13; --focus:#92CDA3; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
:root[data-appearance="dark"][data-palette="midnight"]{ --canvas:#0B1020; --surface:#121931; --surface-2:#1E2742; --raised:#18203A; --line:#29334F; --line-strong:#6A7594; --ink:#EEF1F8; --ink-soft:#C3C9D8; --muted:#99A2B8; --accent:#E8BE63; --accent-ink:#1A1405; --focus:#E8BE63; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
:root[data-appearance="dark"][data-palette="ember"]{ --canvas:#151110; --surface:#1E1917; --surface-2:#2E2724; --raised:#26201D; --line:#3B332F; --line-strong:#7D746E; --ink:#F2ECE8; --ink-soft:#C9C0B9; --muted:#A1978F; --accent:#F0A36E; --accent-ink:#231105; --focus:#F0A36E; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
:root[data-appearance="dark"][data-palette="mono"]{ --canvas:#0A0A0A; --surface:#141414; --surface-2:#242424; --raised:#1C1C1C; --line:#2E2E2E; --line-strong:#737373; --ink:#F0F0F0; --ink-soft:#C4C4C4; --muted:#9A9A9A; --accent:#F0F0F0; --accent-ink:#111111; --focus:#F0F0F0; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
@media (prefers-color-scheme: dark){
  :root[data-appearance="auto"], :root:not([data-appearance]){ --st-none:var(--surface-2); --scrim:rgba(0,0,0,.55); --tint:30%; --shadow-float:0 0 0 1px rgba(255,255,255,.06), 0 12px 32px rgba(0,0,0,.55); --shadow-sheet:0 -12px 40px rgba(0,0,0,.6); color-scheme:dark; }
  :root[data-appearance="auto"][data-palette="tideline"]{ --canvas:#141210; --surface:#1D1B1A; --surface-2:#2D2B28; --raised:#252321; --line:#393634; --line-strong:#797572; --ink:#F0EDEB; --ink-soft:#C3C0BD; --muted:#9E9B97; --accent:#75C6C7; --accent-ink:#151D1D; --focus:#75C6C7; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
  :root[data-appearance="auto"][data-palette="graphite"]{ --canvas:#0E1014; --surface:#16191E; --surface-2:#242830; --raised:#1D2127; --line:#2E333B; --line-strong:#6E7580; --ink:#ECEEF2; --ink-soft:#BFC4CD; --muted:#959CA7; --accent:#8EAEFF; --accent-ink:#0D1530; --focus:#8EAEFF; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
  :root[data-appearance="auto"][data-palette="forest"]{ --canvas:#0F120E; --surface:#171B16; --surface-2:#252A23; --raised:#1E231D; --line:#30372E; --line-strong:#727B6E; --ink:#ECF0E9; --ink-soft:#C1C8BC; --muted:#98A093; --accent:#92CDA3; --accent-ink:#0E1C13; --focus:#92CDA3; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
  :root[data-appearance="auto"][data-palette="midnight"]{ --canvas:#0B1020; --surface:#121931; --surface-2:#1E2742; --raised:#18203A; --line:#29334F; --line-strong:#6A7594; --ink:#EEF1F8; --ink-soft:#C3C9D8; --muted:#99A2B8; --accent:#E8BE63; --accent-ink:#1A1405; --focus:#E8BE63; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
  :root[data-appearance="auto"][data-palette="ember"]{ --canvas:#151110; --surface:#1E1917; --surface-2:#2E2724; --raised:#26201D; --line:#3B332F; --line-strong:#7D746E; --ink:#F2ECE8; --ink-soft:#C9C0B9; --muted:#A1978F; --accent:#F0A36E; --accent-ink:#231105; --focus:#F0A36E; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
  :root[data-appearance="auto"][data-palette="mono"]{ --canvas:#0A0A0A; --surface:#141414; --surface-2:#242424; --raised:#1C1C1C; --line:#2E2E2E; --line-strong:#737373; --ink:#F0F0F0; --ink-soft:#C4C4C4; --muted:#9A9A9A; --accent:#F0F0F0; --accent-ink:#111111; --focus:#F0F0F0; --ok:#84BE8A; --warn:#FAA65C; --danger:#ED8279; }
}

/* ---- Day-type swatches: the colours a day type can have (swatches() in days.php), the same in every
   palette. Each has the fill, -on (text and marks on it: at least 4.5:1 on the fill and on the tint),
   -edge (dashes and outlines, visible on the surface), -tint (the second tone of a two-tone box) and,
   where a pale fill needs one in light mode, -ring (its keyline). The first six are the original
   boxes with their validated values; the --st-* names stay as aliases of them for module CSS
   (type_css() points them at the new swatch when a built-in is recoloured). ---- */
:root{
  --sw-work:#5D678B; --sw-work-on:#FFFFFF; --sw-work-edge:#5D678B; --sw-work-tint:#434B6B;
  --sw-off:#6A917E; --sw-off-on:#1F1D1B; --sw-off-edge:#6A917E; --sw-off-tint:#A9C6B7;
  --sw-mixed:#9785AC; --sw-mixed-on:#1F1D1B; --sw-mixed-edge:#9785AC; --sw-mixed-tint:#CFC6D8;
  --sw-vacation:#FFD565; --sw-vacation-on:#1F1D1B; --sw-vacation-edge:#AC8229; --sw-vacation-tint:#FFEDB8; --sw-vacation-ring:#AC8229;
  --sw-travel:#D8925C; --sw-travel-on:#1F1D1B; --sw-travel-edge:#B57140; --sw-travel-tint:#EDC6A6; --sw-travel-ring:#B57140;
  --sw-sick:#815F6A; --sw-sick-on:#FFFFFF; --sw-sick-edge:#815F6A; --sw-sick-tint:#634650;
  --sw-teal:#3E7E7F; --sw-teal-on:#FFFFFF; --sw-teal-edge:#3E7E7F; --sw-teal-tint:#2C6061;
  --sw-sky:#8DB8D6; --sw-sky-on:#1F1D1B; --sw-sky-edge:#4F82A6; --sw-sky-tint:#C8DDEC; --sw-sky-ring:#4F82A6;
  --sw-indigo:#4F5AA0; --sw-indigo-on:#FFFFFF; --sw-indigo-edge:#4F5AA0; --sw-indigo-tint:#3A4380;
  --sw-plum:#8A5A8C; --sw-plum-on:#FFFFFF; --sw-plum-edge:#8A5A8C; --sw-plum-tint:#6B416D;
  --sw-rose:#D7A1B0; --sw-rose-on:#1F1D1B; --sw-rose-edge:#A8697B; --sw-rose-tint:#EDD0D8; --sw-rose-ring:#A8697B;
  --sw-coral:#E4867A; --sw-coral-on:#1F1D1B; --sw-coral-edge:#B5584C; --sw-coral-tint:#F2C3BC; --sw-coral-ring:#B5584C;
  --sw-gold:#D8B04A; --sw-gold-on:#1F1D1B; --sw-gold-edge:#9C7A1E; --sw-gold-tint:#EDD89E; --sw-gold-ring:#9C7A1E;
  --sw-olive:#8A9352; --sw-olive-on:#1F1D1B; --sw-olive-edge:#6F7839; --sw-olive-tint:#C3C99B;
  --sw-sand:#DCC9A8; --sw-sand-on:#1F1D1B; --sw-sand-edge:#9C8660; --sw-sand-tint:#EEE4D2; --sw-sand-ring:#9C8660;
  --sw-slate:#6B7178; --sw-slate-on:#FFFFFF; --sw-slate-edge:#6B7178; --sw-slate-tint:#50555B;
  --st-work:var(--sw-work); --st-work-on:var(--sw-work-on); --st-off:var(--sw-off); --st-off-on:var(--sw-off-on);
  --st-mixed:var(--sw-mixed); --st-mixed-tint:var(--sw-mixed-tint); --st-mixed-on:var(--sw-mixed-on);
  --st-vacation:var(--sw-vacation); --st-vacation-edge:var(--sw-vacation-edge); --st-vacation-on:var(--sw-vacation-on);
  --st-travel:var(--sw-travel); --st-travel-edge:var(--sw-travel-edge); --st-travel-on:var(--sw-travel-on);
  --st-sick:var(--sw-sick); --st-sick-on:var(--sw-sick-on);
}
:root[data-appearance="dark"]{
  --sw-work:#666E90; --sw-work-on:#FFFFFF; --sw-work-edge:#666E90; --sw-work-tint:#4B5273;
  --sw-off:#7D9F8E; --sw-off-on:#1F1D1B; --sw-off-edge:#7D9F8E; --sw-off-tint:#B3CDBF;
  --sw-mixed:#A08FB4; --sw-mixed-on:#1F1D1B; --sw-mixed-edge:#A08FB4; --sw-mixed-tint:#CFC6D8;
  --sw-vacation:#F3D286; --sw-vacation-on:#1F1D1B; --sw-vacation-edge:#F3D286; --sw-vacation-tint:#F9E8BE; --sw-vacation-ring:transparent;
  --sw-travel:#CE8F5E; --sw-travel-on:#1F1D1B; --sw-travel-edge:#CE8F5E; --sw-travel-tint:#E6C3A6; --sw-travel-ring:transparent;
  --sw-sick:#82606B; --sw-sick-on:#FFFFFF; --sw-sick-edge:#82606B; --sw-sick-tint:#664751;
  --sw-teal:#5E9C9C; --sw-teal-on:#1F1D1B; --sw-teal-edge:#5E9C9C; --sw-teal-tint:#A7CFCD;
  --sw-sky:#86B2D0; --sw-sky-on:#1F1D1B; --sw-sky-edge:#86B2D0; --sw-sky-tint:#C3DAEA; --sw-sky-ring:transparent;
  --sw-indigo:#7A83C4; --sw-indigo-on:#1F1D1B; --sw-indigo-edge:#7A83C4; --sw-indigo-tint:#BCC1E6;
  --sw-plum:#A277A4; --sw-plum-on:#1F1D1B; --sw-plum-edge:#A277A4; --sw-plum-tint:#D3BCD4;
  --sw-rose:#CF9AAA; --sw-rose-on:#1F1D1B; --sw-rose-edge:#CF9AAA; --sw-rose-tint:#E9CBD4; --sw-rose-ring:transparent;
  --sw-coral:#DB8C79; --sw-coral-on:#1F1D1B; --sw-coral-edge:#DB8C79; --sw-coral-tint:#EFC4B9; --sw-coral-ring:transparent;
  --sw-gold:#D4AF52; --sw-gold-on:#1F1D1B; --sw-gold-edge:#D4AF52; --sw-gold-tint:#EBD9A6; --sw-gold-ring:transparent;
  --sw-olive:#98A05F; --sw-olive-on:#1F1D1B; --sw-olive-edge:#98A05F; --sw-olive-tint:#CDD2A6;
  --sw-sand:#CDBB9A; --sw-sand-on:#1F1D1B; --sw-sand-edge:#CDBB9A; --sw-sand-tint:#E7DCC8; --sw-sand-ring:transparent;
  --sw-slate:#8F959C; --sw-slate-on:#1F1D1B; --sw-slate-edge:#8F959C; --sw-slate-tint:#C6CACE;
}
@media (prefers-color-scheme: dark){
  :root[data-appearance="auto"], :root:not([data-appearance]){
    --sw-work:#666E90; --sw-work-on:#FFFFFF; --sw-work-edge:#666E90; --sw-work-tint:#4B5273;
    --sw-off:#7D9F8E; --sw-off-on:#1F1D1B; --sw-off-edge:#7D9F8E; --sw-off-tint:#B3CDBF;
    --sw-mixed:#A08FB4; --sw-mixed-on:#1F1D1B; --sw-mixed-edge:#A08FB4; --sw-mixed-tint:#CFC6D8;
    --sw-vacation:#F3D286; --sw-vacation-on:#1F1D1B; --sw-vacation-edge:#F3D286; --sw-vacation-tint:#F9E8BE; --sw-vacation-ring:transparent;
    --sw-travel:#CE8F5E; --sw-travel-on:#1F1D1B; --sw-travel-edge:#CE8F5E; --sw-travel-tint:#E6C3A6; --sw-travel-ring:transparent;
    --sw-sick:#82606B; --sw-sick-on:#FFFFFF; --sw-sick-edge:#82606B; --sw-sick-tint:#664751;
    --sw-teal:#5E9C9C; --sw-teal-on:#1F1D1B; --sw-teal-edge:#5E9C9C; --sw-teal-tint:#A7CFCD;
    --sw-sky:#86B2D0; --sw-sky-on:#1F1D1B; --sw-sky-edge:#86B2D0; --sw-sky-tint:#C3DAEA; --sw-sky-ring:transparent;
    --sw-indigo:#7A83C4; --sw-indigo-on:#1F1D1B; --sw-indigo-edge:#7A83C4; --sw-indigo-tint:#BCC1E6;
    --sw-plum:#A277A4; --sw-plum-on:#1F1D1B; --sw-plum-edge:#A277A4; --sw-plum-tint:#D3BCD4;
    --sw-rose:#CF9AAA; --sw-rose-on:#1F1D1B; --sw-rose-edge:#CF9AAA; --sw-rose-tint:#E9CBD4; --sw-rose-ring:transparent;
    --sw-coral:#DB8C79; --sw-coral-on:#1F1D1B; --sw-coral-edge:#DB8C79; --sw-coral-tint:#EFC4B9; --sw-coral-ring:transparent;
    --sw-gold:#D4AF52; --sw-gold-on:#1F1D1B; --sw-gold-edge:#D4AF52; --sw-gold-tint:#EBD9A6; --sw-gold-ring:transparent;
    --sw-olive:#98A05F; --sw-olive-on:#1F1D1B; --sw-olive-edge:#98A05F; --sw-olive-tint:#CDD2A6;
    --sw-sand:#CDBB9A; --sw-sand-on:#1F1D1B; --sw-sand-edge:#CDBB9A; --sw-sand-tint:#E7DCC8; --sw-sand-ring:transparent;
    --sw-slate:#8F959C; --sw-slate-on:#1F1D1B; --sw-slate-edge:#8F959C; --sw-slate-tint:#C6CACE;
  }
}

:root{
  /* Fonts — all built into Apple devices, nothing downloaded */
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --display: -apple-system, BlinkMacSystemFont, "SF Pro Display", system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --rounded: ui-rounded, "SF Pro Rounded", -apple-system, system-ui, sans-serif;
  --serif: ui-serif, "New York", "Iowan Old Style", Charter, Georgia, serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* Spacing (4pt base) */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-8:32px; --sp-10:40px; --sp-12:48px;
  --r-xs:4px; --r-sm:8px; --r-md:12px; --r-lg:16px; --r-xl:22px; --r-pill:999px;
  --touch:44px;

  /* Layout */
  --sidebar-w:232px;
  --content-max:1080px;
  --tabbar-h:56px;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);

  --ease: cubic-bezier(.2,.8,.2,1);
  --z-tabbar:40; --z-fab:45; --z-sheet:60; --z-toast:80;
}

/* ---------- Base ---------- */
*,*::before,*::after{box-sizing:border-box}
[hidden]{display:none !important}
html{-webkit-text-size-adjust:100%; text-size-adjust:100%; font-size:100%; background:var(--canvas)}
/* Honour the iPhone/iPad text-size setting (Dynamic Type) */
@supports (font: -apple-system-body) and (-webkit-touch-callout: none){
  html{font: -apple-system-body}
}
body{
  margin:0; min-height:100vh; min-height:100dvh;
  background:var(--canvas); color:var(--ink);
  font-family:var(--sans); font-size:1rem; line-height:1.45;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  -webkit-tap-highlight-color:transparent;
}
h1,h2,h3,h4{margin:0; line-height:1.2; letter-spacing:-.01em; text-wrap:balance; font-family:var(--display)}
p{margin:0}
ul,ol{margin:0; padding:0}
a{color:var(--accent); text-underline-offset:2px}
img{max-width:100%; display:block}
button,input,select,textarea{font:inherit; color:inherit}
button{cursor:pointer}
:focus-visible{outline:2px solid var(--focus); outline-offset:2px; border-radius:6px}
::selection{background:color-mix(in oklab, var(--accent) 28%, transparent)}
svg.i{width:20px; height:20px; flex:none; stroke:currentColor; fill:none; stroke-width:1.75; stroke-linecap:round; stroke-linejoin:round; vertical-align:middle}
svg.i.sm{width:16px; height:16px}
svg.i.lg{width:24px; height:24px}

/* Type scale (rem = your text size; 17px at the default iOS setting) */
.t-display{font:600 2.6rem/1.05 var(--rounded); letter-spacing:-.02em}
.t-large{font:700 2rem/1.15 var(--display); letter-spacing:-.02em}
.t-title{font:700 1.35rem/1.25 var(--display)}
.t-head{font:600 1.05rem/1.3 var(--display)}
.t-body{font-size:1rem}
.t-sub{font-size:.9rem}
.t-foot{font-size:.8rem}
.eyebrow{font:600 .72rem/1.3 var(--rounded); letter-spacing:.07em; text-transform:uppercase; color:var(--muted)}
.muted{color:var(--muted)}
.soft{color:var(--ink-soft)}
.small{font-size:.86rem; line-height:1.45}
.num{font-family:var(--rounded); font-variant-numeric:tabular-nums}
.serif{font-family:var(--serif)}
.center{text-align:center}
.sr-only{position:absolute !important; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0}
/* "Skip to content" shows itself when a keyboard reaches it (!important beats .sr-only) */
.skip:focus{position:fixed !important; top:calc(var(--safe-top) + 8px); left:calc(var(--safe-left) + 8px); width:auto; height:auto; margin:0; clip:auto; overflow:visible; padding:10px 14px; background:var(--raised); color:var(--ink); font-weight:600; text-decoration:none; border-radius:10px; box-shadow:var(--shadow-float); z-index:calc(var(--z-toast) + 1)}
.nowrap{white-space:nowrap}

/* ---------- App shell ---------- */
.shell{min-height:100vh; min-height:100dvh}
.main{min-width:0; padding-bottom:calc(var(--tabbar-h) + var(--safe-bottom) + 28px)}
.topbar{
  position:sticky; top:0; z-index:30;
  padding:calc(var(--safe-top) + 10px) calc(var(--sp-4) + var(--safe-right)) 10px calc(var(--sp-4) + var(--safe-left));
  background:color-mix(in oklab, var(--canvas) 86%, transparent);
  -webkit-backdrop-filter:saturate(170%) blur(18px); backdrop-filter:saturate(170%) blur(18px);
  display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3);
  border-bottom:1px solid transparent; transition:border-color .2s;
}
.topbar.scrolled{border-bottom-color:var(--line)}
@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){ .topbar{background:var(--canvas)} }
.topbar h1{font:700 1.6rem/1.15 var(--display); letter-spacing:-.02em}
.topbar .sub{display:block; font:600 .72rem/1.3 var(--rounded); letter-spacing:.07em; text-transform:uppercase; color:var(--muted); margin-bottom:2px}
.topbar-actions{display:flex; align-items:center; gap:var(--sp-2)}
.page{padding:var(--sp-2) calc(var(--sp-4) + var(--safe-right)) var(--sp-6) calc(var(--sp-4) + var(--safe-left)); max-width:var(--content-max); margin:0 auto; display:grid; gap:var(--sp-5)}
.page.narrow{max-width:720px}

/* Phone tab bar */
.tabbar{
  position:fixed; left:0; right:0; bottom:0; z-index:var(--z-tabbar);
  display:grid; grid-template-columns:repeat(5,1fr);
  padding:6px calc(6px + var(--safe-right)) calc(6px + var(--safe-bottom)) calc(6px + var(--safe-left));
  background:color-mix(in oklab, var(--surface) 88%, transparent);
  -webkit-backdrop-filter:saturate(170%) blur(18px); backdrop-filter:saturate(170%) blur(18px);
  border-top:1px solid var(--line);
}
@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){ .tabbar{background:var(--surface)} }
.tabbar a{display:grid; justify-items:center; gap:3px; padding:5px 2px 3px; min-height:var(--touch); color:var(--muted); text-decoration:none; font:600 .68rem/1.1 var(--rounded); border-radius:10px; touch-action:manipulation}
.tabbar a svg.i{width:23px; height:23px}
.tabbar a[aria-current="page"]{color:var(--accent)}
.fab{
  position:fixed; z-index:var(--z-fab);
  right:calc(16px + var(--safe-right)); bottom:calc(var(--tabbar-h) + var(--safe-bottom) + 16px);
  width:56px; height:56px; border-radius:50%; border:0;
  background:var(--accent); color:var(--accent-ink);
  display:grid; place-items:center; box-shadow:var(--shadow-float); touch-action:manipulation;
}
.fab svg.i{width:26px; height:26px; stroke-width:2.2}
.fab:active{transform:scale(.96)}
body.painting .fab{display:none}

/* Sidebar (iPad and Mac) */
.sidebar{display:none}
@media (min-width:700px){
  .shell{display:grid; grid-template-columns:var(--sidebar-w) minmax(0,1fr)}
  .sidebar{
    display:flex; flex-direction:column; gap:var(--sp-1);
    position:sticky; top:0; height:100vh; height:100dvh; overflow:auto;
    padding:calc(var(--safe-top) + 22px) 14px calc(var(--safe-bottom) + 18px) calc(14px + var(--safe-left));
    border-right:1px solid var(--line); background:var(--canvas);
  }
  .sidebar .brand{display:flex; align-items:center; gap:10px; padding:4px 10px 18px; font:650 1.02rem/1.2 var(--display); color:var(--ink); text-decoration:none}
  .sidebar .brand .brand-mark{width:30px; height:30px}
  .sidebar nav{display:grid; gap:2px}
  .sidebar a.nav{display:flex; align-items:center; gap:12px; min-height:42px; padding:0 12px; border-radius:10px; color:var(--ink-soft); text-decoration:none; font-weight:550; font-size:.95rem}
  .sidebar a.nav:hover{background:var(--surface-2); color:var(--ink)}
  .sidebar a.nav[aria-current="page"]{background:color-mix(in oklab, var(--accent) 13%, var(--canvas)); color:var(--ink)}
  .sidebar a.nav[aria-current="page"] svg.i{color:var(--accent)}
  .sidebar .grow{flex:1}
  .sidebar .add{margin:14px 4px 6px}
  .tabbar,.fab{display:none}
  .main{padding-bottom:40px}
  .topbar{padding-left:calc(var(--sp-8)); padding-right:calc(var(--sp-8) + var(--safe-right))}
  .topbar h1{font-size:1.85rem}
  .page{padding-left:var(--sp-8); padding-right:calc(var(--sp-8) + var(--safe-right))}
}

/* ---------- Layout helpers ---------- */
.stack{display:grid; gap:var(--sp-3)}
.stack-lg{display:grid; gap:var(--sp-5)}
.row{display:flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap}
.row.between{justify-content:space-between}
.row.nowrap{flex-wrap:nowrap}
.spacer{flex:1}
.grid-2{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--sp-4)}
.grid-auto{display:grid; grid-template-columns:repeat(auto-fill, minmax(260px,1fr)); gap:var(--sp-4)}
@media (max-width:699px){ .grid-2{grid-template-columns:1fr} }
.section{display:grid; gap:var(--sp-3)}
.section-head{display:flex; align-items:baseline; justify-content:space-between; gap:var(--sp-3)}
.section-head h2{font:650 1.12rem/1.25 var(--display)}
.section-head a, .section-head button.link{font-size:.9rem; display:inline-flex; align-items:center; gap:4px; min-height:34px; padding:0 6px; margin:-7px -6px}

/* ---------- Surfaces ---------- */
.card{background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg); padding:var(--sp-4)}
.card.pad-lg{padding:var(--sp-5)}
.card.tight{padding:var(--sp-3)}
.card.inset{background:var(--surface-2); border-color:transparent}
.card-head{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3); margin-bottom:var(--sp-3)}
.list{background:var(--surface); border:1px solid var(--line); border-radius:var(--r-lg); overflow:hidden}
.list-row{display:flex; align-items:center; gap:var(--sp-3); min-height:52px; padding:10px var(--sp-4); border-bottom:1px solid var(--line); color:var(--ink); text-decoration:none; background:none; border-left:0; border-right:0; border-top:0; width:100%; text-align:left}
.list-row:last-child{border-bottom:0}
a.list-row:hover, button.list-row:hover{background:color-mix(in oklab, var(--surface-2) 55%, var(--surface))}
.list-row .grow{flex:1; min-width:0}
.list-row .title{font-weight:560}
.list-row .meta{font-size:.84rem; color:var(--muted)}
.list-row .end{color:var(--muted); font-size:.9rem; display:flex; align-items:center; gap:6px}
.kv{display:flex; justify-content:space-between; gap:var(--sp-3); font-size:.95rem; padding:3px 0}
.kv > span:last-child{color:var(--ink-soft); text-align:right}
.divider{height:1px; background:var(--line); border:0; margin:var(--sp-2) 0}

/* ---------- Buttons ---------- */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  min-height:var(--touch); padding:0 16px; border-radius:var(--r-md);
  border:1px solid var(--line-strong); background:var(--surface); color:var(--ink);
  font:600 .95rem/1 var(--sans); text-decoration:none; white-space:nowrap; touch-action:manipulation;
  transition:background .15s, transform .08s;
}
.btn:hover{background:var(--surface-2)}
.btn:active{transform:scale(.985)}
.btn[disabled], .btn[aria-disabled="true"]{opacity:.5; pointer-events:none}
.btn-primary{background:var(--accent); color:var(--accent-ink); border-color:var(--accent)}
.btn-primary:hover{background:color-mix(in oklab, var(--accent) 88%, var(--ink))}
.btn-ghost{background:transparent; border-color:transparent; color:var(--accent)}
.btn-ghost:hover{background:color-mix(in oklab, var(--accent) 10%, transparent)}
.btn-danger{color:var(--danger); border-color:color-mix(in oklab, var(--danger) 45%, var(--line))}
.btn-danger.solid{background:var(--danger); color:var(--canvas); border-color:var(--danger)}
.btn-sm{min-height:34px; padding:0 12px; font-size:.86rem; border-radius:10px}
.btn-block{width:100%}
.btn-icon{width:var(--touch); padding:0; border-color:transparent; background:transparent; color:var(--ink-soft)}
.btn-icon:hover{background:var(--surface-2); color:var(--ink)}
.btn-icon.sm{width:36px; min-height:36px}
button.link{background:none; border:0; padding:0; color:var(--accent); font-weight:600}

/* ---------- Forms ---------- */
.field{display:grid; gap:6px}
.field > label, .label{font-weight:600; font-size:.9rem; color:var(--ink)}
.hint{font-size:.82rem; color:var(--muted)}
.input, .field input[type=text], .field input[type=email], .field input[type=password], .field input[type=number],
.field input[type=date], .field input[type=time], .field input[type=url], .field select, .field textarea{
  width:100%; min-height:var(--touch); padding:10px 12px;
  font-size:max(16px, 1rem); /* 16px+ stops iOS zooming into the field */
  background:var(--surface); color:var(--ink);
  border:1px solid var(--line-strong); border-radius:var(--r-sm);
  -webkit-appearance:none; appearance:none;
}
.field textarea{min-height:96px; resize:vertical; line-height:1.45}
.field select{background-image:linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%); background-position:calc(100% - 18px) 50%, calc(100% - 13px) 50%; background-size:5px 5px; background-repeat:no-repeat; padding-right:34px}
.field input:focus, .field select:focus, .field textarea:focus, .input:focus{outline:2px solid var(--focus); outline-offset:0; border-color:transparent}
input[type=date], input[type=time]{min-height:var(--touch)}
.field-row{display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:var(--sp-3)}
.form-actions{display:flex; gap:var(--sp-2); justify-content:flex-end; flex-wrap:wrap}
.error-text{color:var(--danger); font-size:.88rem}

/* Switch (a checkbox) */
.switch{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3); min-height:var(--touch); cursor:pointer}
.switch input{position:absolute; opacity:0; width:1px; height:1px}
.switch .track{flex:none; width:51px; height:31px; border-radius:31px; background:var(--surface-2); border:1px solid var(--line-strong); position:relative; transition:background .2s}
.switch .track::after{content:""; position:absolute; top:2px; left:2px; width:25px; height:25px; border-radius:50%; background:#fff; box-shadow:0 1px 3px rgba(0,0,0,.25); transition:transform .2s var(--ease)}
.switch input:checked + .track{background:var(--accent); border-color:var(--accent)}
.switch input:checked + .track::after{transform:translateX(20px)}
.switch input:focus-visible + .track{outline:2px solid var(--focus); outline-offset:2px}
.switch .txt{display:grid; gap:2px}
.switch .txt small{color:var(--muted); font-size:.82rem}

/* Segmented control (radio group) */
.seg{display:inline-flex; background:var(--surface-2); border-radius:10px; padding:3px; gap:2px; max-width:100%; overflow-x:auto}
.seg input{position:absolute; opacity:0; width:1px; height:1px}
.seg label{min-height:32px; padding:0 14px; display:flex; align-items:center; justify-content:center; border-radius:8px; font:600 .86rem/1 var(--sans); color:var(--ink-soft); cursor:pointer; white-space:nowrap}
.seg input:checked + label, .seg button[aria-pressed="true"]{background:var(--raised); color:var(--ink); box-shadow:0 1px 2px rgba(0,0,0,.08), 0 0 0 1px var(--line)}
.seg input:focus-visible + label{outline:2px solid var(--focus)}
.seg button{border:0; background:none; min-height:32px; padding:0 14px; border-radius:8px; font:600 .86rem/1 var(--sans); color:var(--ink-soft)}

/* Chips */
.chips{display:flex; gap:var(--sp-2); flex-wrap:wrap}
.chips.scroll{flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none; -webkit-overflow-scrolling:touch; margin:0 calc(-1 * var(--sp-4)); padding:0 var(--sp-4)}
.chips.scroll::-webkit-scrollbar{display:none}
@media (min-width:700px){ .chips.scroll{margin-left:calc(-1 * var(--sp-8)); margin-right:calc(-1 * (var(--sp-8) + var(--safe-right))); padding-left:var(--sp-8); padding-right:calc(var(--sp-8) + var(--safe-right))} }
.chip{display:inline-flex; align-items:center; gap:6px; min-height:34px; padding:0 13px; border-radius:var(--r-pill); border:1px solid var(--line-strong); background:var(--surface); color:var(--ink-soft); font:600 .84rem/1 var(--rounded); white-space:nowrap; text-decoration:none; touch-action:manipulation}
.chip[aria-pressed="true"], .chip.on{background:var(--ink); color:var(--canvas); border-color:var(--ink)}
.chip.soft{border-color:transparent; background:var(--surface-2)}

/* ---------- Day types (the colour boxes) ----------
   Any element with data-s="<type key>" gets, from its day type:
     --c          the fill colour                --on    text and marks on it
     --edge       dashes and outlines (tentative), visible on the surface
     --ring       the keyline a pale fill needs in light mode (transparent otherwise)
     --c2         the second tone (the tint of a two-tone box)
     --fill       what a box is painted with: var(--c), or for a two-tone type (Mixed, by default)
                  the half-and-half linear-gradient(var(--tt-dir, 45deg), var(--c2) 50%, var(--c) 50%)
     --fill-soft  the tentative version (24% of the colour on the surface; two-tone: both halves soft)
   Paint every box, swatch, strip, bar and chart key with background:var(--fill) (tentative:
   var(--fill-soft)), keylines with var(--ring), dashes with var(--edge), and never special-case a
   key: the six built-ins are set here, and type_css() (layout.php) prints the rule for a recoloured,
   two-tone or added type. [data-sw="<swatch>"] does the same for a colour alone (the Settings
   preview; data-two="1" makes it two-tone).
   A status swatch: <span class="st" data-s="work"></span> (status_swatch()). */
.st{display:inline-block; width:14px; height:14px; border-radius:4px; background:var(--st-none); flex:none; position:relative; vertical-align:middle}
[data-s], [data-sw]{--c2:var(--c); --ring:transparent; --fill:var(--c); --fill-soft:color-mix(in oklab, var(--c) 24%, var(--surface))}
[data-s="work"], [data-sw="work"]{--c:var(--sw-work); --on:var(--sw-work-on); --edge:var(--sw-work-edge); --c2:var(--sw-work-tint)}
[data-s="off"], [data-sw="off"]{--c:var(--sw-off); --on:var(--sw-off-on); --edge:var(--sw-off-edge); --c2:var(--sw-off-tint)}
[data-s="mixed"], [data-sw="mixed"]{--c:var(--sw-mixed); --on:var(--sw-mixed-on); --edge:var(--sw-mixed-edge); --c2:var(--sw-mixed-tint)}
[data-s="vacation"], [data-sw="vacation"]{--c:var(--sw-vacation); --on:var(--sw-vacation-on); --edge:var(--sw-vacation-edge); --c2:var(--sw-vacation-tint); --ring:var(--sw-vacation-ring)}
[data-s="travel"], [data-sw="travel"]{--c:var(--sw-travel); --on:var(--sw-travel-on); --edge:var(--sw-travel-edge); --c2:var(--sw-travel-tint); --ring:var(--sw-travel-ring)}
[data-s="sick"], [data-sw="sick"]{--c:var(--sw-sick); --on:var(--sw-sick-on); --edge:var(--sw-sick-edge); --c2:var(--sw-sick-tint)}
[data-sw="teal"]{--c:var(--sw-teal); --on:var(--sw-teal-on); --edge:var(--sw-teal-edge); --c2:var(--sw-teal-tint)}
[data-sw="sky"]{--c:var(--sw-sky); --on:var(--sw-sky-on); --edge:var(--sw-sky-edge); --c2:var(--sw-sky-tint); --ring:var(--sw-sky-ring)}
[data-sw="indigo"]{--c:var(--sw-indigo); --on:var(--sw-indigo-on); --edge:var(--sw-indigo-edge); --c2:var(--sw-indigo-tint)}
[data-sw="plum"]{--c:var(--sw-plum); --on:var(--sw-plum-on); --edge:var(--sw-plum-edge); --c2:var(--sw-plum-tint)}
[data-sw="rose"]{--c:var(--sw-rose); --on:var(--sw-rose-on); --edge:var(--sw-rose-edge); --c2:var(--sw-rose-tint); --ring:var(--sw-rose-ring)}
[data-sw="coral"]{--c:var(--sw-coral); --on:var(--sw-coral-on); --edge:var(--sw-coral-edge); --c2:var(--sw-coral-tint); --ring:var(--sw-coral-ring)}
[data-sw="gold"]{--c:var(--sw-gold); --on:var(--sw-gold-on); --edge:var(--sw-gold-edge); --c2:var(--sw-gold-tint); --ring:var(--sw-gold-ring)}
[data-sw="olive"]{--c:var(--sw-olive); --on:var(--sw-olive-on); --edge:var(--sw-olive-edge); --c2:var(--sw-olive-tint)}
[data-sw="sand"]{--c:var(--sw-sand); --on:var(--sw-sand-on); --edge:var(--sw-sand-edge); --c2:var(--sw-sand-tint); --ring:var(--sw-sand-ring)}
[data-sw="slate"]{--c:var(--sw-slate); --on:var(--sw-slate-on); --edge:var(--sw-slate-edge); --c2:var(--sw-slate-tint)}
/* Two-tone: Mixed by default, and a swatch preview with data-two="1" (a changed type gets its own rule from type_css()).
   The split runs at --tt-dir (default 45deg); boxes that aren't square set it on their container, e.g.
   .cal{--tt-dir:to bottom right} for a corner-to-corner split, and every two-tone type follows. */
[data-s="mixed"], [data-sw][data-two="1"]{--fill:linear-gradient(var(--tt-dir, 45deg), var(--c2) 50%, var(--c) 50%); --fill-soft:linear-gradient(var(--tt-dir, 45deg), color-mix(in oklab, var(--c2) 45%, var(--surface)) 50%, color-mix(in oklab, var(--c) 32%, var(--surface)) 50%)}
[data-s="none"], [data-s=""]{--c:var(--st-none); --on:var(--ink); --edge:var(--st-none); --c2:var(--st-none)}
.st[data-s], .st[data-sw]{background:var(--fill); box-shadow:inset 0 0 0 1px var(--ring)}

/* Tinted status chip: <span class="stchip" data-s="work">Work day</span> (status_chip()) */
.stchip{display:inline-flex; align-items:center; gap:8px; min-height:34px; padding:0 13px 0 10px; border-radius:var(--r-pill); background:color-mix(in oklab, var(--c, var(--st-none)) var(--tint), var(--surface)); color:var(--ink); font:650 .92rem/1 var(--rounded); border:0; white-space:nowrap; transition:background-color .18s var(--ease)}
.stchip::before{content:""; flex:none; width:12px; height:12px; border-radius:4px; background:var(--fill, var(--st-none)); box-shadow:inset 0 0 0 1px var(--ring, transparent)}
.stchip[data-s="none"]::before, .stchip[data-s=""]::before{background:transparent; box-shadow:inset 0 0 0 1.5px var(--line-strong)}
.stchip.lg{min-height:44px; padding:0 18px 0 14px; font-size:1.05rem}
.stchip.lg::before{width:16px; height:16px; border-radius:5px}
.stchip.tentative{background:var(--surface); box-shadow:none; outline:1.5px dashed var(--edge, var(--c, var(--line-strong))); outline-offset:-1.5px} /* dashed only: a solid inset ring would hide the dash */
.stchip .sub-name{margin-left:-3px; overflow:hidden; text-overflow:ellipsis}

/* The big status picker (day sheet, paint palette) */
.status-picker{display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:var(--sp-2)}
@media (min-width:520px){ .status-picker.wide{grid-template-columns:repeat(6, minmax(0,1fr))} }
.status-picker button{
  display:grid; justify-items:center; gap:6px; padding:12px 6px 10px; min-height:64px;
  border-radius:var(--r-md); border:1.5px solid var(--line); background:var(--surface); color:var(--ink);
  font:650 .86rem/1.1 var(--rounded); touch-action:manipulation;
  transition:background-color .18s var(--ease), border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.status-picker button .st{width:24px; height:24px; border-radius:7px}
.status-picker button[aria-pressed="true"]{border-color:var(--ink); box-shadow:inset 0 0 0 1px var(--ink); background:color-mix(in oklab, var(--c) var(--tint), var(--surface))}
.status-picker button .def{font:500 .7rem/1.25 var(--sans); color:var(--muted); text-align:center}

/* Legend */
.legend{display:flex; flex-wrap:wrap; gap:6px 14px; font-size:.82rem; color:var(--ink-soft)}
.legend span{display:inline-flex; align-items:center; gap:6px}
.legend .st{width:12px; height:12px; border-radius:3px}

/* ---------- Day subtitles: the owner's categories, inside the colour box ----------
   .day-sub       the subtitle inside a colour box (month tiles, the This-week strip): one line in
                  the box's own text colour, ellipsis; the short text (.ds-s) on iPhone, the full
                  name (.ds-f) on iPad.                             day_sub() · Life.daySub()
   .sub-chips     the one-row subtitle picker (day sheet, paint bar, Settings → Your week), made of
   .sub-chip      toggle chips (aria-pressed); .sub-edit is its "Edit subtitles…" link.
                                                                    label_chips() · Life.labelChips()
   .sub-name      a subtitle after a status in text: "Work day · CEO / Growth" (status_line(), status_chip 'sub')
   .sub-break     a breakdown under a count: "Tattoo 9 · CEO / Growth 3" (label_counts_line())
   svg.mark-bday  a birthday (cake) or anniversary (heart) on a tile, in the tile's text colour. */
.day-sub{display:block; max-width:100%; min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; font:650 .58rem/1.2 var(--rounded); letter-spacing:-.015em; color:inherit}
.day-sub .ds-f{display:none}
/* In a tile it sits under the number and may use 4px of the tile's right padding. */
.cell .day-sub{position:relative; z-index:1; flex:none; line-height:1.15; max-width:calc(100% + 4px); margin:1px -4px auto 0; opacity:.94} /* flex:none: never squeezed (descenders stay whole) */
.sub-chips{display:flex; gap:var(--sp-2); overflow-x:auto; scrollbar-width:none; -webkit-overflow-scrolling:touch; overscroll-behavior-x:contain; padding:1px; margin:-1px}
.sub-chips::-webkit-scrollbar{display:none}
.sub-chip{flex:none; min-height:var(--touch); padding:0 14px; font-size:.9rem; transition:background-color .15s var(--ease), color .15s var(--ease), border-color .15s var(--ease)}
.sub-chip .st{width:10px; height:10px; border-radius:3px}
.sub-chip[aria-pressed="true"] .st{box-shadow:0 0 0 1.5px var(--canvas)}
.sub-chip.sub-edit{border-style:dashed; color:var(--accent); background:transparent}
.sub-name{font-weight:500; color:var(--ink-soft)}
.sub-break{font-size:.84rem; line-height:1.4; color:var(--muted)}
svg.i.mark-bday{width:11px; height:11px; stroke-width:2.1}
@media (min-width:700px){
  /* iPad: the full name, on up to two lines (a long single word hyphenates, then an ellipsis) */
  .day-sub{font-size:.62rem; line-height:1.12; white-space:normal; display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; -webkit-hyphens:auto; hyphens:auto}
  .day-sub .ds-s{display:none}
  .day-sub .ds-f{display:inline}
  .sub-chips{flex-wrap:wrap; overflow:visible}
  svg.i.mark-bday{width:13px; height:13px; stroke-width:2}
}

/* ---------- Month grid ---------- */
.month{display:grid; gap:var(--sp-2)}
.month-head{display:grid; grid-template-columns:repeat(7, minmax(0,1fr)); gap:4px; font:600 .72rem/1 var(--rounded); letter-spacing:.05em; text-transform:uppercase; color:var(--muted); text-align:center}
.month-head .rest{color:var(--accent)}
.month-grid{display:grid; grid-template-columns:repeat(7, minmax(0,1fr)); gap:4px}
.cell{
  position:relative; aspect-ratio:1/1.08; min-height:46px; border-radius:11px;
  background:var(--surface); border:1px solid var(--line); color:var(--ink);
  display:flex; flex-direction:column; justify-content:space-between; padding:5px 6px; overflow:hidden;
  text-align:left; touch-action:manipulation; -webkit-user-select:none; user-select:none;
}
.cell.pad{visibility:hidden}
.cell .n{position:relative; z-index:1; font:650 .86rem/1 var(--rounded); font-variant-numeric:tabular-nums}
.cell .fill{position:absolute; inset:0; border-radius:inherit; background:var(--fill); box-shadow:inset 0 0 0 1px var(--ring, transparent); transition:background-color .18s var(--ease), box-shadow .18s var(--ease)}
.cell[data-s]:not([data-s="none"]):not([data-s=""]){border-color:transparent; color:var(--on)}
.cell .marks{position:relative; z-index:1; display:flex; gap:3px; align-items:center; min-height:10px}
.cell .dot{width:6px; height:6px; border-radius:50%; background:currentColor; opacity:.9}
.cell .ev{font:700 .62rem/1 var(--rounded); padding:2px 4px; border-radius:5px; background:color-mix(in oklab, currentColor 16%, transparent)}
.cell .hol{position:relative; z-index:1; font:600 .56rem/1.1 var(--rounded); opacity:.85; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
/* Tentative: its status colour at 24% inside a 2px dashed outline in the status's edge colour */
.cell.tentative, .cell.tentative[data-s]:not([data-s="none"]):not([data-s=""]){color:var(--ink); outline:none}
.cell.tentative .fill{background:var(--fill-soft); box-shadow:none; border:2px dashed var(--edge, var(--c)); border-radius:inherit}
.cell.tentative[data-s="none"] .fill, .cell.tentative[data-s=""] .fill{background:var(--st-none); border-color:var(--line-strong)}
.cell.protected::after{content:""; position:absolute; top:5px; right:5px; width:9px; height:10px; background:currentColor; opacity:.85; -webkit-mask:url('../icons/shield.svg') center/contain no-repeat; mask:url('../icons/shield.svg') center/contain no-repeat}
.cell.today{box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--focus)}
.cell.selected{box-shadow:inset 0 0 0 2px var(--surface), inset 0 0 0 4px var(--focus)}
.cell.selected::before{content:"✓"; position:absolute; right:6px; bottom:4px; z-index:2; font:800 .8rem/1 var(--sans); color:var(--on, var(--ink))}
.cell.other{opacity:.35}
.cell .studio{position:relative; z-index:1; display:inline-flex; align-items:center; gap:2px; font:700 .6rem/1 var(--rounded)}
@media (min-width:700px){ .cell{min-height:64px; padding:7px 8px} .cell .n{font-size:.95rem} }

/* ---------- Year (mini-months) ---------- */
.year{--c-size:13px; --g:2px; display:grid; grid-template-columns:repeat(auto-fill, calc(7 * var(--c-size) + 6 * var(--g))); gap:16px 18px; justify-content:space-between}
.year.lg{--c-size:18px}
@media (min-width:700px){ .year{--c-size:22px; --g:3px; gap:22px 26px} }
@media (min-width:1100px){ .year{--c-size:26px} }
.mm{display:grid; gap:6px; text-decoration:none; color:inherit; border-radius:10px}
.mm-h{font:650 .78rem/1 var(--rounded); color:var(--ink-soft)}
.mm-h .cnt{font-weight:500; color:var(--muted); margin-left:4px}
.mm-g{display:grid; grid-template-columns:repeat(7, var(--c-size)); grid-auto-rows:var(--c-size); gap:var(--g)}
.d{position:relative; display:block; border-radius:24%; background:var(--st-none)}
.d.pad{background:transparent}
.d[data-s]:not([data-s="none"]){background:var(--fill); box-shadow:inset 0 0 0 1px var(--ring, transparent)}
.d.mem::after{content:""; position:absolute; inset:0; margin:auto; width:32%; height:32%; min-width:3px; min-height:3px; border-radius:50%; background:var(--on, var(--ink))}
.d.tentative{background:var(--surface) !important; box-shadow:none !important; outline:1.5px dashed var(--edge, var(--c)); outline-offset:-1.5px}
.d.today{outline:2px solid var(--focus); outline-offset:1px; z-index:1}
/* A tentative today keeps its dashed status outline; the today ring moves to a shadow outside it. */
.d.today.tentative{outline:1.5px dashed var(--edge, var(--c)); outline-offset:-1.5px; box-shadow:0 0 0 1.5px var(--surface), 0 0 0 3.5px var(--focus) !important}
.d.trip-start, .d.trip-end{}

/* ---------- Sheets (bottom sheet on phone, dialog on iPad/Mac) ---------- */
/* Closed sheets stay rendered but hidden (display:none would stop them sliding). Hiding waits
   until the slide-out has finished; hidden sheets are out of the tab order and out of reach. */
.sheet-host{position:fixed; inset:0; z-index:var(--z-sheet); visibility:hidden; pointer-events:none; transition:visibility 0s linear .24s}
.sheet-host.open{visibility:visible; pointer-events:auto; transition-delay:0s}
.backdrop{position:absolute; inset:0; background:var(--scrim); opacity:0; transition:opacity .22s}
.sheet-host.open .backdrop{opacity:1}
.sheet{
  /* --kb (app.js) is the iPhone keyboard's height: the open sheet is lifted above it and made that much
     shorter, so Save stays in view. The lift is a transform, so nothing is laid out again while it moves. */
  position:absolute; left:0; right:0; bottom:0; max-height:calc(100dvh - var(--safe-top) - 24px - var(--kb, 0px));
  background:var(--raised); color:var(--ink); border-radius:var(--r-xl) var(--r-xl) 0 0;
  display:flex; flex-direction:column; transform:translateY(100%); transition:transform .24s var(--ease);
  box-shadow:var(--shadow-sheet); overscroll-behavior:contain;
}
.sheet-host.open .sheet{transform:translateY(calc(-1 * var(--kb, 0px)))}
@media (max-width:699px){ .sheet-host .sheet{bottom:0 !important} } /* a page's own bottom:var(--kb) would lift it twice */
.sheet .grabber{width:38px; height:5px; border-radius:5px; background:var(--line-strong); opacity:.6; margin:8px auto 0}
.sheet-head{display:flex; align-items:center; gap:var(--sp-3); padding:12px var(--sp-4) 8px}
.sheet-head h2{flex:1; font:700 1.2rem/1.25 var(--display)}
.sheet-head .sub{display:block; font:600 .72rem/1.3 var(--rounded); letter-spacing:.07em; text-transform:uppercase; color:var(--muted)}
.sheet-body{padding:6px var(--sp-4) var(--sp-4); overflow:auto; -webkit-overflow-scrolling:touch; display:grid; gap:var(--sp-4)}
.sheet-body:last-child{padding-bottom:calc(var(--sp-4) + var(--safe-bottom))} /* no footer: keep clear of the home indicator */
.sheet-foot{padding:10px var(--sp-4) calc(10px + var(--safe-bottom)); border-top:1px solid var(--line); display:flex; gap:var(--sp-2); justify-content:flex-end; background:var(--raised)}
@media (min-width:700px){
  .sheet{left:50%; right:auto; bottom:auto; top:50%; width:min(560px, calc(100vw - 48px)); max-height:min(86dvh, 820px); border-radius:var(--r-xl); transform:translate(-50%, -46%) scale(.98); opacity:0; transition:transform .22s var(--ease), opacity .18s}
  .sheet-host.open .sheet{transform:translate(-50%, -50%); opacity:1}
  .sheet .grabber{display:none}
  .sheet-head{padding-top:18px}
  .sheet-foot{padding-bottom:12px; border-radius:0 0 var(--r-xl) var(--r-xl)}
  .sheet-body:last-child{padding-bottom:var(--sp-4)}
  .sheet.wide{width:min(760px, calc(100vw - 48px))}
}
body.locked{overflow:hidden}

/* ---------- Toasts ---------- */
.toast-host{position:fixed; left:0; right:0; z-index:var(--z-toast); bottom:calc(var(--tabbar-h) + var(--safe-bottom) + 12px); display:grid; justify-items:center; gap:8px; pointer-events:none; padding:0 16px}
@media (min-width:700px){ .toast-host{bottom:24px; left:var(--sidebar-w)} }
/* iPhone pages with the + button: toasts sit above it, so + stays tappable while Undo shows */
@media (max-width:699px){ .fab ~ .toast-host{bottom:calc(var(--tabbar-h) + var(--safe-bottom) + 84px)} }
.toast{pointer-events:auto; display:flex; align-items:center; gap:14px; max-width:min(520px, 100%); padding:11px 12px 11px 16px; border-radius:14px; background:var(--ink); color:var(--canvas); box-shadow:var(--shadow-float); font-size:.92rem; animation:toast-in .22s var(--ease)}
.toast button{background:none; border:0; color:inherit; font:700 .9rem/1 var(--sans); padding:0 12px; min-height:40px; margin:-6px -4px -6px 0; border-radius:8px; text-decoration:underline; text-underline-offset:3px} /* a 40px target that doesn't make the toast taller */
.toast.error{background:var(--danger); color:var(--canvas)} /* canvas on danger reads in light and dark (white on the dark-mode salmon does not) */
@keyframes toast-in{from{transform:translateY(10px); opacity:0}to{transform:none; opacity:1}}

/* ---------- Guidance: tips, empty states, observations ---------- */
.tip{display:grid; grid-template-columns:auto 1fr auto; gap:12px; align-items:start; padding:14px 14px 14px 16px; border-radius:var(--r-lg); background:color-mix(in oklab, var(--accent) 9%, var(--surface)); border:1px solid color-mix(in oklab, var(--accent) 24%, var(--line))}
.tip > svg.i{color:var(--accent); margin-top:1px}
.tip b{display:block; margin-bottom:2px}
.tip p{color:var(--ink-soft); font-size:.92rem}
.tip .close{margin:-8px -6px 0 0}
.empty{display:grid; justify-items:center; text-align:center; gap:10px; padding:28px 16px; border:1.5px dashed var(--line-strong); border-radius:var(--r-lg); color:var(--ink-soft)}
.empty svg.i{width:30px; height:30px; color:var(--muted)}
.empty b{color:var(--ink); font-size:1.02rem}
.empty p{max-width:40ch; font-size:.92rem}
.obs{display:flex; gap:10px; align-items:flex-start; font-size:.93rem; color:var(--ink-soft); border-left:3px solid var(--accent); padding:4px 0 4px 12px}
.obs .x{margin-left:auto}
.banner{display:flex; gap:12px; align-items:center; padding:12px 14px; border-radius:var(--r-md); background:var(--surface-2); font-size:.9rem}
.banner.warn{background:color-mix(in oklab, var(--warn) 14%, var(--surface)); color:var(--ink)}
.banner.ok{background:color-mix(in oklab, var(--ok) 14%, var(--surface))}
.help-dot{display:inline-grid; place-items:center; width:22px; height:22px; border-radius:50%; border:1.5px solid var(--line-strong); color:var(--muted); font:700 .72rem/1 var(--rounded); text-decoration:none}

/* ---------- Today pieces ---------- */
.today-status{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3); flex-wrap:wrap}
.countdown{display:flex; align-items:baseline; gap:10px}
.countdown .n{font:600 2.4rem/1 var(--rounded); letter-spacing:-.02em}
.stat-row{display:flex; flex-wrap:wrap; gap:6px 16px}
.stat{display:inline-flex; align-items:center; gap:7px; font-size:.92rem; color:var(--ink-soft)}
.stat b{font:650 1rem/1 var(--rounded); color:var(--ink); font-variant-numeric:tabular-nums}
.bar{display:flex; height:10px; border-radius:6px; overflow:hidden; background:var(--st-none); gap:2px}
.bar span{display:block; height:100%; background:var(--fill, var(--c))}
.event-line{display:flex; align-items:center; gap:10px; min-height:40px}
.event-line .time{font:600 .88rem/1 var(--rounded); color:var(--ink-soft); min-width:66px; font-variant-numeric:tabular-nums}
.event-line .title{flex:1; min-width:0}
.event-line .star{color:var(--st-vacation-edge)}
.lock{display:inline-flex; align-items:center; gap:4px; font:600 .72rem/1 var(--rounded); color:var(--muted)}

/* ---------- Photos ---------- */
.photo-grid{display:grid; grid-template-columns:repeat(auto-fill, minmax(96px,1fr)); gap:6px}
.photo-grid img, .thumb{width:100%; aspect-ratio:1; object-fit:cover; border-radius:10px; background:var(--surface-2)}
.memory{display:grid; gap:10px}
.memory .body{font-family:var(--serif); font-size:1.12rem; line-height:1.5; color:var(--ink)}
.progress{height:6px; border-radius:6px; background:var(--surface-2); overflow:hidden}
.progress span{display:block; height:100%; background:var(--accent); width:0; transition:width .2s}

/* ---------- Theme picker ---------- */
.theme-grid{display:grid; grid-template-columns:repeat(auto-fill, minmax(150px,1fr)); gap:var(--sp-3)}
.theme-card{display:grid; gap:8px; padding:10px; border-radius:var(--r-lg); border:1.5px solid var(--line); background:var(--surface); text-align:left; color:var(--ink)}
.theme-card[aria-pressed="true"]{border-color:var(--ink); box-shadow:inset 0 0 0 1px var(--ink)}
.theme-card .prev{height:64px; border-radius:10px; display:grid; grid-template-columns:repeat(7,1fr); gap:3px; padding:9px; align-content:end}
.theme-card .prev i{display:block; aspect-ratio:1; border-radius:3px}
.theme-card b{font-size:.92rem}
.theme-card small{color:var(--muted); font-size:.78rem}

/* ---------- Tables (settings, stats) ---------- */
.table-wrap{overflow-x:auto; border:1px solid var(--line); border-radius:var(--r-lg); background:var(--surface)}
table.t{border-collapse:collapse; width:100%; font-size:.92rem}
table.t th, table.t td{padding:10px 14px; text-align:left; border-bottom:1px solid var(--line); vertical-align:top}
table.t tr:last-child td{border-bottom:0}
table.t th{font:600 .72rem/1.3 var(--rounded); letter-spacing:.06em; text-transform:uppercase; color:var(--muted)}

/* ---------- Auth / setup pages (no shell) ---------- */
.auth{min-height:100vh; min-height:100dvh; display:grid; place-items:center; padding:calc(var(--safe-top) + 24px) 20px calc(var(--safe-bottom) + 24px)}
.auth-card{width:min(420px, 100%); display:grid; gap:var(--sp-5)}
.auth-card .brand{display:flex; align-items:center; gap:12px}
.auth-card .brand .brand-mark{width:44px; height:44px}
/* The app mark (layout.php brand_mark): theme colours, so it sits right in light and dark */
.brand-mark{flex:none; display:block}
.brand-mark .bm-bg{fill:var(--surface); stroke:var(--line); stroke-width:3}
.brand-mark .bm-w{fill:var(--sw-work)}   /* the app's own mark: the original colours, whatever the types are called or coloured */
.brand-mark .bm-o{fill:var(--sw-off)}
.brand-mark .bm-v{fill:var(--sw-vacation); stroke:var(--sw-vacation-edge); stroke-width:1.6}
.brand-mark .bm-t{fill:var(--accent)}
.auth-card h1{font:700 1.7rem/1.15 var(--display)}
.steps{display:flex; gap:6px}
.steps i{flex:1; height:4px; border-radius:4px; background:var(--surface-2)}
.steps i.on{background:var(--accent)}

/* ---------- Motion preferences ---------- */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; scroll-behavior:auto !important}
  .sheet-host{transition-delay:0s !important} /* a closing sheet hides at once */
}
@media (prefers-contrast: more){
  :root{--muted:var(--ink-soft); --line:var(--line-strong)}
  .cell, .d{box-shadow:inset 0 0 0 1px var(--line-strong)}
}
@media print{
  .sidebar,.tabbar,.fab,.topbar-actions,.toast-host{display:none !important}
  body{background:#fff}
}

/* ---------- Shell extras ---------- */
.grow{flex:1; min-width:0}
.tb-title{min-width:0}
.tb-back{display:inline-flex; align-items:center; gap:2px; min-height:34px; font-weight:600; font-size:.9rem; text-decoration:none; margin:0 0 0 -4px}
/* The iPhone "More" sheet (layout.php more_sheet): People, Trips, Insights, Help, Settings */
.more-list .list-row{min-height:60px}
.more-list .list-row > svg.i:first-child{color:var(--accent)}
.more-list .grow{display:grid; gap:2px}
.more-list .list-row[aria-current="page"]{background:color-mix(in oklab, var(--accent) 10%, transparent)}
@media (min-width:700px){ .phone-only{display:none !important} }
@media (max-width:699px){ .wide-only{display:none !important} }
body.locked{position:fixed; left:0; right:0; width:100%}
.form-error{color:var(--danger); font-size:.9rem}
[aria-busy="true"]{position:relative; color:transparent !important}
[aria-busy="true"]::after{content:""; position:absolute; left:50%; top:50%; width:18px; height:18px; margin:-9px 0 0 -9px; border-radius:50%; border:2px solid currentColor; border-color:var(--accent-ink) transparent var(--accent-ink) transparent; animation:spin .7s linear infinite}
.btn:not(.btn-primary)[aria-busy="true"]::after{border-color:var(--ink) transparent var(--ink) transparent}
@keyframes spin{to{transform:rotate(360deg)}}
details > summary{cursor:pointer; list-style:none}
details > summary::-webkit-details-marker{display:none}

/* ---------- Quick add ---------- */
.qa-grid{display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:var(--sp-3)}
.qa-tile{display:grid; gap:6px; align-content:start; padding:16px; min-height:124px; border-radius:var(--r-lg); border:1px solid var(--line); background:var(--surface); color:var(--ink); text-decoration:none; touch-action:manipulation}
.qa-tile svg.i{color:var(--accent); margin-bottom:4px}
.qa-tile b{font-size:1.02rem}
.qa-tile span{font-size:.84rem; color:var(--muted); line-height:1.35}
.qa-tile:active{transform:scale(.985)}
.qa-tile:hover{border-color:var(--line-strong)}
/* An odd last tile (the fifth, Birthday, when People is on) spans the row: icon beside the words */
.qa-grid > .qa-tile:last-child:nth-child(odd){grid-column:1 / -1; min-height:0; grid-template-columns:auto minmax(0,1fr); column-gap:14px; row-gap:2px; align-items:center}
.qa-grid > .qa-tile:last-child:nth-child(odd) svg.i{grid-row:1 / span 2; margin:0}

/* ---------- Colour swatches (Settings → Day types) ----------
   <div class="swatch-grid" role="radiogroup"><button class="swatch" data-sw="teal" aria-pressed="true" aria-label="Teal">…</button>…</div>
   A swatch is painted like a day type (data-sw sets --c, --on, --edge, --ring, --fill); data-two="1"
   shows it two-tone. An icon inside (icon('check')) shows only on the pressed one. */
.swatch-grid{display:grid; grid-template-columns:repeat(auto-fill, minmax(44px, 1fr)); gap:10px}
.swatch{display:grid; place-items:center; width:100%; min-width:var(--touch); min-height:var(--touch); aspect-ratio:1; padding:0; border:0; border-radius:12px; background:var(--fill); box-shadow:inset 0 0 0 1px var(--ring); color:var(--on); touch-action:manipulation; transition:box-shadow .15s var(--ease)}
.swatch svg.i{opacity:0; stroke-width:2.4; transition:opacity .15s var(--ease)}
.swatch[aria-pressed="true"], .swatch[aria-checked="true"]{box-shadow:inset 0 0 0 1px var(--ring), 0 0 0 2px var(--raised), 0 0 0 4px var(--ink)}
.swatch[aria-pressed="true"] svg.i, .swatch[aria-checked="true"] svg.i{opacity:1}

/* ---------- View first, edit on request (spec §8) ----------
   An existing record opens read-only; Edit (a pencil, 44px, top right) switches the same sheet or
   page to its editor, Cancel goes back to the view, Save shows the updated view. New records open
   the editor. The contract (core-api.md, "View first", has a full example):
     a box with data-mode="view" | "edit"      a sheet: sheet($id, $title, $body, $foot, ['mode' => 'view', 'edit' => true])
       [data-mode-only="view"]                   shown in view mode only (the .view, a Delete button…)
       [data-mode-only="edit"]                   shown in edit mode only (the form, Save, Cancel)
       [data-sheet-mode="edit" | "view"]         a button that switches (app.js); Life.sheetMode(box, mode) in scripts
   The switch fades the new part in (180ms; none under reduced motion). */
[data-mode="view"] [data-mode-only="edit"], [data-mode="edit"] [data-mode-only="view"]{display:none !important}
.mode-anim [data-mode-only]{animation:mode-in .18s var(--ease)}
@keyframes mode-in{from{opacity:0; transform:translateY(6px)}to{opacity:1; transform:none}}
.view{display:grid; gap:var(--sp-3); min-width:0}
.view-head{display:flex; align-items:flex-start; gap:var(--sp-3)}
.view-head > .grow{display:grid; gap:4px}
.view-title{font:700 1.25rem/1.25 var(--display); overflow-wrap:anywhere}
.view-edit{flex:none; color:var(--accent)}
.view-head .view-edit{margin:-8px -10px 0 0}
.view-meta{display:flex; flex-wrap:wrap; align-items:center; gap:4px 12px; font-size:.88rem; color:var(--muted)}
.view-meta > span{display:inline-flex; align-items:center; gap:5px}
.view-body{font-size:1rem; line-height:1.55; color:var(--ink); white-space:pre-line; overflow-wrap:anywhere}
.view-body.serif{font-family:var(--serif); font-size:1.12rem; line-height:1.5}
.view-photos{display:flex; gap:8px; overflow-x:auto; scroll-snap-type:x mandatory; scrollbar-width:none; -webkit-overflow-scrolling:touch; overscroll-behavior-x:contain; margin:0 calc(-1 * var(--sp-4)); padding:0 var(--sp-4); scroll-padding:0 var(--sp-4)}
.view-photos::-webkit-scrollbar{display:none}
.view-photos > *{flex:none; scroll-snap-align:start; padding:0; border:0; background:none; border-radius:12px; overflow:hidden}
.view-photos img{display:block; height:min(56vw, 260px); width:auto; max-width:none; border-radius:12px; background:var(--surface-2); object-fit:cover}
.view-photos.grid{display:grid; grid-template-columns:repeat(auto-fill, minmax(96px, 1fr)); overflow:visible; margin:0; padding:0}
.view-photos.grid img{width:100%; height:auto; aspect-ratio:1}
.view-list{display:grid; margin:0; padding:0; border:1px solid var(--line); border-radius:var(--r-lg); background:var(--surface); overflow:hidden}
.view-list > div{display:grid; grid-template-columns:minmax(88px, 32%) minmax(0, 1fr); gap:var(--sp-3); padding:11px var(--sp-4); border-bottom:1px solid var(--line)}
.view-list > div:last-child{border-bottom:0}
.view-list dt{font-size:.88rem; color:var(--muted)}
.view-list dd{margin:0; overflow-wrap:anywhere}
.view-list dd > a{display:inline-flex; align-items:center; min-height:var(--touch); margin:-12px 0} /* a 44px target that keeps the row's height */
.view-actions{display:flex; flex-wrap:wrap; gap:var(--sp-2)}
@media (min-width:700px){ .view-photos{margin:0; padding:0; scroll-padding:0} }
