/* Biolink Web UI — light health dashboard (design port from "Biolink webui").
   Left sidebar (grouped nav) + per-screen page header + soft white cards.
   Class names are shared with app.js. All dynamic content is set via textContent (no innerHTML). */

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 13px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
button { font-family: inherit; cursor: pointer; }
a { color: var(--accent); text-decoration: none; }
::selection { background: rgba(29,31,36,0.14); }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: rgba(20,24,31,0.14); border-radius: 8px; }
::-webkit-scrollbar-track { background: transparent; }
.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
/* Global icon-size default: any icon() without a contextual size rule renders at a sane 18px
   instead of ballooning to its intrinsic box. Specific `.x .ico` rules below still override. */
svg.ico { width: 18px; height: 18px; flex: none; }

/* ================= app shell ================= */
#app { display: flex; min-height: 100vh; }

.sidebar {
  position: fixed; top: 0; left: 0; bottom: 0; width: 248px; z-index: 40;
  display: flex; flex-direction: column;
  background: linear-gradient(185deg, var(--sidebar), var(--sidebar-2));
  border-right: 1px solid var(--border);
  padding: 16px 14px;
  transition: width .2s ease;
}
/* ---- brand marks ----
   The logo is a FILE (app/webui/static/brand/*.svg), painted through a CSS mask rather than
   inlined as markup: one source of truth, and the glyph takes `currentColor`, so the same file
   serves every ink context (sidebar, login card, the welcome page's own token) without
   shipping recoloured copies. Aspect ratios are the artwork's own (mark 360x394.86, wordmark
   445x115) — set ONE axis and let the other follow, so the logo can never be stretched. */
.bl-mark, .bl-wordmark {
  display: block; flex: none; background-color: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain;
}
.bl-mark {
  -webkit-mask-image: url("/app/brand/biolink-mark.svg"); mask-image: url("/app/brand/biolink-mark.svg");
  aspect-ratio: 360 / 394.86;
}
.bl-wordmark {
  -webkit-mask-image: url("/app/brand/biolink-wordmark.svg"); mask-image: url("/app/brand/biolink-wordmark.svg");
  aspect-ratio: 445 / 115;
}

.sidebar .brand { display: flex; align-items: center; gap: 11px; padding: 8px 8px 6px; position: relative; }
.brand .mark { width: 34px; height: 34px; border-radius: 10px; flex: none; display: grid; place-items: center;
  background: var(--gradient); color: #fff; box-shadow: var(--glow-accent); }
.brand .mark .ico { width: 20px; height: 20px; }
/* The mark stands in the brand's own ink, not knocked out inside an accent tile — a logo
   handed over in a specific colour should be reproduced, not recoloured. */
.sidebar .brand > .bl-mark { height: 30px; color: var(--text); }
.brand .name { font-size: 16px; font-weight: 800; letter-spacing: -0.3px; line-height: 1.1; }
.brand .sub { font-size: 11.5px; color: var(--text-3); font-weight: 600; }
.collapse-btn { position: absolute; top: -2px; right: -4px; width: 26px; height: 26px; border-radius: 8px;
  display: grid; place-items: center; background: var(--surface); border: 1px solid var(--border); color: var(--text-2); }
.collapse-btn:hover { color: var(--accent); border-color: var(--border-accent); }
.collapse-btn .ico { width: 15px; height: 15px; }

.nav { display: flex; flex-direction: column; gap: 2px; overflow-y: auto; flex: 1; margin-top: 10px; }
.nav .group-label { font-size: 9.5px; letter-spacing: 1.2px; text-transform: uppercase; color: var(--text-3);
  font-weight: 700; padding: 14px 12px 5px; }
.nav-item {
  display: flex; align-items: center; gap: 11px; padding: 8px 11px; border-radius: 10px;
  color: var(--text-2); font-weight: 600; font-size: 13px; border: none; background: none; width: 100%; text-align: left;
  position: relative; transition: background .15s, color .15s, box-shadow .15s;
}
.nav-item:hover { background: rgba(29,31,36,0.05); color: var(--text); }
.nav-item.active { background: var(--surface); color: var(--accent); box-shadow: var(--shadow-nav); font-weight: 700; }
.nav-item .ico { width: 19px; height: 19px; flex: none; opacity: .85; }
.nav-item.active .ico { color: var(--accent); opacity: 1; }
.nav-item .lbl { white-space: nowrap; overflow: hidden; }

.sidebar .foot { border-top: 1px solid var(--border); padding-top: 12px; margin-top: 8px; }
/* The reachability DOT that used to sit here is gone — the system tray in the top right
   reports the link, its strength and internet access, and status in this product is never a
   chrome dot. What remains is the label alone. */
.node-status { display: flex; align-items: center; gap: 8px; padding: 6px 10px 10px; font-size: 12px; color: var(--text-2); font-weight: 600; }
.user-card { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 12px; width: 100%; border: none;
  background: var(--surface); box-shadow: var(--shadow-card); text-align: left; }
.user-card:hover { box-shadow: var(--shadow-nav); }
.user-card .avatar { width: 32px; height: 32px; border-radius: 9px; background: var(--gradient); color: #fff; }
.user-card .nm { font-weight: 700; font-size: 13px; }
.user-card .sub { font-size: 11px; color: var(--text-3); }

/* collapsed rail */
#app.collapsed .sidebar { width: 74px; }
#app.collapsed .brand .name, #app.collapsed .brand .sub,
#app.collapsed .nav-item .lbl, #app.collapsed .group-label,
#app.collapsed .node-status span:last-child, #app.collapsed .user-card .nm, #app.collapsed .user-card .sub { display: none; }
#app.collapsed .nav-item { justify-content: center; padding: 11px; }
#app.collapsed .main { margin-left: 74px; }
#app.collapsed .user-card { justify-content: center; }

/* main column */
.main { flex: 1; min-width: 0; margin-left: 248px; display: flex; flex-direction: column; transition: margin-left .2s ease; }
/* The topbar is present at every width now, because it carries the system tray. Below 860px
   it also carries the drawer button and the mark; on desktop those are redundant with the
   sidebar and are hidden, leaving a thin strip whose only content is pinned right. */
.topbar { position: sticky; top: 0; z-index: 30; display: flex; align-items: center; gap: 12px;
  padding: 10px 16px; background: rgba(248,247,244,0.82); backdrop-filter: blur(10px); border-bottom: 1px solid var(--border); }
.menu-btn { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; color: var(--text); width: 40px; height: 40px; display: grid; place-items: center; }
.content { padding: 20px 26px; max-width: 1140px; width: 100%; }
@media (min-width: 861px) {
  .topbar .menu-btn, .topbar .brand { display: none; }
  .topbar { padding: 8px 26px; }
  .content { padding-top: 14px; }
}

/* ================= system tray (network · power · hardware) =================
   OS chrome, in the ink language: quiet outlined buttons, a popover anchored to the right
   edge, and colour used only where it means something. The network glyph is the one place in
   the product where state is carried by a SHAPE rather than a word — arcs that fill with
   signal, a plug for a cable — because that is the thing a word cannot say compactly. The
   word still exists in the tooltip, the aria-label and the panel. */
/* The CLUSTER is the positioning context, not the individual button. Anchoring each panel to
   its own slot put the leftmost button's 320px panel 57px off the left edge of a phone —
   `right: 0` on a slot that isn't at the right edge still measures from that slot. Hanging
   every panel off the tray's right edge is both bulletproof at any width and the way a real
   system tray behaves. */
.tray { margin-left: auto; display: flex; align-items: center; gap: 8px; position: relative; }
.tray-slot { display: contents; }
.tray-btn { background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
  color: var(--text); width: 40px; height: 40px; display: grid; place-items: center; cursor: pointer; }
.tray-btn:hover { box-shadow: var(--shadow-card); }
.tray-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tray-btn[aria-expanded="true"] { border-color: var(--border-accent); }
/* "Local only" and "unknown" are not faults — they recede rather than alarm. Only a node with
   no network at all earns the danger colour. */
.tray-btn.dim { color: var(--text-3); }
.tray-btn.bad { color: var(--danger); }
.tray-glyph { width: 19px; height: 19px; }

.tray-panel { position: absolute; top: calc(100% + 9px); right: 0; z-index: 60;
  width: min(320px, calc(100vw - 32px)); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-pop); padding: 14px; cursor: default; }
.tray-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.tray-title { font-size: 10.5px; font-weight: 800; letter-spacing: 1.6px; text-transform: uppercase; color: var(--text-3); }
.tray-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 7px 0; font-size: 12.5px; }
.tray-row + .tray-row { border-top: 1px solid var(--border); }
.tray-row-k { color: var(--text-3); font-weight: 650; }
.tray-row-v { color: var(--text); font-weight: 650; text-align: right; min-width: 0; overflow-wrap: anywhere; }
.tray-sig { display: inline-flex; align-items: center; gap: 8px; }
.tray-bar { width: 62px; }
.tray-num { font-family: var(--serif); font-variant-numeric: tabular-nums; font-weight: 545; }
.tray-note { font-size: 12px; line-height: 1.55; color: var(--text-2); margin-top: 10px; overflow-wrap: anywhere; }
.tray-item { display: block; width: 100%; text-align: left; padding: 10px 12px; border: 1px solid var(--border);
  background: var(--surface); border-radius: var(--r-sm); font-size: 13px; font-weight: 650; color: var(--text); cursor: pointer; }
