/* =========================================================================
   UseMyContext - "Refined Ink / Quiet-Luxury"
   Warm bone background · soft warm greys · deep ink · British Racing Green.
   Schibsted Grotesk display. Hairline rules. Generous whitespace. Calm motion.
   ========================================================================= */

/* Fonts (Schibsted Grotesk / Newsreader / Playfair Display) are self-hosted via
   /fonts.css, linked from index.html - no third-party (fonts.googleapis.com) calls. */

:root {
  /* Palette - warm, never pure white, single green accent */
  --bone:        #F4F1EA;  /* page background - warm off-white */
  --bone-2:      #EFEBE2;  /* recessed surfaces */
  --paper:       #FBFAF6;  /* raised cards */
  --ink:         #1A1A17;  /* primary text - deep warm ink */
  --ink-soft:    #4A4843;  /* secondary text */
  --ink-faint:   #5D5B53;  /* tertiary / meta - darkened to meet WCAG AA 4.5:1 on the off-white + green-tint backgrounds */
  --hair:        #DCD7CC;  /* hairline rules */
  --hair-soft:   #E7E2D8;
  --green:       #1F3D2B;  /* British Racing Green - THE accent */
  --green-deep:  #16301F;
  --green-tint:  #E8EDE7;  /* faint green wash */
  --danger:      #7A3B2E;  /* muted oxblood, not red */
  --danger-deep: #632F25;  /* destructive hover */
  --danger-tint: #FBF1EE;  /* the faintest oxblood wash (danger rows) */
  --gold:        #B08D2F;  /* the gold family (warn callouts, bot accents) */
  --gold-tint:   #F6EFDD;
  --gold-hair:   #D8C9A8;
  --amber:       #A8741A;  /* near-full meter fill - calm amber, not alarm red */
  --amber-cue:   #8A5E13;  /* near-full meter cue text */
  --bone-glow:   #FAF7F0;  /* the body radial highlight */
  --row-hover:   rgba(255, 255, 255, 0.65);  /* studio source-row hover wash */

  /* Brand constants - PINNED in every theme. The mark tile stays solid deep
     green with the cream ring/wordmark in Day, Dusk AND Night. */
  --brand-green: #1F3D2B;
  --brand-cream: #F4F1EA;

  color-scheme: light;

  --r:           14px;     /* card radius */
  --r-sm:        9px;

  /* Type */
  --display: "Schibsted Grotesk", ui-sans-serif, sans-serif;
  --serif:   "Newsreader", Georgia, serif;

  /* Motion */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --slow: 620ms;
  --med:  420ms;
}

/* ---- themes: Day / Dusk / Night (design mock screen 6) -------------------
   One palette, three lights. Day is the bare :root above. Dusk and Night
   override the SAME variables on <html data-theme="...">: the racing green
   survives the dark by LIGHTENING (so solid green/bone pairs flip to a legible
   mint-on-charcoal), the gold stays gold, and the brand mark tile is pinned
   via --brand-green/--brand-cream so it never inverts. The attribute lands
   before first paint (inline snippet in index.html); web/theme.js owns the
   per-device choice (localStorage) and the system-preference default. */

/* Dusk - warm sepia-charcoal for low light without going void. */
html[data-theme="dusk"] {
  color-scheme: dark;
  --bone:        #322E28;
  --bone-2:      #2B2722;
  --paper:       #3D3831;
  --ink:         #F2EDE1;
  --ink-soft:    #D8D1C2;
  --ink-faint:   #B3AC9C;
  --hair:        #544E44;
  --hair-soft:   #48433A;
  --green:       #A6D2B2;
  --green-deep:  #BFDFC8;
  --green-tint:  #36413A;
  --danger:      #D89483;
  --danger-deep: #E2A695;
  --danger-tint: #463029;
  --gold:        #D9B45E;
  --gold-tint:   #453C28;
  --gold-hair:   #6B5B33;
  --amber:       #D9A84E;
  --amber-cue:   #D9A84E;
  --bone-glow:   #38332C;
  --row-hover:   rgba(255, 255, 255, 0.05);
}

/* Night - true black for OLED; hairlines go barely-there, cards float. */
html[data-theme="night"] {
  color-scheme: dark;
  --bone:        #000000;
  --bone-2:      #0D0E0B;
  --paper:       #191B16;
  --ink:         #F4F1E8;
  --ink-soft:    #CFCBBE;
  --ink-faint:   #9A968A;
  --hair:        #2C2D26;
  --hair-soft:   #22231D;
  --green:       #9ED1AC;
  --green-deep:  #B8DEC2;
  --green-tint:  #1C2A20;
  --danger:      #D89483;
  --danger-deep: #E2A695;
  --danger-tint: #33201A;
  --gold:        #E0BC66;
  --gold-tint:   #322914;
  --gold-hair:   #574826;
  --amber:       #DBA94F;
  --amber-cue:   #DBA94F;
  --bone-glow:   #0A0B08;
  --row-hover:   rgba(255, 255, 255, 0.06);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bone);
  color: var(--ink);
  font-family: var(--display);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: "ss01" 1, "cv01" 1;
}

body {
  min-height: 100vh;
  /* a single, barely-there warm radial - no gradient soup */
  background:
    radial-gradient(120% 90% at 50% -10%, var(--bone-glow) 0%, var(--bone) 46%) fixed;
}

::selection { background: var(--green); color: var(--bone); }

button { font-family: inherit; cursor: pointer; }
input, textarea { font-family: inherit; }

a { color: var(--green); text-decoration: none; }
a:hover { font-weight: 700; }

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

#app { min-height: 100vh; display: flex; flex-direction: column; }

/* STUDIO (item 8) — the sticky Profile save bar is GONE (rows save themselves;
   the composite chip is the only save indicator). `--savebar-h` stays declared
   (always 0) because the chat FAB offsets read it with a 0px fallback. */
body { --savebar-h: 0px; }

/* The SHARED authenticated app shell (wraps EVERY authed view: Profile / Storage /
   Connect / Settings / Usage). The authed app scrolls the DOCUMENT (it is NOT a
   fixed inner scroller - that pattern is the logged-out `.landing` only), so the
   GLOBAL safe-area inset belongs HERE, applied ONCE, never per-view. `viewport-fit=
   cover` (index.html) makes the inset non-zero on notched phones so content stops
   bleeding under the status bar; on devices without a notch it resolves to 0. */
.shell {
  width: 100%;
  max-width: 880px;
  margin: 0 auto;
  padding: env(safe-area-inset-top) 28px 0;
  flex: 1;
  display: flex;
  flex-direction: column;
}

/* Top nav - appears only when authenticated. Quiet, hairline-anchored. A SINGLE
   non-wrapping row at every width (mark -> tabs -> avatar all inline); the narrow
   media query below hides the wordmark text rather than letting items wrap. */
.nav {
  display: flex;
  align-items: center;
  gap: 30px;
  padding: 26px 0 22px;
  border-bottom: 1px solid var(--hair);
  margin-bottom: 56px;
  flex-wrap: nowrap;
}
/* The brand lockup is a SPA link home (#/profile). It is a link but reads as the
   wordmark: no underline, inherits ink colour, hover goes BOLD not underline. */
.brand {
  display: flex; align-items: center; gap: 11px;
  font-weight: 600; letter-spacing: -0.01em; font-size: 16px;
  margin-right: auto;
  color: var(--ink); text-decoration: none; flex: none;
}
.brand:hover { font-weight: 700; }
.brand:focus-visible {
  outline: none; border-radius: 8px;
  box-shadow: 0 0 0 3px var(--green-tint), 0 0 0 1px var(--green);
}
.brand .wordmark { white-space: nowrap; }
/* The mark tile is PINNED to the brand constants: solid deep green with the
   cream ring in every theme (Day / Dusk / Night) - it never inverts. */
.brand .mark {
  width: 26px; height: 26px; border-radius: 7px;
  background: var(--brand-green);
  display: grid; place-items: center; flex: none;
}
.brand .mark::after {
  content: ""; width: 11px; height: 11px; border-radius: 50%;
  border: 2px solid var(--brand-cream);
}
.nav a.tab {
  color: var(--ink-soft);
  font-size: 14.5px;
  letter-spacing: -0.005em;
  padding: 4px 0;
  position: relative;
  text-decoration: none;
  white-space: nowrap;
}
.nav a.tab:hover { color: var(--ink); }
.nav a.tab.active { color: var(--green); font-weight: 500; }
.nav a.tab.active::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -23px;
  height: 1.5px; background: var(--green);
}
/* Account avatar + dropdown profile menu (replaces the old plain Sign out link). */
.acct { position: relative; display: flex; align-items: center; }
.acct-avatar {
  background: none; border: none; padding: 0; margin: 0;
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center; flex: none; line-height: 0;
  box-shadow: 0 0 0 1px var(--hair);
  transition: box-shadow 160ms var(--ease), transform 160ms var(--ease);
}
.acct-avatar:hover { box-shadow: 0 0 0 2px var(--green-tint); }
.acct-avatar:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--green-tint), 0 0 0 1px var(--green); }
.acct-avatar[aria-expanded="true"] { box-shadow: 0 0 0 2px var(--green); }
.acct-avatar .nav-avatar-svg { display: block; border-radius: 50%; }

.acct-menu {
  position: absolute; top: calc(100% + 10px); right: 0;
  min-width: 168px; padding: 6px;
  background: var(--paper);
  border: 1px solid var(--hair);
  border-radius: var(--r-sm);
  box-shadow: 0 12px 30px -10px rgba(26, 26, 23, 0.22), 0 2px 8px -3px rgba(26, 26, 23, 0.12);
  display: none; flex-direction: column; gap: 2px;
  z-index: 60;
}
.acct-menu.show { display: flex; }
.acct-item {
  background: none; border: none; text-align: left;
  font-family: inherit; font-size: 14px; color: var(--ink-soft);
  padding: 9px 12px; border-radius: 7px; width: 100%;
  transition: background 130ms var(--ease), color 130ms var(--ease);
}
.acct-item:hover, .acct-item:focus-visible {
  background: var(--green-tint); color: var(--green); font-weight: 600;
  outline: none;
}
/* SMC-CONSENT: the avatar carries a small pending-invite count badge so a waiting
   shared-context invite is discoverable WITHOUT opening the menu. Racing-green
   (the brand accent, an existing token) on bone; a thin bone ring lifts it off the
   avatar. Hidden at 0 (display:none set inline). */
.acct { position: relative; }
.acct-badge {
  position: absolute; top: -4px; right: -4px;
  min-width: 17px; height: 17px; padding: 0 4px; box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--green); color: var(--bone);
  font-size: 10.5px; font-weight: 700; line-height: 1; letter-spacing: 0;
  border-radius: 999px; border: 1.5px solid var(--bone);
  pointer-events: none;
}
/* The "Shared with me" item stands out from the plain items + shows the pending
   count chip when there are invites waiting. */
.acct-item-shared {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.acct-item-shared.has-pending { color: var(--green); font-weight: 600; }
.acct-shared-count {
  flex: none; min-width: 17px; height: 17px; padding: 0 5px; box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--green); color: var(--bone);
  font-size: 11px; font-weight: 700; line-height: 1; border-radius: 999px;
}

/* Settings view - account surface. */
.set-card {
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: var(--r); padding: 20px 22px;
}
.set-row { display: flex; align-items: baseline; gap: 16px; }
.set-label { font-size: 13px; color: var(--ink-faint); min-width: 120px; font-weight: 500; }
.set-value { font-size: 15px; color: var(--ink); }
.set-mono { font-family: var(--display); font-size: 14px; color: var(--green); }
.set-region { display: flex; align-items: center; gap: 14px; }
.set-region .flag { font-size: 22px; flex: none; }
.set-region-title { font-size: 16px; font-weight: 600; color: var(--ink); }
.set-region-sub { font-size: 14px; color: var(--ink-faint); margin-top: 3px; line-height: 1.45; }
.set-region .pill.soon { margin-left: auto; flex: none; }
.set-note { font-size: 13.5px; color: var(--ink-faint); line-height: 1.5; margin: 14px 0 0; }
/* #42 - settings action row: "Edit your profile" stays left, "Replay the
   welcome tour" sits at the far right; wraps gracefully on narrow widths. */
.set-actions {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}
/* Appearance (mock screen 12 panel A): three half-split theme discs - each
   previews its OWN palette, so the disc halves are LITERAL theme colors and
   deliberately do not follow the active theme's variables. Selected = green
   ring; labels go bold on hover (house rule), never underline. */
