/* ============================================================
   Self-hosted webfont — Baloo 2 (the display/brand face).
   Was loaded from Google Fonts (fonts.googleapis.com CSS + gstatic woff2);
   self-hosted now so no third-party CDN sees our users' IP/referrer on every
   pageload, and the CSP can drop Google entirely. Baloo 2 ships as a VARIABLE
   font — one woff2 per subset covers weights 500–700, so a single @font-face
   with a weight range is correct (and we only ship latin + latin-ext; the
   devanagari/vietnamese subsets Google served are dropped — unused here).
   Body copy stays system-ui (no webfont). SIL OFL 1.1 (Ek Type).
============================================================ */
@font-face {
  font-family: "Baloo 2";
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url("/fonts/baloo2-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Baloo 2";
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url("/fonts/baloo2-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Icons — self-hosted inline SVG (lib/icons.js via the {{{icon}}} helper); size with
   font-size or width/height, color via currentColor. Replaced Font Awesome. */
.icon { display: inline-block; width: 1em; height: 1em; vertical-align: -0.125em; flex: none; }

/* ============================================================
   Design tokens — warm palette, light + dark.
   :root is the light theme (also the no-JS fallback); [data-theme="dark"]
   overrides. theme.js resolves "auto" → light|dark before paint, so the html
   element always carries a concrete data-theme. Components consume tokens only,
   never raw hex — the palette is the single knob.
============================================================ */
:root {
  --bg: #faf7f3;          /* warm off-white, not clinical */
  --surface: #ffffff;     /* cards, bubbles, raised UI */
  --panel: var(--surface); /* legacy alias */
  --ink: #1b1a17;         /* warm near-black text */
  --text: var(--ink);     /* legacy alias (inputs, chips) */
  --muted: #8a857c;
  --accent: #ff6a3d;      /* warm coral — the brand */
  --accent-ink: #ffffff;  /* text/icon on an accent fill */
  --border: #ece7df;
  --error: #d64545;

  --font-display: "Baloo 2", system-ui, sans-serif;
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* App-shell geometry — a messaging client. Desktop: a fixed left nav rail +
     a full-width pane. Mobile (< 880px): the rail is replaced by a fixed top bar
     + bottom tab bar. --content-max caps reading width WITHIN the pane (chat,
     prose) so full-width text stays legible. The 880px breakpoint is hardcoded in
     media queries (custom props can't be used in media conditions). */
  --rail-w: 248px;        /* desktop nav rail */
  --content-max: 760px;   /* readable cap inside the pane */
  --chat-max: 1080px;     /* wider cap for the chat thread (full-width, left-aligned msgs) */
  --mtop-h: 54px;         /* mobile fixed top bar */
  --tabbar-h: 64px;       /* mobile fixed bottom nav */
}
[data-theme="dark"] {
  --bg: #16140f;          /* warm charcoal, not cold black */
  --surface: #1f1c16;
  --ink: #f0ece4;
  --muted: #9a948a;
  --accent: #ff7a52;      /* a touch brighter for dark contrast */
  --accent-ink: #ffffff;
  --border: #2c2820;
  --error: #ff6b6b;
}

/* ── Accent skins ("skins" in the UI) ────────────────────────────────────────
   The accent color is independent of light/dark — data-accent on <html> swaps
   the --accent token, mirroring how data-theme swaps the palette. Server-rendered
   before paint (layouts) so there's no flash; persisted on the User (POST /api/accent).
   "coral" is the default — it's the :root/[data-theme] values above, so it needs
   no block here. Every skin keeps white ink (--accent-ink stays #fff), at parity
   with coral, so the hardcoded white-on-accent fills (buttons, chips) stay legible.
   Each skin declares a LIGHT value and a (slightly brighter) DARK value; the
   two-attribute dark selector outranks the single-attribute [data-theme="dark"]
   base, so dark mode picks the dark value. The swatch list in lib/skins.js must
   stay in sync with the keys here (the route validates against it).

   Coral IS the default (the :root/[data-theme] values), but it gets an explicit
   block too so a coral SWATCH (a button carrying its own data-accent="coral") can
   paint itself from --accent regardless of the page's current skin. */
[data-accent="coral"]  { --accent: #ff6a3d; }
[data-theme="dark"][data-accent="coral"]  { --accent: #ff7a52; }
[data-accent="amber"]  { --accent: #f59e0b; }
[data-theme="dark"][data-accent="amber"]  { --accent: #fbb024; }
[data-accent="rose"]   { --accent: #f43f6b; }
[data-theme="dark"][data-accent="rose"]   { --accent: #ff5c81; }
[data-accent="violet"] { --accent: #8b5cf6; }
[data-theme="dark"][data-accent="violet"] { --accent: #a78bfa; }
[data-accent="teal"]   { --accent: #14b8a6; }
[data-theme="dark"][data-accent="teal"]   { --accent: #2dd4bf; }
[data-accent="blue"]   { --accent: #3b82f6; }
[data-theme="dark"][data-accent="blue"]   { --accent: #5b9bff; }

* { box-sizing: border-box; }
body {
  margin: 0;
  font: 16px/1.5 var(--font-body);
  background: var(--bg);
  color: var(--ink);
}
h1, h2, h3, .brand-wordmark { font-family: var(--font-display); }
/* .wrap is the NON-dashboard page frame (landing, auth, onboarding). The
   dashboard uses the app-shell (rail + pane) instead — see .app-shell below. */
.wrap { max-width: 980px; margin: 0 auto; padding: 24px; }
a { color: var(--accent); }
.muted { color: var(--muted); }
/* The HTML `hidden` attribute must win — any component that sets its own `display`
   (flex/grid/inline-flex) otherwise overrides it, so a JS/template `hidden` toggle
   silently does nothing (this was the storefront's "everything looks installed" bug:
   .skill-installed { display: inline-flex } beat [hidden]). One global rule fixes it
   everywhere and lets the per-component [hidden] overrides retire. */
[hidden] { display: none !important; }
.error { color: var(--error); }
/* Utility: hide regardless of a component's own display rule (the onboarding
   chat box, error lines, etc. carry class="hidden" until JS reveals them). */
.hidden { display: none !important; }
code, pre { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
pre { background: var(--panel); padding: 12px 14px; border-radius: 8px; overflow:auto; }

.hero { text-align: center; padding: 64px 0; }
.hero h1 { font-size: 56px; margin: 0; }
.tagline { font-size: 22px; }
.sub { color: var(--muted); }
.cta-row { margin-top: 28px; display: flex; gap: 12px; justify-content: center; }

.btn {
  display: inline-block; padding: 10px 18px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--panel); color: var(--ink);
  text-decoration: none; cursor: pointer; font-size: 15px;
}
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-ghost { background: transparent; }
.btn-danger { background: transparent; border-color: var(--error); color: var(--error); }
.btn-danger:hover { background: var(--error); color: #fff; }

/* Kill iOS Safari's double-tap-to-zoom on tappable controls (e.g. the chat
   jump-to-latest arrow read as a double-tap → the view zoomed in). Pinch-zoom
   is untouched, so accessibility zoom still works. */
button, a, textarea, .btn { touch-action: manipulation; }

/* ── Account / Settings (the human's profile) ─────────────────────────────── */
.settings { display: flex; flex-direction: column; gap: 16px; max-width: 540px; margin: 0 auto; }
.settings-head { display: flex; align-items: center; gap: 14px; }
.settings-title { margin: 0; font-size: 22px; }
.settings-sub { margin: 2px 0 0; font-size: 14px; }
.settings-section { background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 20px; display: flex; flex-direction: column; gap: 14px; }
.settings-section > h2 { margin: 0; font-size: 16px; }
.settings-section > h3 { margin: 0; }
.settings-section > .sub { margin: -8px 0 2px; font-size: 13px; }
.settings-section .field { gap: 6px; }
.settings-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.ff-input:disabled { opacity: 0.65; cursor: not-allowed; }
/* Notifications toggle: label left, switch right. */
.settings-toggle { justify-content: space-between; flex-wrap: nowrap; cursor: pointer; gap: 16px; }
.settings-toggle > span:first-child { font-size: 14px; line-height: 1.45; }
.ff-switch { flex: none; -webkit-appearance: none; appearance: none; width: 44px; height: 26px; border-radius: 999px; background: var(--border); position: relative; cursor: pointer; transition: background 0.15s ease; }
.ff-switch::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: #fff; transition: transform 0.15s ease; box-shadow: 0 1px 2px rgba(0,0,0,0.25); }
.ff-switch:checked { background: var(--accent); }
.ff-switch:checked::after { transform: translateX(18px); }
.ff-switch:disabled { opacity: 0.6; cursor: wait; }
/* Standalone notice page (unsubscribe confirmation). */
.notice { max-width: 480px; margin: 12vh auto 0; text-align: center; display: flex; flex-direction: column; gap: 14px; align-items: center; }
.notice-heading { margin: 0; }
.notice-message { margin: 0; line-height: 1.55; }

.key-status { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0; font-size: 14px; }
.key-status .ok { color: var(--accent); font-weight: 600; }
.key-status .warn { color: var(--error); font-weight: 600; }
.key-status .ok .icon, .key-status .warn .icon { margin-right: 4px; }
.key-rotate { display: flex; gap: 8px; }
.key-rotate .ff-input { flex: 1; }

.plan-badge { display: inline-block; padding: 5px 14px; border-radius: 999px; border: 1px solid var(--border); background: var(--bg); font-size: 13px; text-transform: capitalize; font-weight: 600; }

/* Danger zone (Profile tab) — the data-custody delete affordance. */
/* The danger zone is a .settings-section card like the others — it sits in the
   same flex gap, so it needs NO extra top margin/padding (that double-spaced it).
   A faint error-tinted border keeps it distinct without shouting. */
.danger-zone { border-color: color-mix(in srgb, var(--error) 35%, var(--border)); }
.danger-zone h3 { margin: 0 0 6px; color: var(--error); font-size: 15px; }
.danger-zone .muted { margin: 0 0 12px; }
.acct-delete-confirm { margin-top: 14px; display: flex; flex-direction: column; gap: 8px; max-width: 360px; }
.acct-delete-actions { display: flex; gap: 8px; }

/* Inputs (shared by onboarding + the profile knobs) */
.ff-input {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 16px; /* 16px keeps iOS from auto-zooming on focus */
  font-family: inherit;
}
.ff-input:focus { outline: none; border-color: var(--accent); }

/* Form fields + chips — shared by the account/settings page. */
.field { display: flex; flex-direction: column; gap: 8px; }
.field > label { font-size: 13px; color: var(--text); font-weight: 600; }
.field > label .muted { font-weight: 400; }
.chipset { display: flex; gap: 8px; flex-wrap: wrap; }
.chip {
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 8px 16px;
  border-radius: 999px;
  cursor: pointer;
  font-size: 14px;
  transition: border-color 0.12s, background 0.12s;
}
.chip:hover { border-color: var(--accent); }
.chip.active { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Accent skin picker — a row of color swatches. Each swatch carries its OWN
   data-accent="<key>", so the [data-accent] blocks above re-set --accent on that
   button and it paints itself (no inline styles — the CSP forbids them, and this
   reuses the one accent palette so the preview can't drift from the applied color).
   The selected one gets a ring. Same data-field wiring shape as the theme chipset. */
.swatchset { display: flex; gap: 12px; flex-wrap: wrap; }
.swatch {
  width: 34px; height: 34px; border-radius: 50%; padding: 0; cursor: pointer;
  background: var(--accent); border: 2px solid var(--surface);
  box-shadow: 0 0 0 1px var(--border);
  transition: box-shadow 0.12s, transform 0.08s;
}
.swatch:hover { transform: scale(1.06); }
.swatch.active { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent); }
.swatch:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent); }

.pf-status { min-height: 18px; font-size: 13px; margin: 0; }
.pf-status.err { color: var(--error); }

/* ── About <buddy> (read-only profile — the friendly face of the glass box) ── */
.about { display: flex; flex-direction: column; gap: 16px; max-width: 540px; margin: 0 auto; }
.about-hero { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px; padding: 16px 0 4px; }
.about-avatar { font-size: 64px; line-height: 1; }
.about-name { margin: 0; font-size: 28px; }
.about-creature { margin: 0; color: var(--muted); font-size: 15px; }

.about-invite { background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 20px; display: flex; flex-direction: column; gap: 12px; }
.about-invite__lead { margin: 0; line-height: 1.6; }
.about-invite__eg { margin: 0; font-size: 14px; line-height: 1.7; }
.about-invite__eg em { color: var(--ink); font-style: italic; }
.about-invite__cta { align-self: flex-start; }

.about-glass { display: flex; align-items: center; gap: 12px; padding: 14px 16px; background: var(--surface); border: 1px solid var(--border); border-radius: 16px; text-decoration: none; color: var(--ink); }
.about-glass:hover { border-color: var(--accent); }
.about-glass__icon { display: grid; place-items: center; flex: none; width: 40px; height: 40px; border-radius: 10px; background: var(--bg); color: var(--accent); font-size: 18px; }
.about-glass__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.about-glass__title { font-weight: 600; }
.about-glass__sub { font-size: 13px; }
.about-glass > .icon--chevron-right { margin-left: auto; color: var(--muted); width: 12px; height: 12px; }

.card { background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 28px; }
.card.narrow { max-width: 420px; margin: 48px auto; }
.stack { display: flex; flex-direction: column; gap: 14px; }
.stack label { display: flex; flex-direction: column; gap: 6px; font-size: 14px; }
.stack input {
  padding: 10px 12px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--bg); color: var(--ink); font-size: 15px;
}

/* ════════════════════════════════════════════════════════════════════════════
   APP SHELL — a messaging client. Desktop (≥880px): a fixed left nav rail + a
   scrolling pane. Mobile (<880px): the rail is hidden; a fixed top bar (.mtop) +
   bottom tab bar (.tabbar) take over. The 880px breakpoint is hardcoded (custom
   props can't drive media queries).
   ════════════════════════════════════════════════════════════════════════════ */
.app-shell { display: flex; min-height: 100dvh; }
.pane { flex: 1; min-width: 0; }

.brand { display: inline-flex; align-items: center; gap: 8px; text-decoration: none; }
.brand .icon { width: 24px; height: 24px; color: var(--accent); }
/* Brand mark = the same 🙂 emoji the account avatar uses (.acct-avatar), so the
   product face and the "you" face match. Emoji, not the {{icon "friend"}} glyph. */
.brand-face { font-size: 24px; line-height: 1; flex: none; }
.brand-wordmark { font-weight: 700; font-size: 22px; letter-spacing: -0.02em; color: var(--ink); }
.brand-dot { color: var(--accent); }

/* ── The rail (desktop) ─────────────────────────────────────────────────────── */
.rail {
  position: sticky; top: 0; align-self: flex-start; flex: none;
  width: var(--rail-w); height: 100dvh;
  display: flex; flex-direction: column; gap: 6px;
  padding: 18px 14px; background: var(--bg); border-right: 1px solid var(--border);
}
.rail__brand { padding: 4px 10px 12px; }

.rail__nav { display: flex; flex-direction: column; gap: 2px; margin-top: 6px; }
.rail__item {
  display: flex; align-items: center; gap: 12px; padding: 10px 12px;
  border-radius: 10px; color: var(--muted); text-decoration: none; font-size: 15px;
}
.rail__item .icon { width: 20px; height: 20px; }
.rail__item:hover { background: var(--surface); color: var(--ink); }
.rail__item.is-active { background: var(--surface); color: var(--ink); font-weight: 600; }
.rail__item.is-active .icon { color: var(--accent); }
.rail__count {
  margin-left: auto; font-size: 12px; color: var(--muted);
  background: var(--bg); border: 1px solid var(--border); border-radius: 999px; padding: 0 7px;
  /* Always 600 so the active state's font-weight bump (.rail__item.is-active) doesn't
     re-weight the digits and jiggle the pill's width when you click between sections. */
  font-weight: 600;
}
.rail__foot { margin-top: auto; }

/* ── Mobile top bar (.mtop) — brand left, buddy + account right. Hidden ≥880px. ── */
.mtop {
  display: none; position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  align-items: center; justify-content: space-between; gap: 10px;
  height: var(--mtop-h); padding: 0 14px;
  background: var(--bg); border-bottom: 1px solid var(--border);
}
.mtop__brand { flex: none; }
.mtop__right { display: flex; align-items: center; gap: 8px; }

/* ── Buddy switcher (.bswitch) — rail row by default; avatar circle in the mtop.
      The menu (switch / new / About) is identical in both. ───────────────────── */
.bswitch { position: relative; }
.bswitch-btn {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 10px;
  border: 1px solid transparent; border-radius: 12px; background: none;
  color: var(--ink); font-family: inherit; text-align: left; cursor: pointer;
}
.bswitch-btn:hover { background: var(--surface); }
/* Mid-birth: a non-interactive switcher (no menu, no caret) — just the newborn's
   ✨+name, filling in live. Mirrors .bswitch-btn padding so it sits identically. */
.bswitch--newborn { display: flex; align-items: center; gap: 10px; width: 100%; padding: 10px; }
.bswitch-avatar { font-size: 28px; line-height: 1; flex: none; }
.bswitch-label { display: flex; flex-direction: column; min-width: 0; }
.bswitch-name { font-family: var(--font-display); font-weight: 700; font-size: 17px; }
.bswitch-sub { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bswitch-caret { margin-left: auto; flex: none; font-size: 12px; color: var(--muted); }
/* Mobile top bar: avatar-only circular trigger. */
.mtop .bswitch-btn { width: 38px; height: 38px; padding: 0; justify-content: center; border-color: var(--border); border-radius: 999px; background: var(--surface); }
.mtop .bswitch-avatar { font-size: 22px; }
.mtop .bswitch-label, .mtop .bswitch-caret { display: none; }

.bswitch-menu {
  position: absolute; left: 0; top: calc(100% + 8px); z-index: 60;
  min-width: 220px; padding: 8px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
}
.bswitch-menu[hidden] { display: none; }
.mtop .bswitch-menu { left: auto; right: 0; }
.bswitch-menu__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); padding: 6px 10px 4px; }
.bswitch-menu__sep { height: 1px; background: var(--border); margin: 6px 4px; }
.bswitch-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px 10px; border-radius: 10px; text-decoration: none; color: var(--ink); font-size: 14px;
}
.bswitch-item:hover { background: var(--bg); }
.bswitch-item.is-active { font-weight: 600; }
.bswitch-item__avatar { display: grid; place-items: center; flex: none; width: 28px; height: 28px; border-radius: 999px; background: var(--bg); font-size: 16px; }
.bswitch-item__avatar--new, .bswitch-item__avatar--ghost { color: var(--muted); font-size: 12px; }
.bswitch-item__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bswitch-item__check { margin-left: auto; color: var(--accent); font-size: 12px; }

/* ── Account cluster (shared: rail foot + mobile top bar) ───────────────────── */
.acct { position: relative; }
.acct-btn {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 10px;
  border-radius: 12px; border: 1px solid transparent; background: none;
  color: var(--ink); font-family: inherit; text-align: left; cursor: pointer; line-height: 1.2;
}
.acct-btn:hover { background: var(--surface); }
.acct-avatar { font-size: 22px; line-height: 1; flex: none; }
.acct-avatar--lg { font-size: 26px; }
.acct-btn__label { display: flex; flex-direction: column; min-width: 0; }
.acct-btn__name { font-size: 14px; font-weight: 600; }
.acct-btn__email { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 150px; }
/* Mobile top bar: avatar-only circular trigger (no label row). */
.mtop .acct-btn { width: 38px; height: 38px; padding: 0; justify-content: center; border-color: var(--border); border-radius: 999px; background: var(--surface); }
.mtop .acct-btn__label { display: none; }

.acct-menu {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 60;
  min-width: 210px; padding: 8px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
}
/* Rail foot opens UPWARD and stretches to the rail width. */
.acct--up .acct-menu { top: auto; bottom: calc(100% + 8px); left: 0; right: 0; }
.acct-menu[hidden] { display: none; }
.acct-menu__head {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px 12px; margin-bottom: 6px; border-bottom: 1px solid var(--border);
}
.acct-email { font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acct-menu__form { margin: 0; }
.acct-menu__item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px; border: none; background: none; border-radius: 10px;
  color: var(--ink); font-size: 14px; font-family: inherit; text-align: left;
  text-decoration: none; cursor: pointer;
}
.acct-menu__item:hover { background: var(--bg); }
.acct-menu__item .icon { width: 18px; height: 18px; color: var(--muted); }
.acct-menu__item--dev { color: var(--muted); }

/* ── Bottom tab bar (mobile only, full width) ──────────────────────────────── */
.tabbar {
  display: none; position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
  background: var(--surface); border-top: 1px solid var(--border);
  box-shadow: 0 -6px 20px rgba(0, 0, 0, 0.12);
  padding: 6px 6px calc(6px + env(safe-area-inset-bottom));
}
.tabbar__item {
  flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 2px; padding: 6px 0; border-radius: 10px;
  color: var(--muted); text-decoration: none; font-size: 11px;
}
.tabbar__item .icon { width: 18px; height: 18px; }
.tabbar__item:hover { color: var(--ink); }
.tabbar__item.is-active { color: var(--accent); }

/* ── The pane content: a readable column, centered. Files/Skills opt wider. ─── */
.tabpane { max-width: var(--content-max); margin: 0 auto; padding: 28px 24px 56px; }
.tabpane.hidden { display: none; }
#tab-files, #tab-skills { max-width: 1080px; }

/* ── Mobile: hide the rail, show the bars, pad the pane clear of both. ──────── */
@media (max-width: 879px) {
  .rail { display: none; }
  .mtop { display: flex; }
  .tabbar { display: flex; }
  .tabpane { max-width: 640px; padding: calc(var(--mtop-h) + 16px) 16px calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 16px); }
  #tab-files, #tab-skills { max-width: 640px; }
}

/* ── Chat — a native thread filling the WHOLE pane: full-width header + scroller
      + composer, each with its inner content centered to reading width. The
      scrollbar rides the panel edge; the text stays in a tidy column. ───────── */
#tab-chat {
  max-width: none; margin: 0;            /* fill the pane, edge to edge */
  display: flex; flex-direction: column;
  height: 100dvh; padding: 0;            /* the three bars own their padding */
}

/* Fixed header bar — spans the pane, content centered. */
.chat-head { flex: none; border-bottom: 1px solid var(--border); padding: 12px 24px; }
.buddy-strip { display: flex; align-items: center; gap: 8px; max-width: var(--chat-max); margin: 0 auto; }
.buddy-strip__avatar { font-size: 22px; }
.buddy-strip__name { font-weight: 600; }
.buddy-strip__copy { margin-left: auto; font-size: 13px; padding: 5px 12px; }
.buddy-strip__restart { font-size: 13px; padding: 5px 12px; color: var(--muted); }
.buddy-strip__restart:hover { color: var(--error); }
.onb-restart-msg { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.5; }

/* The scroller IS the panel; each row centers itself to the (wide) chat width. */
.messages { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; overflow-y: auto; padding: 16px 24px; }
.messages > .ce-row { width: 100%; max-width: var(--chat-max); margin-left: auto; margin-right: auto; }
.note { align-self: center; font-size: 12px; color: var(--muted); }

/* Composer docked at the foot — full-width bar, content centered. The input is a
   <textarea> so long messages word-wrap; it auto-grows one line at a time (chat-core)
   up to max-height, then scrolls. align-items:flex-end keeps the send button on the
   last line as it grows. */
.chat-form { flex: none; border-top: 1px solid var(--border); padding: 12px 24px; }
.chat-form__inner { display: flex; gap: 10px; align-items: flex-end; max-width: var(--chat-max); margin: 0 auto; }
.chat-form textarea {
  flex: 1; padding: 11px 18px; border-radius: 14px;
  border: 1px solid var(--border); background: var(--surface); color: var(--ink);
  font-size: 16px; font-family: inherit; line-height: 1.4; box-sizing: border-box;
  resize: none; min-height: calc(1.4em * 2 + 24px); max-height: 160px; overflow-y: hidden;
}
.chat-form textarea:focus { outline: none; border-color: var(--accent); }
.chat-form button[type="submit"] {
  flex: none; width: 44px; height: 44px; padding: 0; border-radius: 999px;
  display: grid; place-items: center; font-size: 16px;
}
.chat-tip {
  max-width: var(--content-max); margin: 8px auto 0; padding: 0 6px;
  font-size: 12px; color: var(--muted); text-align: center;
}
.chat-tip kbd {
  font: inherit; background: var(--surface); border: 1px solid var(--border);
  border-radius: 5px; padding: 1px 6px; color: var(--ink);
}

@media (max-width: 879px) {
  /* The mobile top bar already shows the active buddy (avatar + name), so the
     in-pane buddy header is redundant here — drop it to give chat breathing room.
     Scoped to the dashboard pane: the onboarding ceremony's .chat-head carries the
     Copy / Start-over controls and must stay. */
  #tab-chat .chat-head { display: none; }
  #tab-chat { height: 100dvh; padding: var(--mtop-h) 0 0; }
  .messages { padding: 8px 16px; }
  .messages > .ce-row { max-width: 640px; }
  .chat-form { padding: 8px 16px; margin-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); }
  .chat-form__inner { max-width: 640px; }
  /* Shorter composer on mobile — start one line tall (it auto-grows as you type)
     so the keyboard + thread get more of the viewport. */
  .chat-form textarea { min-height: calc(1.4em + 24px); }
}

/* ── Glass box (Files) — legible, grouped, read-only ──────────────────────── */
.glass-intro { margin: 0 0 16px; font-size: 14px; }
.glass-group { margin-bottom: 24px; }
.glass-group__label {
  font-family: var(--font-body); font-weight: 600; font-size: 12px;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin: 0 0 10px;
}

.glass-item {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  padding: 12px 14px; margin-bottom: 8px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
  color: var(--ink); font-family: inherit; cursor: pointer;
  transition: border-color 0.12s, transform 0.04s;
}
.glass-item:hover { border-color: var(--accent); }
.glass-item:active { transform: scale(0.995); }
.glass-item.is-active { border-color: var(--accent); }
.glass-item__icon {
  display: grid; place-items: center; flex: none; width: 38px; height: 38px;
  border-radius: 10px; background: var(--bg); color: var(--accent); font-size: 16px;
}
.glass-item__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.glass-item__title { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-weight: 600; font-size: 15px; }
.glass-item__file { background: none; padding: 0; font-size: 11px; font-weight: 400; color: var(--muted); }
.glass-item__blurb { font-size: 13px; color: var(--muted); }
.glass-item__chev { margin-left: auto; flex: none; font-size: 12px; color: var(--muted); }

.glass-timeline {
  margin-top: 4px; padding: 8px 14px 6px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
}
.glass-timeline__head { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); padding: 6px 0; }
.glass-timeline__head .icon { color: var(--accent); }
.glass-timeline__empty { font-size: 13px; padding: 4px 0 8px; }
.glass-day {
  display: flex; align-items: baseline; gap: 10px; width: 100%; text-align: left;
  padding: 10px 6px; border: none; border-bottom: 1px solid var(--border);
  background: none; color: var(--ink); font-family: inherit; cursor: pointer; border-radius: 8px;
}
.glass-day:last-child { border-bottom: none; }
.glass-day:hover { background: var(--bg); }
.glass-day.is-active { color: var(--accent); }
.glass-day__label { font-weight: 600; font-size: 14px; }
.glass-day__date { margin-left: auto; font-size: 12px; }

/* Reader — BASE = mobile: a full-screen slide-in overlay ("like turning a page").
   files.js toggles .is-open on click / Back. The desktop master-detail override
   follows below (source order: base first, so the media query wins ≥880px). */
.glass-reader {
  position: fixed; inset: 0; z-index: 60; overflow: auto;
  background: var(--bg);
  transform: translateX(100%); transition: transform 0.22s ease;
}
.glass-reader.is-open { transform: translateX(0); }
.glass-reader__inner {
  max-width: 640px; margin: 0 auto;
  padding: calc(var(--mtop-h) + 12px) 16px calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 16px);
}
.glass-reader__back {
  display: inline-flex; align-items: center; gap: 6px; margin-bottom: 14px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 999px;
  padding: 8px 14px; color: var(--ink); font-family: inherit; font-size: 14px; cursor: pointer;
}
.glass-reader__back:hover { border-color: var(--accent); }
.glass-reader__head { border-bottom: 1px solid var(--border); padding-bottom: 10px; margin-bottom: 14px; }
.glass-reader__title { margin: 0 0 2px; font-size: 20px; }
.glass-reader__path { background: none; padding: 0; font-size: 12px; color: var(--muted); }
.glass-reader__empty { padding: 8px 0; }

/* Desktop (≥880px): Files fills the whole pane like Chat. A fixed file-nav column
   sits flush against the rail (its own scroll — an "expanded menu" off the sidebar);
   the reader fills the rest and behaves like the chat thread — a full-height scroller
   with the bar at the pane edge and the TEXT centered to reading width. The mobile
   slide-in overlay above is untouched (it's the base style; this media query wins). */
@media (min-width: 880px) {
  #tab-files {
    max-width: none; margin: 0; padding: 0;   /* fill the pane, like #tab-chat */
    height: 100dvh;
    display: grid; grid-template-columns: 480px minmax(0, 1fr);
  }
  /* The file nav — an expanded menu against the rail, with its own scroll. */
  .glass-list {
    height: 100dvh; overflow-y: auto;
    padding: 28px 20px 56px;
    border-right: 1px solid var(--border);
  }
  /* The reader — a chat-style full-height scroller. Neutralize the mobile slide-in
     (fixed/transform), let the text center itself like .messages rows do. */
  .glass-reader {
    position: static; inset: auto; z-index: auto; transform: none;
    height: 100dvh; max-height: none; overflow-y: auto;
    background: var(--bg); border: none; border-radius: 0;
  }
  .glass-reader__inner { max-width: none; margin: 0; padding: 0; }   /* full-bleed; head + body self-center */
  /* Match the chat header (.chat-head + .buddy-strip): a full-width, bottom-bordered
     bar pinned to the top, its content LEFT-aligned in the same centered reading
     column — title + filename inline, exactly like a menu row / the buddy name. */
  .glass-reader__head {
    position: sticky; top: 0; z-index: 1; background: var(--bg);
    border-bottom: 1px solid var(--border);
    padding: 14px 0; margin: 0; display: flex;   /* border full-width; sides padded on the inner */
  }
  .glass-reader__headinner {
    max-width: var(--content-max); width: 100%; margin: 0 auto;
    padding: 0 24px;   /* same 24px side inset as the doc body → title aligns with the text */
    display: flex; align-items: baseline; gap: 10px;
  }
  .glass-reader__title { margin: 0; font-size: 18px; font-weight: 700; }
  .glass-reader__path { font-size: 12px; font-weight: 400; color: var(--muted); background: none; padding: 0; }
  /* The doc body + empty/loading states share the centered reading column. */
  .glass-reader__body .md { max-width: var(--content-max); margin: 0 auto; padding: 28px 24px 56px; }
  .glass-reader__empty { max-width: var(--content-max); margin: 0 auto; padding: 28px 24px; }
  .glass-reader__back { display: none; }
}

/* Reader loading spinner — sits in the body while the doc fetches, so the header
   (the file name) renders instantly and never flickers. Centered in either layout. */
.glass-spinner {
  width: 22px; height: 22px; margin: 56px auto;
  border: 2px solid var(--border); border-top-color: var(--accent);
  border-radius: 50%; animation: glass-spin 0.7s linear infinite;
}
@keyframes glass-spin { to { transform: rotate(360deg); } }

/* Rendered markdown body (shared by the reader). */
.md { line-height: 1.6; }
.md h1, .md h2, .md h3 { margin: 0.8em 0 0.3em; }
.md code { background: var(--bg); padding: 1px 5px; border-radius: 4px; }
.md ul { padding-left: 20px; }

/* ── Skills (marketplace placeholder) ──────────────────────────────────────── */
.skills-head { margin-bottom: 22px; }
.skills-title { margin: 0 0 6px; }
.skills-soon {
  text-align: center; padding: 48px 28px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 18px;
}
.skills-soon__icon {
  display: inline-grid; place-items: center; width: 64px; height: 64px; margin-bottom: 14px;
  border-radius: 16px; background: var(--bg); color: var(--accent); font-size: 28px;
}
.skills-soon__title { margin: 0 0 6px; }

/* Storefront grid */
.skill-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.skill-card { background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 20px; display: flex; flex-direction: column; gap: 12px; }
.skill-card__top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.skill-card__name { margin: 0; font-size: 18px; display: flex; align-items: center; gap: 10px; }
.skill-card__icon { display: grid; place-items: center; flex: none; width: 38px; height: 38px; border-radius: 11px; background: var(--bg); color: var(--accent); font-size: 17px; }
.skill-card__price { font-size: 13px; font-weight: 600; color: var(--accent); flex: none; }
.skill-card__blurb { margin: 0; font-size: 14px; line-height: 1.5; }
.skill-card__action { margin-top: auto; display: flex; flex-direction: column; gap: 6px; }
.skill-installed { display: inline-flex; align-items: center; gap: 10px; color: var(--accent); font-weight: 600; font-size: 14px; }
.skill-installed .btn { font-weight: 400; }

/* Skill tag (Free / Plus) — replaces the old per-skill price chip. */
.skill-card__tag { font-size: 12px; font-weight: 600; color: var(--muted); flex: none; border: 1px solid var(--border); border-radius: 999px; padding: 2px 10px; }
.skill-card__tag--plus { color: var(--accent); border-color: var(--accent); }
.skill-card--locked { opacity: 0.92; }
.skill-card--locked .skill-card__icon { color: var(--muted); }
.skill-unlock { display: inline-flex; align-items: center; gap: 8px; }
.skill-unlock .icon { width: 15px; height: 15px; }

/* Marketplace "unlock with Plus" banner (storefront, when locked). */
.skills-unlock {
  display: flex; align-items: center; gap: 16px; margin-bottom: 20px;
  background: var(--surface); border: 1px solid var(--accent); border-radius: 14px; padding: 16px 18px;
}
.skills-unlock__icon { display: grid; place-items: center; flex: none; width: 42px; height: 42px; border-radius: 11px; background: var(--bg); color: var(--accent); }
.skills-unlock__icon .icon { width: 21px; height: 21px; }
.skills-unlock__copy { display: flex; flex-direction: column; gap: 2px; }
.skills-unlock .btn { margin-left: auto; flex: none; }

/* Billing card (Settings → pal.fun Plus). */
.plan-badge--plus { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.billing-plans { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 4px; }
.billing-banner { display: flex; align-items: center; gap: 8px; border-radius: 10px; padding: 10px 14px; font-size: 14px; margin: 0 0 12px; }
.billing-banner .icon { width: 17px; height: 17px; flex: none; }
.billing-banner--ok { background: rgba(255,106,61,0.1); color: var(--ink); border: 1px solid var(--accent); }
.billing-banner--cancel { background: var(--bg); color: var(--muted); border: 1px solid var(--border); }

/* Calendar — co-owned month grid + agenda. Events + days are clickable; edits go
   through a modal (cal-modal). The buddy writes the same events via chat. */
.cal-empty { text-align: center; padding: 48px 28px; background: var(--surface); border: 1px solid var(--border); border-radius: 18px; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.cal-empty__icon { display: inline-grid; place-items: center; width: 64px; height: 64px; border-radius: 16px; background: var(--bg); color: var(--accent); font-size: 28px; }
.cal-empty h1 { margin: 6px 0 0; }
.cal-empty p { max-width: 420px; }
.cal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; gap: 12px; flex-wrap: wrap; }
.cal-title { margin: 0; font-size: 22px; }
.cal-actions { display: flex; align-items: center; gap: 10px; }
.cal-nav { display: flex; gap: 6px; }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
.cal-dow { background: var(--surface); text-align: center; font-size: 12px; color: var(--muted); padding: 8px 0; font-weight: 600; }
.cal-day { background: var(--panel); min-height: 92px; padding: 6px; display: flex; flex-direction: column; gap: 3px; cursor: pointer; transition: background 0.1s; }
.cal-day:hover { background: var(--bg); }
.cal-day--out { background: var(--surface); }
.cal-day--out .cal-day__num { color: var(--muted); opacity: 0.6; }
.cal-day--today .cal-day__num { background: var(--accent); color: #fff; border-radius: 50%; width: 22px; height: 22px; display: inline-grid; place-items: center; }
.cal-day__num { font-size: 12px; color: var(--ink); }
.cal-ev { display: block; width: 100%; text-align: left; font-family: inherit; border: none; cursor: pointer; font-size: 11px; line-height: 1.3; background: rgba(255,106,61,0.14); color: var(--ink); border-radius: 6px; padding: 2px 5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-ev:hover { background: rgba(255,106,61,0.28); }
.cal-ev b { font-weight: 600; }
.cal-agenda { margin-top: 26px; }
.cal-agenda__list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; }
.cal-agenda__btn { display: flex; gap: 14px; width: 100%; text-align: left; font-family: inherit; background: none; border: none; border-bottom: 1px solid var(--border); cursor: pointer; padding: 10px 4px; color: var(--ink); border-radius: 6px; }
.cal-agenda__btn:hover { background: var(--bg); }
.cal-agenda__when { flex: none; width: 180px; color: var(--muted); font-size: 14px; }
.cal-agenda__title { font-size: 15px; }
.cal-agenda__empty { padding: 10px 4px; }

/* Edit/create modal (native <dialog>). */
.cal-modal { width: min(480px, calc(100vw - 32px)); border: 1px solid var(--border); border-radius: 16px; padding: 0; background: var(--surface); color: var(--ink); box-shadow: 0 18px 50px rgba(0,0,0,0.28); }
.cal-modal::backdrop { background: rgba(0,0,0,0.45); }
.cal-modal form { padding: 18px 20px 20px; display: flex; flex-direction: column; gap: 12px; }
.cal-modal__head { display: flex; align-items: center; justify-content: space-between; }
.cal-modal__title { margin: 0; font-size: 18px; }
.cal-modal__x { background: none; border: none; cursor: pointer; color: var(--muted); font-size: 18px; padding: 4px; line-height: 1; }
.cal-modal__x:hover { color: var(--ink); }
.cal-modal__err { margin: 0; color: var(--error); font-size: 13px; }
.cal-field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
.cal-field > span { color: var(--muted); }
.cal-field input, .cal-field select, .cal-field textarea {
  font-family: inherit; font-size: 14px; color: var(--ink); background: var(--bg);
  border: 1px solid var(--border); border-radius: 9px; padding: 8px 10px; width: 100%;
}
.cal-field textarea { resize: vertical; }
.cal-field input:focus, .cal-field select:focus, .cal-field textarea:focus { outline: none; border-color: var(--accent); }
.cal-field-row { display: flex; gap: 12px; flex-wrap: wrap; }
.cal-field-row > .cal-field { flex: 1; min-width: 120px; }
.cal-times { display: flex; gap: 12px; flex: 2; min-width: 180px; }
.cal-times > .cal-field { flex: 1; }
.cal-check { display: flex; align-items: center; gap: 8px; font-size: 14px; cursor: pointer; }
.cal-check input { width: auto; }
.cal-modal__actions { display: flex; align-items: center; gap: 10px; margin-top: 4px; }
.cal-modal__spacer { flex: 1; }
.btn-danger-ghost { background: transparent; border: 1px solid transparent; color: var(--error); cursor: pointer; font-family: inherit; padding: 8px 12px; border-radius: 9px; }
.btn-danger-ghost:hover { border-color: var(--error); }

@media (max-width: 620px) {
  .cal-day { min-height: 64px; }
  .cal-agenda__btn { flex-direction: column; gap: 2px; }
  .cal-agenda__when { width: auto; }
}

/* Recipe/artifact DETAIL body styles — used by the artifact-doc / artifact-list partials
   injected into the shared glass-box reader. The Library LIST itself now reuses the Files
   glass-box classes (.glass-list / .glass-group / .glass-item) for true parity — see the
   Library block further down. */
.rec-tag { font-size: 11px; background: var(--bg); border: 1px solid var(--border); color: var(--muted); border-radius: 6px; padding: 1px 7px; }

/* The rendered recipe body (injected into the shared reader). */
.rec-recipe__tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.rec-recipe h3 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); margin: 20px 0 8px; }
.rec-ingredients { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 4px; }
.rec-method { margin: 0; padding-left: 22px; display: flex; flex-direction: column; gap: 8px; line-height: 1.5; }
.rec-recipe__notes { margin: 0; line-height: 1.55; }
.rec-recipe__source { margin: 18px 0 0; font-size: 12px; font-style: italic; }

/* Desktop (≥880px): the rendered artifact body shares the centered reading column (the
   parallel of .glass-reader__body .md). The Library list's master-detail grid lives in the
   Library block below; the .glass-list / .glass-reader desktop rules are global, so they
   already style both columns. */
@media (min-width: 880px) {
  .glass-reader__body .rec-recipe { max-width: var(--content-max); margin: 0 auto; padding: 28px 24px 56px; }
}

/* onboarding ceremony — centering/width come from .tabpane (it's pane content now) */
.stage .step { background: var(--panel); border: 1px solid var(--border); border-radius: 16px; padding: 36px; text-align: center; }
.stage h1 { font-size: 34px; margin: 0 0 8px; }
.stage .q { font-size: 24px; margin: 0 0 22px; font-weight: 600; }
.stage .answer { margin: 0 auto 8px; max-width: 460px; }
.step-actions { margin-top: 18px; }
.small { font-size: 13px; }

/* Provider picker (the Awakening) — "works with Claude or ChatGPT" as a segmented
   choice. Selected option is .btn-primary; the other a plain .btn. */
.provider-pick { display: flex; gap: 8px; margin: 0 0 12px; flex-wrap: wrap; }
.provider-pick .btn { flex: 1; min-width: 120px; }
.provider-pick .btn .muted { font-weight: 400; margin-left: 4px; }
.provider-pick .btn-primary .muted { color: rgba(255,255,255,0.85); }

/* Onboarding bootstrap chat — the buddy wakes up and interviews you. It uses the
   EXACT same chrome as the dashboard chat: when the ceremony enters its chat phase
   (.chatting, set by onboarding.js) the section drops its .tabpane centering and
   becomes a full-pane native thread — full-width header + scroller + docked pill
   composer — driven by the shared .chat-head/.messages/.chat-form rules below. The
   bubbles were already shared (.ce-* rows, incl. the in-bubble working spinner). */
.ceremony.chatting { max-width: none; margin: 0; padding: 0; height: 100dvh; display: flex; flex-direction: column; }
.ceremony.chatting #stage { display: none; }
.onb-chat { flex: 1; min-height: 0; display: flex; flex-direction: column; }

@media (max-width: 879px) {
  /* Match #tab-chat on mobile: fill the viewport, clear the fixed top bar. */
  .ceremony.chatting { height: 100dvh; padding: var(--mtop-h) 0 0; }
  /* The bottom tab bar only exists once you have a buddy (adding another) — on the
     first-ever onboarding there's none, so don't reserve space for it. */
  .ceremony.chatting .chat-form { margin-bottom: env(safe-area-inset-bottom); }
  .ceremony.chatting.with-tabbar .chat-form { margin-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom)); }
}

/* ── The chat component (public/js/chat-core.js) ───────────────────────────── */

/* A messaging-client thread, but laid out like Claude Code: BOTH senders start at
   the left margin (avatar → name → text), and the text fills the full column width
   instead of a narrow 78% bubble — so long replies read horizontally, not as a tall
   vertical ribbon. The user is distinguished by a subtle card; the buddy is plain
   page text. */
.ce-row { position: relative; display: flex; gap: 10px; align-items: flex-start; margin: 14px 0; }
.ce-row.grouped { margin-top: 4px; }

/* Per-message hover actions (copy this / copy to end) — a floating pill toolbar at
   the row's top-right. Hidden until you hover the row (or focus a button); on touch
   (no hover) it sits faintly visible since there's no hover to reveal it. A surface
   background keeps it legible where it overlaps the start of a full-width reply. */
.ce-actions {
  position: absolute; top: -6px; right: 0; display: flex; gap: 4px; padding: 3px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.10); opacity: 0; pointer-events: none;
  transition: opacity 0.12s; z-index: 2;
}
.ce-row:hover > .ce-actions, .ce-actions:focus-within,
.ce-row.actions-open > .ce-actions { opacity: 1; pointer-events: auto; }
.ce-act {
  border: none; background: none; color: var(--muted); cursor: pointer;
  font-family: inherit; font-size: 12px; padding: 3px 8px; border-radius: 7px; white-space: nowrap;
}
.ce-act:hover { background: var(--bg); color: var(--ink); }

/* "Loading older messages" spinner — absolute (out of flow, so toggling it never
   shifts the scroll-position math) at the top of the thread during a scroll-up load. */
.ce-top-loader { position: absolute; top: 8px; left: 50%; transform: translateX(-50%); z-index: 3; }

/* Jump-to-latest — a floating round button anchored to the chat pane (NOT the
   scroller, so it stays put while you scroll). The host gets position:relative; the
   button's `bottom` is set by JS to sit just above the composer at any height. */
.ce-has-jump { position: relative; }
.ce-jump {
  position: absolute; right: 24px; /* bottom set inline by chat-core.js */
  width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center;
  background: var(--surface); color: var(--ink); border: 1px solid var(--border);
  box-shadow: 0 3px 12px rgba(0,0,0,0.16); cursor: pointer; z-index: 5;
  transition: border-color 0.12s, color 0.12s, transform 0.08s;
}
.ce-jump:hover { border-color: var(--accent); color: var(--accent); transform: translateY(1px); }
.ce-jump svg { width: 20px; height: 20px; }
@media (max-width: 879px) { .ce-jump { right: 16px; } }

.ce-avatar { flex: 0 0 auto; width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; font-size: 17px; background: var(--bg); border: 1px solid var(--border); }
.ce-row.grouped .ce-avatar { visibility: hidden; }

/* Fill the row so text uses the full width (both senders left-aligned). */
.ce-body { display: flex; flex-direction: column; gap: 4px; flex: 1 1 auto; min-width: 0; }

.ce-meta { display: flex; gap: 8px; align-items: baseline; font-size: 12px; color: var(--muted); }
.ce-name { font-weight: 600; color: var(--ink); }
.ce-row.grouped .ce-meta { display: none; }
/* Unprompted (task-woken) message: a soft accent edge on the bubble, so it feels
   like the buddy reached out without shouting it. */
.ce-row.proactive .ce-text { border-left: 2px solid var(--accent); padding-left: 12px; }

/* Buddy: plain text on the canvas (no bubble), so it reads full-width like a doc. */
.ce-text { padding: 2px 0; word-wrap: break-word; overflow-wrap: anywhere; }
/* User: a subtle card so the alternation stays legible at full width. */
.ce-row.user .ce-text { padding: 10px 14px; border-radius: 14px; background: var(--panel); border: 1px solid var(--border); }
.ce-caret::after { content: "▍"; opacity: 0.5; margin-left: 1px; }
.ce-text.err { color: var(--error); }
.ce-text p { margin: 0 0 8px; }
.ce-text p:last-child { margin-bottom: 0; }
.ce-text ul, .ce-text ol { margin: 4px 0; padding-left: 20px; }
.ce-text code { font-family: ui-monospace, Menlo, monospace; font-size: 0.92em; background: rgba(127,127,127,0.18); padding: 1px 5px; border-radius: 5px; }
.ce-text pre { background: rgba(127,127,127,0.14); border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; overflow-x: auto; }
.ce-text pre code { background: none; padding: 0; }
.ce-text a { color: var(--accent); text-decoration: underline; }

.ce-events { display: flex; flex-direction: column; gap: 2px; }
.ce-note { font-size: 12px; color: var(--muted); }
/* Retry — the recovery affordance under a dropped turn. align-self:flex-start so it
   hugs the text, not the full row width. */
.ce-retry {
  align-self: flex-start; margin-top: 4px; padding: 4px 12px; border-radius: 999px;
  border: 1px solid var(--border); background: transparent; color: var(--muted);
  font-size: 13px; font-family: inherit; cursor: pointer; transition: border-color 0.12s, color 0.12s;
}
.ce-retry:hover { border-color: var(--accent); color: var(--accent); }

/* "Working" status — sits at the BOTTOM of the pending buddy bubble (inside .ce-text)
   while the turn is in flight, so the bubble is never an empty panel and a long tool op
   never reads as a dead stall. Spinner + a verb, gently breathing. The :only-child rule
   tightens the gap when the bubble is still empty (spinner alone, pre-first-token). */
.ce-working {
  display: flex; align-items: center; gap: 8px; margin-top: 6px;
  font-size: 13px; color: var(--muted);
  animation: ce-working-pulse 1.6s ease-in-out infinite;
}
.ce-text > .ce-working:only-child { margin-top: 0; }
.ce-spinner {
  flex: none; width: 13px; height: 13px; border-radius: 50%;
  border: 2px solid var(--border); border-top-color: var(--accent);
  animation: glass-spin 0.7s linear infinite;
}
.ce-working__label { font-style: italic; }
@keyframes ce-working-pulse { 0%, 100% { opacity: 0.6; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .ce-spinner, .ce-working { animation: none; }
  .ce-spinner { border-top-color: var(--accent); } /* still reads as a status dot */
}

.ce-choices { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2px; }
.ce-choice { padding: 7px 13px; border-radius: 999px; border: 1px solid var(--accent); background: transparent; color: var(--accent); font-size: 14px; font-family: inherit; cursor: pointer; }
.ce-choice:hover:not(:disabled) { background: var(--accent); color: #fff; }
.ce-choice:disabled { cursor: default; opacity: 0.55; }
.ce-choice.picked { background: var(--accent); color: #fff; opacity: 1; }

/* ── Library — the Files glass-box shape, one tier deeper: each collection is a
   .glass-group heading with its artifacts as .glass-items beneath. Reuses the glass-box
   classes wholesale; only the per-collection profile peek + empty line are bespoke. ── */

/* Desktop (≥880px): the same master-detail grid as #tab-files. The global .glass-list /
   .glass-reader desktop rules style the two columns; we only need the grid container. */
@media (min-width: 880px) {
  #tab-library.glass--cols {
    max-width: none; margin: 0; padding: 0; height: 100dvh;
    display: grid; grid-template-columns: 480px minmax(0, 1fr);
  }
}

/* The collection's scoped profile peek (e.g. Recipes' Kitchen) — a quiet panel under the
   heading, read-only like everything here. */
.lib-profile { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 12px 14px; margin-bottom: 10px; }
.lib-profile__head { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; margin-bottom: 8px; }
.lib-profile__head .icon { color: var(--accent); }
.lib-profile__list { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.lib-profile__list li { background: var(--bg); border: 1px solid var(--border); border-radius: 999px; padding: 3px 10px; font-size: 12px; color: var(--muted); }

.lib-empty { font-size: 13px; padding: 4px 2px 8px; }

/* ── List-shaped artifact detail (groceries): the checklist ── */
.art-checklist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.art-checklist__item { display: flex; align-items: baseline; gap: 10px; font-size: 16px; }
.art-checklist__item .icon { color: var(--accent); width: 15px; height: 15px; }
.art-checklist__item.is-done { color: var(--text-muted, #8a8276); }
.art-checklist__item.is-done span { text-decoration: line-through; }
.art-checklist__item.is-done .icon { color: var(--text-muted, #8a8276); }

/* ============================================================
   Public pages — marketing landing + legal/contact. These render
   through the main layout (.wrap, max-width 980px); the header and
   footer partials (pub-head / pub-foot) frame every public page.
============================================================ */

/* Larger CTA button used on the landing page. */
.btn-lg { padding: 13px 26px; font-size: 17px; border-radius: 12px; }

/* ── Public header ── */
.pub-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 6px 0 28px;
}
.pub-head__brand { display: inline-flex; align-items: center; gap: 9px; text-decoration: none; color: var(--ink); }
.pub-head__brand .brand-face { font-size: 22px; line-height: 1; }
.pub-head__brand .brand-wordmark { font-family: var(--font-display); font-weight: 700; font-size: 22px; }
.pub-head__nav { display: flex; align-items: center; gap: 16px; }
.pub-head__link { color: var(--ink); text-decoration: none; font-size: 15px; }
.pub-head__link:hover { color: var(--accent); }

/* ── Landing ── */
.land { display: flex; flex-direction: column; gap: 8px; }

.land-hero { text-align: center; padding: 40px 0 56px; }
.land-hero__title { font-size: 52px; line-height: 1.05; margin: 0 0 18px; letter-spacing: -0.02em; }
.land-hero__title em { color: var(--accent); font-style: normal; }
.land-hero__lede { max-width: 620px; margin: 0 auto; font-size: 20px; line-height: 1.5; color: var(--ink); }
.land-hero__cta { margin-top: 30px; }
.land-hero__note { margin-top: 16px; font-size: 14px; }

/* Three pillars */
.land-pillars {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px;
  padding: 12px 0 24px;
}
.land-pillar {
  background: var(--panel); border: 1px solid var(--border); border-radius: 16px;
  padding: 24px 22px; display: flex; flex-direction: column; gap: 10px;
}
.land-pillar__icon {
  display: grid; place-items: center; width: 44px; height: 44px; border-radius: 12px;
  background: var(--bg); color: var(--accent);
}
.land-pillar__icon .icon { width: 22px; height: 22px; }
.land-pillar h3 { margin: 6px 0 0; font-size: 19px; }
.land-pillar p { margin: 0; line-height: 1.5; font-size: 15px; }

/* Content sections */
.land-section { padding: 48px 0; border-top: 1px solid var(--border); }
.land-section--alt {
  background: var(--panel); border: 1px solid var(--border); border-radius: 20px;
  padding: 44px 36px; margin: 16px 0;
}
.land-eyebrow {
  margin: 0 0 6px; font-size: 12px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--accent);
}
.land-section h2 { font-size: 30px; margin: 0 0 16px; letter-spacing: -0.01em; }
.land-lead { max-width: 660px; font-size: 17px; line-height: 1.6; margin: 0; }

/* Steps */
.land-steps { list-style: none; margin: 24px 0 0; padding: 0; display: flex; flex-direction: column; gap: 22px; }
.land-steps li { display: flex; gap: 16px; align-items: flex-start; }
.land-steps__n {
  flex: none; display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 50%; background: var(--accent); color: var(--accent-ink);
  font-family: var(--font-display); font-weight: 700; font-size: 16px;
}
.land-steps h4 { margin: 4px 0 4px; font-size: 18px; }
.land-steps p { margin: 0; line-height: 1.5; }

/* Glass-box checklist */
.land-checks { list-style: none; margin: 22px 0 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.land-checks li { display: flex; align-items: center; gap: 12px; font-size: 16px; }
.land-checks .icon { color: var(--accent); width: 18px; height: 18px; flex: none; }

/* Skills cards */
.land-skills { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 26px; }
.land-skillcard { background: var(--bg); border: 1px solid var(--border); border-radius: 14px; padding: 20px; }
.land-skillcard__icon {
  display: grid; place-items: center; width: 40px; height: 40px; border-radius: 11px;
  background: var(--panel); color: var(--accent); margin-bottom: 10px;
}
.land-skillcard__icon .icon { width: 20px; height: 20px; }
.land-skillcard h4 { margin: 0 0 4px; font-size: 17px; }
.land-skillcard p { margin: 0; font-size: 14px; line-height: 1.45; }
.land-pricing { margin: 22px 0 0; font-size: 16px; color: var(--muted); }
.land-pricing strong { color: var(--ink); }

/* Final CTA */
.land-final { text-align: center; padding: 60px 0 48px; border-top: 1px solid var(--border); }
.land-final h2 { font-size: 32px; margin: 0 0 8px; }

/* ── Public footer ── */
.pub-foot { margin-top: 40px; padding: 28px 0 12px; border-top: 1px solid var(--border); }
.pub-foot__inner { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.pub-foot__brand .brand-wordmark { font-family: var(--font-display); font-weight: 700; font-size: 18px; }
.pub-foot__tag { margin: 4px 0 0; font-size: 14px; }
.pub-foot__links { display: flex; flex-wrap: wrap; gap: 16px; }
.pub-foot__links a { color: var(--muted); text-decoration: none; font-size: 14px; }
.pub-foot__links a:hover { color: var(--accent); }
.pub-foot__copy { margin: 20px 0 0; font-size: 13px; }

/* ── Legal / contact pages ── */
.legal { max-width: 760px; margin: 0 auto; line-height: 1.65; }
.legal--narrow { max-width: 620px; }
.legal__head { padding: 8px 0 28px; border-bottom: 1px solid var(--border); margin-bottom: 24px; }
.legal__head h1 { font-size: 38px; margin: 0 0 6px; }
.legal__intro { font-size: 17px; }
.legal__section { margin: 28px 0; }
.legal__section h2 { font-size: 21px; margin: 0 0 10px; }
.legal__section ul { padding-left: 22px; display: flex; flex-direction: column; gap: 7px; }
.legal__section li { line-height: 1.55; }
.contact-email {
  display: flex; align-items: center; gap: 10px; font-size: 20px; margin: 18px 0 28px;
}
.contact-email .icon { color: var(--accent); width: 22px; height: 22px; }

/* ── Public responsive ── */
@media (max-width: 760px) {
  .land-hero__title { font-size: 38px; }
  .land-hero__lede { font-size: 18px; }
  .land-pillars, .land-skills { grid-template-columns: 1fr; }
  .land-section { padding: 36px 0; }
  .land-section--alt { padding: 32px 22px; }
  .land-section h2 { font-size: 25px; }
  .legal__head h1 { font-size: 30px; }
}