.tray-item + .tray-item { margin-top: 8px; }
.tray-item:hover { background: var(--surface-2); }
.tray-item.danger { color: var(--danger); }

/* On the sign-in screen there is no top bar to sit in, so the glyph pins to the window —
   the same corner it will occupy once you are signed in, so it doesn't appear to move. */
.tray-login { position: fixed; top: 14px; right: 18px; z-index: 50; }

/* The wait screen after a restart: the node stops answering, then answers again. */
.tray-wait { position: fixed; inset: 0; z-index: 90; display: grid; place-items: center; background: rgba(20,24,31,0.35); }
.tray-wait-card { background: var(--surface); border-radius: var(--r-xl); box-shadow: var(--shadow-pop); padding: 24px 28px; text-align: center; max-width: 320px; }
.tray-wait-title { font-family: var(--serif); font-size: 19px; font-weight: 560; margin-bottom: 6px; }

/* scrim for mobile drawer */
.scrim { display: none; position: fixed; inset: 0; background: rgba(20,24,31,0.35); z-index: 35; }

/* ================= page header (per screen) ================= */
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 16px; flex-wrap: wrap; }
.page-head .eyebrow { color: var(--text-3); font-weight: 700; font-size: 11px; margin-bottom: 5px; text-transform: uppercase; letter-spacing: 2.4px; }
.page-head .page-title { font-family: var(--serif); font-size: clamp(26px, 3.6vw, 34px); font-weight: 560; letter-spacing: -0.4px; line-height: 1.04; font-variation-settings: "opsz" 72; }
.page-head .actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* ================= headings ================= */
.screen h2 { display: none; }  /* legacy titles suppressed — page-head owns the title now */
.eyebrow { color: var(--text-3); font-weight: 700; font-size: 11px; letter-spacing: 1px; text-transform: uppercase; }
.section-label { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px;
  color: var(--text-3); margin: 16px 2px 9px; }
.section-row { display: flex; align-items: center; justify-content: space-between; margin: 22px 2px 12px; gap: 12px; }
.section-row .head-ico { display: inline-flex; color: var(--text-3); }
.section-row .head-ico .ico { width: 17px; height: 17px; }
.section-row .section-label { margin: 0; }

/* ================= cards ================= */
.card {
  background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-lg); padding: 16px;
  margin-bottom: 14px; box-shadow: var(--shadow-card);
}
.card.pad-lg { padding: 18px; border-radius: var(--r-xl); }
.card h3 { margin: 0 0 4px; font-size: 15.5px; font-weight: 700; }
.card .muted, .muted { color: var(--text-2); }
.card .sub { color: var(--text-3); font-size: 12.5px; }
.card.hero { background: var(--surface); border-color: var(--border); border-radius: var(--r-2xl); }

.row { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.row + .row { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }

/* ================= grids ================= */
.grid { display: grid; gap: 12px; }
.grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
.grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
.grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.dash { display: grid; grid-template-columns: 1.6fr 1fr; gap: 14px; align-items: start; }
/* Today is a single-column feed — a focused centered column, not side-by-side cards. */
.screen.today { max-width: 900px; margin-left: auto; margin-right: auto; }
.screen.today .quick-add { margin-bottom: 16px; }

/* ================= stat / metric cards ================= */
.stat { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); padding: 16px;
  box-shadow: var(--shadow-card); transition: transform .18s, box-shadow .18s; }
.stat:hover { transform: translateY(-2px); box-shadow: var(--shadow-nav); }
.stat .top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.stat .name { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .7px; color: var(--text-3); }
.stat .chip-ico { width: 32px; height: 32px; border-radius: 10px; display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent); }
.stat .chip-ico .ico { width: 17px; height: 17px; }
.stat .value { font-size: 23px; font-weight: 800; letter-spacing: -0.4px; font-variant-numeric: tabular-nums; line-height: 1.1; }
.stat .value small { font-size: 13px; font-weight: 600; color: var(--text-2); margin-left: 3px; }
.stat .delta { font-size: 12px; color: var(--text-3); margin-top: 6px; font-weight: 600; }
.stat .delta.up { color: var(--success); }
.stat .delta.down { color: var(--danger); }

.metric-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
.metric { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); padding: 14px; box-shadow: var(--shadow-card); }
.metric .label { font-size: 10.5px; text-transform: uppercase; letter-spacing: .6px; color: var(--text-3); font-weight: 700; }
.metric .value { font-size: 18px; font-weight: 800; margin-top: 2px; font-variant-numeric: tabular-nums; }
.metric .value small { font-size: 12px; font-weight: 600; color: var(--text-2); }

/* ================= pills / badges ================= */
.pill, .badge { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: var(--r-pill);
  font-size: 11px; font-weight: 700; background: var(--muted-soft); color: var(--text-2); border: 1px solid transparent; white-space: nowrap; }
.pill.accent { background: var(--accent-soft); color: var(--accent-deep); }
.pill.ok { background: var(--success-soft); color: var(--success); }
.pill.warn { background: var(--warning-soft); color: var(--warning); }
.pill.bad { background: var(--danger-soft); color: var(--danger); }
.pill.info { background: rgba(29,31,36,0.06); color: var(--text-2); }
.pill.info .d { background: var(--accent-2); }
.pill.outline { background: var(--surface); border-color: var(--border); color: var(--text-2); }
.pill .d { width: 7px; height: 7px; border-radius: 50%; background: var(--text-3); }
.pill.live .d, .pill.ok .d { background: var(--success); }
.pill.warn .d { background: var(--warning); }
.pill.bad .d { background: var(--danger); }

/* ================= buttons ================= */
.btn { border: 1px solid transparent; border-radius: var(--r-md); padding: 9px 14px; font-size: 13px; font-weight: 700;
  background: var(--gradient); color: #fff; box-shadow: var(--glow-accent);
  transition: filter .15s, transform .1s, box-shadow .15s; display: inline-flex; align-items: center; gap: 7px; justify-content: center; }