.swatches { display: flex; gap: 20px; margin: 2px 0; }
.swatch {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  background: none; border: none; padding: 2px;
  font-family: inherit; font-size: 12px; color: var(--ink-soft);
}
.swatch:hover { font-weight: 700; color: var(--ink); }
.swatch .disc {
  width: 34px; height: 34px; border-radius: 50%;
  border: 2px solid var(--hair);
  transition: border-color 160ms var(--ease), box-shadow 160ms var(--ease);
}
.swatch.sel { color: var(--green); font-weight: 600; }
.swatch.sel .disc { border-color: var(--green); box-shadow: 0 0 0 3px var(--green-tint); }
.swatch:focus-visible { outline: none; }
.swatch:focus-visible .disc { box-shadow: 0 0 0 3px var(--green-tint), 0 0 0 1px var(--green); }
.disc.d-day   { background: linear-gradient(135deg, #F4F1EA 55%, #1F3D2B 55%); }
.disc.d-dusk  { background: linear-gradient(135deg, #322E28 55%, #A6D2B2 55%); }
.disc.d-night { background: linear-gradient(135deg, #000000 55%, #9ED1AC 55%); }
/* The Data-residency brand glyph (replaces the emoji globe): a quiet ring/globe
   stroked in the accent green, sized to sit where the emoji sat. */
.set-region .res-glyph {
  flex: none; width: 26px; height: 26px;
  display: grid; place-items: center; color: var(--green); line-height: 0;
}

/* Usage view (#26-web) - simple, calm per-user analytics. */
.usage-stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
}
.usage-stat {
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: var(--r); padding: 22px 22px 20px;
}
.usage-stat-num {
  font-family: var(--display); font-size: 40px; line-height: 1;
  font-weight: 600; color: var(--green); letter-spacing: -0.02em;
}
.usage-stat-cap {
  font-size: 13px; color: var(--ink-faint); margin-top: 10px;
  line-height: 1.4;
}
.usage-card {
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: var(--r); padding: 8px 22px;
}
/* "What it read" rows (studio refit, mock screen 12 B): product label, a
   quiet bar scaled to the max count, the number right-aligned. */
.usage-tool-row {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 0; border-bottom: 1px solid var(--hair);
}
.usage-tool-row:last-child { border-bottom: none; }
.usage-tool-name { flex: none; width: 200px; font-size: 15px; color: var(--ink); }
.usage-tool-bar {
  flex: 1; height: 4px; border-radius: 2px;
  background: var(--hair-soft); overflow: hidden;
}
.usage-tool-bar-fill {
  display: block; height: 100%; border-radius: 2px;
  background: var(--green);
}
.usage-tool-count {
  flex: none; min-width: 36px; text-align: right;
  font-family: var(--display); font-size: 18px; font-weight: 600;
  color: var(--green);
}
/* Connected-AI CAST ROWS (studio refit): a deterministic brand avatar per
   client + name + a quiet "last active · reads" sub-line. The brand discs are
   PINNED hexes (Claude coral / ChatGPT teal) so they hold in every theme; the
   neutral disc follows the theme surfaces. */
.usage-cast-row {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 0; border-bottom: 1px solid var(--hair);
}
.usage-cast-row:last-child { border-bottom: none; }
.usage-avatar {
  position: relative; flex: none; width: 36px; height: 36px;
  border-radius: 50%; display: grid; place-items: center;
  background: var(--bone-2); border: 1px solid var(--hair);
  color: var(--ink-soft); font-family: var(--display);
  font-size: 12px; font-weight: 700; line-height: 1;
}
.usage-avatar-claude { background: #BF6A4B; border-color: #BF6A4B; color: #F4F1EA; font-size: 15px; }
.usage-avatar-gpt { background: #4E7D74; border-color: #4E7D74; color: #F4F1EA; font-size: 14px; }
/* Live-presence dot: the client was active within the last hour. */
.usage-avatar.live::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--green); border: 2px solid var(--paper);
}
.usage-cast-meta { min-width: 0; }
.usage-cast-name {
  font-family: var(--display); font-size: 16px; font-weight: 600; color: var(--ink);
}
.usage-cast-sub { font-size: 13px; color: var(--ink-faint); margin-top: 2px; }
.usage-empty {
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: var(--r); padding: 48px 28px; text-align: center;
}
.usage-empty-mark { font-size: 32px; color: var(--green); opacity: 0.55; line-height: 1; }
.usage-empty-title { font-size: 18px; font-weight: 600; color: var(--ink); margin: 16px 0 6px; }
.usage-empty-sub { font-size: 15px; color: var(--ink-faint); line-height: 1.55; margin: 0 auto; max-width: 360px; }

/* BILL-UX-1 - the "Your plan" block: a calm plan card above the stat cards. */
.usage-plan-card { padding: 22px 22px 8px; }
.usage-plan-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; padding: 0 0 18px;
  border-bottom: 1px solid var(--hair);
}
.usage-plan-head-left { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.usage-plan-tier {
  font-family: var(--display); font-size: 26px; font-weight: 600;
  color: var(--green); letter-spacing: -0.01em; line-height: 1;
}
.usage-plan-tier-sub { font-size: 13px; color: var(--ink-faint); }
.usage-plan-note { font-size: 13px; line-height: 1.45; max-width: 320px; }
.usage-plan-limits {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px;
  padding: 18px 0;
}
.usage-plan-limit { display: flex; flex-direction: column; gap: 4px; }
.usage-plan-limit-num {
  font-family: var(--display); font-size: 19px; font-weight: 600; color: var(--ink);
}
.usage-plan-limit-cap { font-size: 13px; color: var(--ink-faint); line-height: 1.4; }

/* BILL-UX-2 - headroom inside the plan card: project count + the coarse storage
   meter. A flex column whose hidden (display:none) children take no space, so an
   all-hidden row collapses cleanly (no orphan border/padding). Each VISIBLE piece
   carries its own top divider so the separation only appears when there's content. */
.usage-plan-headroom { display: flex; flex-direction: column; }
.usage-plan-headroom > .proj-headroom,
.usage-plan-headroom > .usage-meter {
  padding-top: 18px; margin-top: 18px; border-top: 1px solid var(--hair);
}
/* The first VISIBLE piece needs no extra top margin (the card's own limitRow
   padding already spaces it); the border + padding give the divider. The meter
   inside the plan card sits flush (no extra card chrome / bottom margin). */
.usage-plan-headroom > .proj-headroom { margin-top: 0; }
.usage-plan-headroom > .usage-meter { margin-top: 0; }

/* BILL-UX-2 - project headroom: a calm "N of M projects" readout + near/at-cap
   cue. A project COUNT is fine to show (unlike storage bytes). */
.proj-headroom-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.proj-headroom-head-left { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.proj-headroom-num {
  font-family: var(--display); font-size: 19px; font-weight: 600; color: var(--ink);
}
.proj-headroom-cap { font-size: 13px; color: var(--ink-faint); line-height: 1.4; }
.proj-headroom-cue {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 10px; font-size: 14px; color: var(--ink-faint);
}
/* At the cap a calm amber nudge (matches the storage meter's near-full hue),
   one project left a quieter green. Never alarming. */
.proj-headroom-cue[data-level="full"] { color: var(--amber-cue); }
.proj-headroom-cue[data-level="near"] { color: var(--green); }

@media (max-width: 640px) {
  .usage-stats { grid-template-columns: 1fr; }
  .usage-plan-limits { grid-template-columns: 1fr; }
  /* Narrower label column on phones so the bars keep breathing room. */
  .usage-tool-name { width: 150px; font-size: 14px; }
}

/* ---- type scale -------------------------------------------------------- */

.eyebrow {
  font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--green); font-weight: 600;
}
h1.display {
  font-size: clamp(30px, 5.4vw, 46px);
  line-height: 1.06;
  letter-spacing: -0.025em;
  font-weight: 600;
  margin: 18px 0 0;
  max-width: 16ch;
}
.lede {
  font-family: var(--serif);
  font-size: clamp(17px, 2.4vw, 20px);
  line-height: 1.5;
  color: var(--ink-soft);
  margin: 18px 0 0;
  max-width: 46ch;
}
/* #43b — the Profile lede ("These facts power the profile tool...") was wrapping
   to two lines well before the available width under the shared 46ch measure cap.
   Scoped here (not on `.lede`, which is shared across pages) it gets a wider cap
   so it sits on ONE line at desktop; it still wraps gracefully on a phone. */
.lede-profile { max-width: 72ch; }
@media (max-width: 640px) { .lede-profile { max-width: 46ch; } }
/* #55 — same fix for the Activity-section lede ("Recent changes and events on your
   context. Only you can see this."): the shared 46ch cap wrapped it early. Scoped
   widen so it sits on ONE line at desktop, still wraps gracefully on a phone. */
.lede-activity { max-width: 72ch; }
@media (max-width: 640px) { .lede-activity { max-width: 46ch; } }
h2.section {
  font-size: 23px; letter-spacing: -0.02em; font-weight: 600; margin: 0;
}
.muted { color: var(--ink-faint); }
.serif { font-family: var(--serif); }

/* ---- hairline rule ----------------------------------------------------- */
.rule { height: 1px; background: var(--hair); border: 0; margin: 0; }

/* ---- buttons ----------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  font-size: 15px; font-weight: 500; letter-spacing: -0.005em;
  padding: 13px 24px; border-radius: 999px;
  border: 1px solid transparent;
  transition: background var(--med) var(--ease), color var(--med) var(--ease),
              border-color var(--med) var(--ease), transform 120ms var(--ease),
              opacity var(--med) var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--green); color: var(--bone); }
.btn-primary:hover { background: var(--green-deep); }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--hair); }
.btn-ghost:hover { border-color: var(--ink-faint); background: var(--paper); }
.btn-text {
  background: none; border: none; color: var(--ink-faint);
  padding: 10px 4px; font-size: 14px;
}
.btn-text:hover { color: var(--ink); }
/* Nuclear / destructive action (Disconnect all). Muted oxblood, not red. */
.btn-danger {
  background: var(--danger); color: var(--bone); border-color: var(--danger);
}
.btn-danger:hover { background: var(--danger-deep); border-color: var(--danger-deep); }
.btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }
.btn .arrow { transition: transform var(--med) var(--ease); }
.btn-primary:hover .arrow { transform: translateX(3px); }
.btn-block { width: 100%; }

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

.field { display: flex; flex-direction: column; gap: 8px; }
.field label {
  font-size: 13px; color: var(--ink-soft); letter-spacing: 0.005em; font-weight: 500;
}
.input, .textarea {
  background: var(--paper);
  border: 1px solid var(--hair);
  border-radius: var(--r-sm);
  padding: 14px 16px;
  font-size: 16px;
  color: var(--ink);
  width: 100%;
  transition: border-color var(--med) var(--ease), box-shadow var(--med) var(--ease);
}
.input::placeholder, .textarea::placeholder { color: var(--ink-faint); }
.input:focus, .textarea:focus {
  outline: none; border-color: var(--green);
  box-shadow: 0 0 0 3px var(--green-tint);
}
.textarea { resize: vertical; min-height: 84px; line-height: 1.45; }

/* OTP input - wide tracking, centered, monospaced feel */
.otp-input {
  text-align: center;
  letter-spacing: 0.5em;
  font-size: 26px;
  font-weight: 500;
  padding-left: 0.5em; /* compensate tracking */
}

/* ---- choice cards (residency) ----------------------------------------- */

.choices { display: grid; gap: 16px; }
.choice {
  text-align: left;
  background: var(--paper);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  padding: 24px 26px;
  display: flex; align-items: flex-start; gap: 18px;
  transition: border-color var(--med) var(--ease), background var(--med) var(--ease),
              transform 160ms var(--ease);
  width: 100%;
}
.choice:hover { border-color: var(--ink-faint); transform: translateY(-1px); }
.choice.selected {
  border-color: var(--green);
  background: var(--green-tint);
  box-shadow: 0 0 0 1px var(--green) inset;
}
.choice .flag {
  font-size: 26px; line-height: 1; margin-top: 2px; flex: none;
  width: 40px; height: 40px; border-radius: 9px;
  display: grid; place-items: center;
  background: var(--bone-2); border: 1px solid var(--hair-soft);
}
.choice.selected .flag { background: var(--paper); border-color: var(--green); }
.choice .ctitle { font-weight: 600; font-size: 16.5px; letter-spacing: -0.01em; }
.choice .csub { color: var(--ink-faint); font-size: 14px; margin-top: 4px; line-height: 1.45; }
.choice .tick {
  margin-left: auto; flex: none; width: 22px; height: 22px; border-radius: 50%;
  border: 1.5px solid var(--hair); display: grid; place-items: center;
  transition: all var(--med) var(--ease);
}
.choice.selected .tick { border-color: var(--green); background: var(--green); }
.choice.selected .tick::after {
  content: ""; width: 9px; height: 5px; border-left: 2px solid var(--bone);
  border-bottom: 2px solid var(--bone); transform: rotate(-45deg) translate(0, -1px);
}

/* ---- terms acceptance (login email screen) ---------------------------- */

.tos-row { display: flex; align-items: flex-start; gap: 10px; }
.tos-check {
  margin-top: 2px; width: 16px; height: 16px; flex: none; cursor: pointer;
  accent-color: var(--green);
}
.tos-text { font-size: 13.5px; color: var(--ink-soft); line-height: 1.5; cursor: pointer; }
.tos-text a { color: var(--green); text-decoration: underline; text-underline-offset: 2px; }

/* ---- marketing landing (UseMyContext front door) ----------------------- */
.landing {
  position: fixed; inset: 0; overflow-y: auto; z-index: 60;
  background: linear-gradient(135deg, #f4f0f8 0%, #e8e0f4 40%, #ddd8f0 70%, #d8d4ee 100%);
  color: #0a0a0a;
}
.lp-top {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; max-width: 1024px; margin: 0 auto;
  padding: 24px clamp(20px, 5vw, 48px);
}
.lp-logo { color: #0a0a0a; font-size: 17px; font-weight: 500; letter-spacing: -0.02em; }
.lp-logo b { font-weight: 700; }
.lp-signin { color: #6c5ce7; font-size: 14.5px; font-weight: 600; }
.lp-signin:hover { font-weight: 700; }
.lp-hero {
  min-height: 74vh; display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center;
  padding: 32px 24px 20px;
}
.lp-badge {
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: #6c5ce7; border: 1.5px solid #c8bfff; border-radius: 100px;
  padding: 8px 18px; margin-bottom: 34px;
  animation: lp-fade 0.8s var(--ease) forwards 0.1s; opacity: 0;
}
.lp-title {
  font-family: 'Playfair Display', Georgia, serif; font-weight: 900;
  font-size: clamp(2.5rem, 7vw, 5.4rem); line-height: 1.05; letter-spacing: -0.025em;
  max-width: 14ch; color: #0a0a0a;
  /* perf-lcp: the hero <h1> IS the LCP element. It previously held opacity:0 for a
     0.28s delay + 0.8s fade (~1.08s invisible), deferring LCP. We keep the gentle
     fade-up but start it immediately (no delayed hold) so the largest paint lands
     ~0.28s sooner; the rest of the hero still staggers behind it. */
  animation: lp-fade 0.7s var(--ease) forwards; opacity: 0;
}
.lp-hl {
  background: linear-gradient(180deg, transparent 52%, #bfc8f0 52%, #bfc8f0 88%, transparent 88%);
  padding: 0 0.04em;
}
.lp-sub {
  margin: 28px auto 0; max-width: 46ch; font-size: clamp(15px, 2vw, 18px);
  line-height: 1.55; color: #3a3550;
  animation: lp-fade 0.8s var(--ease) forwards 0.42s; opacity: 0;
}
.lp-cta-row { margin-top: 36px; animation: lp-fade 0.8s var(--ease) forwards 0.54s; opacity: 0; }
.lp-cta {
  display: inline-flex; align-items: center; gap: 9px;
  background: #6c5ce7; color: #fff; border: none; border-radius: 999px;
  font-size: 15.5px; font-weight: 600; padding: 14px 28px;
  transition: background 200ms var(--ease), transform 120ms var(--ease);
}
.lp-cta:hover { background: #5a48d6; }
.lp-cta:active { transform: translateY(1px); }
.lp-cta .arrow { transition: transform 200ms var(--ease); }
.lp-cta:hover .arrow { transform: translateX(3px); }
.lp-cols {
  max-width: 980px; margin: 0 auto; padding: 36px clamp(20px, 5vw, 48px) 12px;
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 6vw, 72px);
}
.lp-eyebrow {
  font-size: 12px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: #6c5ce7; margin-bottom: 18px;
}
.lp-list { list-style: none; display: flex; flex-direction: column; gap: 15px; }
.lp-point {
  font-size: 16.5px; line-height: 1.5; color: #2a2640;
  padding-left: 26px; position: relative;
}
.lp-point::before {
  content: ""; position: absolute; left: 0; top: 9px; width: 8px; height: 8px;
  border-radius: 50%; background: #c8bfff;
}
.lp-list-value .lp-point::before { background: #6c5ce7; }
.lp-foot { text-align: center; padding: 60px 24px 84px; }
.lp-foot-title {
  font-family: 'Playfair Display', Georgia, serif; font-weight: 700;
  font-size: clamp(1.55rem, 4vw, 2.5rem); letter-spacing: -0.02em;
  margin-bottom: 26px; color: #0a0a0a;
}
@keyframes lp-fade { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }
@media (max-width: 680px) { .lp-cols { grid-template-columns: 1fr; gap: 34px; } .lp-hero { min-height: 64vh; } }

/* landing site footer */
.lp-sitefoot { border-top: 1px solid rgba(108, 92, 231, 0.16); margin-top: 8px; }
.lp-sitefoot-in {
  max-width: 1024px; margin: 0 auto; padding: 26px clamp(20px, 5vw, 48px);
  display: flex; align-items: center; justify-content: space-between; gap: 18px; flex-wrap: wrap;
}
/* Left cluster: copyright + nav links. The version link is the flush-right
   sibling (lp-sitefoot-in is space-between). */
.lp-foot-left { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.lp-copy { font-size: 13.5px; color: #6a6580; }
.lp-version { white-space: nowrap; }
.lp-flinks { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.lp-flink {
  background: none; border: none; padding: 0; cursor: pointer;
  font-size: 13.5px; color: #4a4560; font-family: inherit; letter-spacing: -0.005em;
}
.lp-flink:hover { color: #6c5ce7; font-weight: 700; }

/* contact-us popup */
.lp-modal-ov {
  position: fixed; inset: 0; z-index: 100; padding: 20px;
  background: rgba(30, 24, 55, 0.34); backdrop-filter: blur(3px);
  display: grid; place-items: center;
  /* A tall modal (e.g. the invite composer with the bundle label + Premium gate
     showing) can exceed the viewport height. Let the overlay scroll so the
     bottom action row (Send) is always reachable, never clipped off-screen. */
  overflow-y: auto;
  animation: lp-fade 0.18s var(--ease) forwards;
}
.lp-modal {
  position: relative; background: #fbfaff; color: #0a0a0a;
  border-radius: 18px; padding: 42px 38px 36px; max-width: 420px; width: 100%;
  box-shadow: 0 24px 64px rgba(40, 30, 80, 0.30); text-align: left;
  /* Cap the card to the viewport and scroll inside it; combined with the
     overlay scroll above this keeps the Send button reachable on short screens. */
  max-height: calc(100vh - 40px); overflow-y: auto;
}
.lp-modal-x {
  position: absolute; top: 14px; right: 16px; background: none; border: none;
  font-size: 26px; line-height: 1; color: #9a93b5; cursor: pointer;
}
.lp-modal-x:hover { color: #0a0a0a; }
.lp-modal-title {
  font-family: 'Playfair Display', Georgia, serif; font-weight: 700;
  font-size: 30px; letter-spacing: -0.02em; margin: 10px 0 12px;
}
.lp-modal-text { font-size: 15.5px; line-height: 1.55; color: #3a3550; margin: 0 0 20px; }
.lp-modal-email { display: inline-block; font-size: 16px; font-weight: 600; color: #6c5ce7; }
.lp-modal-email:hover { font-weight: 700; }

/* ---- subtle region selector (legacy - no longer on the login screen) -- */

.region { margin-top: 4px; }
.region-row {
  display: flex; align-items: center; gap: 14px;
}
.region-label {
  font-size: 13px; color: var(--ink-soft); font-weight: 500; letter-spacing: 0.005em;
}
.region-segs {
  display: inline-flex; gap: 0;
  border: 1px solid var(--hair); border-radius: 999px;
  background: var(--paper); padding: 3px; margin-left: auto;
}
.region-seg {
  background: none; border: none; border-radius: 999px;
  padding: 6px 16px; font-size: 13.5px; color: var(--ink-faint);
  font-weight: 500; letter-spacing: -0.005em;
  transition: background var(--med) var(--ease), color var(--med) var(--ease);
}
.region-seg:hover { color: var(--ink); }
.region-seg.active { background: var(--green); color: var(--bone); }
.region-note {
  font-family: var(--serif);
  font-size: 13.5px; line-height: 1.45; color: var(--ink-faint);
  margin: 10px 0 0; max-width: 44ch;
}

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

.card {
  background: var(--paper);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  padding: 26px 28px;
}
.stack { display: flex; flex-direction: column; }
.stack-lg > * + * { margin-top: 22px; }
.stack-md > * + * { margin-top: 16px; }
.stack-sm > * + * { margin-top: 10px; }

/* ---- wizard scaffolding ------------------------------------------------ */

.wizard { padding: 64px 0 90px; }
.steps-meter {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-faint); margin-bottom: 8px;
}
.steps-meter .dots { display: flex; gap: 6px; margin-left: 12px; }
.steps-meter .dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--hair);
  transition: background var(--med) var(--ease), width var(--med) var(--ease);
}
.steps-meter .dot.done { background: var(--ink-faint); }
.steps-meter .dot.now { background: var(--green); width: 18px; border-radius: 4px; }

.wizard-foot {
  display: flex; align-items: center; gap: 14px; margin-top: 36px;
}
.wizard-foot .spacer { margin-left: auto; }

/* ---- the dev-otp / info callout ---------------------------------------- */

.callout {
  border: 1px dashed var(--hair);
  background: var(--bone-2);
  border-radius: var(--r-sm);
  padding: 14px 18px;
  font-size: 14px; color: var(--ink-soft);
  display: flex; align-items: center; gap: 12px;
}
.callout.dev { border-color: var(--green); background: var(--green-tint); }
.callout .tag {
  font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase;
  font-weight: 600; color: var(--green); flex: none;
  border: 1px solid var(--green); border-radius: 999px; padding: 3px 9px;
}
.callout.warn { border-style: solid; border-color: var(--gold-hair); background: var(--gold-tint); }
.callout.warn .tag { color: var(--danger); border-color: var(--danger); }
/* BILL-UX-5: the post-checkout banner. Pending = the default dashed callout
   ("unlocking momentarily"); CONFIRMED (the entitlement poll read premium) goes a
   calm solid racing-green tint so the upgrade reads as live, not still-pending. */
.callout.checkout-flash.checkout-flash-confirmed {
  border-style: solid; border-color: var(--green); background: var(--green-tint);
}
.callout.checkout-flash.checkout-flash-confirmed .checkout-flash-text { color: var(--ink); }
/* #49: a calm prose notice (not an icon-row). Left-aligned text block, used for
   the Perplexity "custom connectors disabled" message. */
.callout.notice { display: block; font-size: 14.5px; color: var(--ink-soft); }
.callout.notice .perplexity-mailto { color: var(--green); font-weight: 600; }
.callout code {
  font-family: var(--display); font-weight: 600; font-size: 18px;
  letter-spacing: 0.18em; color: var(--ink); margin-left: auto;
}

/* ---- error / status line ----------------------------------------------- */
.formerr { color: var(--danger); font-size: 13.5px; min-height: 18px; }

/* ---- storage + provider rows ------------------------------------------ */

.row {
  display: flex; align-items: center; gap: 16px;
  padding: 20px 22px;
  border: 1px solid var(--hair);
  border-radius: var(--r);
  background: var(--paper);
}
.row + .row { margin-top: 12px; }
.row.disabled { background: var(--bone-2); border-style: dashed; }
.row.disabled .row-name { color: var(--ink-faint); }
.row-icon {
  width: 42px; height: 42px; border-radius: 10px; flex: none;
  display: grid; place-items: center; font-size: 19px;
  background: var(--green-tint); color: var(--green);
  border: 1px solid var(--hair-soft);
}
.row.disabled .row-icon { background: var(--bone); color: var(--ink-faint); }
.row-main { min-width: 0; }
.row-name { font-weight: 600; font-size: 15.5px; letter-spacing: -0.005em; }
.row-meta { color: var(--ink-faint); font-size: 13px; margin-top: 3px; }
.row-aside { margin-left: auto; display: flex; align-items: center; gap: 14px; }

.pill {
  font-size: 11.5px; letter-spacing: 0.04em; font-weight: 600;
  padding: 5px 11px; border-radius: 999px;
}
.pill.live { background: var(--green); color: var(--bone); }
.pill.live::before {
  content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--bone); margin-right: 7px; vertical-align: 1px;
  animation: pulse 2.4s var(--ease) infinite;
}
.pill.soon { background: var(--bone); color: var(--ink-faint); border: 1px solid var(--hair); }
/* #27: "Disconnected" is a STATUS, not an action. It is a quiet passive label —
   muted uppercase text with NO border / pill background / hover, so it never
   reads as the actionable, button-shaped "Reconnect" sitting beside it. We keep
   the `.pill.off` class name (the #23-web connections-toggle spec selects it) but
   strip its button-like affordance and route it through the shared `.status`
   label style below. Likewise `.pill.live` ("Connected") is a status, but its
   green dot + fill already read as a passive indicator, distinct from the
   "Disconnect" text button. */
.pill.off { padding: 0; background: none; border: none; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }

/* #27: shared passive STATUS-label style. A status REPORTS state (Connected /
   Disconnected); it is text, never interactive — no border, no fill, no hover,
   no pointer. This is deliberately, visibly different from the `.btn` / button
   actions ("Reconnect" / "Disconnect") it sits next to, so the user can tell a
   read-only state indicator from a thing they can click. */
.status, .pill.off {
  font-size: 11.5px; letter-spacing: 0.08em; font-weight: 600;
  text-transform: uppercase; color: var(--ink-soft);
  background: none; border: none; cursor: default;
}

/* ---- the source shelf (mock screen 10) ---------------------------------- */
/* One header (project eyebrow + "Sources" + the compact inline meter), source
   CARDS each wearing their own passive status label, tangible file TILES, and
   a drop-zone. Dashed borders are reserved EXCLUSIVELY for not-yet-real things
   (the drop-zone invitation + the v1 providers row). */

.shelf-meter {
  display: flex; align-items: center; gap: 10px;
  font-size: 12.5px; color: var(--ink-faint);
  margin-top: 10px;
}
.shelf-meter b { color: var(--green); font-weight: 700; }
.shelf-meter .meter {
  flex: 0 1 180px; height: 4px; border-radius: 2px; overflow: hidden;
  background: var(--hair-soft); display: block;
}
.shelf-meter .meter > span {
  display: block; height: 100%; background: var(--green); border-radius: 2px;
  transition: width var(--med) var(--ease);
}
.shelf-meter[data-level="full"] .meter > span { background: var(--amber); }
.shelf-meter[data-level="full"] .shelf-tone { color: var(--amber-cue); }
.shelf-tone { white-space: nowrap; }

.src-card {
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: var(--r); padding: 20px 22px 18px;
}
.src-head { display: flex; align-items: center; gap: 12px; }
.src-name { font-weight: 600; font-size: 15.5px; letter-spacing: -0.005em; flex: 1; min-width: 0; }
.src-aside { margin-left: auto; display: flex; align-items: center; gap: 14px; flex: none; }
.src-sub { font-size: 13px; color: var(--ink-faint); line-height: 1.55; margin-top: 6px; }

/* #27 convention carried into the shelf: the status is a passive LABEL (muted
   caps, a green dot when connected), visibly distinct from the action button. */
.status-lab {
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  font-weight: 600; color: var(--ink-faint); cursor: default; white-space: nowrap;
}
.status-lab.on { color: var(--green); }
.status-lab .dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--green); margin-right: 6px; vertical-align: 1px;
  animation: pulse 2.4s var(--ease) infinite;
}

/* The drop-zone: the whole zone IS the control. The transparent file input
   stretches across it, so click opens the picker and a drop lands natively. */
.dropzone {
  position: relative;
  border: 1.5px dashed var(--hair); border-radius: 11px;
  padding: 18px; text-align: center;
  font-size: 13.5px; color: var(--ink-faint);
  margin-top: 14px;
  transition: border-color var(--med) var(--ease), background var(--med) var(--ease);
}
.dropzone b { color: var(--green); font-weight: 700; }
.dropzone.drag,
.dropzone:has(.owned-file-input:focus-visible) { border-color: var(--green); background: var(--green-tint); }
.dropzone.busy { border-style: solid; }
.dropzone .owned-file-input {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer; margin: 0; padding: 0;
}
.dropzone .owned-file-input:disabled { cursor: progress; }

/* Tangible file tiles: page-preview thumb (ghost lines + folded corner),
   name, "MD · 26 KB" meta + status chip, byline, quiet Download + a 34px
   "..." overflow. */
.file-tile {
  display: flex; align-items: center; gap: 14px;
  border: 1px solid var(--hair); border-radius: 11px;
  background: var(--paper);
  padding: 12px 14px;
}
.file-tile + .file-tile { margin-top: 10px; }
.thumb-page {
  position: relative; overflow: hidden; flex: none;
  width: 64px; height: 46px; padding: 7px 8px; box-sizing: border-box;
  background: var(--bone); border: 1px solid var(--hair-soft); border-radius: 7px;
}
.thumb-page::after {
  content: ""; position: absolute; top: 0; right: 0; width: 0; height: 0;
  border-style: solid; border-width: 0 14px 14px 0;
  border-color: var(--paper) var(--paper) var(--hair-soft) transparent;
}
.pg-line { height: 4px; border-radius: 2px; background: var(--hair-soft); margin-bottom: 5px; }
.pg-line.t { background: var(--green-tint); width: 55%; }
.pg-line.w85 { width: 85%; }
.pg-line.w70 { width: 70%; }
.pg-line.w45 { width: 45%; }
.tile-main { flex: 1; min-width: 0; }
.tile-title { font-size: 14.5px; font-weight: 600; color: var(--ink); word-break: break-word; }
.tile-meta {
  font-size: 12.5px; color: var(--ink-faint);
  display: flex; gap: 9px; align-items: center; flex-wrap: wrap; margin-top: 3px;
}
.byline { font-size: 11.5px; color: var(--ink-faint); margin-top: 6px; }
.tile-download { flex: none; }

/* The 34px "..." overflow target + its small menu (Download / Delete). */
.more-wrap { position: relative; flex: none; }
.more {
  width: 34px; height: 34px; border: 0; background: none; border-radius: 9px;
  color: var(--ink-faint); font-size: 17px; line-height: 1; cursor: pointer;
  display: grid; place-items: center;
  transition: background var(--med) var(--ease), color var(--med) var(--ease);
}
.more:hover { background: var(--green-tint); color: var(--ink); }
.more-menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 30;
  min-width: 140px; background: var(--paper); border: 1px solid var(--hair);
  border-radius: 10px; box-shadow: 0 8px 24px rgba(26, 26, 23, 0.12);
  padding: 6px; display: flex; flex-direction: column;
}
.menu-item {
  font: inherit; font-size: 13.5px; text-align: left;
  padding: 8px 10px; border: 0; background: none; border-radius: 7px;
  color: var(--ink); cursor: pointer;
}
.menu-item:hover { background: var(--green-tint); font-weight: 600; }
.menu-item.menu-danger { color: var(--danger); }

/* The single quiet dashed providers row (the three v1 boxes, collapsed). */
.providers {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: 13.5px; color: var(--ink-faint);
  padding: 16px 20px; border: 1.5px dashed var(--hair); border-radius: var(--r);
}
.prov-glyph {
  width: 26px; height: 26px; border-radius: 7px; flex: none;
  background: var(--paper); border: 1px solid var(--hair);
  display: grid; place-items: center; font-size: 11px; color: var(--ink-soft);
}
.prov-copy { min-width: 0; }
.v1-chip {
  margin-left: auto; flex: none; font-size: 10px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  border: 1px solid var(--hair); border-radius: 999px; padding: 3px 9px;
  color: var(--ink-faint);
}

@media (max-width: 560px) {
  .file-tile { flex-wrap: wrap; }
  /* On a phone the quiet Download hides; the "..." menu still carries it. */
  .tile-download { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .status-lab .dot { animation: none; }
}

/* ---- owned data (#7): upload errors + lists ----------------------------- */

.owned-err {
  margin-top: 12px; font-size: 14px; color: var(--danger);
  background: #F6EFDD; border: 1px solid #D8C9A8; border-radius: var(--r-sm);
  padding: 10px 14px;
}
.owned-list { display: flex; flex-direction: column; }
.owned-row .row-name { word-break: break-word; }

/* Per-file #8b processing status badge. Vocabulary: not-processed / processing
   / available / error — one calm, legible badge per state. */
.status-badge {
  font-size: 11.5px; letter-spacing: 0.03em; font-weight: 600;
  padding: 5px 11px; border-radius: 999px; white-space: nowrap;
  border: 1px solid var(--hair); background: var(--bone); color: var(--ink-faint);
}
.status-badge.status-available {
  background: var(--green); color: var(--bone); border-color: var(--green);
}
.status-badge.status-processing {
  background: var(--green-tint); color: var(--green); border-color: var(--green-tint);
}
.status-badge.status-processing::before {
  content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--green); margin-right: 7px; vertical-align: 1px;
  animation: pulse 1.6s var(--ease) infinite;
}
.status-badge.status-error {
  background: #F6EFDD; color: var(--danger); border-color: #D8C9A8;
}
@media (prefers-reduced-motion: reduce) {
  .status-badge.status-processing::before { animation: none; }
}
.owned-export { flex-wrap: wrap; }

/* ---- demo drive files (#8a): list with #8b status + "Use these to try" --- */
/* Indented under the connected Demo Drive row so it reads as that drive's
   contents. Reuses .owned-list / .row / .status-badge for the rows. */
.demo-files {
  margin-left: 8px; padding-left: 18px;
  border-left: 1px solid var(--hair);
}
.demo-try { display: flex; flex-wrap: wrap; gap: 12px; }
.demo-row .row-name { word-break: break-word; }

/* ---- composite profile (#18-web): the compiled context the AI reads ----- */
/* Sits ABOVE the Name field. Read-only compiled body + a three-state status
   chip + a client-side Download .md + an Upload-.md bootstrap. */
/* PROJ-W2 — Chrome-browser-style project tab strip, sitting just above the
   Composite block. A clean horizontal strip of tabs; the active one reads as the
   foreground "sheet" merging into the composite card below it, the rest sit
   quietly recessed. Scrolls horizontally on a phone rather than wrapping into a
   ragged pile. Racing-green accent; Schibsted Grotesk display; hover goes bold,
   never underline (house convention). */
.proj-tabs-slot { /* stable mount point - empty until projects load */ }
.proj-tabs {
  display: flex; align-items: flex-end; gap: 4px;
  margin-bottom: -1px; /* the active tab overlaps the composite top border */
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: thin; -webkit-overflow-scrolling: touch;
  padding-top: 2px;
}
/* The ARIA tablist is an inner wrapper holding ONLY the tabs (role="tablist"
   children must be tabs; "+ New" is a sibling button). display: contents keeps
   the strip's flex row laying out exactly as before. */
.proj-tablist { display: contents; }
.proj-tabs::-webkit-scrollbar { height: 5px; }
.proj-tabs::-webkit-scrollbar-thumb { background: var(--hair); border-radius: 999px; }
.proj-tab {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 7px;
  max-width: 200px;
  font-family: var(--display); font-size: 13.5px; font-weight: 500;
  color: var(--ink-faint);
  background: var(--bone-2);
  border: 1px solid var(--hair); border-bottom: none;
  border-radius: 9px 9px 0 0;
  padding: 9px 16px; cursor: pointer;
  transition: color var(--ease) 0.15s, background var(--ease) 0.15s, font-weight var(--ease) 0.15s;
  white-space: nowrap;
}
.proj-tab .proj-tab-label {
  overflow: hidden; text-overflow: ellipsis; max-width: 160px;
}
.proj-tab:hover { color: var(--ink); font-weight: 600; }
.proj-tab:focus-visible {
  outline: none; box-shadow: 0 0 0 2px var(--green-tint), 0 0 0 1px var(--green);
}
/* The active tab is the foreground sheet: same fill as the composite card it
   sits on, so it reads as one continuous surface, with a green top accent. */
.proj-tab.active {
  color: var(--green); font-weight: 600;
  background: var(--green-tint);
  border-color: var(--hair);
  box-shadow: inset 0 2px 0 var(--green);
  cursor: default;
}
.proj-tab-spin {
  width: 12px; height: 12px; border-width: 2px; flex: 0 0 auto;
}
/* "+ New" reads as a quiet new-tab affordance at the end of the strip. */
.proj-tab-new {
  color: var(--ink-faint); background: transparent; border-style: dashed;
  font-weight: 600;
}
.proj-tab-new:hover { color: var(--green); background: var(--green-tint); font-weight: 600; }
/* Calm inline notice for the create-limit (402) case - PROJ-W3 replaces this
   exact slot with the $20/mo upsell. */
.proj-new-notice {
  margin: 10px 0 0; font-size: 13.5px; line-height: 1.5;
  color: var(--ink-faint);
}
/* PROJ-UX(d) — the in-app inline "name your project" form (replaces window.prompt),
   sitting just below the strip. A compact field + Create/Cancel on one row. */
.proj-new-form { margin: 12px 0 0; }
.proj-new-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.proj-new-input {
  flex: 1 1 220px; max-width: 320px; min-width: 0;
}
.proj-new-confirm { flex: 0 0 auto; }
.proj-new-cancel { flex: 0 0 auto; }
.proj-new-formerr { margin-top: 6px; min-height: 0; }
.proj-new-formerr:empty { display: none; }
/* PROJ-UX(e) — the inline rename input swapped into the ACTIVE tab's label. It
   inherits the tab's display type + sizing so the tab doesn't jump on edit. */
.proj-rename-input {
  font-family: var(--display); font-size: 13.5px; font-weight: 600;
  color: var(--green); background: var(--paper);
  border: 1px solid var(--green); border-radius: 5px;
  padding: 2px 6px; max-width: 160px; width: 140px; min-width: 0;
}
.proj-rename-input:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--green-tint); }
/* PROJ-DEL — the small "x" delete affordance on the ACTIVE tab. Racing-green to
   match the active tab; hover goes BOLD (the project convention), not underline. */
.proj-tab-del {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; margin-left: 2px; border-radius: 4px;
  font-family: var(--display); font-size: 15px; line-height: 1; font-weight: 500;
  color: var(--green); opacity: 0.6; cursor: pointer;
  transition: opacity var(--ease) 0.15s, font-weight var(--ease) 0.15s, background var(--ease) 0.15s;
}
.proj-tab-del:hover { opacity: 1; font-weight: 700; background: var(--green-tint); }
.proj-tab-del:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--green-tint), 0 0 0 1px var(--green); opacity: 1; }
/* PROJ-DEL — the destructive type-to-confirm panel under the strip (oxblood wash,
   matching the Connect page's disconnect-all double-confirm language). */
.proj-del-form {
  margin: 14px 0 0; padding: 16px 18px;
  border: 1px solid var(--danger); border-radius: var(--r-sm);
  background: var(--danger-tint); /* the faintest oxblood wash, same as .danger-row */
}
.proj-del-title { font-weight: 600; color: var(--danger); font-size: 15px; line-height: 1.4; }
.proj-del-sub { margin: 6px 0 0; font-size: 13.5px; color: var(--ink-soft); line-height: 1.5; }
.proj-del-typehint { margin: 12px 0 6px; font-size: 13px; color: var(--ink-soft); font-weight: 500; }
.proj-del-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.proj-del-input { flex: 1 1 220px; max-width: 320px; min-width: 0; }
.proj-del-confirm { flex: 0 0 auto; }
.proj-del-cancel { flex: 0 0 auto; }
.proj-del-formerr { margin-top: 6px; min-height: 0; color: var(--danger); }
.proj-del-formerr:empty { display: none; }
@media (max-width: 640px) {
  .proj-new-input { flex-basis: 160px; }
}
@media (max-width: 640px) {
  .proj-tab { padding: 8px 13px; font-size: 13px; }
  .proj-tab .proj-tab-label { max-width: 120px; }
}

/* PROJ-W3 — the $20/mo upgrade modal shown when a FREE user at their project
   limit clicks "+ New". Reuses the shared `.lp-modal-ov`/`.lp-modal` shell but
   re-skins it into the in-APP aesthetic: warm paper surface, racing-green accent
   (#1F3D2B), Schibsted Grotesk display (var(--display)) - NOT the landing modal's
   serif/purple. The CTA is a VISUAL placeholder (no Stripe yet). */
.upsell-modal {
  background: var(--paper); color: var(--ink); max-width: 440px;
  border: 1px solid var(--hair);
  box-shadow: 0 24px 64px rgba(22, 48, 31, 0.22);
}
.upsell-title {
  font-family: var(--display); font-weight: 700; color: var(--ink);
  font-size: 27px; letter-spacing: -0.02em;
}
.upsell-modal .lp-modal-text { color: var(--ink-soft); }
.upsell-modal .lp-eyebrow { color: var(--green); }
.upsell-values { list-style: none; margin: 0 0 22px; padding: 0; display: grid; gap: 12px; }
.upsell-value {
  display: flex; flex-direction: column; gap: 3px;
  background: var(--green-tint); border: 1px solid var(--hair);
  border-radius: var(--r-sm); padding: 13px 16px;
}
.upsell-value-num {
  font-family: var(--display); font-weight: 700; font-size: 17px;
  color: var(--green); letter-spacing: -0.01em;
}
.upsell-value-sub { font-size: 13px; line-height: 1.45; color: var(--ink-faint); }
/* BILL-UX-4 - the FREE-vs-PREMIUM comparison inside the upgrade modal. Two columns
   side by side on desktop; they stack cleanly on a phone (<=375px) via the single-
   column fallback below. Free is the muted current plan ("Your plan" tag); Premium
   is the racing-green upgrade target carrying the $20/mo price. */
.upsell-compare {
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 0 0 20px;
}
.upsell-col {
  display: flex; flex-direction: column; gap: 10px;
  border: 1px solid var(--hair); border-radius: var(--r-sm);
  padding: 14px 16px; background: var(--paper);
}
.upsell-col-premium {
  border-color: var(--green); background: var(--green-tint);
  box-shadow: inset 0 0 0 1px var(--green);
}
.upsell-col-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }
.upsell-col-name {
  font-family: var(--display); font-weight: 700; font-size: 16px;
  letter-spacing: -0.01em; color: var(--ink);
}
.upsell-col-premium .upsell-col-name { color: var(--green); }
.upsell-col-tag {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--ink-faint); background: var(--green-tint);
  border: 1px solid var(--hair); border-radius: 999px; padding: 2px 8px;
}
.upsell-col-price {
  font-family: var(--display); font-weight: 700; font-size: 14px; color: var(--green);
  letter-spacing: -0.01em;
}
.upsell-col-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.upsell-col-item { font-size: 14px; line-height: 1.4; color: var(--ink-soft); }
.upsell-col-premium .upsell-col-item { color: var(--ink); font-weight: 600; }
@media (max-width: 420px) {
  .upsell-compare { grid-template-columns: 1fr; }
}
.upsell-price { display: flex; align-items: baseline; gap: 10px; margin: 0 0 18px; }
.upsell-price-amt {
  font-family: var(--display); font-weight: 700; font-size: 24px; color: var(--ink);
  letter-spacing: -0.02em;
}
.upsell-price-sub { font-size: 13px; color: var(--ink-faint); }
.upsell-cta-wrap { display: grid; gap: 12px; }
.upsell-cta { width: 100%; justify-content: center; }
.upsell-note {
  margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--green);
  background: var(--green-tint); border: 1px solid var(--hair);
  border-radius: var(--r-sm); padding: 11px 14px;
}
@media (max-width: 640px) {
  .upsell-modal { padding: 36px 24px 28px; }
}

/* STUDIO (item 8) — the composite card: "What your AI reads". Green-tint panel,
   sticky on desktop (via .studio-comp), the serif compiled body inside, the
   Download + share cluster footer. */
.composite {
  background: var(--green-tint);
  border: 1px solid var(--hair);
  border-radius: var(--r);
  padding: 22px 24px 18px;
}
.comp-head { display: flex; align-items: center; gap: 12px; }
.comp-head .col-label { margin: 0; flex: 1; }
.comp-sub {
  margin: 6px 0 14px; font-size: 13px; line-height: 1.5; color: var(--ink-faint);
}
/* The three-state chip - with no Save button this IS the page's save indicator.
   up-to-date=green solid, updating=tinted, error=oxblood; all carry the pulse dot. */
.composite-chip {
  margin-left: auto; flex: none;
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 11.5px; letter-spacing: 0.03em; font-weight: 600;
  padding: 5px 13px; border-radius: 999px; white-space: nowrap;
  border: 1px solid var(--hair); background: var(--bone); color: var(--ink-faint);
}
.composite-chip.ok { background: var(--green); color: var(--bone); border-color: var(--green); }
.composite-chip.updating { background: var(--paper); color: var(--green); border-color: var(--hair); }
.composite-chip.err { background: var(--gold-tint); color: var(--danger); border-color: var(--gold-hair); }
.chip-pulse {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: currentColor; opacity: 0.7;
  animation: pulse 2.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .chip-pulse { animation: none; }
}
/* The read-only compiled body - the ONLY serif surface on the page (Newsreader
   inside composite bodies, Schibsted everywhere else). Preserves the compiled
   markdown's line breaks. */
.composite-body {
  background: var(--paper);
  border: 1px solid var(--hair);
  border-radius: var(--r-sm);
  padding: 18px 20px;
  font-family: var(--serif);
  font-size: 16px; line-height: 1.6; color: var(--ink);
  white-space: pre-wrap; word-break: break-word;
}
.composite-body.muted { color: var(--ink-faint); }
/* Footer: a quiet Download .md + the share cluster (share lives ON the thing
   being shared). */
.comp-foot {
  display: flex; align-items: center; gap: 14px; margin-top: 16px; flex-wrap: wrap;
}
.foot-spacer { flex: 1; }
.btn-quiet {
  border: 1px solid var(--hair); background: var(--paper); color: var(--ink);
  border-radius: 999px; font-size: 13.5px; font-weight: 500; padding: 8px 18px;
  transition: border-color var(--med) var(--ease);
}
.btn-quiet:hover:not(:disabled) { border-color: var(--green); }
.btn-quiet:disabled { opacity: 0.5; cursor: default; }
.share-cluster { display: flex; align-items: center; gap: 10px; }
.share-cluster .avatars { display: flex; }
.share-avatar {
  width: 28px; height: 28px; border-radius: 50%; border: 2px solid var(--green-tint);
  display: grid; place-items: center; font-size: 11px; font-weight: 700; color: #fff;
}
.share-avatar + .share-avatar { margin-left: -9px; }
.share-avatar.av1 { background: #5B7B6A; }
.share-avatar.av2 { background: var(--gold); }
.share-label { font-size: 13px; color: var(--ink-soft); }
.btn-share {
  background: var(--green); color: var(--bone); border: 0; border-radius: 999px;
  font-size: 13.5px; font-weight: 600; padding: 9px 20px;
  transition: background var(--med) var(--ease);
}
.btn-share:hover { background: var(--green-deep); }
/* First-run ghost composite: silhouette lines + one honest note, no filler prose. */
.comp-ghost {
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: var(--r-sm); padding: 22px 24px;
}
.ghost-h { width: 90px; height: 9px; border-radius: 5px; background: var(--green-tint); margin: 18px 0 10px; }
.comp-ghost .ghost-h:first-child { margin-top: 0; }
.ghost-line { height: 11px; border-radius: 5px; background: var(--hair-soft); margin: 10px 0; }
.ghost-line.w80 { width: 80%; }
.ghost-line.w60 { width: 60%; }
.ghost-line.w40 { width: 40%; }
.comp-ghost-note {
  margin: 14px 2px 0; font-size: 13.5px; line-height: 1.55; color: var(--ink-faint);
}

/* #45-web / STUDIO — the link RETRY form + its live preview card. A failed
   composer link-add reopens this pre-filled in the stable slot beneath the
   composer (in place, not a modal). */
.link-form-slot:empty { display: none; }
.link-form {
  margin-top: 12px; padding: 16px;
  background: var(--paper); border: 1px solid var(--hair); border-radius: var(--r-sm);
  display: flex; flex-direction: column; gap: 12px;
}
.link-input-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.link-url-input { flex: 1 1 280px; min-width: 0; }
.link-preview-btn { flex: 0 0 auto; }
.link-cancel-btn { flex: 0 0 auto; color: var(--ink-faint); font-weight: 500; }
.link-cancel-btn:hover:not(:disabled) { color: var(--ink-soft); font-weight: 600; }
/* The live preview card: favicon + title + site + description. */
.link-preview-card {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 14px; background: var(--bone-2);
  border: 1px solid var(--hair); border-radius: var(--r-sm);
}
.link-preview-main { flex: 1; min-width: 0; }
.link-preview-title {
  font-family: var(--display); font-weight: 600; font-size: 15px; line-height: 1.4;
  color: var(--ink); word-break: break-word;
}
.link-preview-site {
  margin-top: 2px; font-size: 12.5px; letter-spacing: 0.01em; color: var(--green);
}
.link-preview-desc {
  margin-top: 6px; font-size: 13.5px; line-height: 1.5; color: var(--ink-faint);
  word-break: break-word;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.link-confirm-row { display: flex; align-items: center; gap: 10px; }
.link-err { margin-top: 0; }

/* #45-web — the favicon glyph (a remote <img> from the link's own absolute URL;
   on error it swaps to the fallback dot). Shared by preview card + link rows. */
.link-fav {
  width: 16px; height: 16px; flex: none; border-radius: 3px;
  margin-top: 2px; object-fit: contain;
}
.link-fav-fallback {
  width: 14px; height: 14px; border-radius: 3px; background: var(--green-tint);
  border: 1px solid var(--hair); display: inline-block; margin-top: 3px;
}
/* The calm transient "Added to Your Data" confirmation — racing-green, no flash. */
.addfile-ok { font-size: 13px; font-weight: 600; color: var(--green); white-space: nowrap; }
@media (max-width: 640px) {
  /* #45-web — on a phone the link retry form goes full-width and the preview
     wraps gracefully (no horizontal overflow). */
  .link-input-row { flex-direction: column; align-items: stretch; }
  .link-url-input { flex: 1 1 auto; }
}

/* ---- the source stream (STUDIO left pane) -------------------------------
   Facts are quiet ROWS, not cards: a grip glyph, the editable text, and a
   hover-revealed 34px "..." overflow holding Remove. Rows save themselves
   (blur / Cmd+Return) - the composite chip is the only save indicator. */

.facts-list { display: flex; flex-direction: column; gap: 2px; }
.fact {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 12px;
  border-radius: var(--r-sm);
  transition: background 0.2s var(--ease), box-shadow var(--med) var(--ease);
  position: relative;
}
.fact:hover { background: var(--row-hover); }
.fact:focus-within { background: var(--row-hover); box-shadow: 0 0 0 1.5px var(--green-tint); }
.grip {
  color: var(--hair); font-size: 13px; letter-spacing: -1px; user-select: none;
  width: 12px; flex: none; margin-top: 4px;
}
.fact:hover .grip { color: var(--ink-faint); }
.fact-text {
  flex: 1; border: none; background: none; color: var(--ink);
  font-size: 15.5px; line-height: 1.5; padding: 2px 0; resize: none;
  font-family: var(--display);
}
.fact-text:focus { outline: none; }
.fact-acts { display: flex; align-items: center; gap: 2px; flex: none; position: relative; }
/* The 34px "..." overflow target - generous, hover-revealed on desktop, always
   visible on touch. Never a cramped delete glyph. */
.more {
  flex: none; width: 34px; height: 34px; border: 0; background: none;
  border-radius: var(--r-sm); color: var(--ink-faint);
  font-size: 17px; letter-spacing: 0.5px; line-height: 1;
  display: grid; place-items: center;
  opacity: 0; transition: opacity 0.15s var(--ease), background 0.15s var(--ease);
}
.fact:hover .more, .fact:focus-within .more, .more[aria-expanded="true"] { opacity: 1; }
.more:hover, .more:focus-visible { background: var(--green-tint); color: var(--ink); opacity: 1; }
@media (hover: none) {
  .more { opacity: 1; }
}
/* The row overflow menu (Remove). */
.row-menu {
  display: none; position: absolute; right: 0; top: 38px; z-index: 30;
  min-width: 130px; padding: 4px;
  background: var(--paper); border: 1px solid var(--hair); border-radius: var(--r-sm);
  box-shadow: 0 10px 26px rgba(26, 26, 23, 0.14);
}
.row-menu.open { display: block; }
.row-menu-item {
  display: block; width: 100%; text-align: left; padding: 9px 12px;
  border: 0; background: none; border-radius: 7px;
  font-size: 13.5px; color: var(--ink); cursor: pointer;
}
.row-menu-item:hover { background: var(--bone-2); font-weight: 600; }
.row-menu-item.fact-del { color: var(--danger); }

/* The Name row leads the stream: inline editable, existing save semantics.
   Label + input value share ONE vertically-centred baseline; the field reserves
   its border at rest (transparent) so the green focus ring never shifts layout. */
.row.name-row {
  display: flex; align-items: center; gap: 9px;
  padding: 12px 16px; margin: 0 0 12px;
}
.name-row .k {
  font-size: 11.5px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-faint); width: auto; flex: none; line-height: 1;
  align-self: center;
}
.name-row .profile-name-input {
  flex: 1; max-width: 340px; font-weight: 600; font-size: 17px; line-height: 1.2;
  background: transparent; border: 1px solid transparent; border-radius: 9px;
  padding: 7px 9px; box-shadow: none;
}
.name-row .profile-name-input:hover { border-color: var(--hair); }
.name-row .profile-name-input:focus {
  background: var(--paper); border-color: var(--green);
  box-shadow: 0 0 0 3px var(--green-tint);
}

/* #45-web — a LINK row: the favicon + title link is the row's identity, sitting
   ABOVE the editable summary (in a .fact-main column). The summary textarea
   stays editable exactly like a plain fact. */
.fact-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.fact-main .fact-text { width: 100%; }
.link-head { display: flex; align-items: center; gap: 8px; min-width: 0; }
.link-title {
  font-family: var(--display); font-weight: 600; font-size: 15px; line-height: 1.4;
  color: var(--green); text-decoration: none; word-break: break-word;
  min-width: 0; overflow-wrap: anywhere;
}
/* Hover affordance is bold, not an underline (house convention). */
.link-title:hover { font-weight: 700; text-decoration: none; }

/* #51-web — a PENDING optimistic link row: the link header appears instantly
   from the preview while the summary settles server-side. A calm muted note +
   a tiny inline spinner stand in for the editable summary; the whole row reads
   slightly dimmed so it's clearly settling (no blocking full-width spinner). */
.fact.is-pending { opacity: 0.72; }
.link-pending {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--serif); font-size: 14px; color: var(--ink-faint);
}
.link-pending-spin { width: 12px; height: 12px; border-width: 2px; color: var(--green); }

/* ---- the ONE composer (STUDIO) ------------------------------------------
   Replaces the +fact / +link / +file button row: type a fact, paste a URL, or
   attach/drop a file - the input figures out which lane. */
.composer {
  margin-top: 18px;
  background: var(--paper); border: 1px solid var(--hair); border-radius: 12px;
  padding: 4px 6px 4px 16px;
  display: flex; align-items: center; gap: 8px;
  box-shadow: 0 1px 2px rgba(26, 26, 23, 0.04);
  transition: border-color var(--med) var(--ease), box-shadow var(--med) var(--ease);
}
.composer:focus-within { border-color: var(--green); box-shadow: 0 0 0 3px var(--green-tint); }
.composer-input {
  flex: 1; min-width: 0; border: 0; background: none; outline: none;
  font-size: 15px; padding: 11px 0; color: var(--ink);
}
.composer-input::placeholder { color: var(--ink-faint); }
.composer-attach {
  flex: none; border: 0; background: none; color: var(--ink-faint);
  font-size: 16px; padding: 8px; border-radius: 8px; line-height: 1;
}
.composer-attach:hover:not(:disabled) { color: var(--green); background: var(--green-tint); }
.composer-commit {
  flex: none; background: var(--green); color: var(--bone); border: 0;
  border-radius: var(--r-sm); font-size: 13.5px; font-weight: 600; padding: 9px 16px;
}
.composer-commit:hover:not(:disabled) { background: var(--green-deep); }
.composer-commit:disabled, .composer-attach:disabled { opacity: 0.5; cursor: default; }
/* The hidden file input behind attach / "drop in a doc". */
.composer-file {
  position: absolute; width: 1px; height: 1px; opacity: 0;
  pointer-events: none; clip-path: inset(50%);
}
.composer-hint {
  margin-top: 8px; padding-left: 4px;
  font-size: 12.5px; color: var(--ink-faint);
}
.composer-hint kbd {
  font-family: inherit; border: 1px solid var(--hair); border-bottom-width: 2px;
  border-radius: 4px; padding: 0 5px; font-size: 11px; background: var(--paper);
  margin-right: 2px;
}
/* The composer's transient status line (import/upload busy, ok, calm errors). */
.composer-status { margin-top: 8px; padding-left: 4px; display: flex; flex-direction: column; gap: 6px; }
.composer-status:empty { display: none; }
.composer-busy { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-faint); }
.composer-err { font-size: 13px; }
/* Drop affordance while a file is dragged over the source side. */
.studio-source.drag-over .composer { border-color: var(--green); box-shadow: 0 0 0 3px var(--green-tint); }

/* ---- THE STUDIO GRID (item 8, mock screens 1 + 2) ------------------------
   Two panes joined by the compile spine: left "What you tell it" (the source
   stream), a narrow center column, right "What your AI reads" (the sticky
   composite). Single column on narrow viewports (the real mobile dock is
   part 2). The Profile shell widens to make room. */
.shell-studio { max-width: 1200px; }
.studio {
  display: grid;
  grid-template-columns: 1fr 96px 1.15fr;
  align-items: stretch;
}
/* The source side is a tall column: content flows from the TOP, the composer is
   pinned to the BOTTOM (chat-composer pattern) so empty space sits in the middle
   and the left pane reads as one container the same height as the right card. A
   matching subtle border ties it to the composite without heavy chrome. */
.studio-source {
  min-width: 0; position: relative;
  display: flex; flex-direction: column;
  border: 1px solid var(--hair-soft); border-radius: var(--r);
  padding: 20px 20px 18px;
  background: var(--bone-2);
}
/* The composer block (composer + hint + status + link retry form) sinks to the
   foot of the source column; whatever space is left opens up above it. */
.studio-source > .composer { margin-top: auto; }
.studio-comp { min-width: 0; position: sticky; top: 24px; }
.col-label {
  font-size: 11.5px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-faint); font-weight: 600; margin-bottom: 14px;
  display: flex; align-items: baseline; gap: 10px;
}
.col-label .sub {
  letter-spacing: 0; text-transform: none; font-weight: 400; font-size: 12.5px;
}