.btn .ico { width: 16px; height: 16px; }
.btn:hover { filter: brightness(1.05); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .55; cursor: default; filter: none; }
.btn.block { display: flex; width: 100%; }
.btn.grad { background: var(--gradient); }
.btn.accent { background: var(--gradient); }
.btn.ghost { background: var(--surface); color: var(--text); border-color: var(--border-strong); box-shadow: none; }
.btn.ghost:hover { border-color: var(--accent); color: var(--accent); filter: none; }
.btn.soft { background: var(--accent-soft); color: var(--accent-deep); box-shadow: none; }
.btn.soft:hover { filter: brightness(0.98); }
.btn.danger { background: var(--danger-soft); color: var(--danger); border-color: transparent; box-shadow: none; }
.btn.danger:hover { filter: brightness(0.97); }
.btn.sm { padding: 7px 12px; font-size: 12.5px; border-radius: 9px; box-shadow: none; }

/* ================= inputs ================= */
label.field { display: block; margin-bottom: 14px; }
label.field .lbl { display: block; font-size: 12px; font-weight: 600; margin-bottom: 6px; color: var(--text-2); }
.input, textarea, select { width: 100%; padding: 11px 13px; background: var(--surface); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--r-md); font-size: 14px; font-family: inherit;
  transition: border-color .15s, box-shadow .15s; }
.input::placeholder, textarea::placeholder { color: var(--text-3); }
.input:focus, textarea:focus, select:focus { outline: none; border-color: var(--text-3); box-shadow: 0 0 0 3px rgba(29,31,36,0.06); }
textarea { min-height: 92px; resize: vertical; }

/* password field + Show/Hide toggle (see revealable() in app.js) */
.pw-wrap { position: relative; display: block; }
.pw-wrap .input { padding-right: 62px; }
.pw-reveal { position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  padding: 5px 9px; border-radius: var(--r-sm); border: 1px solid transparent;
  background: transparent; color: var(--text-3); font-size: 12px; font-weight: 700;
  font-family: inherit; line-height: 1; }
.pw-reveal:hover { color: var(--accent); border-color: var(--border-strong); }
.pw-reveal:focus-visible { outline: none; color: var(--accent); border-color: var(--accent); }

.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip { padding: 8px 14px; border-radius: var(--r-pill); border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text-2); font-size: 13px; font-weight: 700; transition: .15s; }
.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip.active { background: var(--gradient); color: #fff; border-color: transparent; box-shadow: var(--glow-accent); }

/* segmented control (range chips / tabs) */
.segmented { display: inline-flex; background: var(--surface-3); border: 1px solid var(--border); border-radius: var(--r-md); padding: 4px; gap: 2px; }
.segmented .seg { border: none; background: none; padding: 7px 16px; border-radius: 9px; font-size: 13px; font-weight: 700; color: var(--text-2); }
.segmented .seg:hover { color: var(--text); }
.segmented .seg.active { background: var(--surface); color: var(--accent); box-shadow: var(--shadow-card); }

/* ================= switch ================= */
.switch { position: relative; width: 46px; height: 26px; flex: none; }
.switch input { display: none; }
.switch .slider { position: absolute; inset: 0; background: var(--surface-3); border: 1px solid var(--border-strong); border-radius: var(--r-pill); transition: .18s; }
.switch .slider::before { content: ""; position: absolute; width: 18px; height: 18px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: .18s; box-shadow: 0 1px 3px rgba(0,0,0,0.2); }
.switch input:checked + .slider { background: var(--accent); border-color: var(--accent); }
.switch input:checked + .slider::before { transform: translateX(20px); }

/* ================= login ================= */
.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px;
  background: var(--bg); }
.login-card { width: 100%; max-width: 392px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow-pop); border-radius: var(--r-xl); }
/* Sign-in is the one screen with room for the full identity: mark over wordmark, the vertical
   lockup composed from the two assets rather than shipping a third file. */
.login-card .brand { display: flex; flex-direction: column; align-items: center; gap: 14px; margin-bottom: 24px; }
.login-card .brand .bl-mark { height: 52px; color: var(--text); }
.login-card .brand .bl-wordmark { width: 158px; color: var(--text); }
.login-card .brand .sub { color: var(--text-3); font-size: 12.5px; margin-top: -2px; }
.err { color: var(--danger); font-size: 13px; margin: 6px 0; min-height: 18px; font-weight: 600; }
.note { color: var(--text-3); font-size: 11.5px; margin-top: 14px; line-height: 1.5; }

/* ================= chat (AI Coach) ================= */
.chat-screen { display: flex; flex-direction: column; min-height: calc(100vh - 150px); }
.chat-log { display: flex; flex-direction: column; gap: 14px; padding-bottom: 14px; flex: 1; }
.bubble { max-width: 78%; padding: 13px 16px; border-radius: 16px; font-size: 14px; line-height: 1.55; white-space: pre-wrap; word-wrap: break-word; }
.bubble.user { align-self: flex-end; background: var(--gradient); color: #fff; border-bottom-right-radius: 5px; box-shadow: var(--glow-accent); }
.bubble.ai { align-self: flex-start; background: var(--surface); border: 1px solid var(--border); border-bottom-left-radius: 5px; box-shadow: var(--shadow-card); }
.bubble .meta { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.sources { margin-top: 10px; border-top: 1px dashed var(--border-strong); padding-top: 8px; }
.sources summary { font-size: 11.5px; font-weight: 700; color: var(--accent-deep); cursor: pointer; }
.sources li { font-size: 11.5px; color: var(--text-2); margin-top: 4px; }
.composer { position: sticky; bottom: 0; display: flex; gap: 10px; padding: 14px 0 6px; background: linear-gradient(180deg, transparent, var(--bg) 34%); }
.composer .input { flex: 1; }
.suggest { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.chat-empty { text-align: center; padding: 30px 0 18px; }
.chat-empty .ic { width: 54px; height: 54px; border-radius: 16px; display: inline-grid; place-items: center; background: var(--accent-soft); color: var(--accent); margin-bottom: 12px; }
.chat-empty .ic .ico { width: 28px; height: 28px; }

/* ================= chart ================= */
.chart { width: 100%; }
.chart svg { display: block; width: 100%; height: auto; }
.chart svg.line-chart { cursor: crosshair; touch-action: pan-y; }
.chart text { font-variant-numeric: tabular-nums; font-family: var(--mono); }

/* ================= list-row ================= */
.list-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 13px 0; border-bottom: 1px solid var(--border); }
.list-row:last-child { border-bottom: none; }
.list-row .lead { display: flex; align-items: center; gap: 12px; min-width: 0; }
.list-row .lead .t { font-weight: 700; }
.list-row .lead .s { color: var(--text-3); font-size: 12px; }
.avatar { width: 36px; height: 36px; border-radius: 10px; flex: none; display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent); font-weight: 800; font-size: 12px; }
.avatar .ico { width: 18px; height: 18px; }

/* ================= ring / donut (built in JS via SVG) ================= */
.ring { position: relative; display: inline-grid; place-items: center; }
.ring .ring-center { position: absolute; inset: 0; display: grid; place-items: center; text-align: center; }
.ring .ring-val { font-size: 28px; font-weight: 800; letter-spacing: -0.8px; line-height: 1; font-variant-numeric: tabular-nums; }
.ring .ring-lbl { font-size: 9.5px; font-weight: 700; letter-spacing: .7px; text-transform: uppercase; color: var(--text-3); margin-top: 3px; }
.ring-stack { display: inline-grid; justify-items: center; gap: 9px; }
.ring-stack .ring-lbl.below { font-size: 11px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--text-3); }
.ring-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); padding: 18px; box-shadow: var(--shadow-card);
  display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; }
.ring-card .rc-label { font-size: 12px; font-weight: 700; color: var(--text-2); }
.ring-card .rc-sub { font-size: 11px; color: var(--text-3); }

/* ================= score dial (hero) — segmented biometric dial ================= */
/* Precision-instrument dial: hairline chronometer ticks, ink fill, serif numeral, rotating
   notch. Entirely token-driven (works on any theme); depth via the instrument face + tick
   weight, no gradients or glow. */
.score-dial { position: relative; display: inline-grid; place-items: center; width: var(--sd-size, 168px); flex: none; }
.score-dial svg { width: 100%; height: auto; display: block; }
.score-dial .sd-face { fill: var(--surface-2); stroke: var(--border); stroke-width: 1; }
.score-dial .tk { stroke: var(--border-strong); stroke-width: 1.5; stroke-linecap: round; transition: stroke .34s ease, stroke-width .34s ease; }
.score-dial .tk.on { stroke: var(--text); }
.score-dial .tk.major.on { stroke-width: 2; }
.score-dial .sd-notch { transition: transform .52s cubic-bezier(.3,.85,.3,1), opacity .3s ease; }
.score-dial .sd-notch .nl { stroke: var(--text); stroke-width: 2.2; stroke-linecap: round; }
.score-dial .sd-notch .nd { fill: var(--text); }
.score-dial .sd-center { position: absolute; inset: 0; display: grid; place-items: center; text-align: center; transition: opacity .13s ease, transform .13s ease; }
.score-dial .sd-center.swap { opacity: 0; transform: translateY(3px); }
.score-dial .sd-eyebrow { font-size: 9px; font-weight: 800; letter-spacing: 1.8px; text-transform: uppercase; color: var(--text-3); }
.score-dial .sd-num { font-family: var(--serif); font-weight: 560; font-size: 40px; line-height: 1; letter-spacing: -1px;
  font-variation-settings: "opsz" 60; font-variant-numeric: tabular-nums; color: var(--text); margin-top: 3px; }
.score-dial .sd-status { font-size: 10px; font-weight: 750; letter-spacing: 1.4px; text-transform: uppercase; color: var(--text-2); margin-top: 5px; min-height: 12px; }
.score-dial.compact { --sd-size: 128px; }
.score-dial.compact .sd-num { font-size: 30px; }
@media (prefers-reduced-motion: reduce) {
  .score-dial .tk, .score-dial .sd-notch, .score-dial .sd-center, .hero-text { transition: none !important; }
}

/* ================= hero (Today carousel) ================= */
.hero-wrap { position: relative; }
.hero-body { display: grid; grid-template-columns: auto 1fr; gap: 26px; align-items: center; }
.hero-text { transition: opacity .16s ease; min-width: 0; }
.hero-text.swapping { opacity: 0; }
.hero-insight { font-size: 15px; line-height: 1.5; font-weight: 500; color: var(--text); }
.hero-stats { display: flex; gap: 26px; margin-top: 14px; padding-top: 13px; border-top: 1px solid var(--border); }
.hero-stats .hs .l { font-size: 10px; font-weight: 700; color: var(--text-3); text-transform: uppercase; letter-spacing: .5px; }
.hero-stats .hs .v { font-size: 19px; font-weight: 800; font-variant-numeric: tabular-nums; }
.hero-stats .hs .v small { font-size: 11px; color: var(--text-2); font-weight: 600; }
.hero-stats .hs .d { font-size: 11.5px; font-weight: 700; margin-top: 2px; }
.hero-nav { position: absolute; top: 16px; right: 16px; display: flex; gap: 6px; }
.hero-nav button { width: 30px; height: 30px; border-radius: 9px; background: var(--surface); border: 1px solid var(--border); color: var(--text-2); display: grid; place-items: center; }
.hero-nav button:hover { color: var(--accent); }
.carousel-dots { display: flex; gap: 6px; justify-content: center; margin-top: 14px; }
.carousel-dots .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--border-strong); border: none; padding: 0; }
.carousel-dots .dot.active { background: var(--accent); width: 20px; border-radius: 4px; }

/* ================= top movers (health report) ================= */
/* A DIVERGING bar: one shared centre line, bar length = how far the metric moved against its
   own usual swing, side = direction. "What moved and which way" is one glance down a single
   axis instead of a hunt through per-section percent pills. Colour says GOOD or NOT, never
   merely up or down — a lower resting HR and a higher HRV are both improvements. */
.mv-card { margin-bottom: 14px; }
.mv-legend { display: flex; align-items: center; gap: 7px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .6px; text-transform: uppercase; color: var(--text-3); }
.mv-axis-key { width: 26px; height: 1px; background: var(--border-strong); display: inline-block; }
.mv-row { display: grid; grid-template-columns: minmax(96px, 1.1fr) minmax(120px, 2fr) auto;
  align-items: center; gap: 14px; padding: 9px 0; border-top: 1px solid var(--border); }
.mv-row:first-of-type { border-top: none; }
.mv-title { font-size: 13.5px; font-weight: 650; color: var(--text); line-height: 1.25; }
.mv-sub { font-size: 10.5px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
  color: var(--text-3); margin-top: 2px; }
.mv-track { position: relative; height: 18px; min-width: 0; }
.mv-axis { position: absolute; left: 50%; top: 0; bottom: 0; width: 1px; background: var(--border-strong); }
.mv-bar { position: absolute; top: 3px; bottom: 3px; border-radius: 3px; background: var(--text-3); }
.mv-bar.good { background: var(--success); }
.mv-bar.bad { background: var(--warning); }
.mv-val { text-align: right; min-width: 92px; }
.mv-delta { font-size: 14px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--text); }
.mv-val.good .mv-delta { color: var(--success); }
.mv-val.bad .mv-delta { color: var(--warning); }
.mv-pct { font-size: 11.5px; font-weight: 650; color: var(--text-3); font-variant-numeric: tabular-nums;
  margin-top: 1px; }
.mv-note { font-size: 11.5px; line-height: 1.5; color: var(--text-3); margin-top: 12px;
  padding-top: 10px; border-top: 1px solid var(--border); }
.mv-steady { font-size: 13px; color: var(--text-2); margin: 10px 0 14px; }
@media (max-width: 620px) {
  .mv-row { grid-template-columns: 1fr auto; gap: 6px 10px; }
  .mv-track { grid-column: 1 / -1; order: 3; }
  .mv-val { min-width: 0; }
}

/* ================= markdown in chat answers ================= */
/* A model asked for advice answers in markdown; before this the SOURCE rendered — "###" and
   pipe tables, verbatim. Built with textContent only (never innerHTML): the text is model
   output that has read the user's data. Sized to sit inside a chat bubble, not to become a
   document — headings are weight + size, not rules and margins. */
.md > :first-child { margin-top: 0; }
.md > :last-child { margin-bottom: 0; }
.md-p { margin: 0 0 9px; line-height: 1.55; }
.md-h { font-weight: 750; line-height: 1.3; margin: 14px 0 6px; color: var(--text); }
.md-h1, .md-h2 { font-family: var(--serif); font-weight: 560; letter-spacing: -0.3px; font-size: 17px; }
.md-h3, .md-h4, .md-h5, .md-h6 { font-size: 13px; letter-spacing: .3px; text-transform: uppercase;
  color: var(--text-2); }