/* The compile seam - the literal data flow made ALIVE: the LEFT source becomes
   the right composite. A thin "current" line carries a single node drifting
   LEFT -> RIGHT (facts continuously flowing into context), the lowercase label
   "becomes" centred on the line. On desktop it reads LEFT -> RIGHT; on a phone
   (stacked) the same markup reads TOP -> BOTTOM (CSS rotates it). The seam IS
   the loading indicator: while the composite recompiles (.compiling) it SURGES
   (rule further below). */
.studio-spine {
  align-self: center; display: flex; flex-direction: column; align-items: center;
  gap: 10px; padding: 0 6px;
}
.spine-flow {
  position: relative; display: flex; align-items: center; width: 100%;
}
/* The current line: subtle flowing dashes at rest (low opacity), full at surge.
   The dash flow is GPU-cheap (background-position drift). */
.spine-track {
  position: relative; height: 2px; flex: 1 1 auto; min-width: 44px;
  border-radius: 2px; overflow: visible; opacity: 0.45;
  background-image: linear-gradient(90deg, var(--green) 0 50%, transparent 50% 100%);
  background-size: 10px 2px; background-repeat: repeat-x;
  animation: spine-current 2.8s linear infinite;
  transition: opacity 0.45s ease;
}
@keyframes spine-current {
  0% { background-position: 0 0; }
  100% { background-position: 20px 0; }
}
/* The node: a small dot that slowly drifts the length of the line on a loop. */
.spine-node {
  position: absolute; top: 50%; left: 0; width: 7px; height: 7px;
  border-radius: 50%; background: var(--green); transform: translateY(-50%);
  opacity: 0.55; box-shadow: 0 0 0 0 var(--green);
  animation: spine-drift 2.8s ease-in-out infinite;
  transition: opacity 0.45s ease;
}
@keyframes spine-drift {
  0% { left: 2%; opacity: 0; }
  12% { opacity: 0.55; }
  88% { opacity: 0.55; }
  100% { left: 98%; opacity: 0; }
}
/* The label rides ON the line, centred; one word visible at a time (idle vs
   busy crossfade via the .compiling toggle). A small pad of canvas behind it
   keeps the current line from striking through the text. */