.md-hr { height: 1px; background: var(--border); margin: 12px 0; }
.md-list { margin: 0 0 9px; padding-left: 20px; }
.md-list li { margin: 3px 0; line-height: 1.5; }
/* A sub-list sits under its parent step, not as another top-level item. */
.md-list .md-list { margin: 4px 0 2px; }
/* Multi-line table cells (the model writes them with <br>) need to breathe and wrap. */
.md-table td { white-space: normal; min-width: 0; }
.md-table td:first-child, .md-table th:first-child { white-space: nowrap; }
.md code { font-family: var(--mono, ui-monospace, monospace); font-size: 0.92em;
  background: var(--surface-2); padding: 1px 5px; border-radius: 5px; }
/* Tables scroll INSIDE the bubble — a wide lab table must never widen the chat column. */
.md-tablewrap { overflow-x: auto; margin: 0 0 10px; }
.md-table { border-collapse: collapse; font-size: 13px; min-width: 100%; }
.md-table th, .md-table td { text-align: left; padding: 6px 12px 6px 0;
  border-bottom: 1px solid var(--border); white-space: nowrap; }
.md-table th { font-size: 10.5px; font-weight: 800; letter-spacing: .6px; text-transform: uppercase;
  color: var(--text-3); }
.md-table td { font-variant-numeric: tabular-nums; }
.md-table tr:last-child td { border-bottom: none; }

/* ================= sync nudge (Today banner) ================= */
/* One line, one action. Deliberately NOT a card: Today is legitimately half-empty sometimes
   (a night without the ring, a morning before the sync), and a hero-sized placeholder would
   make an ordinary gap look like a failure. */
.sync-banner { display: flex; align-items: center; gap: 12px; margin-bottom: 16px;
  padding: 10px 12px 10px 14px; border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--surface-2); }
.sync-banner .sb-ico { display: inline-flex; color: var(--text-3); flex: none; }
.sync-banner .sb-ico .ico { width: 17px; height: 17px; }
.sync-banner .sb-text { flex: 1; min-width: 0; font-size: 13.5px; line-height: 1.45; color: var(--text-1); }
.sync-banner .btn { flex: none; }
.sync-banner .sb-x { flex: none; width: 26px; height: 26px; padding: 0; border: none; background: none;
  color: var(--text-3); display: grid; place-items: center; border-radius: 8px; cursor: pointer; }
.sync-banner .sb-x:hover { color: var(--text); background: var(--surface); }
.sync-banner .sb-x .ico { width: 14px; height: 14px; }
.sync-banner .sb-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ================= last night (sleep card) ================= */
/* HIERARCHY: score → interpretation + factors → duration context → chart detail. The score
   leads because it is the one number that answers "how did I sleep"; the hypnogram, which
   used to open this card, is the evidence and now sits below a rule as supporting detail. */
/* Two rows: the score and the night span both, the reading column carries the sentence and
   the factor chips sit beneath it. The chips are a grid ITEM rather than a child of the text
   column so a narrow screen can hand them the card's full width instead of a ~220px sliver. */
.sleep-summary { display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 0 26px; align-items: start; }
.sl-score { grid-column: 1; grid-row: 1 / span 2; text-align: center; padding-top: 2px; }
.sl-num { font-family: var(--serif); font-weight: 560; font-size: 54px; line-height: 0.92;
  letter-spacing: -2px; font-variation-settings: "opsz" 72; font-variant-numeric: tabular-nums;
  color: var(--text); }
.sl-lbl { font-size: 12px; font-weight: 650; color: var(--text-2); margin-top: 8px; white-space: nowrap; }
.sl-read { grid-column: 2; grid-row: 1; min-width: 0; }
.sl-word { font-size: 13px; font-weight: 800; letter-spacing: 1.6px; text-transform: uppercase;
  color: var(--text-2); }
.sl-word.ok { color: var(--success); }
.sl-word.warn { color: var(--warning); }
.sl-interp { font-size: 14.5px; line-height: 1.5; color: var(--text); margin-top: 7px; }
.sl-chips { grid-column: 2; grid-row: 2; display: flex; flex-wrap: wrap; gap: 8px; margin-top: 11px; }
.sl-chip { display: flex; align-items: center; gap: 9px; padding: 6px 12px; min-width: 0;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface); }
.sl-chip .ci { display: inline-flex; color: var(--text-3); flex: none; }
.sl-chip .ci .ico { width: 16px; height: 16px; }
.sl-chip .ck { font-size: 10.5px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
  color: var(--text-3); }
.sl-chip .cv { font-size: 14px; font-weight: 750; color: var(--text); font-variant-numeric: tabular-nums;
  margin-top: 1px; }
.sl-chip .cv.warn { color: var(--warning); }
/* The duration column, ruled off: a second reading of the same night, not a third factor. */
.sl-night { grid-column: 3; grid-row: 1 / span 2; padding-left: 26px;
  border-left: 1px solid var(--border); min-width: 148px; }
.sl-night-lbl { font-size: 13px; font-weight: 600; color: var(--text-2); }
.sl-dur { font-family: var(--serif); font-weight: 560; font-size: 36px; line-height: 1.05;
  letter-spacing: -1px; font-variation-settings: "opsz" 60; font-variant-numeric: tabular-nums;
  color: var(--text); margin-top: 4px; }
.sl-delta { display: flex; align-items: center; gap: 5px; margin-top: 9px; font-size: 15px;
  font-weight: 750; color: var(--text-2); font-variant-numeric: tabular-nums; }
.sl-delta.warn { color: var(--warning); }
.sl-delta .ar { font-size: 13px; }
.sl-vs { font-size: 12.5px; color: var(--text-3); margin-top: 3px; line-height: 1.4; }
/* The subtle divider: everything below it is the chart and its legend. */
.sl-rule { height: 1px; background: var(--border); margin: 15px 0 11px; }
.sl-note { font-size: 13.5px; line-height: 1.45; color: var(--text-1); }

/* ================= health monitor (2x2 gauges) ================= */
/* 3 or 4 uniform tiles (HRV joins async once its balance resolves) — auto-fit keeps the row
   evenly filled either way. */
.monitor-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 11px; }
.monitor-card { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md); padding: 13px; box-shadow: var(--shadow-card); display: flex; gap: 12px; align-items: stretch; }
.monitor-card .mc-main { flex: 1; min-width: 0; }
.monitor-card .mc-top { display: flex; align-items: center; gap: 6px; color: var(--text-3); font-size: 10px; font-weight: 800; letter-spacing: 1.2px; text-transform: uppercase; }
.monitor-card .mc-top .ico { width: 14px; height: 14px; }
.monitor-card .mc-val { font-family: var(--serif); font-weight: 560; font-size: 22px; letter-spacing: -0.2px;
  font-variation-settings: "opsz" 50; margin-top: 8px; font-variant-numeric: tabular-nums; line-height: 1; }
.monitor-card .mc-val small { font-family: var(--font); font-size: 11px; color: var(--text-3); font-weight: 650; margin-left: 3px; letter-spacing: 0; }
.monitor-card .mc-status { display: flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 700; margin-top: 10px; }
.monitor-card .mc-status .ico { width: 15px; height: 15px; }
.monitor-card .mc-status.ok { color: var(--success); }
.monitor-card .mc-status.warn { color: var(--warning); }
.monitor-card .mc-status.bad { color: var(--danger); }
.monitor-card .mc-status.info { color: var(--accent); }
.monitor-card .mc-sub { font-size: 11px; color: var(--text-3); font-weight: 600; margin-top: 6px; }
.monitor-card .mc-gauge { width: 8px; border-radius: 999px; background: var(--surface-3); position: relative; align-self: stretch; min-height: 70px; flex: none; }
.monitor-card .mc-gauge .band { position: absolute; left: 0; right: 0; background: rgba(76,175,125,0.22); border-radius: 999px; }
.monitor-card .mc-gauge .thumb { position: absolute; left: 50%; width: 12px; height: 12px; border-radius: 50%; background: var(--accent); transform: translate(-50%,-50%); box-shadow: 0 1px 4px rgba(0,0,0,0.2); }

/* Clickable vitals — drill into the Metrics detail. Keyboard-focusable (role=button/tabindex). */
.clickable { cursor: pointer; transition: transform .18s, box-shadow .18s, border-color .18s, background .15s; }
.monitor-card.clickable:hover { transform: translateY(-2px); box-shadow: var(--shadow-nav); border-color: var(--border-accent); }
.clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ================= sleep hypnogram ================= */
/* Stepped stage chart (Apple/Oura style): stage bands at 4 levels over the night timeline. */
.hypno-svg { width: 100%; height: auto; display: block; margin-top: 6px; cursor: crosshair; touch-action: pan-y; }
/* Fallback flat proportional bar (only when no per-stage intervals exist). */
.hypno { display: flex; gap: 0; height: 40px; border-radius: 7px; overflow: hidden; }
.hypno .seg { height: 100%; min-width: 0.5px; }
.hypno-legend { display: flex; flex-wrap: wrap; gap: 8px 18px; margin-top: 9px; }
.hypno-legend .lg { display: flex; align-items: center; gap: 7px; font-size: 12px; }
.hypno-legend .lg .sw { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.hypno-legend .lg-name { color: var(--text-2); font-weight: 600; }
.hypno-legend .lg-val { color: var(--text); font-weight: 700; font-variant-numeric: tabular-nums; }
.hypno-legend .lg-pct { color: var(--text-3); font-weight: 600; font-variant-numeric: tabular-nums; }

/* ================= today timeline ================= */
.timeline { position: relative; }
.tl-ev { display: flex; gap: 13px; padding: 11px 0; align-items: flex-start; }
.tl-ev .ic { width: 34px; height: 34px; border-radius: 10px; flex: none; display: grid; place-items: center; background: var(--accent-soft); color: var(--accent); }
.tl-ev .ic .ico { width: 17px; height: 17px; }
.tl-ev .body { flex: 1; min-width: 0; }
.tl-ev .ttl { font-weight: 700; font-size: 13.5px; }
.tl-ev .det { color: var(--text-2); font-size: 12.5px; margin-top: 1px; }
.tl-ev .when { font-family: var(--mono); font-size: 11.5px; color: var(--text-3); white-space: nowrap; }

/* ================= quick-add tiles (square) ================= */
/* Quick add — hairline action pills (actions are pills, never content-weight cards). */
.quick-add { display: flex; flex-wrap: wrap; gap: 8px; }
.qa-pill { display: inline-flex; align-items: center; gap: 8px; padding: 9px 14px 9px 12px; border-radius: var(--r-pill);
  background: var(--surface); border: 1px solid var(--border-strong); color: var(--text-2);
  font-weight: 700; font-size: 12.5px;
  transition: color .15s, border-color .15s, transform .12s, box-shadow .15s; }
.qa-pill .ico { width: 15px; height: 15px; color: var(--text-2); transition: color .15s; flex: none; }
.qa-pill .ico.plus { width: 11px; height: 11px; margin-left: 2px; color: var(--text-3); }
.qa-pill:hover { color: var(--text); border-color: var(--border-accent); transform: translateY(-1px); box-shadow: var(--shadow-nav); }
.qa-pill:hover .ico { color: var(--text); }
.qa-pill:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .qa-pill { transition: none; } }

/* ================= connections (MCP) ================= */
.mcp-prov { display: flex; align-items: center; gap: 12px; width: 100%; padding: 12px 14px; border: 1px solid var(--border);
  border-radius: var(--r-lg); background: var(--surface); box-shadow: var(--shadow-card); color: var(--text); transition: .15s; }
.mcp-prov:hover { border-color: var(--border-accent); box-shadow: var(--shadow-nav); transform: translateY(-1px); }
.mcp-prov .mcp-ic { width: 38px; height: 38px; border-radius: 11px; flex: none; display: grid; place-items: center; background: var(--accent-soft); color: var(--accent); }
.mcp-prov .mcp-ic .ico { width: 20px; height: 20px; }
.mcp-prov .mcp-chev { width: 16px; height: 16px; color: var(--text-3); flex: none; }
.code-block { background: var(--surface-3); border: 1px solid var(--border); border-radius: var(--r-md); padding: 12px 13px;
  overflow-x: auto; font-family: var(--mono); font-size: 11.5px; line-height: 1.55; color: var(--text); white-space: pre; margin: 0; }

/* ================= CTA (doctor visit) ================= */
/* Doctor-brief prompt — plain paper card in the ink system (no gradient wash), serif heading. */
.cta { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-xl); padding: 22px; box-shadow: var(--shadow-card); }
.cta .ic { width: 40px; height: 40px; border-radius: 13px; display: grid; place-items: center; background: var(--accent-soft); color: var(--accent); margin-bottom: 12px; }
.cta h3 { font-family: var(--serif); font-size: 18px; font-weight: 560; letter-spacing: -0.1px; font-variation-settings: "opsz" 40; }
.cta p { color: var(--text-2); font-size: 13.5px; line-height: 1.5; margin: 6px 0 14px; }

/* ================= hydration pips ================= */
.pips { display: flex; flex-wrap: wrap; gap: 8px; margin: 14px 0; }
/* pips are BUTTONS (tap cup N to log up to N cups) — clickable affordance, not decoration */
.pip { width: 26px; height: 32px; border-radius: 7px; border: 2px solid var(--border-strong); background: var(--surface-3); display: grid; place-items: center; color: var(--accent); padding: 0; transition: border-color .15s, background .15s, transform .12s; }
.pip:hover { border-color: var(--accent); transform: translateY(-1px); }
.pip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pip.full { background: var(--accent-soft); border-color: var(--accent); }
.pip .ico { width: 14px; height: 14px; }
.pip-ctl { display: flex; align-items: center; gap: 12px; }
.pip-ctl button { width: 38px; height: 38px; border-radius: 11px; border: 1px solid var(--border-strong); background: var(--surface); color: var(--accent); font-size: 20px; font-weight: 700; }
.pip-ctl button:hover { border-color: var(--accent); }

/* ================= lab / panel rows ================= */
.lab-row { display: grid; grid-template-columns: 1.4fr 1fr auto; gap: 12px; align-items: center; padding: 13px 0; border-bottom: 1px solid var(--border); }
.lab-row:last-child { border-bottom: none; }
.lab-row .ln { font-weight: 700; font-size: 13.5px; }
.lab-row .ln .dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 7px; }
.lab-row .lv { font-family: var(--mono); font-weight: 700; font-variant-numeric: tabular-nums; }
/* Thin editorial bar (nutrition's 3px bar language) — track hairline, tinted good-zone band,
   crisp white-ringed thumb. Shared by metric tiles + Explore pattern cards. */
.range-bar { position: relative; height: 3px; border-radius: 999px; background: rgba(29,31,36,0.08); margin-top: 13px; }
.range-bar .band { position: absolute; top: 0; bottom: 0; background: rgba(63,157,110,0.30); border-radius: 999px; }
.range-bar .thumb { position: absolute; top: 50%; width: 9px; height: 9px; border-radius: 50%; transform: translate(-50%,-50%); box-shadow: 0 0 0 2px var(--surface), 0 1px 3px rgba(0,0,0,0.22); }

/* metric tiles (Metrics grid) — ink editorial: eyebrow label, serif tabular numeral, quiet
   right-aligned status word; NO chrome status dot. */
.metric-tile .mt-label { font-size: 10px; font-weight: 800; letter-spacing: 1.6px; text-transform: uppercase; color: var(--text-3); }
.metric-tile .mt-row { display: flex; align-items: baseline; gap: 10px; margin-top: 9px; }
.metric-tile .mt-val { font-family: var(--serif); font-weight: 560; font-size: 23px; letter-spacing: -0.2px;
  font-variation-settings: "opsz" 50; font-variant-numeric: tabular-nums; color: var(--text); line-height: 1.05; }