.spine-label {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  display: grid; place-items: center; padding: 1px 7px;
  background: var(--bone); border-radius: 10px; pointer-events: none;
}
.spine-word {
  grid-area: 1 / 1; font-size: 11px; letter-spacing: 0.01em;
  color: var(--ink-faint); line-height: 1.2; white-space: nowrap;
  transition: opacity 0.25s ease;
}
.spine-word-busy { opacity: 0; }
.studio-spine.compiling .spine-word-idle { opacity: 0; }
.studio-spine.compiling .spine-word-busy { opacity: 1; color: var(--green); }
@media (prefers-reduced-motion: reduce) {
  /* No drift/surge - just the label swap (above) carries the state change. */
  .studio-spine .spine-track, .studio-spine .spine-node,
  .studio-spine.compiling .spine-track, .studio-spine.compiling .spine-node {
    animation: none;
  }
  .studio-spine .spine-node { opacity: 0.55; left: 50%; }
}

/* First-run: the same instrument, dimmed. Ghost rows / card / composer below a
   LIVE focused Name entry; the composite card's chrome falls away around its
   ghost. No filler prose. */
.ghosted { opacity: 0.42; pointer-events: none; }
.first-hint {
  font-size: 13.5px; color: var(--ink-soft); margin: 10px 14px 26px; line-height: 1.65;
}
.first-hint .first-drop-link,
.first-hint .first-interview-link {
  color: var(--green); font-weight: 600; padding: 0; font-size: inherit;
}
.first-hint .first-drop-link:hover,
.first-hint .first-interview-link:hover { font-weight: 700; }
.ghost-stream .g-row { display: flex; align-items: center; gap: 10px; padding: 13px 14px; }
.g-bar { height: 10px; border-radius: 5px; background: var(--hair-soft); flex: 1; }
.g-bar.short { flex: 0 0 55%; }
.g-bar.w62 { flex: none; width: 62%; margin: 8px 0 9px; }
.g-bar.w38 { flex: none; width: 38%; height: 8px; }
.g-av { width: 18px; height: 18px; border-radius: 50%; background: var(--hair); flex: none; }
.g-card {
  display: flex; gap: 13px; align-items: center;
  background: var(--paper); border: 1px solid var(--hair); border-radius: 11px;
  padding: 11px 13px; margin: 8px 0 0;
}
.g-thumb { width: 92px; height: 64px; border-radius: 7px; background: var(--hair-soft); flex: none; }
.g-card-main { flex: 1; min-width: 0; }
.first-run .name-row { border-bottom: 0; margin-bottom: 0; }
.first-run .name-row .profile-name-input {
  background: var(--paper); border-color: var(--green);
  box-shadow: 0 0 0 3px var(--green-tint); border-radius: 10px;
}
.first-run .composite { background: transparent; border-color: transparent; padding: 0; }
/* First-run: the source container loses its frame too, so the dimmed instrument
   reads as one quiet silhouette (no heavy box around the ghosts). The composer
   still sinks to the foot. */
.first-run .studio-source { border-color: transparent; background: transparent; padding: 0; }

/* ---- THE IN-STUDIO INTERVIEW (item 1b, mock screen 5) --------------------
   Your Bot builds the user's context WITH them, one question at a time. The
   thread (gold banner + Q/A bubbles) lives at the TOP of the left source pane;
   distilled facts settle into the NORMAL stream below (bot-signed rows). */