.metric-tile .mt-val small { font-family: var(--font); font-size: 11px; font-weight: 650; color: var(--text-3); margin-left: 4px; letter-spacing: 0; }
.metric-tile .mt-status { margin-left: auto; font-size: 11.5px; font-weight: 750; flex: none; }
.metric-tile .mt-cap { font-size: 10.5px; font-weight: 600; color: var(--text-3); margin-top: 8px; font-variant-numeric: tabular-nums; }
/* The night a CARRIED value actually came from. Metrics shows the last known reading rather
   than an empty grid before the morning sync, so the date is not decoration — it is the thing
   that keeps an older night from reading as this morning's. Quiet, but never absent. */
.metric-tile .mt-when { margin-left: 6px; font-weight: 700; letter-spacing: 0.8px; color: var(--text-3); opacity: 0.75; }
.metric-tile .mt-when::before { content: "· "; }
.metric-tile.clickable:hover { transform: translateY(-2px); box-shadow: var(--shadow-nav); border-color: var(--border-accent); }

/* ================= two-column report/brief viewer ================= */
.doc-grid { display: grid; grid-template-columns: 1.7fr 1fr; gap: 16px; align-items: start; }
.doc-body h4 { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; color: var(--text-3); margin: 20px 0 8px; }
.doc-body h4:first-child { margin-top: 0; }
.doc-body p, .doc-body li { line-height: 1.6; color: var(--text); }
.doc-trend { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.doc-trend .mono { font-weight: 700; }

/* ================= misc ================= */
.spinner { display: inline-block; width: 16px; height: 16px; border: 2px solid rgba(29,31,36,0.15); border-top-color: var(--accent); border-radius: 50%; animation: spin .7s linear infinite; vertical-align: middle; }
@keyframes spin { to { transform: rotate(360deg); } }
.center { text-align: center; }
.hidden { display: none !important; }
.empty { color: var(--text-3); font-size: 13px; text-align: center; padding: 26px 0; }
.placeholder { border: 1px dashed var(--border-strong); border-radius: var(--r-lg); padding: 28px; text-align: center; color: var(--text-2); background: var(--surface-2); }
.placeholder .ic { width: 44px; height: 44px; border-radius: 12px; display: inline-grid; place-items: center; background: var(--accent-soft); color: var(--accent); margin-bottom: 10px; }
.placeholder .ic .ico { width: 22px; height: 22px; }
.placeholder .ph-title { font-weight: 800; color: var(--text); font-size: 15px; margin-bottom: 4px; }
.toast { position: fixed; bottom: 26px; left: 50%; transform: translateX(-50%); background: var(--text); color: #fff;
  padding: 11px 18px; border-radius: var(--r-pill); font-size: 13px; font-weight: 600; z-index: 80; opacity: 0; transition: opacity .2s; box-shadow: var(--shadow-pop); }
.toast.show { opacity: 1; }

/* ================= modals ================= */
.modal-overlay { position: fixed; inset: 0; background: rgba(20,24,31,0.4); z-index: 90; display: flex; align-items: center; justify-content: center; padding: 18px; backdrop-filter: blur(2px); }
.modal-card { width: 100%; max-width: 460px; margin: 0; box-shadow: var(--shadow-pop); border-radius: var(--r-xl); max-height: 90vh; overflow-y: auto; }
.modal-card.wide { max-width: 560px; }
/* The trend modal: a chart at 560px is a postage stamp. */
.modal-card.xl { max-width: 780px; }
.modal-card video { width: 100%; max-height: 240px; background: #000; border-radius: var(--r-md); object-fit: cover; }
.modal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.modal-head .x { width: 32px; height: 32px; border-radius: 9px; border: 1px solid var(--border); background: var(--surface); color: var(--text-2); display: grid; place-items: center; }

/* ---- nutrition goals modal: derivation text, never chrome ---- */
/* `reco` is the active preset's one-sentence derivation — a hairline-accented aside,
   read before the numbers. `note` carries provenance and the editability hint. */
.goal-reco { font-size: 13px; line-height: 1.55; color: var(--text-2); margin: 2px 0 14px;
  padding: 9px 12px; border-left: 2px solid var(--accent); background: var(--surface); border-radius: 0 var(--r-md) var(--r-md) 0; }
.goal-note { font-size: 12.5px; line-height: 1.55; color: var(--text-2); margin-top: 10px; }

/* ---- sync modal ---- */
.sync-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.sync-row:last-of-type { border-bottom: none; }
.sync-row .mid { flex: 1; min-width: 0; }
.sync-row .nm { font-weight: 700; }
.sync-row .st { font-size: 12px; color: var(--text-3); margin-top: 2px; }
.sync-row .st.bad { color: var(--danger); }
.sync-row .st.ok { color: var(--success); }
.prog { height: 7px; border-radius: 999px; background: var(--surface-3); overflow: hidden; margin-top: 7px; }
.prog .fill { height: 100%; width: 100%; border-radius: 999px; background: var(--accent); transition: width .4s ease; }
.prog .fill.ok { background: var(--success); }
.prog .fill.bad { background: var(--danger); }
.prog .fill.muted { background: var(--border-strong); }
.prog.indet { position: relative; }
.prog.indet .fill { width: 38%; animation: indet 1.15s infinite ease-in-out; }
@keyframes indet { 0% { transform: translateX(-110%); } 100% { transform: translateX(285%); } }
.sync-row .tick { width: 22px; text-align: center; font-weight: 800; }
.sync-row .tick.ok { color: var(--success); }
.sync-row .tick.bad { color: var(--danger); }

/* ================= collapsible (settings/panels) ================= */
.collapse { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--shadow-card); margin-bottom: 14px; overflow: hidden; }
.collapse > .head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 20px; cursor: pointer; }
.collapse > .head .ttl { font-weight: 700; font-size: 14.5px; }
.collapse > .head .chev { transition: transform .2s; color: var(--text-3); }
.collapse.open > .head .chev { transform: rotate(180deg); }
.collapse > .body { padding: 0 20px 18px; }

/* ================= responsive ================= */
@media (max-width: 1080px) {
  .dash { grid-template-columns: 1fr; }
  .doc-grid { grid-template-columns: 1fr; }
  .grid.cols-4 { grid-template-columns: repeat(2,1fr); }
  .hero-body { grid-template-columns: 1fr; gap: 18px; }
}
@media (max-width: 860px) {
  .sidebar { transform: translateX(-100%); transition: transform .22s ease; box-shadow: var(--shadow-pop); width: 248px; }
  #app.nav-open .sidebar { transform: translateX(0); }
  #app.collapsed .sidebar { width: 248px; }
  #app.nav-open .scrim { display: block; }
  .main, #app.collapsed .main { margin-left: 0; }
  .collapse-btn { display: none; }
  .content { padding: 18px; }
  .page-head .page-title { font-size: 25px; }
}
/* The sleep summary's third column is the first thing to run out of room. Rather than shrink
   it, it becomes a RULED ROW under the score and factors — same reading order, one dimension
   instead of two. */
@media (max-width: 900px) {
  .sleep-summary { grid-template-columns: auto minmax(0, 1fr); gap: 0 20px; }
  .sl-night { grid-column: 1 / -1; grid-row: 3; min-width: 0; margin-top: 16px;
    padding: 14px 0 0; border-left: none;
    border-top: 1px solid var(--border); display: flex; align-items: baseline;
    flex-wrap: wrap; gap: 4px 12px; }
  .sl-night-lbl { order: 1; }
  .sl-dur { order: 2; margin-top: 0; font-size: 30px; }
  .sl-delta { order: 3; margin-top: 0; }
  .sl-vs { order: 4; margin-top: 0 !important; }
}
@media (max-width: 620px) {
  .grid.cols-4, .grid.cols-3, .grid.cols-2, .metric-grid { grid-template-columns: 1fr 1fr; }
  .monitor-grid { grid-template-columns: 1fr 1fr; }
  .score-dial { --sd-size: 136px; margin: 0 auto; }
  .score-dial .sd-num { font-size: 32px; }
  .bubble { max-width: 90%; }
  .hero-stats { gap: 18px; flex-wrap: wrap; }
  .sleep-summary { gap: 0 16px; }
  .sl-num { font-size: 44px; }
  .sl-dur { font-size: 27px; }
  /* All three factors on ONE line, always. Beside the score they had ~220px and "Deep" fell
     to a second row; spanning the card they get the full width and divide it evenly, so the
     row reads as one comparison instead of two-and-a-remainder. Icon and label shrink to buy
     the space rather than the value, which is the part being read. */
  .sl-score { grid-row: 1; }
  .sl-chips { grid-column: 1 / -1; gap: 6px; flex-wrap: nowrap; }
  .sl-chip { flex: 1 1 0; min-width: 0; padding: 7px 9px; gap: 6px; }
  .sl-chip .ci .ico { width: 14px; height: 14px; }
  .sl-chip .ck { font-size: 9.5px; letter-spacing: .2px; }
  .sl-chip .cv { font-size: 13.5px; }
  .snap-headline { font-size: 19px; }
  /* The nudge stays one strip, but the sentence gets its own line rather than being squeezed
     to two words beside the button. Dismiss stays pinned to the text row's right edge. */
  .sync-banner { flex-wrap: wrap; gap: 8px 10px; }
  .sync-banner .sb-text { flex: 1 1 0; }
  .sync-banner .btn { flex: 1 1 100%; order: 3; justify-content: center; }
}

/* Smallest phones (SE-class). Keeping the three factors on one line costs the glyph before it
   costs a word: the label and the value are the information, the icon is only orientation. */
@media (max-width: 360px) {
  .sl-chip { padding: 7px 8px; }
  .sl-chip .ci { display: none; }
}

/* ---- Backup & restore (backup.js) ---- */
.bk-danger { border: 1px solid var(--danger); background: var(--danger-soft); color: var(--danger);
  border-radius: var(--r-md); padding: 9px 11px; font-size: 12.5px; font-weight: 600; margin-top: 10px; }
.bk-note { border: 1px solid var(--border); background: var(--warning-soft); color: var(--text-1);
  border-radius: var(--r-md); padding: 8px 11px; font-size: 12.5px; margin: 6px 0; }
.bk-counts { border: 1px solid var(--border); border-radius: var(--r-md); margin: 8px 0; overflow: hidden; }
.bk-counts-row { display: grid; grid-template-columns: 1fr auto auto; gap: 12px; padding: 5px 10px;
  font-size: 12px; border-top: 1px solid var(--border); }
.bk-counts-row:first-child { border-top: none; }
.bk-counts-head { color: var(--text-3); font-weight: 700; text-transform: uppercase; font-size: 10.5px;
  letter-spacing: .04em; }
.bk-counts-row span:nth-child(2), .bk-counts-row span:nth-child(3) { text-align: right; min-width: 56px; }

/* Health snapshot (Today): the saved reports condensed. Attention items are colored words,
   never dots; provenance lives behind the title's info button (.info-panel below). */
/* The point in one line, then the evidence under it. Fraunces here (not another 13.5px
   paragraph) is what lets the card be read at a glance instead of scanned. */
.snap-headline { font-family: var(--serif); font-weight: 560; font-size: 21px; line-height: 1.22;
  letter-spacing: -0.4px; font-variation-settings: "opsz" 40; color: var(--text); margin-top: 5px; }
.snap-lead { font-size: 13.5px; line-height: 1.55; margin-top: 5px; }
.snap-headline + .snap-lead { margin-top: 7px; color: var(--text-2); }
.snap-meta { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 6px; font-size: 12px; }
.snap-att { color: #A8532B; font-weight: 700; }

/* Footnotes behind an info button (provenance, arrival semantics): true and occasionally
   needed, but as grey lines under a summary they compete with it every day. The panel is
   anchored to the title row, so it opens under the icon rather than floating. */
.row-title { display: flex; align-items: center; gap: 7px; position: relative; min-width: 0; }
.info-btn { position: relative; width: 20px; height: 20px; padding: 0; border: none;
  background: none; flex: none; color: var(--text-3); display: grid; place-items: center;
  border-radius: 50%; cursor: pointer; }
/* A 20px glyph is the right WEIGHT beside a section label and the wrong TAP TARGET. The hit
   area grows to 44px on a transparent pseudo-element, so touch gets the reach without the
   icon getting louder or the title row getting taller. */
.info-btn::after { content: ""; position: absolute; inset: -12px; border-radius: 50%; }
.info-btn:hover, .info-btn[aria-expanded="true"] { color: var(--accent); }
.info-btn .ico { width: 15px; height: 15px; }
.info-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.info-panel { position: absolute; top: calc(100% + 9px); left: -6px; z-index: 40;
  width: min(360px, 74vw); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-pop); padding: 12px 14px; cursor: default; }
.info-line { font-size: 12.5px; line-height: 1.55; color: var(--text-2); }
.info-line + .info-line { margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--border); }

/* Lab panels on Metrics: compact scan rows — name + reference beneath, serif tabular
   value, a mini range bar, and the verdict word pinned to the right edge so one column
   scan finds everything out of range. Band/thumb reuse the range-bar language. */
.lab-panel { padding: 12px 18px 14px; margin-bottom: 12px; }
.lab-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding: 4px 0 8px; }
.lab-title { font-size: 10.5px; font-weight: 800; letter-spacing: 1.6px; text-transform: uppercase; color: var(--text-3); }
.lab-meta { font-size: 12px; font-weight: 650; color: var(--text-3); }
.lab-meta.warn { color: var(--warning); }
.labx-row { display: grid; grid-template-columns: minmax(0,1fr) auto 120px 74px; gap: 16px; align-items: center; padding: 8px 0; border-top: 1px solid var(--border); cursor: pointer; }
.labx-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.labx-row .nm { font-weight: 700; font-size: 13.5px; line-height: 1.3; }
.labx-row .ref { font-size: 11px; color: var(--text-3); margin-top: 1px; }
.labx-val { font-family: var(--serif); font-weight: 560; font-size: 17px; letter-spacing: -0.2px;
  font-variation-settings: "opsz" 40; font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.labx-val small { font-family: var(--font); font-size: 11px; color: var(--text-3); font-weight: 650; letter-spacing: 0; }
.labx-bar { position: relative; height: 3px; border-radius: 999px; background: rgba(29,31,36,0.08); }
.labx-bar.none { background: transparent; }
.labx-bar .band { position: absolute; top: 0; bottom: 0; background: rgba(63,157,110,0.30); border-radius: 999px; }
.labx-bar .thumb { position: absolute; top: 50%; width: 8px; height: 8px; border-radius: 50%; transform: translate(-50%,-50%); box-shadow: 0 0 0 2px var(--surface), 0 1px 3px rgba(0,0,0,0.22); }
.labx-status { font-size: 12.5px; font-weight: 700; text-align: right; white-space: nowrap; }
@media (max-width: 640px) { .labx-row { grid-template-columns: minmax(0,1fr) auto 64px; gap: 10px; } .labx-bar { display: none; } }