.iv-thread:empty { display: none; }
.iv-thread { margin: 6px 0 4px; }
.iv-bar {
  display: flex; align-items: center; gap: 9px;
  background: var(--gold-tint); border: 1px solid var(--gold-hair);
  border-radius: 11px; padding: 10px 14px; font-size: 13px; color: var(--ink-soft);
  margin-bottom: 14px;
}
.iv-bar .iv-bar-label { font-weight: 600; color: var(--ink); }
.iv-bar .iv-end { margin-left: auto; font-size: 12px; padding: 6px 14px; }
.iv-q { display: flex; gap: 9px; align-items: flex-start; margin: 12px 0 8px; }
.iv-q .bubble {
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: 3px 13px 13px 13px; padding: 11px 15px;
  font-size: 14.5px; line-height: 1.5; color: var(--ink); max-width: 86%;
}
.iv-q .bubble.iv-starting { display: inline-flex; align-items: center; gap: 4px; color: var(--ink-faint); }
.iv-a {
  margin: 8px 0 10px auto; max-width: 82%; width: fit-content;
  background: var(--green); color: var(--bone);
  border-radius: 13px 3px 13px 13px; padding: 11px 15px;
  font-size: 14.5px; line-height: 1.5;
}
.iv-err { margin: 6px 2px 10px; font-size: 13px; }
/* The interview answer-box composer keeps the same chrome; only the copy
   changes (handled in JS). Nothing extra needed here. */

/* The share sheet hangs below the composite card. */
.share-slot:not(:empty) { margin-top: 14px; }

/* THE SURGE - while the composite recompiles the seam ANSWERS (a class toggle
   riding the existing status polling): the node SPEEDS UP (~0.7s), and line +
   node go FULL opacity. The label swap ("becomes" -> "reading…") is handled in
   the base block above. prefers-reduced-motion (above) drops all of this and
   keeps only the label swap. */
.studio-spine.compiling .spine-track {
  opacity: 1; animation-duration: 0.7s;
}
.studio-spine.compiling .spine-node {
  opacity: 1; animation: spine-drift 0.7s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .studio-spine.compiling .spine-track,
  .studio-spine.compiling .spine-node { animation: none; }
}

/* ---- THE MULTIPLAYER CAST (item 9) ---------------------------------------
   One face per actor, everywhere: You (green, your initial), Your Bot (gold
   "My"), Claude (coral spark), ChatGPT (teal G), unknown neutral. The brand
   discs are PINNED hexes so they hold across Day/Dusk/Night. */
.cast-av {
  position: relative; display: inline-grid; place-items: center; flex: none;
  width: 18px; height: 18px; border-radius: 50%;
  border: 1.5px solid var(--bone);
  background: var(--bone-2); color: var(--ink-soft);
  font-family: var(--display); font-size: 8px; font-weight: 800; line-height: 1;
  letter-spacing: 0;
}
.cast-av-you { background: var(--green); color: var(--bone); }
.cast-av-bot { background: var(--gold); color: #fff; font-size: 7.5px; }
.cast-av-claude { background: #BF6A4B; color: #F4F1EA; font-size: 9px; }
.cast-av-gpt { background: #4E7D74; color: #F4F1EA; }
.cast-av.live::after {
  content: ""; position: absolute; right: -2px; bottom: -2px;
  width: 6px; height: 6px; border-radius: 50%;
  background: #3E8E5A; border: 1.5px solid var(--paper);
}
.avatars { display: flex; }
.avatars .cast-av + .cast-av { margin-left: -6px; }

/* The contributor stack on the left column label: avatars + "N voices write
   here". Rides the col-label row, pushed to its right edge. */
.cast { display: inline-flex; align-items: center; gap: 7px; margin-left: auto; align-self: center; }
.cast:empty { display: none; }
.cast .cast-label {
  letter-spacing: 0; text-transform: none; font-weight: 400;
  font-size: 12px; color: var(--ink-faint); white-space: nowrap;
}

/* The quiet per-row byline avatar (who put this row here). */
.fact .row-av { margin-top: 5px; opacity: 0.85; }

/* The gold suggestion row's attribution line gains the suggester's face. */
.cand-source { display: flex; align-items: center; gap: 6px; }
.cand-source .cast-av { width: 15px; height: 15px; font-size: 7px; border-color: var(--gold-tint); }

/* ---- TANGIBLE CARDS in the source stream (item 9) -------------------------
   A link is a card you can see and trust: thumb (og-image or the solid deep-
   green wordmark tile - NO gradients, NO glass), title link, favicon + domain,
   the editable summary, a byline. Files get the page-preview tile. */
.fact.is-link {
  background: var(--paper); border: 1px solid var(--hair); border-radius: 11px;
  padding: 11px 13px; margin-top: 8px; align-items: center;
  box-shadow: 0 1px 4px rgba(26, 26, 23, 0.06);
}
.fact.is-link:hover { background: var(--paper); box-shadow: 0 3px 10px rgba(26, 26, 23, 0.1); }
.link-thumb {
  width: 92px; height: 64px; border-radius: 7px; flex: none;
  overflow: hidden; position: relative; display: grid; align-self: center;
}
.link-thumb-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumb-og {
  display: grid; place-items: center; width: 100%; height: 100%;
  border-radius: 7px; background: var(--brand-green);
}
.thumb-og .wordmark {
  font-family: var(--serif); font-style: italic; font-weight: 700;
  font-size: 22px; color: var(--brand-cream);
}
.link-meta {
  display: flex; align-items: center; gap: 7px; min-width: 0;
  font-size: 12px; color: var(--ink-faint);
}
.link-domain { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.byline.card-byline {
  display: flex; align-items: center; gap: 6px; margin-top: 2px;
  font-size: 11.5px; color: var(--ink-faint);
}
.byline.card-byline .cast-av { width: 14px; height: 14px; font-size: 7px; border-color: var(--paper); }

/* A file/import card: the page-preview tile (shared .thumb-page ghost lines +
   folded corner, sized up to the card thumb), name, meta + extraction chip. */
.file-card {
  display: flex; align-items: center; gap: 13px;
  background: var(--paper); border: 1px solid var(--hair); border-radius: 11px;
  padding: 11px 13px; margin-top: 8px; position: relative;
  box-shadow: 0 1px 4px rgba(26, 26, 23, 0.06);
}
.file-card .card-thumb-page { width: 92px; height: 64px; padding: 9px 10px; }
.card-main { flex: 1; min-width: 0; }
.card-title {
  font-size: 14.5px; font-weight: 600; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.card-meta {
  font-size: 12px; color: var(--ink-faint);
  display: flex; gap: 7px; align-items: center; margin-top: 3px;
}
.extract-chip {
  font-size: 11px; color: var(--green); background: var(--green-tint);
  border-radius: 5px; padding: 1.5px 8px; font-weight: 600; white-space: nowrap;
}
.file-card .more, .fact.is-link .more { opacity: 1; }

/* ---- READ RECEIPTS on the composite (item 9) ------------------------------
   Who consumed this context and when; a live dot on a currently-active
   reader. Renders NOTHING when there are no reads yet. */
.readers {
  display: flex; align-items: center; gap: 9px;
  margin: 12px 2px; font-size: 12.5px; color: var(--ink-soft);
}
.readers .cast-av { border-color: var(--green-tint); }
.readers b { font-weight: 600; color: var(--green); }
.readers-text { min-width: 0; }

/* Single column on narrow viewports: source stream first, composite below.
   The grid seat is a display:contents slot so the phone bottom sheet can
   borrow the live card and hand it back. */
.studio-comp-slot { display: contents; }
@media (max-width: 940px) {
  .studio { grid-template-columns: 1fr; }
  .studio-comp { position: static; margin-top: 4px; }
  /* Stacked: the seam sits BETWEEN the panes and reads TOP -> DOWN (the source
     above becomes the composite below). Same markup, rotated current. The label
     sits beside the vertical line (not over it). */
  .studio-spine {
    align-self: center; flex-direction: row; gap: 10px; align-items: center;
    margin: 18px 0 2px; padding: 0;
  }
  .studio-spine .spine-flow { flex-direction: column; width: auto; height: 44px; }
  .studio-spine .spine-track {
    width: 2px; height: auto; flex: 1 1 auto; min-width: 0; min-height: 28px;
    background-image: linear-gradient(180deg, var(--green) 0 50%, transparent 50% 100%);
    background-size: 2px 10px; background-repeat: repeat-y;
    animation: spine-current-v 2.8s linear infinite;
  }
  @keyframes spine-current-v {
    0% { background-position: 0 0; }
    100% { background-position: 0 20px; }
  }
  /* The node drifts DOWN the line; the label sits to the side (static). */
  .studio-spine .spine-node {
    left: 50%; top: 0; transform: translateX(-50%);
    animation: spine-drift-v 2.8s ease-in-out infinite;
  }
  @keyframes spine-drift-v {
    0% { top: 2%; opacity: 0; }
    12% { opacity: 0.55; }
    88% { opacity: 0.55; }
    100% { top: 98%; opacity: 0; }
  }
  .studio-spine .spine-label {
    position: static; left: auto; top: auto; transform: none; background: none; padding: 0;
  }
  .studio-spine.compiling .spine-track {
    opacity: 1; animation-duration: 0.7s;
  }
  .studio-spine.compiling .spine-node {
    opacity: 1; animation: spine-drift-v 0.7s ease-in-out infinite;
  }
}
@media (max-width: 940px) and (prefers-reduced-motion: reduce) {
  .studio-spine .spine-track, .studio-spine .spine-node,
  .studio-spine.compiling .spine-track, .studio-spine.compiling .spine-node {
    animation: none;
  }
  .studio-spine .spine-node { top: 50%; opacity: 0.55; }
}

/* ---- Item 9: the MOBILE DOCK + BOTTOM SHEET (<=720px) ---------------------
   The composite folds into a fixed racing-green mini-player bar; its 2.5px
   top edge runs the compile light while updating (the spine, folded into the
   bar). Tapping the dock raises the composite as a bottom sheet. Hidden
   entirely on wider viewports. */
.studio-dock { display: none; }
.studio-sheet { display: none; }
body.dock-sheet-open { overflow: hidden; }

@media (max-width: 720px) {
  /* The grid copy of the composite yields to the dock; the inter-pane spine
     goes with it (the dock's top edge runs the compile light instead). */
  .studio-comp-slot .studio-comp { display: none; }
  .studio-spine { display: none; }

  .studio-dock {
    display: flex; align-items: center; gap: 10px;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 180;
    width: 100%; border: 0; text-align: left; cursor: pointer;
    padding: 14px 16px calc(14px + env(safe-area-inset-bottom));
    background: var(--green); color: #fff;
  }
  .studio-dock .dock-line {
    font-family: var(--display); font-weight: 500; font-size: 13px;
    opacity: 0.88; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    flex: 1; min-width: 0;
  }
  .studio-dock .dock-chip {
    flex: none; font-size: 9.5px; font-weight: 700; letter-spacing: 0.05em;
    text-transform: uppercase; color: #fff;
    background: rgba(255, 255, 255, 0.18); border-radius: 999px; padding: 3px 9px;
  }
  .studio-dock .dock-chev { flex: none; opacity: 0.65; font-size: 10px; }
  /* First-run ghost: a grey silhouette bar that wakes on the first compile. */
  .studio-dock.dock-ghost { background: var(--hair-soft); color: var(--ink-faint); cursor: default; }
  .studio-dock.dock-ghost .dock-line { opacity: 1; }
  /* The compile light along the dock's top edge, only while updating. */
  .dock-edge {
    position: absolute; top: 0; left: 0; right: 0; height: 2.5px;
    overflow: hidden; display: none;
  }
  .dock-edge span {
    position: absolute; top: 0; width: 36px; height: 2.5px;
    background: #9CC8A8; border-radius: 2px;
    animation: dock-slide 1.3s linear infinite;
  }
  .dock-edge span:nth-child(2) { animation-delay: 0.65s; }
  .studio-dock.compiling .dock-edge { display: block; }

  /* Reserve room so the dock never covers the composer / activity tail, and
     lift the Your Bot launcher clear of the bar (never colliding). */
  body.has-dock .shell-studio { padding-bottom: calc(88px + env(safe-area-inset-bottom)); }
  body.has-dock .bot-root {
    bottom: calc(84px + var(--savebar-h, 0px) + env(safe-area-inset-bottom));
  }

  /* The bottom sheet: scrim + drag handle + the borrowed composite card. */
  .studio-sheet { display: block; position: fixed; inset: 0; z-index: 320; }
  .studio-sheet[hidden] { display: none; }
  .sheet-scrim { position: absolute; inset: 0; background: rgba(26, 26, 23, 0.32); }
  .sheet-panel {
    position: absolute; left: 0; right: 0; bottom: 0;
    max-height: 86vh; overflow-y: auto; outline: none;
    background: var(--green-tint);
    border: 1px solid var(--hair); border-bottom: 0;
    border-radius: 18px 18px 0 0;
    padding: 10px 16px calc(18px + env(safe-area-inset-bottom));
    animation: sheet-rise 0.22s var(--ease) both;
  }
  .sheet-handle {
    width: 34px; height: 4px; border-radius: 2px;
    background: var(--hair); margin: 2px auto 12px;
  }
  /* Inside the sheet the borrowed card is just content (no sticky/grid). */
  .sheet-body .studio-comp { display: block; position: static; margin-top: 0; }
}

@keyframes dock-slide { from { left: -36px; } to { left: 100%; } }
@keyframes sheet-rise {
  from { transform: translateY(24px); opacity: 0.6; }
  to { transform: translateY(0); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .dock-edge span { animation: none; }
  .sheet-panel { animation: none; }
}

/* ---- activity feed + reserved recommendations slot --------------------- */

.activity-list { list-style: none; margin: 0; padding: 0; }
.activity-item {
  display: flex; align-items: baseline; gap: 14px;
  padding: 12px 0;
}
.activity-item + .activity-item { border-top: 1px solid var(--hair); }
.activity-dot {
  flex: none; width: 6px; height: 6px; margin-top: 6px; border-radius: 50%;
  background: var(--green); opacity: 0.7;
}
.activity-body { flex: 1; min-width: 0; }
.activity-main {
  display: flex; align-items: baseline; gap: 10px;
  min-width: 0; flex-wrap: wrap;
}
/* ACTOR badge — who caused the entry. "You" for the user; a future bot/system
   actor renders its own label via the .bot variant. */
.activity-actor {
  flex: none; font-size: 11.5px; line-height: 1.4; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--ink-faint);
  border: 1px solid var(--hair); border-radius: 999px; padding: 1px 8px;
}
.activity-actor.bot {
  color: var(--green); border-color: var(--green);
}
/* The specific committed change IS the inline headline (e.g. removed "I love
   India."). One readable line beside the actor chip; wraps under it if narrow. */
.activity-label {
  flex: 1 1 auto; min-width: 0;
  font-size: 15px; line-height: 1.5; color: var(--ink);
}
.activity-time {
  flex: none; font-size: 12.5px; color: var(--ink-faint); margin-left: auto;
  white-space: nowrap; letter-spacing: 0.01em;
}
/* #34-web: the "Load more" pager beneath the feed. Calm, centered, top hairline so
   it reads as the tail of the list. Shown only while older entries remain. */
.activity-more {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  margin-top: 6px; padding-top: 12px; border-top: 1px solid var(--hair);
}
.activity-more-btn {
  color: var(--green); font-weight: 500; letter-spacing: 0.01em;
}
/* Hover affordance is bold, not an underline (house convention). */
.activity-more-btn:hover:not(:disabled) { color: var(--green-deep); font-weight: 600; }
.activity-more-btn:disabled { color: var(--ink-faint); cursor: default; }
.activity-more-err {
  margin: 0; font-size: 13px; color: var(--ink-faint); text-align: center;
}
/* ---- learning-loop candidates (#28 / STUDIO): suggestions inline ---------
   A pending candidate from suggest_update is a message from a collaborator: a
   GOLD row inline in the source stream, with a "Claude suggests · 2h ago"
   attribution and Accept/Ignore minis. It stays gold-and-left until accepted
   (the PRISTINE COMPOSITE invariant). */
.candidate-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.candidate {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 14px; margin-top: 8px;
  background: var(--gold-tint);
  border: 1px solid var(--gold-hair);
  border-radius: var(--r-sm);
}
.cand-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cand-source {
  font-size: 12px; color: var(--gold); font-weight: 600; letter-spacing: 0.01em;
}
.cand-text {
  color: var(--ink-soft); font-size: 15.5px; line-height: 1.45;
  font-family: var(--display); word-break: break-word;
}
.cand-acts { display: flex; align-items: center; gap: 6px; flex: none; }
.mini {
  border-radius: 999px; font-size: 13px; padding: 5px 13px;
  border: 1px solid transparent; line-height: 1.4;
}
.mini:disabled { opacity: 0.4; cursor: default; }
.mini-accept { background: var(--green); color: var(--bone); }
.mini-accept:hover:not(:disabled) { background: var(--green-deep); }
.mini-ignore { background: none; border-color: var(--hair); color: var(--ink-soft); }
.mini-ignore:hover:not(:disabled) { border-color: var(--ink-faint); color: var(--ink); }
@media (max-width: 640px) {
  .candidate { flex-direction: column; align-items: flex-start; gap: 8px; }
}

/* ---- connect panel (MCP url + token) ----------------------------------- */

.copyfield {
  display: flex; align-items: stretch; gap: 0;
  border: 1px solid var(--hair); border-radius: var(--r-sm);
  background: var(--paper); overflow: hidden;
}
.copyfield .val {
  flex: 1; min-width: 0; padding: 13px 16px; font-size: 14px;
  color: var(--ink-soft); white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; align-self: center;
  font-feature-settings: "tnum" 1;
}
.copyfield .copy {
  flex: none; border: none; border-left: 1px solid var(--hair);
  background: var(--bone-2); color: var(--ink); padding: 0 20px; font-size: 13.5px;
  font-weight: 500; transition: background var(--med) var(--ease), color var(--med) var(--ease);
}
.copyfield .copy:hover { background: var(--green); color: var(--bone); }
.copyfield .copy.done { background: var(--green); color: var(--bone); }

.steplist { counter-reset: s; list-style: none; padding: 0; margin: 0; }
.steplist li {
  position: relative; padding: 4px 0 22px 44px; counter-increment: s;
  color: var(--ink-soft); font-size: 15px; line-height: 1.55;
}
.steplist li::before {
  content: counter(s);
  position: absolute; left: 0; top: 0;
  width: 28px; height: 28px; border-radius: 50%;
  border: 1px solid var(--green); color: var(--green);
  display: grid; place-items: center; font-size: 13px; font-weight: 600;
}
.steplist li:not(:last-child)::after {
  content: ""; position: absolute; left: 13.5px; top: 32px; bottom: 8px;
  width: 1px; background: var(--hair);
}
.steplist code {
  background: var(--bone-2); border: 1px solid var(--hair-soft);
  border-radius: 5px; padding: 1px 6px; font-size: 13px; color: var(--ink);
}
/* Sub-bullets inside a single step (e.g. Goose's two header fields). No
   numbered counter - plain discs, tucked under the step's text. */
.steplist-sub { list-style: disc; margin: 0; padding: 0 0 0 18px; }
.steplist-sub li {
  position: static; padding: 0 0 4px 0; counter-increment: none;
  color: var(--ink-soft); font-size: 14.5px; line-height: 1.5;
}
.steplist-sub li::before, .steplist-sub li::after { content: none; }

/* Inline MCP-URL chip inside a steplist line: the styled URL + a small Copy,
   so the value is right in step 2 (no scroll to the field below). */
.inline-url {
  display: inline-flex; align-items: center; gap: 6px;
  vertical-align: baseline; max-width: 100%;
}
.inline-url .mcp-url-inline {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 320px; vertical-align: baseline;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.copy-inline {
  font-size: 11.5px; padding: 2px 8px; line-height: 1.4;
  border: 1px solid var(--hair-soft); border-radius: 5px;
  background: var(--bone-2); color: var(--ink-soft); cursor: pointer;
  flex: none;
}
.copy-inline:hover { background: var(--green); color: var(--bone); border-color: var(--green); }
.copy-inline.done { background: var(--green); color: var(--bone); border-color: var(--green); }

.code-block {
  background: #1A1A17; color: #E9E6DE; border-radius: var(--r-sm);
  padding: 18px 20px; font-size: 12.5px; line-height: 1.6;
  overflow-x: auto; white-space: pre;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.code-block .k { color: #9DB8A4; }
.code-block .s { color: #D8C9A8; }

/* ---- success / done flourish ------------------------------------------ */
.done-mark {
  width: 56px; height: 56px; border-radius: 50%; background: var(--green);
  display: grid; place-items: center; margin-bottom: 6px;
}
.done-mark::after {
  content: ""; width: 18px; height: 9px;
  border-left: 2.5px solid var(--bone); border-bottom: 2.5px solid var(--bone);
  transform: rotate(-45deg) translate(0, -2px);
}

/* ---- footer ------------------------------------------------------------ */
.foot {
  margin-top: auto; padding: 40px 0 28px;
  border-top: 1px solid var(--hair);
  display: flex; gap: 12px 18px; align-items: center; justify-content: space-between; flex-wrap: wrap;
  color: var(--ink-faint); font-size: 12.5px; letter-spacing: 0.01em;
}
/* Left cluster: copyright + tagline + usemycontext.ai. The version link is the
   flush-right sibling (the .foot space-between row pushes it to the far edge). */
.foot .foot-left { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; }
.foot .dot-sep { width: 3px; height: 3px; border-radius: 50%; background: var(--hair); }
/* Footer links (incl. the Changelog opener): hover affordance is BOLD, not underline. */
.foot a, .foot .foot-link {
  color: var(--ink-faint); cursor: pointer; text-decoration: none;
  transition: color var(--med) var(--ease), font-weight var(--med) var(--ease);
}
.foot a:hover, .foot .foot-link:hover { color: var(--green); font-weight: 700; }

/* MOBILE footer (#30-web): the desktop single space-between row reads as 4 stacked
   left-aligned rows on narrow screens. Remap to a tidy 3-row grid:
     row 1 — © copyright (left)            v0.5 / changelog trigger (right, inline)
     row 2 — the tagline
     row 3 — usemycontext.ai (right-aligned, on its own row)
   .foot-left becomes display:contents so its children promote into the .foot grid
   and can share row 1 with the version link. The dot separators drop out. Desktop
   (>640px) is untouched — it keeps the flex space-between row above. */
@media (max-width: 640px) {
  .foot {
    display: grid;
    grid-template-columns: 1fr auto;
    column-gap: 14px;
    row-gap: 8px;
    align-items: center;
  }
  .foot .foot-left { display: contents; }
  .foot .dot-sep { display: none; }
  /* Pin explicit row+column so source order (copy, tagline, site, version) doesn't
     scatter the version onto its own auto-placed row. */
  .foot .foot-copy { grid-row: 1; grid-column: 1; justify-self: start; }
  .foot .foot-version { grid-row: 1; grid-column: 2; justify-self: end; }
  .foot .foot-tagline { grid-row: 2; grid-column: 1 / -1; justify-self: start; }
  .foot .foot-site { grid-row: 3; grid-column: 1 / -1; justify-self: end; }
}

/* ---- motion: staggered reveal ----------------------------------------- */

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
.reveal { opacity: 0; animation: rise var(--slow) var(--ease) forwards; }
.reveal.d1 { animation-delay: 70ms; }
.reveal.d2 { animation-delay: 150ms; }
.reveal.d3 { animation-delay: 240ms; }
.reveal.d4 { animation-delay: 340ms; }
.reveal.d5 { animation-delay: 450ms; }

@media (prefers-reduced-motion: reduce) {
  .reveal { animation: none; opacity: 1; }
  .pill.live::before { animation: none; }
}

/* small spinner */
.spin {
  width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent;
  display: inline-block; animation: rot 700ms linear infinite;
}
@keyframes rot { to { transform: rotate(360deg); } }

/* ---- first-run onboarding (#/welcome) ---------------------------------- */
.welcome-values {
  list-style: none; padding: 0; margin: 22px 0 0;
  display: grid; gap: 12px; max-width: 56ch;
}
.welcome-point {
  position: relative; padding-left: 26px;
  font-family: var(--serif); font-size: 17px; line-height: 1.5; color: var(--ink-soft);
}
.welcome-point::before {
  content: ""; position: absolute; left: 4px; top: 11px;
  width: 7px; height: 7px; border-radius: 50%; background: var(--green);
}
.welcome-steps { display: grid; gap: 18px; max-width: 640px; }
.welcome-step {
  display: flex; gap: 18px; align-items: flex-start;
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: var(--r-lg, 16px); padding: 22px 24px;
}
.welcome-step-num {
  flex: none; width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--green); color: var(--green);
  display: grid; place-items: center; font-weight: 600; font-size: 15px;
}
.welcome-step-body { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.welcome-step-title { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.welcome-step-sub {
  margin: 0; font-family: var(--serif); font-size: 15px; line-height: 1.5; color: var(--ink-soft);
}
.welcome-step-body .btn { margin-top: 6px; }
/* Phase 4 (#6 cold-start): the #/welcome paste-to-seed box + its action row. The
   textarea matches the studio composer's calm field; the row keeps the action
   buttons + status inline (wraps on a phone) and never em-dashes. */
.welcome-paste {
  width: 100%; box-sizing: border-box; margin-top: 4px;
  background: var(--paper); border: 1px solid var(--hair); border-radius: var(--r, 12px);
  padding: 12px 14px; font-family: var(--serif); font-size: 15px; line-height: 1.5;
  color: var(--ink); resize: vertical; min-height: 92px;
}
.welcome-paste:focus { outline: none; border-color: var(--green); }
.welcome-paste:disabled { opacity: 0.6; }
.welcome-paste-row .btn { margin-top: 0; }
.welcome-paste-status { font-size: 13px; }

/* ---- connect: per-client toggle + advanced ----------------------------- */
.client-toggle {
  display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 22px;
}
.client-tab {
  background: var(--paper); border: 1px solid var(--hair); color: var(--ink-soft);
  border-radius: 999px; padding: 8px 18px; font-size: 14px; font-weight: 500;
  letter-spacing: -0.005em; cursor: pointer;
  transition: background var(--med) var(--ease), color var(--med) var(--ease),
              border-color var(--med) var(--ease);
}
.client-tab:hover { border-color: var(--ink-faint); color: var(--ink); }
.client-tab.active { background: var(--green); color: var(--bone); border-color: var(--green); }

.advanced {
  border: 1px solid var(--hair); border-radius: var(--r-sm);
  background: var(--bone-2); padding: 0 20px;
}
.advanced > summary {
  cursor: pointer; list-style: none; padding: 16px 0;
  font-size: 14px; font-weight: 600; color: var(--ink-soft);
  display: flex; align-items: center; gap: 10px;
}
.advanced > summary::-webkit-details-marker { display: none; }
.advanced > summary::before {
  content: "+"; font-size: 16px; font-weight: 600; color: var(--green);
  width: 18px; text-align: center;
}
.advanced[open] > summary::before { content: "−"; }
.advanced > summary:hover { color: var(--ink); }
.advanced > .stack { padding-bottom: 22px; }

/* Sealed access token: masked value + reveal/hide toggle + copy. The masked
   display uses tabular spacing and a touch more tracking so the bullets read
   as a deliberate seal rather than truncation. */
.copyfield .val.sealed {
  letter-spacing: 0.02em; color: var(--ink-faint);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.copyfield .copy.seal-toggle { font-weight: 500; }
.copyfield .copy.seal-toggle[aria-pressed="true"] { background: var(--green); color: var(--bone); }

/* Refresh control row beneath the token + its transient confirmation. */
.token-actions {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-top: 4px;
}
.token-actions .refresh-note {
  font-size: 12.5px; color: var(--green); font-weight: 500;
}

/* ---- responsive -------------------------------------------------------- */
@media (max-width: 620px) {
  /* Keep the GLOBAL safe-area top inset (notch / status bar) on phones, where it
     matters most - only the horizontal padding narrows here. */
  .shell { padding: env(safe-area-inset-top) 20px 0; }
  /* Single non-wrapping row stays - the avatar must NOT drop to its own line.
     Tighter gaps to fit mark + tabs + avatar inline; the wordmark is hidden at
     the narrower 520px breakpoint below. */
  .nav { gap: 18px; margin-bottom: 40px; flex-wrap: nowrap; }
  .nav a.tab.active::after { bottom: -19px; }
  .wizard { padding: 40px 0 60px; }
  .card { padding: 22px 20px; }
  .row { padding: 16px 18px; }
  .callout { flex-wrap: wrap; }
  .callout code { margin-left: 0; }
  .welcome-step { flex-direction: column; gap: 12px; }
  .client-toggle { gap: 6px; }
}

/* Narrow widths (phones, ~320-520px): hide the "UseMyContext" WORDMARK text and
   keep only the logo MARK, then tighten the nav so the mark + Profile/Storage/
   Connect + the account avatar stay on ONE row with no horizontal overflow.
   The avatar never wraps to a second line. */
@media (max-width: 520px) {
  .brand .wordmark { display: none; }
  .nav { gap: 14px; }
  .nav a.tab { font-size: 14px; }
}
@media (max-width: 360px) {
  .nav { gap: 11px; }
  .nav a.tab { font-size: 13.5px; }
}

/* ---- Disconnect-all (nuclear) danger zone — Connect page bottom -------- */
.danger-zone { margin-top: 8px; }
.danger-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 18px;
  padding: 18px 20px;
  border: 1px solid var(--danger);
  border-radius: var(--r-sm);
  background: var(--danger-tint); /* the faintest oxblood wash */
}
.danger-row.confirming { align-items: flex-start; }
.danger-main { min-width: 0; }
.danger-title {
  font-weight: 600; color: var(--danger); font-size: 15px; line-height: 1.4;
}
.danger-sub {
  margin: 6px 0 0; font-size: 13.5px; color: var(--ink-soft); line-height: 1.5;
}
.danger-aside {
  display: flex; align-items: center; gap: 12px; flex-shrink: 0;
}
.danger-note { display: block; margin-top: 10px; font-size: 13px; color: var(--danger); }

@media (max-width: 620px) {
  .danger-row { flex-direction: column; align-items: stretch; }
  .danger-aside { justify-content: flex-end; }
}

/* ---- "Connected right now" - the sessions ledger (mock screen 11) -------
   One row per live session: the Usage cast avatar (reused), the name, an
   honest sub-line, and a QUIET oxblood per-row action - Disconnect for AI
   clients, Sign out for this browser. The nuclear card sits right below. */
.sessions-label {
  font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
  font-weight: 600; margin: 0;
}
.sessions-card {
  border: 1px solid var(--hair); border-radius: var(--r-sm);
  background: var(--paper); padding: 2px 20px;
}
.session-row {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 0; border-top: 1px solid var(--hair);
}
.session-row:first-child { border-top: none; }
.session-meta { min-width: 0; flex: 1; }
.session-name {
  font-family: var(--display); font-size: 16px; font-weight: 600; color: var(--ink);
}
.session-sub { font-size: 13px; color: var(--ink-faint); margin-top: 2px; }
.session-actions { display: flex; align-items: center; gap: 10px; flex: none; flex-wrap: wrap; justify-content: flex-end; }
.session-err { font-size: 12.5px; color: var(--danger); }
.session-err:empty { display: none; }
/* The green you-avatar for the current web session ("This browser"). */
.usage-avatar-you {
  background: var(--green); border-color: var(--green);
  color: var(--bone); font-size: 10.5px;
}
/* Quiet destructive row action: outlined oxblood, never a solid block. */
.btn-danger-quiet {
  border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent);
  background: none; color: var(--danger);
  border-radius: 999px; padding: 8px 16px;
  font-size: 13.5px; font-weight: 600; line-height: 1;
  cursor: pointer;
  transition: border-color var(--med) var(--ease), background var(--med) var(--ease);
}
.btn-danger-quiet:hover { border-color: var(--danger); background: var(--danger-tint); }
.btn-danger-quiet:disabled { opacity: 0.4; cursor: not-allowed; }
.sessions-note { font-size: 13px; margin: 0 2px; }

@media (max-width: 620px) {
  .session-row { flex-wrap: wrap; }
  .session-actions { width: 100%; }
}

/* ---- "Your Bot" - the in-product chat assistant (#15-web) ---------------
   A floating launcher (bottom-right) opens an accessible chat panel. Lives on
   document.body so it survives the SPA's per-route re-render. Sits BELOW the
   changelog modal (z 1000) so that always wins. Racing green, hyphens, hovers
   go bold (inherited), self-hosted fonts (inherited from the page). */
/* The FAB anchor. `--savebar-h` (set on body: 0 normally, the bar height while the
   Profile save bar is mounted via `body.has-savebar`) lifts the launcher ABOVE the
   sticky save bar so the two never collide, plus the bottom safe-area inset. This
   is the SINGLE place the FAB-clears-the-save-bar rule lives (the global FAB
   module); no per-view duplication. With no save bar it resolves to the normal
   22px anchor. */
.bot-root {
  position: fixed; right: 22px; z-index: 200;
  bottom: calc(22px + var(--savebar-h, 0px) + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; align-items: flex-end; gap: 14px;
}

.bot-launcher {
  width: 54px; height: 54px; border-radius: 50%; border: none; cursor: pointer;
  background: var(--green); color: var(--bone);
  display: grid; place-items: center;
  box-shadow: 0 8px 24px rgba(31, 61, 43, 0.34), 0 1px 0 rgba(255,255,255,0.04) inset;
  transition: transform 0.18s var(--ease), box-shadow 0.18s var(--ease), background 0.18s var(--ease);
}
.bot-launcher:hover { background: var(--green-deep); transform: translateY(-1px); box-shadow: 0 12px 30px rgba(31, 61, 43, 0.40); }
.bot-launcher:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--green-tint), 0 0 0 1px var(--green); }
.bot-launcher svg { display: block; }
/* #32a: when the panel is open the launcher is HIDDEN entirely - the panel's
   own close (x) is the sole dismiss affordance, so we don't show both. When the
   panel closes the launcher returns. (display:none also drops it from the tab
   order, which is correct while the dialog is the active surface.) */
.bot-root.open .bot-launcher { display: none; }

.bot-panel {
  width: min(380px, calc(100vw - 32px));
  height: min(560px, calc(100vh - 120px));
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--hair); border-radius: 18px;
  box-shadow: 0 24px 64px rgba(26, 22, 40, 0.26);
  display: flex; flex-direction: column; overflow: hidden;
  animation: bot-rise 0.2s var(--ease) both;
}
.bot-panel[hidden] { display: none; }
@keyframes bot-rise {
  from { opacity: 0; transform: translateY(10px) scale(0.99); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.bot-head {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 18px 18px 14px; border-bottom: 1px solid var(--hair-soft);
}
.bot-head-main { flex: 1 1 auto; min-width: 0; }
.bot-title {
  font-family: var(--serif); font-weight: 600; font-size: 19px;
  letter-spacing: -0.01em; margin: 0; color: var(--ink); line-height: 1.1;
}
.bot-tagline { margin: 4px 0 0; font-size: 12.5px; line-height: 1.45; color: var(--ink-faint); }
/* #46: the header action group - the expand toggle + the close x, with a clear
   gap so each is separately, comfortably clickable. */
.bot-head-actions { flex: 0 0 auto; display: flex; align-items: center; gap: 12px; }
.bot-close {
  flex: 0 0 auto; background: none; border: none; cursor: pointer;
  font-size: 24px; line-height: 1; color: var(--ink-faint); padding: 0 2px;
  transition: color 0.16s ease;
}
.bot-close:hover { color: var(--ink); font-weight: 700; }
.bot-close:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; border-radius: 4px; }

/* #46: the expand / collapse toggle - a desktop affordance left of the x. Quiet
   by default, matches the x's weight; hidden on phones (the panel is already
   full-screen there per #32b). */
.bot-expand {
  flex: 0 0 auto; display: grid; place-items: center;
  background: none; border: none; cursor: pointer; padding: 2px;
  color: var(--ink-faint); transition: color 0.16s ease;
}
.bot-expand:hover { color: var(--ink); }
.bot-expand:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; border-radius: 4px; }
.bot-expand svg { display: block; }

.bot-messages {
  flex: 1 1 auto; overflow-y: auto; padding: 16px;
  display: flex; flex-direction: column; gap: 12px;
}
.bot-turn { display: flex; }
.bot-turn-user { justify-content: flex-end; }
.bot-turn-bot { justify-content: flex-start; }
.bot-bubble {
  max-width: 84%; padding: 10px 13px; border-radius: 14px;
  font-size: 14px; line-height: 1.5; white-space: pre-wrap; word-wrap: break-word;
}
.bot-turn-user .bot-bubble {
  background: var(--green); color: var(--bone); border-bottom-right-radius: 5px;
}
.bot-turn-bot .bot-bubble {
  background: var(--green-tint); color: var(--ink); border-bottom-left-radius: 5px;
}

/* #48: inline-markdown formatting inside an assistant bubble (the renderer emits
   only this fixed, known set of tags). Tight margins so a reply stays calm; lists
   indent modestly; code reads as monospace; links go BOLD on hover, not underline
   (house rule). pre-wrap on the bubble already preserves single newlines. */
.bot-bubble p { margin: 0; }
.bot-bubble p + p { margin-top: 8px; }
.bot-bubble ul, .bot-bubble ol { margin: 6px 0; padding-left: 20px; }
.bot-bubble li { margin: 2px 0; }
.bot-bubble code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.88em; background: rgba(31, 61, 43, 0.10);
  padding: 1px 5px; border-radius: 5px;
}
.bot-bubble a { color: var(--green); text-decoration: none; font-weight: 500; }
.bot-bubble a:hover { text-decoration: none; font-weight: 700; }

/* The calm "thinking..." state. */
.bot-thinking-text { color: var(--ink-faint); font-size: 13px; margin-left: 8px; }
.bot-dots { display: inline-flex; gap: 4px; vertical-align: middle; }
.bot-dots span {
  width: 6px; height: 6px; border-radius: 50%; background: var(--green);
  opacity: 0.5; animation: bot-blink 1.1s var(--ease) infinite;
}
.bot-dots span:nth-child(2) { animation-delay: 0.18s; }
.bot-dots span:nth-child(3) { animation-delay: 0.36s; }
@keyframes bot-blink { 0%, 60%, 100% { opacity: 0.3; } 30% { opacity: 0.95; } }

.bot-notice {
  align-self: stretch; padding: 10px 13px; border-radius: 12px;
  background: #FBF1EE; color: var(--danger);
  font-size: 13.5px; line-height: 1.5;
}
/* #47: a failed-send notice carries a calm inline Retry control under the text. */
.bot-notice-error { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.bot-notice-text { display: block; }
.bot-retry {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 1px solid rgba(122, 59, 46, 0.35);
  color: var(--danger); border-radius: 999px; padding: 4px 11px;
  font-family: inherit; font-size: 12.5px; cursor: pointer;
  transition: background 0.16s ease, border-color 0.16s ease, font-weight 0.16s ease;
}
.bot-retry:hover { background: rgba(122, 59, 46, 0.08); border-color: var(--danger); font-weight: 600; }
.bot-retry:focus-visible { outline: 2px solid var(--danger); outline-offset: 2px; }
.bot-retry svg { display: block; }

/* Per-page suggested prompts - light, optional. Hidden once a conversation
   starts (the JS empties the row). */
.bot-suggest {
  display: flex; flex-wrap: wrap; gap: 8px; padding: 0 16px 12px;
}
.bot-suggest:empty { display: none; }
.bot-chip {
  background: var(--bone-2); color: var(--ink-soft);
  border: 1px solid var(--hair-soft); border-radius: 999px;
  padding: 7px 12px; font-family: inherit; font-size: 12.5px; cursor: pointer;
  transition: background 0.16s ease, color 0.16s ease, border-color 0.16s ease;
}
.bot-chip:hover { background: var(--green-tint); color: var(--green); border-color: var(--green-tint); font-weight: 600; }
.bot-chip:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }

/* bot-history-pager: a calm, centered "Load earlier" control pinned to the TOP of
   the message log; shown only when an older history page exists. Quiet ghost
   styling so it never competes with the conversation; hover goes BOLD (house
   rule), not underline. Hidden via the [hidden] attribute when exhausted. */
.bot-load-earlier {
  align-self: center; flex: 0 0 auto;
  background: none; border: 1px solid var(--hair-soft); border-radius: 999px;
  color: var(--ink-soft); padding: 5px 14px;
  font-family: inherit; font-size: 12.5px; cursor: pointer;
  transition: background 0.16s ease, color 0.16s ease, border-color 0.16s ease, font-weight 0.16s ease;
}
.bot-load-earlier:hover { background: var(--green-tint); color: var(--green); border-color: var(--green-tint); font-weight: 600; }
.bot-load-earlier:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }
.bot-load-earlier[disabled] { opacity: 0.55; cursor: default; }

.bot-composer {
  display: flex; align-items: flex-end; gap: 8px;
  padding: 12px 14px; border-top: 1px solid var(--hair-soft);
  background: var(--paper);
}
.bot-input {
  flex: 1 1 auto; resize: none; min-height: 40px; max-height: 120px;
  padding: 9px 12px; border: 1px solid var(--hair); border-radius: 12px;
  font-family: inherit; font-size: 14px; line-height: 1.4; color: var(--ink);
  background: var(--bone); transition: border-color 0.16s ease, box-shadow 0.16s ease;
}
.bot-input:focus-visible {
  outline: none; border-color: var(--green);
  box-shadow: 0 0 0 3px var(--green-tint);
}
.bot-input:disabled { opacity: 0.6; }
.bot-send {
  flex: 0 0 auto; background: var(--green); color: var(--bone);
  border: none; border-radius: 12px; padding: 10px 16px; cursor: pointer;
  font-family: inherit; font-size: 14px; font-weight: 500;
  transition: background 0.16s ease, transform 0.16s ease;
}
.bot-send:hover:not(:disabled) { background: var(--green-deep); font-weight: 600; }
.bot-send:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--green-tint), 0 0 0 1px var(--green); }
.bot-send:disabled { opacity: 0.55; cursor: default; }

/* #46: the EXPANDED state - the panel grows to about 50% of the viewport
   (noticeably wider AND taller), while staying within the viewport with the log
   scrollable and the composer reachable (the panel is a flex column). Desktop
   affordance only; the phone full-screen rule below overrides this. */
.bot-root.expanded .bot-panel {
  width: min(50vw, calc(100vw - 32px));
  height: min(82vh, calc(100vh - 80px));
}

/* #32b: on phones the OPEN panel goes FULL-SCREEN and covers the page behind it
   (the floating-card treatment only makes sense with room around it). We use the
   app's dominant 640px breakpoint (matches the other phone rules in this file),
   NOT a bespoke one. While CLOSED the launcher keeps its calm bottom-right anchor;
   only the open panel takes over the viewport. The opaque full-bleed panel hides
   the page, and the composer stays reachable above the on-screen keyboard because
   the panel is a flex column with a scrollable message region and the composer
   pinned at the bottom. Desktop (the bottom-right card) is unchanged. */
@media (max-width: 640px) {
  /* CLOSED launcher on a phone: tighter anchor, but STILL clears the sticky save
     bar (and the bottom safe-area inset) via the shared --savebar-h so the FAB and
     the save bar never collide. The OPEN panel below goes full-screen (bottom:0). */
  .bot-root {
    right: 14px;
    bottom: calc(14px + var(--savebar-h, 0px) + env(safe-area-inset-bottom));
  }
  .bot-root.open {
    right: 0; bottom: 0; top: 0; left: 0;
    width: 100vw; height: 100vh; height: 100dvh;
    gap: 0; align-items: stretch;
  }
  .bot-root.open .bot-panel,
  .bot-root.open.expanded .bot-panel {
    width: 100vw; height: 100vh; height: 100dvh;
    max-width: none; border: none; border-radius: 0;
    box-shadow: none; animation: none;
  }
  /* #46: the expand toggle is a DESKTOP affordance only - on phones the open
     panel is already full-screen (#32b), so hide it and no-op the class. */
  .bot-expand { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .bot-panel { animation: none; }
  .bot-dots span { animation: none; opacity: 0.6; }
  .bot-launcher { transition: none; }
}

/* ---- SMC-W2: Share this project --------------------------------------- */
.share-slot { display: block; }
/* The whole Share area sits in its OWN card with a subtle brand-green accent
   border + a faint green wash, so it reads as a distinct zone from the
   profile-editing flow above it. Uses the EXISTING green tokens only - no new
   colour introduced. */
.share-card {
  border: 1px solid var(--green);
  border-radius: var(--r);
  background: var(--green-tint);
  padding: 20px;
}
.share-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.share-head-text { min-width: 0; }
.share-lede {
  margin: 4px 0 0; font-size: 14px; color: var(--ink-soft);
  max-width: 46ch;
}
.share-toggle { flex: none; }

.share-panel {
  margin-top: 16px; padding: 18px; border: 1px solid var(--hair);
  border-radius: var(--r); background: var(--paper);
  display: flex; flex-direction: column; gap: 16px;
}
.share-warning {
  border: 1px solid var(--gold-hair); background: var(--gold-tint);
  border-radius: var(--r-sm); padding: 12px 14px; line-height: 1.55;
}
.share-warning b { color: var(--ink); }

.share-field { display: block; }
.share-field > label {
  display: block; font-size: 13px; font-weight: 500;
  color: var(--ink-soft); margin-bottom: 8px;
}
/* FUSED recipient input + Share button: one attached unit, NO gap, shared radius -
   the input's right corners and the button's left corners are flattened so they
   read as a single control. They stay attached on a phone (no wrap), so the seam
   is preserved. */
.share-row { display: flex; gap: 0; align-items: stretch; flex-wrap: nowrap; }
.share-email-input {
  flex: 1 1 auto; min-width: 0;
  border-top-right-radius: 0; border-bottom-right-radius: 0;
  border-right: none;
}
.share-submit {
  flex: none; border-radius: var(--r-sm);
  border-top-left-radius: 0; border-bottom-left-radius: 0;
}
/* Keep the button visible above the input's focus ring (it shares the seam). */
.share-email-input:focus { position: relative; z-index: 1; }
.share-formerr { margin-top: 8px; }
.share-ok {
  margin: 0; font-size: 14px; color: var(--green); font-weight: 500;
}

/* team / group - Premium-gated */
.share-team {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; padding: 14px; border: 1px dashed var(--hair);
  border-radius: var(--r-sm); background: var(--bone-2);
}
.share-team.is-locked { opacity: 0.7; }
.share-team-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.share-team-title { font-weight: 600; font-size: 14.5px; color: var(--ink); }
.share-team-sub { font-size: 13px; color: var(--ink-faint); }
.share-team-lock, .share-team-soon {
  flex: none; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  font-weight: 600; color: var(--green); border: 1px solid var(--green);
  border-radius: 999px; padding: 4px 10px; display: inline-flex;
  align-items: center; gap: 6px; white-space: nowrap;
}
.share-team-soon { color: var(--ink-faint); border-color: var(--hair); }
.share-team-lock .lock-glyph { font-size: 11px; }

/* outbound shares list */
.shares-list { margin-top: 16px; }
.shares-head {
  font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase;
  font-weight: 600; color: var(--ink-faint); margin-bottom: 8px;
}
.shares-loading, .shares-err, .shares-empty {
  font-size: 13.5px; color: var(--ink-faint);
}
.shares-loading .spin { margin-right: 6px; }
.share-item {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; padding: 12px 0; border-top: 1px solid var(--hair-soft);
}
.share-item:first-of-type { border-top: none; }
.share-item-main { min-width: 0; }
.share-item-who {
  font-size: 14.5px; font-weight: 500; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.share-item-meta { font-size: 12.5px; color: var(--ink-faint); margin-top: 2px; }
/* SMC-CONSENT: the derived consent status line under the meta (Sent - awaiting
   their accept / Accepted - not opened yet / Opened - N reads / etc.). A calm
   muted line by default; `.warn` (revoked/expired/limit/declined) uses the muted
   oxblood --danger token (an existing token), never a new colour. */
.share-status {
  font-size: 12px; color: var(--ink-faint); margin-top: 4px; line-height: 1.4;
}
.share-status::before {
  content: ""; display: inline-block; vertical-align: middle;
  width: 6px; height: 6px; border-radius: 50%; margin-right: 6px;
  background: var(--green); opacity: 0.7;
}
.share-status.warn { color: var(--danger); }
.share-status.warn::before { background: var(--danger); opacity: 0.7; }
.share-revoke { flex: none; }
.share-revoke .spin { margin-right: 4px; }

@media (max-width: 640px) {
  .share-head { flex-direction: column; gap: 10px; }
  .share-toggle { align-self: flex-start; }
  /* Tighter card padding on a phone so the fused input+button never overflows. */
  .share-card { padding: 16px; }
}

/* ---- SHARE DRAWER (2026-06-15): the bottom-drawer overlay -------------------
   Share no longer expands inline (which reflowed the columns). It opens as a
   bottom drawer that OVERLAYS the page: a dim scrim + a rounded-top panel that
   slides up, a drag handle, a header (Share · Project + the live visibility
   pill), then TWO verticals - Zone A read-only access (one person / link /
   network) + Zone B the accented Team card. Theme-aware (CSS variables only). */
.share-drawer { position: fixed; inset: 0; z-index: 360; }
.share-drawer[hidden] { display: none; }
body.share-drawer-open { overflow: hidden; }
.share-drawer-scrim {
  position: absolute; inset: 0; background: rgba(26, 26, 23, 0.42);
  backdrop-filter: blur(2px);
  animation: share-dr-fade 0.18s var(--ease) both;
}
.share-drawer-panel {
  position: absolute; left: 0; right: 0; bottom: 0;
  max-height: 75vh; overflow-y: auto; outline: none;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--hair); border-bottom: 0;
  border-radius: 20px 20px 0 0;
  padding: 8px 22px calc(26px + env(safe-area-inset-bottom));
  box-shadow: 0 -20px 60px rgba(26, 22, 40, 0.22);
  animation: share-dr-rise 0.24s var(--ease) both;
}
/* Center the panel content on a wide screen (it reads as a tray, not full-bleed). */
@media (min-width: 720px) {
  .share-drawer-panel { max-width: 640px; margin: 0 auto; border-left: 1px solid var(--hair); border-right: 1px solid var(--hair); }
}
.share-drawer-handle {
  width: 38px; height: 4px; border-radius: 2px;
  background: var(--hair); margin: 4px auto 8px;
}
.share-drawer-x {
  position: absolute; top: 12px; right: 16px; z-index: 2;
  background: none; border: none; font-size: 26px; line-height: 1;
  color: var(--ink-faint); cursor: pointer; padding: 2px 6px;
}
.share-drawer-x:hover { color: var(--ink); font-weight: 700; }
@keyframes share-dr-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes share-dr-rise {
  from { transform: translateY(28px); opacity: 0.5; }
  to { transform: translateY(0); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .share-drawer-scrim, .share-drawer-panel { animation: none; }
}
/* Inside the drawer the share card is plain (the drawer panel IS the surface). */
.share-drawer-panel .share-card {
  border: none; background: transparent; padding: 0;
}

/* Header: "Share · Project" + the live visibility pill. */
.share-dr-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; padding: 2px 32px 14px 0;
  border-bottom: 1px solid var(--hair-soft); margin-bottom: 16px;
}
.share-dr-title {
  font-family: var(--display); font-weight: 600; font-size: 18px; color: var(--ink);
}
.share-dr-dot { color: var(--green); margin: 0 2px; }
.share-pill {
  flex: none; font-size: 11.5px; font-weight: 600; letter-spacing: 0.03em;
  border-radius: 999px; padding: 4px 11px; white-space: nowrap;
  border: 1px solid var(--hair); color: var(--ink-faint); background: var(--bone-2);
}
.share-pill.pill-shared, .share-pill.pill-pub, .share-pill.pill-net {
  color: var(--green); border-color: var(--green); background: var(--green-tint);
}

/* Zones. */
.share-zone { margin: 0 0 4px; }
.share-zone-h {
  font-family: var(--display); font-weight: 600; font-size: 15.5px;
  color: var(--ink); margin: 0 0 4px;
}
.share-zone-sub { margin: 0 0 14px; font-size: 13.5px; color: var(--ink-faint); line-height: 1.5; }

/* Zone A: one bordered container, three rows on hairline dividers. */
.share-rows {
  border: 1px solid var(--hair); border-radius: var(--r);
  background: var(--paper); overflow: hidden;
}
.share-row-item {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 16px; border-top: 1px solid var(--hair-soft);
}
.share-row-item:first-child { border-top: none; }
.share-row-ico, .share-team-ico, .share-foot-ico {
  flex: none; color: var(--green); margin-top: 1px; display: inline-flex;
}
.share-foot-ico { color: var(--green); margin-top: 2px; }
.share-row-body { flex: 1 1 auto; min-width: 0; }
.share-row-title { font-weight: 600; font-size: 14.5px; color: var(--ink); display: flex; align-items: center; gap: 8px; }
.share-row-meta { font-size: 13px; color: var(--ink-faint); margin-top: 3px; line-height: 1.45; }
.share-row-action { flex: none; align-self: center; }
/* Row 1 control: fused email + Send, like the original share row. */
.share-row-ctl { display: flex; gap: 0; align-items: stretch; flex-wrap: nowrap; margin-top: 8px; }
.share-row-ctl .share-email-input {
  flex: 1 1 auto; min-width: 0;
  border-top-right-radius: 0; border-bottom-right-radius: 0; border-right: none;
}
.share-row-ctl .share-send {
  flex: none; border-radius: var(--r-sm);
  border-top-left-radius: 0; border-bottom-left-radius: 0;
}
.share-row-ctl .share-email-input:focus { position: relative; z-index: 1; }
.share-row-item .share-formerr:empty { display: none; }
.share-row-item .share-ok { margin-top: 8px; }
/* The small "live" pill on the network row + the Team "always live" pill share a look. */
.share-live-pill {
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--green); border: 1px solid var(--green); border-radius: 999px;
  padding: 2px 7px; line-height: 1;
}
.share-net-ok { color: var(--ink-faint) !important; font-weight: 500 !important; }

/* The growth-loop footnote (seedling) + the condensed residency line. */
.share-foot.share-grow {
  display: flex; align-items: flex-start; gap: 9px;
  margin: 14px 0 0; font-size: 12.5px; color: var(--ink-faint); line-height: 1.5;
}
.share-residency {
  margin: 8px 0 0; font-size: 12px; color: var(--ink-faint); line-height: 1.5;
}

/* The "or work together" divider. */
.share-or {
  display: flex; align-items: center; text-align: center;
  gap: 12px; margin: 22px 0 16px; color: var(--ink-faint);
  font-size: 12px; letter-spacing: 0.04em;
}
.share-or::before, .share-or::after {
  content: ""; flex: 1; height: 1px; background: var(--hair-soft);
}

/* Zone B: the accented Team premium card (visually dominant). */
.share-team-card {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 18px; border: 1.5px solid var(--green); border-radius: var(--r);
  background: var(--green-tint);
}
.share-team-ico { margin-top: 2px; }
.share-team-body { flex: 1 1 auto; min-width: 0; }
.share-team-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.share-team-name { font-family: var(--display); font-weight: 700; font-size: 16px; color: var(--ink); }
.share-team-pill {
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.04em; text-transform: lowercase;
  color: var(--green); border: 1px solid var(--green); border-radius: 999px; padding: 3px 9px;
}
.share-team-copy { margin: 8px 0 0; font-size: 13.5px; color: var(--ink-soft); line-height: 1.5; }
.share-team-ok { color: var(--green) !important; }
.share-team-action { flex: none; align-self: center; }

@media (max-width: 560px) {
  .share-drawer-panel { padding: 8px 16px calc(22px + env(safe-area-inset-bottom)); max-height: 82vh; }
  .share-row-item { flex-wrap: wrap; }
  .share-row-action { align-self: flex-start; margin-left: 32px; }
  .share-team-card { flex-wrap: wrap; }
  .share-team-action { align-self: flex-start; margin-left: 34px; }
}

/* ---- VISIBILITY SWITCH (item 4b, mock 9A) ----------------------------- */
/* The repo-style Private / Shared / Public switch leads the share sheet. It sits
   ON the composite (share lives on the thing being shared). Public mints the URL +
   states the trade in the moment. Brand green only - no new colour. */
.vis-switch {
  border: 1px solid var(--hair); border-radius: var(--r);
  background: var(--paper); padding: 16px 18px; margin-bottom: 16px;
}
.vis-lede { margin: 4px 0 12px; font-size: 13.5px; color: var(--ink-soft); max-width: 50ch; }
.vis-loading { font-size: 13.5px; color: var(--ink-faint); }
.vis-loading .spin { margin-right: 6px; }
.vis-row {
  display: flex; align-items: flex-start; gap: 12px; width: 100%; text-align: left;
  padding: 12px 14px; border: 1px solid var(--hair); border-radius: var(--r-sm);
  background: var(--bone); margin-bottom: 8px;
  transition: border-color var(--med) var(--ease), background var(--med) var(--ease);
}
.vis-row:hover:not(:disabled) { border-color: var(--green); }
.vis-row.on { border-color: var(--green); background: var(--green-tint); }
.vis-row:disabled { opacity: 0.6; cursor: default; }
.vis-box {
  flex: none; width: 18px; height: 18px; border-radius: 50%;
  border: 1.5px solid var(--hair); background: var(--paper);
  display: grid; place-items: center; font-size: 11px; color: var(--green);
  margin-top: 1px;
}
.vis-row.on .vis-box { border-color: var(--green); background: var(--green); color: var(--bone); }
.vis-grow { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.vis-title { font-weight: 600; font-size: 14.5px; color: var(--ink); }
.vis-sub { font-size: 13px; color: var(--ink-faint); line-height: 1.45; }
.vis-err { margin-top: 6px; }
/* The "Open" chip on Public (and on the public page header). */
.pub-chip {
  flex: none; align-self: center; font-size: 11px; letter-spacing: 0.06em;
  text-transform: uppercase; font-weight: 700; color: var(--green);
  border: 1px solid var(--green); border-radius: 999px; padding: 3px 10px;
  white-space: nowrap;
}
/* The minted URL row + Copy. */
.url-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 10px; padding: 10px 14px; border: 1px solid var(--hair);
  border-radius: var(--r-sm); background: var(--bone-2); flex-wrap: wrap;
}
.url-text {
  font-size: 13.5px; color: var(--ink-soft); word-break: break-all; min-width: 0;
}
.url-text b { color: var(--green); font-weight: 700; }
.vis-copy { flex: none; }
.vis-trade {
  margin: 10px 0 0; font-size: 12.5px; color: var(--ink-faint); line-height: 1.55;
}
.vis-trade b { color: var(--ink); }
/* The inline handle-claim field (first public flip). */
.handle-claim {
  margin-top: 12px; padding: 14px; border: 1px solid var(--green);
  border-radius: var(--r-sm); background: var(--green-tint);
}
.handle-lede { margin: 0 0 10px; font-size: 13.5px; color: var(--ink-soft); }
.handle-prefix-row { display: flex; align-items: stretch; gap: 0; }
.handle-at {
  flex: none; display: grid; place-items: center; padding: 0 12px;
  border: 1px solid var(--hair); border-right: none; background: var(--bone);
  border-top-left-radius: var(--r-sm); border-bottom-left-radius: var(--r-sm);
  font-weight: 700; color: var(--green);
}
.handle-input {
  flex: 1 1 auto; min-width: 0;
  border-top-left-radius: 0; border-bottom-left-radius: 0;
}
.handle-actions { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.handle-claim-btn .spin { margin-right: 4px; }
.handle-err { margin-top: 8px; }

/* ---- PUBLIC PAGE (item 4b, mock 9B) ----------------------------------- */
/* The unauthenticated page at /@handle/<project>: the composite in the same green
   card (someone's name on it), the read count, and the funnel footer. No authed
   chrome. Reuses the landing top bar; the card mirrors the studio composite. */
.pub-page { min-height: 100vh; }
.pub-section { max-width: 720px; margin: 0 auto; padding: 48px 20px 80px; }
.pub-stage { width: 100%; }
.pub-loading { font-size: 14px; color: var(--ink-faint); display: flex; align-items: center; gap: 8px; }
.pub-card {
  background: var(--green-tint); border: 1px solid var(--green);
  border-radius: var(--r); padding: 24px 26px 20px;
}
.pub-card-head { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.pub-av {
  flex: none; width: 36px; height: 36px; border-radius: 50%;
  background: var(--green); color: var(--bone); display: grid; place-items: center;
  font-weight: 700; font-size: 15px;
}
.pub-card-title { font-weight: 700; font-size: 18px; color: var(--ink); flex: 1; min-width: 0; }
/* The composite body - the ONLY serif (Newsreader) surface, like the studio. */
.pub-body { /* inherits .composite-body (serif, paper, pre-wrap) */ }
.pub-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; margin-top: 18px; flex-wrap: wrap;
}
.pub-reads { font-size: 13px; color: var(--ink-soft); font-weight: 500; }
.pub-foot-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.btn-small { font-size: 13px; padding: 8px 16px; }
.pub-make {
  background: var(--green); color: var(--bone); border: 0; border-radius: 999px;
  font-weight: 600; text-decoration: none; display: inline-flex; align-items: center;
  transition: background var(--med) var(--ease);
}
.pub-make:hover { background: var(--green-deep); }
.pub-powered {
  margin-top: 16px; text-align: center; font-size: 12.5px; color: var(--ink-faint);
}
.pub-powered b { color: var(--green); font-weight: 700; }
.pub-empty { text-align: center; }
.pub-empty-title { font-size: 22px; font-weight: 700; color: var(--ink); margin: 4px 0 10px; }
.pub-empty-sub { font-size: 14.5px; color: var(--ink-soft); line-height: 1.6; max-width: 44ch; margin: 0 auto 18px; }
.pub-empty .pub-foot-actions { justify-content: center; }
@media (max-width: 640px) {
  .vis-switch { padding: 14px; }
  .pub-section { padding: 32px 16px 64px; }
  .pub-card { padding: 18px; }
  .pub-foot { flex-direction: column; align-items: flex-start; }
}

/* ---- SHARED WITH ME (#/shared) — SMC-W3 -------------------------------- */
/* The inbox of curated contexts OTHERS shared with this user, read-only. */
.shared-body { margin-top: 6px; }
.shared-empty {
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: 14px; padding: 40px 28px; text-align: center; margin-top: 10px;
}
.shared-empty-mark { font-size: 32px; color: var(--green); opacity: 0.55; line-height: 1; }
.shared-empty-title { font-size: 18px; font-weight: 600; color: var(--ink); margin: 16px 0 6px; }
.shared-empty-sub { font-size: 15px; color: var(--ink-faint); line-height: 1.55; margin: 0 auto; max-width: 380px; }

.shared-list {
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: 14px; padding: 6px 20px;
}
.shared-item { border-top: 1px solid var(--hair-soft); padding: 4px 0; }
.shared-item:first-child { border-top: none; }
.shared-item.gone { opacity: 0.6; }
.shared-item-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; padding: 14px 0;
}
.shared-item-main { min-width: 0; }
.shared-item-who {
  font-size: 15px; font-weight: 500; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.shared-item-meta { font-size: 12.5px; color: var(--ink-faint); margin-top: 2px; }
.shared-open { flex: none; }
.shared-open .spin { margin-right: 4px; }

/* SMC-CONSENT — a PENDING inbound invite: Accept / Decline (it is NOT openable
   until accepted, since the composite is gated server-side). The action zone holds
   either Accept+Decline (pending) or the Open toggle (accepted). */
.shared-actions { flex: none; display: inline-flex; align-items: center; gap: 6px; }
/* A compact primary button for the inline Accept (the base .btn is large). */
.btn-sm { padding: 8px 16px; font-size: 13.5px; gap: 6px; }
.shared-accept .spin { margin-right: 2px; }
.shared-decline { flex: none; }
.shared-decline .spin { margin-right: 4px; }
/* The pending hint / inline error sits under the meta line. */
.shared-pending-hint {
  font-size: 12.5px; color: var(--ink-faint); margin: 4px 0 0; line-height: 1.4;
}
.shared-pending-hint.is-err { color: var(--danger); }
/* A GOLD left accent + faint gold wash marks a pending invite as YOUR move
   (mock screens 8A / 12C: pending-you is the one solid-gold state). */
.shared-item.pending {
  border-left: 2px solid var(--gold); padding-left: 12px; margin-left: -14px;
  background: linear-gradient(to right, var(--gold-tint), transparent 70%);
}

@media (max-width: 640px) {
  .shared-actions { align-self: flex-start; }
}

.shared-panel { display: none; }
.shared-panel.show { display: block; padding: 0 0 16px; }
.shared-readonly-note {
  font-size: 13px; color: var(--ink-faint); margin: 0 0 12px; line-height: 1.5;
}
.shared-readonly-note strong { color: var(--ink); font-weight: 600; }
/* The shared composite text: read-only display, never an editable field. */
.shared-composite {
  background: var(--green-tint);
  border: 1px solid var(--hair);
  border-radius: 10px;
  padding: 16px 18px;
  font-size: 14.5px; line-height: 1.6; color: var(--ink);
  white-space: pre-wrap; word-break: break-word;
  max-height: 420px; overflow-y: auto;
}
.shared-gone, .shared-err { font-size: 13.5px; color: var(--ink-faint); padding: 4px 0 12px; }

@media (max-width: 640px) {
  .shared-list { padding: 4px 16px; }
  .shared-item-head { flex-direction: column; align-items: flex-start; gap: 8px; }
  .shared-open { align-self: flex-start; }
}

/* ---- The Sharing page (#/sharing) - studio-build item 5 ------------------
   "Shared with me" grown up: pending invites + shared-with-you mirrors + the
   person-first People ledger, one status-chip vocabulary (mock 7/8/12C). */

.sharing-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; }
.sharing-head-text { min-width: 0; }
.sharing-invite-btn { flex: none; margin-top: 6px; }
@media (max-width: 640px) {
  .sharing-head { flex-direction: column; }
  .sharing-invite-btn { margin-top: 0; }
}

.sharing-sec { margin-top: 28px; }
.sharing-sec:first-child { margin-top: 0; }
.sharing-sec .eyebrow { margin-bottom: 10px; }
.sharing-people-sub { font-size: 13px; color: var(--ink-faint); line-height: 1.55; margin: 0 0 12px; max-width: 56ch; }

/* The row avatar beside the owner label on inbound rows. */
.shared-av { flex: none; display: inline-flex; }
.shared-item-main { flex: 1; }

/* The ONE status-chip vocabulary (mock screen 12C): every grant wears exactly
   one of six states, same chip wherever it renders. Theme-aware tokens only. */
.st {
  font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 700;
  border-radius: 5px; padding: 2.5px 8px; flex: none; white-space: nowrap; line-height: 1.5;
}
.st-active  { background: var(--green-tint); color: var(--green); }        /* Sharing / Shared with you */
.st-invited { background: var(--gold-tint);  color: var(--amber-cue); }    /* Invited (awaiting their accept) */
/* Waiting (you asked for theirs, item 2): gold-FAMILY but DISTINCT from Invited -
   an outlined gold (tint fill + gold ink + gold-hair ring), so an open ASK never
   reads as an outbound GRANT awaiting accept. */
.st-waiting { background: var(--gold-tint);  color: var(--gold); box-shadow: inset 0 0 0 1px var(--gold-hair); }
.st-action  { background: var(--amber-cue);  color: var(--bone); }         /* Pending you - YOUR move */
.st-faint   { background: var(--hair-soft);  color: var(--ink-faint); }    /* Expired / lapsed */
.st-stopped { background: var(--danger-tint); color: var(--danger); }      /* Stopped (revoked / declined) */

/* People - the person-first ledger (mock screen 7B): one card per person,
   each direction its own line with the arrow + chip. */
.people-list { display: grid; gap: 10px; }
.person {
  display: flex; gap: 14px; align-items: flex-start;
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: var(--r); padding: 14px 16px;
}
.person-av { flex: none; display: inline-flex; margin-top: 2px; }
.person-main { flex: 1; min-width: 0; }
.person-name { font-weight: 600; font-size: 15px; color: var(--ink); }
.dir {
  display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap;
  font-size: 13px; color: var(--ink-soft); margin-top: 7px; line-height: 1.5;
}
.dir .aro { font-weight: 800; flex: none; width: 14px; }
.dir .aro.out { color: var(--green); }  /* -> outbound, racing green */
.dir .aro.inn { color: var(--gold); }   /* <- inbound, gold */
.dir .dir-text { min-width: 0; }
.dir .dir-text b { color: var(--ink); font-weight: 600; }
.dir .st { margin-left: auto; align-self: center; }
.person-side { flex: none; display: flex; flex-direction: column; gap: 7px; align-items: flex-end; }
@media (max-width: 640px) {
  .person { flex-wrap: wrap; }
  .person-side { flex-direction: row; width: 100%; justify-content: flex-end; }
  .dir .st { margin-left: 21px; }
}

/* The page foot-note: per-project share management stays on each project. */
.sharing-footnote {
  font-size: 12.5px; color: var(--ink-faint); line-height: 1.55;
  border-top: 1px solid var(--hair-soft); padding-top: 14px; margin: 4px 0 0;
}

/* The empty state always offers the Invite door (never a dead end) + nudges
   toward Team (the living-context tier), echoing the per-project drawer. */
.shared-empty-cta { margin-top: 18px; display: inline-flex; gap: 10px; flex-wrap: wrap; align-items: center; }

/* The rollup Team section (2026-06-15): bundles when present, else the Team
   nudge toward the living-context tier. */
.sharing-sec.sec-team .team-list { margin-top: 4px; }
.sharing-team-empty { margin-top: 2px; }

/* The invite composer modal (the person-to-person door). Reuses the shared
   .lp-modal-ov/.lp-modal shell, re-skinned to the in-APP aesthetic like the
   upsell modal: warm paper, racing-green accent, Schibsted Grotesk. */
.invite-modal {
  background: var(--paper); color: var(--ink); max-width: 440px;
  border: 1px solid var(--hair);
  box-shadow: 0 24px 64px rgba(22, 48, 31, 0.22); text-align: left;
}
.invite-modal .lp-modal-title { font-family: var(--display); font-weight: 700; color: var(--ink); font-size: 27px; letter-spacing: -0.02em; }
.invite-modal .lp-eyebrow { color: var(--green); }
.invite-modal .lp-modal-x { color: var(--ink-faint); }
.invite-modal .lp-modal-x:hover { color: var(--ink); }
.invite-form .field { margin-top: 14px; }
.invite-project-select { width: 100%; appearance: auto; }
.invite-note { font-size: 12.5px; color: var(--ink-faint); line-height: 1.55; margin: 12px 0 0; }
.invite-actions { margin-top: 16px; display: flex; justify-content: flex-end; }
.invite-ok { font-size: 14.5px; color: var(--ink); line-height: 1.55; margin: 16px 0 0; }
.invite-ok + .invite-ok { margin-top: 8px; }
.invite-ok-sub { font-size: 12.5px; color: var(--ink-faint); line-height: 1.55; margin: 10px 0 0; }
.invite-done { margin-top: 16px; }

/* The two composer toggles (mock screen 7C): "Share my context" + "Ask for
   theirs". Each is a calm checkbox row; the share toggle's project picker rides
   under it (hidden when the toggle is off). Both can be on in one send. */
.invite-offers { margin-top: 16px; display: grid; gap: 10px; }
.invite-offer {
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  border: 1px solid var(--hair); border-radius: 10px; padding: 11px 13px;
  background: var(--bg-soft, var(--paper));
}
.invite-offer input[type="checkbox"] { flex: none; width: 16px; height: 16px; accent-color: var(--green); cursor: pointer; }
.invite-offer-label { font-size: 14px; font-weight: 500; color: var(--ink); flex: 1; }
.invite-offer-hint { font-size: 11.5px; color: var(--ink-faint); flex: none; }
/* The share project picker sits just under the "Share my context" toggle. */
.invite-share-field { margin-top: 0; padding: 0 2px; }
.invite-share-field label { font-size: 12px; color: var(--ink-faint); }

/* ---- the multi-email chip input (item 3b: share with a group) -----------
   Each committed recipient is a chip; the trailing input grows the row. >1
   recipient is a bundle (Premium). The hint sits beside the field label. */
.invite-multi-hint { font-size: 11px; color: var(--ink-faint); font-weight: 400; margin-left: 8px; }
.invite-chipbox {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  padding: 8px 10px; min-height: 42px; cursor: text;
}
.invite-chips { display: contents; }
.invite-chip {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--green-tint, var(--gold-tint)); border: 1px solid var(--hair);
  border-radius: 999px; padding: 3px 5px 3px 10px; font-size: 12.5px;
  color: var(--ink); max-width: 100%;
}
.invite-chip-email { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.invite-chip-x {
  flex: none; width: 18px; height: 18px; border: 0; border-radius: 50%;
  background: transparent; color: var(--ink-faint); font-size: 15px; line-height: 1;
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
}
.invite-chip-x:hover { color: var(--danger); font-weight: 700; }
.invite-email-input {
  flex: 1; min-width: 120px; border: 0; outline: 0; background: transparent;
  font: inherit; font-size: 14px; color: var(--ink); padding: 4px 2px;
}

/* The optional group label, shown only for a bundle (>1 recipient). */
.invite-label-field { margin-top: 0; padding: 0 2px; }
.invite-label-field label { font-size: 12px; color: var(--ink-faint); }

/* The Premium gate hint - shown to a FREE user pointing a bundle. Calm, never
   a wall: the send opens the upsell instead. Reuses the gold/lock language. */
.invite-gate {
  display: flex; align-items: center; gap: 10px; padding: 10px 13px;
  border: 1px solid var(--gold-hair); background: var(--gold-tint);
  border-radius: 10px;
}
.invite-gate-lock {
  flex: none; display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--gold); white-space: nowrap;
}
.invite-gate-lock .lock-glyph { font-size: 11px; }
.invite-gate-text { font-size: 12.5px; color: var(--ink-soft); line-height: 1.5; }

/* ---- the Premium bundle row (item 3b, mock 7B) --------------------------
   A bundle (N grants, one bundleId) renders as ONE People row: an avatar STACK
   of members + the label + a "Premium" chip + a single "Stop sharing all". */
.bundle-chip {
  display: inline-block; margin-left: 8px; vertical-align: middle;
  font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 600;
  background: var(--gold-tint); color: var(--gold); border: 1px solid var(--gold-hair);
  border-radius: 999px; padding: 2px 8px;
}
.bundle-avatars { display: inline-flex; align-items: center; }
.bundle-av { display: inline-flex; margin-left: -8px; border-radius: 50%; }
.bundle-av:first-child { margin-left: 0; }
.bundle-av :where(span, svg) { box-shadow: 0 0 0 2px var(--paper); border-radius: 50%; }
.bundle-av-more {
  width: 32px; height: 32px; border-radius: 50%; flex: none;
  align-items: center; justify-content: center;
  background: var(--green); color: var(--paper); font-size: 11px; font-weight: 600;
  box-shadow: 0 0 0 2px var(--paper);
}

/* ---- "Requests for you" (ask-for-theirs item 2): inbound asks ------------
   Others asking YOU to share. Each row = who asked + their note, with Fulfil
   (a project picker) + Decline. Reuses the shared-list card frame. */
.req-list {
  background: var(--paper); border: 1px solid var(--hair);
  border-radius: 14px; padding: 6px 20px;
}
.req-item { border-top: 1px solid var(--hair-soft); padding: 4px 0; }
.req-item:first-child { border-top: none; }
.req-item-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; padding: 14px 0;
}
.req-av { flex: none; display: inline-flex; }
.req-item-main { flex: 1; min-width: 0; }
.req-item-who { font-size: 15px; font-weight: 500; color: var(--ink); }
.req-item-meta { font-size: 12.5px; color: var(--ink-faint); margin-top: 2px; line-height: 1.45; }
.req-err { font-size: 12.5px; color: var(--danger); margin: 4px 0 0; line-height: 1.4; }
.req-actions { flex: none; display: inline-flex; align-items: center; gap: 6px; }
.req-fulfil .spin { margin-right: 2px; }
.req-decline { flex: none; }
.req-decline .spin { margin-right: 4px; }
@media (max-width: 640px) {
  .req-list { padding: 4px 16px; }
  .req-item-head { flex-direction: column; align-items: flex-start; gap: 8px; }
  .req-actions { align-self: flex-start; }
}

/* The fulfil project-picker modal reuses the invite-modal frame. */
.fulfil-modal {
  background: var(--paper); color: var(--ink); max-width: 420px;
  border: 1px solid var(--hair);
  box-shadow: 0 24px 64px rgba(22, 48, 31, 0.22); text-align: left;
}
.fulfil-modal .lp-modal-title { font-family: var(--display); font-weight: 700; color: var(--ink); font-size: 24px; letter-spacing: -0.02em; }
.fulfil-modal .lp-eyebrow { color: var(--green); }
.fulfil-modal .field { margin-top: 14px; }
.fulfil-project-select { width: 100%; appearance: auto; }
.fulfil-actions { margin-top: 16px; display: flex; justify-content: flex-end; }

/* Storage-usage-meter: a COARSE proportion meter (thin bar + qualitative cue).
   Deliberately NO granular byte figures - just a fill fraction + a word + a
   low/near-full colour cue (racing-green when there's room, a calm amber as it
   fills). Compact card that sits above the storage groups. */
.usage-meter {
  background: var(--paper);
  border: 1px solid var(--hair-soft);
  border-radius: var(--r-sm);
  padding: 16px 18px;
}
.usage-meter-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 11px; flex-wrap: wrap;
}
.usage-meter-label {
  font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
  font-weight: 600; color: var(--ink-faint);
}
.usage-meter-cue {
  font-size: 13.5px; font-weight: 600; color: var(--green);
}
.usage-meter-track {
  width: 100%; height: 8px; border-radius: 999px;
  background: var(--bone-2); overflow: hidden;
}
.usage-meter-fill {
  display: block; height: 100%; width: 0;
  background: var(--green); border-radius: 999px;
  transition: width var(--med) var(--ease), background-color var(--med) var(--ease);
}
/* Near-full bands shift the cue + fill to a calm amber (not alarm red). */
.usage-meter[data-level="high"] .usage-meter-fill,
.usage-meter[data-level="full"] .usage-meter-fill { background: var(--amber); }
.usage-meter[data-level="high"] .usage-meter-cue,
.usage-meter[data-level="full"] .usage-meter-cue { color: var(--amber-cue); }
