/* =========================================================================
   FELIX · CLICKPOST
   Editorial newsprint × ops terminal. Cream paper, deep ink, vermilion signal.
   ========================================================================= */

:root {
  --paper:        #ffffff;
  --paper-2:      #f5f8ff;
  --paper-3:      #e6eeff;
  --ink:          #0b1e4a;        /* deep navy */
  --ink-2:        #14306b;
  --muted:        #56688f;
  --muted-2:      #8d9cbd;
  --rule:         #d6deef;
  --rule-2:       #b6c4e2;
  --signal:       #3b6ef6;        /* ClickPost interactive blue (shared) */
  --signal-soft:  #eaf0ff;        /* tinted fill behind active/selected */
  --signal-deep:  #2f5ad8;        /* hover / pressed */
  --good:         #0e7490;
  --good-soft:    #d6eef5;
  --bad:          #b91c1c;

  --font-display: "Inter", -apple-system, system-ui, sans-serif;
  --font-body:    "Inter", -apple-system, system-ui, sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;
  /* Uppercase utility labels (eyebrows, meta, button text) use sans, not mono —
     monospace is reserved as the `felix` wordmark's signature. */
  --font-label:   var(--font-body);

  --rail: 240px;

  /* Shape language — Felix runs sharp (radius 0); ClickPost runs soft (8–12px).
     These meet the two halfway so the products read as one family. */
  --radius:    6px;   /* buttons, chips, framed cards */
  --radius-lg: 8px;   /* larger surfaces: popovers, grouped panels */
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: "ss01", "cv01", "cv02";
  overflow: hidden;
}

button, input, textarea, select {
  font: inherit;
  color: inherit;
}

a { color: var(--ink); text-decoration: none; }
a:hover { text-decoration: underline; text-decoration-color: var(--signal); text-underline-offset: 3px; }

/* ---------- paper grain overlay ---------- */
.grain {
  position: fixed; inset: 0;
  pointer-events: none;
  z-index: 100;
  opacity: 0.35;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.08  0 0 0 0 0.12  0 0 0 0 0.24  0 0 0 0.05 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  mix-blend-mode: multiply;
}

/* ---------- shared utility ---------- */
.kicker {
  font-family: var(--font-label);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}
.eyebrow {
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted-2);
}
.rule { border: 0; border-top: 1px solid var(--rule); margin: 0; }
.rule-ink { border: 0; border-top: 1.5px solid var(--ink); margin: 0; }

/* =========================================================================
   LOGIN
   Split layout: editorial brand statement on the left, surgical form on the right.
   ========================================================================= */

.login-shell {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  min-height: 100vh;
}
@media (max-width: 820px) {
  .login-shell { grid-template-columns: 1fr; }
  .login-brand { padding: 48px 36px !important; min-height: auto !important; }
}

.login-brand {
  background: var(--ink);
  color: var(--paper);
  padding: 64px 72px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  position: relative;
  overflow: hidden;
  min-height: 100vh;
}
.login-brand::after {
  /* faint vermilion glyph in the corner */
  content: "";
  position: absolute;
  right: -120px; bottom: -120px;
  width: 480px; height: 480px;
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 50%;
  pointer-events: none;
}
.login-brand::before {
  content: "";
  position: absolute;
  right: 60px; top: 60px;
  width: 8px; height: 8px;
  background: var(--signal);
  border-radius: 50%;
  box-shadow: 0 0 24px var(--signal);
}

.brand-masthead {
  display: flex;
  align-items: baseline;
  gap: 14px;
}
.brand-masthead .glyph {
  font-family: var(--font-mono);   /* matches the rail wordmark — mono is the felix signature */
  font-style: normal;
  font-weight: 700;
  font-size: 28px;
  letter-spacing: -0.02em;
  color: var(--signal);
}
.brand-masthead .name {
  font-family: var(--font-label);
  font-size: 11px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--paper);
  opacity: 0.85;
}

.brand-statement {
  max-width: 520px;
}
.brand-statement h1 {
  font-family: var(--font-display);
  font-weight: 300;
  font-style: normal;
  font-size: clamp(40px, 4.6vw, 68px);
  line-height: 1.02;
  letter-spacing: -0.025em;
  margin: 0 0 28px;
  color: var(--paper);
  font-variation-settings: "opsz" 96, "SOFT" 30;
  overflow-wrap: break-word;
  word-break: normal;
}
.brand-statement h1 em {
  font-style: normal;
  color: var(--signal);
  font-weight: 500;
}
.brand-statement p {
  font-size: 16px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.72);
  max-width: 420px;
  margin: 0;
}

.brand-footer {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px;
  font-family: var(--font-label);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
}
.brand-footer .vol {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.brand-footer .vol span:first-child {
  color: rgba(255, 255, 255, 0.7);
  font-weight: 500;
}

/* Login form pane */
.login-form-pane {
  background: var(--paper);
  padding: 64px 72px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
}
@media (max-width: 820px) {
  .login-form-pane { padding: 44px 28px; }
}
.login-card {
  width: 100%;
  max-width: 420px;
}
.login-card .eyebrow { margin-bottom: 18px; }
.login-card h2 {
  font-family: var(--font-display);
  font-weight: 500;
  font-style: normal;
  font-size: 40px;
  line-height: 1.05;
  letter-spacing: -0.018em;
  margin: 0 0 12px;
  color: var(--ink);
}
.login-card .lede {
  color: var(--muted);
  margin: 0 0 36px;
  max-width: 360px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 22px;
}
.field label {
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
}
.field input[type="password"],
.field input[type="text"] {
  background: transparent;
  border: 0;
  border-bottom: 1.5px solid var(--ink);
  padding: 10px 0;
  font-family: var(--font-label);
  font-size: 14px;
  color: var(--ink);
  outline: none;
  border-radius: 0;
}
.field input::placeholder { color: var(--muted-2); font-family: var(--font-label); }
.field input:focus { border-bottom-color: var(--signal); }
.field .hint {
  font-size: 12px;
  color: var(--muted);
  margin: 0;
}
.field .hint code {
  font-family: var(--font-mono);
  font-size: 11px;
  background: var(--paper-3);
  padding: 1px 6px;
}

.btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  background: var(--signal);
  color: var(--paper-2);
  border: 0;
  padding: 16px 22px;
  font-family: var(--font-label);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 600;
  cursor: pointer;
  transition: transform 80ms ease, background 120ms ease;
  border-radius: 0;
}
.btn-primary:hover { background: var(--signal-deep); }
.btn-primary:active { transform: translateY(1px); }
.btn-primary::after {
  content: "→";
  font-family: var(--font-display);
  font-size: 18px;
  letter-spacing: 0;
  transform: translateY(-1px);
}

.alert {
  background: var(--paper-2);
  border-left: 2px solid var(--bad);
  padding: 12px 14px;
  font-size: 13px;
  color: var(--bad);
  margin-bottom: 22px;
  font-family: var(--font-label);
}

.login-altlink {
  margin-top: 28px;
  padding-top: 18px;
  border-top: 1px solid var(--paper-3);
  font-family: var(--font-label);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
.login-altlink a { color: var(--signal); text-decoration: none; }
.login-altlink a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* =========================================================================
   CHAT SHELL
   Thin masthead rail (left) + wide reading column (right).
   ========================================================================= */

.app {
  display: grid;
  grid-template-columns: var(--rail) 1fr;
  height: 100vh;
  height: 100dvh;   /* dynamic viewport height — 100vh can exceed the visible area
                       (browser chrome / zoom / mobile URL bar) and clip the composer + rail bottom */
}
@media (max-width: 880px) {
  .app { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .rail { border-right: 0 !important; border-bottom: 1px solid var(--rule); }
}

.rail {
  border-right: 1px solid var(--rule);
  background: var(--paper-2);
  display: flex;
  flex-direction: column;
  padding: 28px 20px;
  gap: 24px;
  position: relative;
  min-height: 0;
  overflow-y: auto;
  box-shadow: inset -1px 0 0 var(--rule);
}
.rail .masthead {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.rail .masthead .mark {
  font-family: var(--font-mono);   /* monospace IS the wordmark's signature now */
  font-style: normal;
  font-weight: 700;
  font-size: 23px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--ink);
  display: flex;
  align-items: baseline;
  gap: 0;
}
.rail .masthead .mark em { font-style: normal; }   /* wordmark is upright mono, not italic */
.rail .masthead .mark .dot {
  color: var(--signal);
  font-style: normal;
}
.rail .masthead .tagline {
  font-family: var(--font-label);
  font-size: 9.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 8px;
}

.rail-block {
  border-top: 1px solid var(--rule);
  padding-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.rail-block .eyebrow { margin-bottom: 4px; }
.rail-block .live-date {
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1.1;
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.rail-block .live-date .day {
  display: block;
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--signal);
  margin-bottom: 4px;
}

.rail .examples {
  display: flex;
  flex-direction: column;
  gap: 0;
}
.rail .examples .example-q {
  display: block;
  padding: 10px 0;
  border-bottom: 1px dashed var(--rule);
  font-size: 13px;
  line-height: 1.35;
  color: var(--ink-2);
  cursor: pointer;
  transition: color 100ms ease, padding-left 120ms ease;
}
.rail .examples .example-q:hover {
  color: var(--signal);
  padding-left: 6px;
}
.rail .examples .example-q::before {
  content: "› ";
  color: var(--signal);
  font-family: var(--font-label);
}

.rail .note {
  font-size: 11px;
  line-height: 1.5;
  color: var(--muted);
  font-style: normal;
  font-family: var(--font-body);
  margin-top: 4px;
}

.rail .spacer { flex: 1; }

.rail .rail-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  border-top: 1px solid var(--rule);
  padding-top: 18px;
}
.btn-new-chat {
  background: transparent;
  border: 1px solid var(--rule-2);
  color: var(--ink-2);
  padding: 9px 12px;
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  text-align: center;
  border-radius: var(--radius);
  transition: background 100ms ease, border-color 100ms ease, color 100ms ease;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.btn-new-chat:hover { background: var(--paper-3); border-color: var(--signal); color: var(--signal); }
.btn-new-chat .btn-new-chat-plus {
  font-size: 16px;
  font-style: normal;
  font-weight: 300;
  line-height: 1;
  color: var(--signal);
  font-family: var(--font-display);
}
.btn-ghost {
  background: transparent;
  border: 1px solid var(--rule-2);
  color: var(--muted);
  padding: 9px 12px;
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
  text-align: center;
  border-radius: var(--radius);
  transition: background 100ms ease, color 100ms ease, border-color 100ms ease;
}
.btn-ghost:hover { background: var(--paper-3); color: var(--signal); border-color: var(--signal); text-decoration: none; }

/* ---- account chip ---- */
.rail-account {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--paper-3);
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: 8px 10px;
}
.rail-account-avatar {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--signal);
  color: #fff;
  font-family: var(--font-label);
  font-size: 11px;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
}
.rail-account-info {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.rail-account-name {
  font-size: 12px;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rail-account-org {
  font-family: var(--font-label);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- past-chats history list ---- */
.rail-history { min-height: 0; }
.history-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 34vh;
  overflow-y: auto;
}
.history-item {
  display: flex;
  align-items: stretch;
  gap: 4px;
  border-bottom: 1px dashed var(--rule);
}
.history-item.active { background: var(--paper-3); }
.history-open {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: transparent;
  border: 0;
  padding: 8px 4px;
  cursor: pointer;
  text-align: left;
}
.history-title {
  font-size: 13px;
  line-height: 1.3;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color 100ms ease;
}
.history-open:hover .history-title { color: var(--signal); }
.history-time {
  font-family: var(--font-label);
  font-size: 9.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.history-del {
  flex: 0 0 auto;
  align-self: center;
  background: transparent;
  border: 0;
  color: var(--muted-2);
  font-size: 18px;
  line-height: 1;
  padding: 0 6px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 100ms ease, color 100ms ease;
}
.history-item:hover .history-del { opacity: 1; }
.history-del:hover { color: #b3261e; }

.rail form { margin: 0; }

/* ---------- main reading column ---------- */
.main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  position: relative;
  overflow: hidden;
}

.main-head {
  padding: 22px 56px 18px;
  border-bottom: 1px solid var(--rule);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  background: var(--paper);
}
.main-head h1 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 28px;
  letter-spacing: -0.015em;
  margin: 0;
  color: var(--ink);
}
.main-head h1 em {
  font-style: normal;        /* emphasis via colour, not italic (ClickPost-restrained) */
  color: var(--signal);
  font-weight: 500;
}
.main-head .meta {
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: right;
}

.thread {
  flex: 1;
  overflow-y: auto;
  padding: 36px 56px 24px;
  scroll-behavior: smooth;
}
/* When only the empty state is present (no conversation yet), center it
   vertically and horizontally in the available thread height. */
.thread:has(> #empty-state) {
  display: flex;
  flex-direction: column;   /* keep stacking vertical even if a stray
                               empty-state lingers alongside messages */
  align-items: center;
  justify-content: center;
  padding: 24px 56px;
}
@media (max-width: 720px) {
  .main-head { padding: 18px 24px; }
  .thread { padding: 24px 24px 16px; }
}
.thread::-webkit-scrollbar { width: 10px; }
.thread::-webkit-scrollbar-thumb { background: var(--rule-2); }
.thread::-webkit-scrollbar-track { background: transparent; }

.empty-state {
  max-width: 640px;
  width: 100%;
  margin: 0 auto;
  text-align: left;
}
.empty-state .stamp {
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--signal);
  margin-bottom: 12px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.empty-state .stamp::before {
  content: "";
  display: inline-block;
  width: 24px; height: 1.5px;
  background: var(--signal);
}
.empty-state h2 {
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 500;
  font-size: clamp(32px, 3.6vw, 48px);
  line-height: 1.02;
  letter-spacing: -0.022em;
  margin: 0 0 16px;
  color: var(--ink);
  font-variation-settings: "opsz" 144, "SOFT" 50;
}
.empty-state p em { font-style: normal; color: var(--ink-2); font-weight: 500; }
.empty-state p {
  font-size: 15px;
  color: var(--muted);
  max-width: 480px;
  margin: 0 0 24px;
}

/* ---------- empty-state suggestion grid (prominent) ---------- */
.suggestion-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* 1px gap over a ruled background paints pixel-perfect, uniform light
     hairlines (cards sit opaque on top) — interior lines and the outer frame
     are the same single hairline, no doubled edges. */
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  overflow: hidden;
  max-width: 640px;
}
@media (max-width: 560px) {
  .suggestion-grid { grid-template-columns: 1fr; }
}
.suggestion-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px 18px 16px;
  background: var(--paper);
  border: 0;                /* reset the <button> UA border; the grid gap is the only line */
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
  position: relative;
  transition: background 120ms ease, padding-left 140ms ease;
}
.suggestion-card:hover {
  background: var(--paper-2);
  padding-left: 26px;
}
.suggestion-card:hover .suggestion-arrow { color: var(--signal); transform: translateX(2px); }
.suggestion-card .suggestion-tag {
  font-family: var(--font-label);
  font-size: 9.5px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--signal);
}
.suggestion-card .suggestion-text {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 17px;
  line-height: 1.25;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.suggestion-card .suggestion-text em { font-style: normal; font-weight: 500; }
.suggestion-card .suggestion-arrow {
  position: absolute;
  right: 16px; bottom: 14px;
  font-family: var(--font-display);
  font-size: 18px;
  color: var(--muted-2);
  transition: color 140ms ease, transform 140ms ease;
}

/* ---------- composer-area suggestion strip (always visible) ---------- */
.composer-suggestions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  max-width: 980px;
  /* Sits directly above the textarea, so keep the gap tight — the row and the
     input read as one composing area, not two stacked blocks. */
  margin: 0 auto 7px;
}
/* The eyebrow is data-driven: "Try" while the rail holds starters, "Ask next"
   once it has been handed over to follow-up chips (see chat.js showFollowups). */
.composer-suggestions::before {
  content: attr(data-label);
  font-family: var(--font-label);
  font-size: 9.5px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--muted-2);
  align-self: center;
  margin-right: 4px;
  white-space: nowrap;
  transition: color 200ms ease;
}
/* In follow-up mode the rail is the primary call to action, not a hint, so the
   eyebrow takes the signal colour. */
.composer-suggestions.followup-mode::before { color: var(--signal); }
/* Collapsed: mid-conversation, before the chips for the current answer arrive.
   Removed from layout entirely so it leaves no empty band above the composer. */
.composer-suggestions.is-empty { display: none; }
/* On a phone, four wrapped chips stack ~140px tall and push the composer down.
   Keep them on one swipeable line instead, with the eyebrow pinned so you can
   still tell what the row is while scrolling it. */
@media (max-width: 640px) {
  .composer-suggestions {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;              /* the chips themselves signal scrollability */
    -webkit-overflow-scrolling: touch;
    scroll-padding-left: 34px;
  }
  .composer-suggestions::-webkit-scrollbar { display: none; }
  .composer-suggestions::before {
    position: sticky;
    left: 0;
    background: var(--paper);
    padding-right: 6px;
    z-index: 1;
  }
  .composer-suggestions > * { flex: 0 0 auto; }   /* don't squeeze chips to fit */
}
/* One-shot cue when chips arrive: the eyebrow brightens and settles. Nothing
   loops, nothing moves the layout — the reader's eye is drawn once, then it's a
   normal part of the page. */
.composer-suggestions.just-arrived::before {
  animation: rail-cue 1.1s ease-out;
}
@keyframes rail-cue {
  0%   { color: var(--signal); letter-spacing: 0.28em; }
  18%  { color: var(--signal-deep); letter-spacing: 0.34em; }
  100% { color: var(--signal); letter-spacing: 0.28em; }
}
.chip {
  background: transparent;
  border: 1px solid var(--rule);
  padding: 5px 11px 6px;
  font-family: var(--font-label);
  font-size: 11px;
  letter-spacing: 0.02em;
  color: var(--muted);
  cursor: pointer;
  border-radius: var(--radius);
  transition: all 120ms ease;
  line-height: 1.2;
  text-align: left;
}
/* Same hover language as the follow-up chips that replace these in the rail —
   tint + signal border + a small lift, rather than the old solid fill that flipped
   the label to white. The two sets swap in and out of the same row, so a shared
   treatment is what makes them read as one control family. */
.chip:hover {
  background: rgba(59, 110, 246, 0.05);
  color: var(--signal-deep);
  border-color: var(--signal);
}
.chip:focus-visible {
  outline: none;
  background: rgba(59, 110, 246, 0.05);
  border-color: var(--signal);
  color: var(--signal-deep);
  box-shadow: 0 0 0 2px var(--signal-soft);
}


/* ---------- message rows ---------- */
.msg-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 36px;
  max-width: 760px;
}
.msg-row.user {
  align-items: flex-end;
  margin-left: auto;
}

.msg-user {
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink);
  background: transparent;
  border-right: 2px solid var(--signal);
  padding: 4px 16px 4px 0;
  max-width: 100%;
  white-space: pre-wrap;
  text-align: right;
}
.msg-user::before {
  content: "YOU ASKED ";
  font-size: 9px;
  letter-spacing: 0.24em;
  color: var(--muted-2);
  display: block;
  margin-bottom: 4px;
  font-weight: 500;
}

.assistant-block {
  display: flex;
  flex-direction: column;
  gap: 10px;
  border-left: 2px solid var(--rule-2);   /* softened from a hard ink bar */
  padding-left: 22px;
  position: relative;
}

.tools-container {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 2px;
}

/* ---------- /usage command card ---------- */
.usage-card {
  max-width: 460px;
  width: 100%;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-top: 1.5px solid var(--ink);
  padding: 18px 22px 20px;
}
.usage-card .usage-head {
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--signal);
  margin-bottom: 16px;
}
.usage-row + .usage-row { margin-top: 16px; }
.usage-row-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}
.usage-row .usage-label {
  font-family: var(--font-display);
  font-size: 16px;
  color: var(--ink);
}
.usage-row .usage-count {
  font-family: var(--font-label);
  font-size: 12.5px;
  color: var(--ink-2);
}
.usage-row .usage-count.over { color: var(--bad); }
.usage-bar {
  position: relative;
  height: 4px;
  background: var(--paper-3);
  margin: 8px 0 5px;
  overflow: hidden;
}
.usage-bar > span {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  background: var(--signal);
  transition: width 200ms ease;
}
.usage-bar > span.over { background: var(--bad); }
.usage-row .usage-reset {
  font-family: var(--font-label);
  font-size: 9px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted-2);
}
.usage-card .usage-note {
  margin-top: 14px;
  font-size: 12px;
  font-style: normal;
  color: var(--muted);
}
/* Why the rows above look fine yet nothing sends: the organization's cap. Carries
   the same red accent as the composer strip so the two read as one state. */
.usage-card .usage-note-blocked {
  padding-left: 9px;
  border-left: 2px solid var(--bad);
  color: var(--ink-2);
}

/* Single animated "working" indicator (no per-tool chips, no SQL). */
.work-indicator {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  padding: 5px 12px;
  font-family: var(--font-label);
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  border-radius: 0;
  animation: work-in 0.2s ease both;
}
.work-indicator .work-square {
  width: 7px; height: 7px;
  background: var(--signal);
  flex-shrink: 0;
  animation: pulse-dot 1.1s infinite ease-in-out;
}
.work-indicator .work-label { color: var(--ink); font-weight: 700; }
.work-indicator .work-dots { display: inline-flex; gap: 3px; }
.work-indicator .work-dots i {
  width: 4px; height: 4px; border-radius: 50%;
  background: var(--muted);
  animation: work-bounce 1.2s infinite ease-in-out;
}
.work-indicator .work-dots i:nth-child(2) { animation-delay: 0.16s; }
.work-indicator .work-dots i:nth-child(3) { animation-delay: 0.32s; }

/* THINKING state: while streaming, text renders in muted gray with a pulsing
   gray dot on the left, so it reads as Felix thinking out loud — never as the
   committed answer. Interim thinking (a turn that then calls a tool) is cleared;
   the final turn's text "graduates" to the answer when endStream drops .thinking
   (color/indent transition back to the committed style). */
.msg-assistant.thinking {
  position: relative;
  padding-left: 22px;
  color: var(--muted);
  /* transition lives on the base .msg-assistant so it applies both when
     entering thinking and when graduating out of it. */
}
.msg-assistant.thinking::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.55em;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--muted);
  animation: pulse-dot 1.1s infinite ease-in-out;
}

@keyframes pulse-dot {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.3; transform: scale(0.6); }
}
@keyframes work-bounce {
  0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
  40% { opacity: 1; transform: translateY(-3px); }
}
@keyframes work-in {
  from { opacity: 0; transform: translateY(2px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Blinking caret while an answer streams. The live answer is rendered append-only
   (smd), so the caret can't be a node inside the last inline run — it hangs off
   the streaming container and trails the last rendered node. */
.msg-assistant.streaming::after {
  content: "";
  display: inline-block;
  width: 7px; height: 1.02em;
  margin-left: 1px;
  background: var(--signal);
  vertical-align: text-bottom;
  animation: caret-blink 1s steps(1, end) infinite;
}
@keyframes caret-blink {
  0%, 50% { opacity: 1; }
  50.01%, 100% { opacity: 0; }
}

/* Thumbs up/down feedback on a completed answer */
.feedback-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  padding-top: 9px;
  border-top: 1px dashed var(--rule);
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  opacity: 0;
  animation: work-in 0.3s ease 0.1s forwards;
}
.feedback-bar .fb-label { margin-right: 2px; }
.feedback-bar .fb-btn {
  width: 24px; height: 21px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--rule);
  background: var(--paper-2);
  color: var(--muted);
  font-size: 13px; line-height: 1;
  cursor: pointer;
  border-radius: 0;
  transition: color 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}
.feedback-bar .fb-btn:hover { color: var(--signal); border-color: var(--signal); }
.feedback-bar .fb-btn.selected {
  background: var(--signal);
  border-color: var(--signal);
  color: #fff;
}

/* ---------- follow-up chips ("Ask next") ----------
   These live in the rail above the composer (`.composer-suggestions`), taking over
   the space the 4 starters occupy on an empty chat. Two-part pill: the text is the
   send button, the pencil loads it into the composer to edit first — so the fast
   path stays one tap and nothing is ever sent that the reader didn't choose.

   Hover is designed around one rule: the pill must always read as ONE object.
   Tinting only the half under the cursor made it look broken in half, so the pill
   lifts and tints as a whole, and the half that would actually fire gets a
   *deeper* tint on top of that. You can see both what you're about to click and
   that it belongs to a single chip. */
.followup-chip {
  display: inline-flex;
  align-items: stretch;
  max-width: 100%;
  /* Deliberately the SAME shape, border and metrics as the `.chip` starters that
     occupy this rail on an empty chat — the two sets swap in and out of one row,
     so a different radius/typeface made the handover look like a different widget.
     The only structural difference is the pencil half; the only tonal one is a
     slightly stronger ink, since these are the live call to action. */
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: transparent;
  overflow: hidden;                  /* clips the inner tints to the chip radius */
  /* `backwards`, NOT `forwards`: a forwards-filled animation keeps asserting its
     final `transform: translateY(0)`, and animations outrank normal declarations
     in the cascade — so the hover lift below silently did nothing. Filling
     backwards covers the staggered delay (no pre-animation flash of a chip at full
     opacity) and then hands transform back to the base rule once it ends. */
  opacity: 1;
  animation: chip-in 240ms cubic-bezier(0.22, 0.61, 0.36, 1) backwards;
  transition: background 150ms ease, border-color 150ms ease,
              box-shadow 150ms ease, transform 150ms ease;
}
@keyframes chip-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Hover is a SMALL delta from the resting chip, not a transformation. Two earlier
   attempts were worse: tinting only the hovered half split the chip visually in
   two, and then tinting the whole chip in `--signal-soft` (~11% signal) with a
   deeper patch on the active half turned a 26px control into a heavy blue button
   with a seam down the middle. At this size any second background inside one chip
   reads as banding.

   So: ONE whisper-light fill across the whole chip (~5% signal), a signal border,
   and no lift or shadow — a 1px rise on a 26px chip is jitter, not depth. Which
   half will fire is signalled by that control's OWN colour, never by another
   background: over the text, the text darkens; over the pencil, only the pencil
   does. Precise feedback, no banding. */
.followup-chip:hover,
.followup-chip:focus-within {
  background: rgba(59, 110, 246, 0.05);
  border-color: var(--signal);
}
.followup-chip:focus-within {
  box-shadow: 0 0 0 2px var(--signal-soft);
}

.followup-chip .fu-send,
.followup-chip .fu-edit {
  background: transparent;
  border: 0;
  cursor: pointer;
  font-family: var(--font-label);
  color: var(--ink-2);
  transition: color 130ms ease;
}
/* Scoped to the half actually under the cursor — darkening the text while the
   pencil is hovered would point at the wrong action. */
.followup-chip .fu-send:hover,
.followup-chip .fu-send:focus-visible { color: var(--signal-deep); }
.followup-chip .fu-send:focus-visible,
.followup-chip .fu-edit:focus-visible { outline: none; }

/* Matches `.chip`'s 5px/11px/6px padding and 11px label type, minus the right
   padding the pencil takes over. */
.followup-chip .fu-send {
  padding: 5px 6px 6px 11px;
  font-size: 11px;
  letter-spacing: 0.02em;
  line-height: 1.2;
  text-align: left;
  min-width: 0;                      /* let long text shrink instead of overflowing */
}

/* The pencil stays quiet at rest — four always-lit icons make the row look busy,
   and sending is the primary action. It brightens whenever the chip is engaged, so
   it never reads as disabled. The 26px box keeps it a real tap target on touch
   even though the glyph is 12px. */
.followup-chip .fu-edit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  flex: 0 0 26px;
  color: var(--rule-2);
  /* Stays a neutral hairline on hover too: tinting it signal-blue turned the
     divider into a hard seam and made the chip look like two joined panels. */
  border-left: 1px solid var(--rule);
  transition: color 130ms ease;
}
.followup-chip .fu-edit svg {
  width: 12px; height: 12px; display: block;
  transition: transform 130ms ease;
}
.followup-chip:hover .fu-edit,
.followup-chip:focus-within .fu-edit { color: var(--muted-2); }
.followup-chip .fu-edit:hover,
.followup-chip .fu-edit:focus-visible { color: var(--signal-deep); }
/* A touch of movement so the pencil feels like a control, not a label. */
.followup-chip .fu-edit:hover svg { transform: rotate(-8deg) scale(1.06); }
.followup-chip .fu-edit:active svg { transform: rotate(-8deg) scale(0.94); }

/* Respect a reduced-motion preference: still reveal and still show every hover
   state, just without the travel. */
/* Hover is colour-only now, so only the entry reveal and the pencil's nudge need
   suppressing here. */
@media (prefers-reduced-motion: reduce) {
  .followup-chip { animation-duration: 1ms; }
  .followup-chip .fu-edit:hover svg,
  .followup-chip .fu-edit:active svg { transform: none; }
  .composer-suggestions.just-arrived::before { animation: none; }
}

/* Inline free-text note, revealed under the bar once a rating is picked. The
   parent .assistant-block is a flex column with its own row-gap, so this needs
   no top margin — the internal gap matches that spacing above and below. */
.fb-note {
  display: flex;
  flex-direction: column;
  gap: 8px;
  opacity: 0;
  animation: work-in 0.3s ease forwards;
}
/* Author `display: flex` above beats the UA `[hidden]{display:none}`, so the
   hidden attribute must be re-asserted explicitly or the box always shows. */
.fb-note[hidden] { display: none; }
.fb-note .fb-note-input {
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
  padding: 7px 9px;
  border: 1px solid var(--rule);
  background: var(--paper-2);
  color: var(--ink);
  font-family: inherit;
  font-size: 13px;
  line-height: 1.4;
  border-radius: 0;
}
.fb-note .fb-note-input:focus {
  outline: none;
  border-color: var(--signal);
}
.fb-note .fb-note-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.fb-note .fb-note-send {
  border: 1px solid var(--rule);
  background: var(--paper-2);
  color: var(--ink);
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 4px 12px;
  cursor: pointer;
  border-radius: 0;
  transition: color 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}
.fb-note .fb-note-send:hover { color: var(--signal); border-color: var(--signal); }
.fb-note .fb-note-status {
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Send button becomes a Stop button while a request is in flight. */
#send-btn.stop { background: var(--signal); }
#send-btn.stop:hover { filter: brightness(0.92); }

/* "Stopped" note shown when the user cancels mid-stream. */
.stopped-note {
  margin-top: 12px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 11px 6px 9px;
  border: 1px solid var(--rule);
  border-left: 2px solid var(--muted);
  background: var(--paper-2);
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
/* A small stop square so the note reads as a status, not stray text. */
.stopped-note::before {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  background: var(--muted);
}

/* ---------- assistant markdown rendering ---------- */
.msg-assistant {
  color: var(--ink);
  font-size: 15.5px;
  line-height: 1.62;
  /* Declared on the BASE (not only on .thinking) so the graduation — when
     .thinking is removed — animates too. A transition fires using the rule on
     the element's target state; without it here the color/indent snapped back
     instantly and the text jumped left. */
  transition: color 0.18s ease, padding-left 0.18s ease;
}
.msg-assistant > *:first-child { margin-top: 0; }
.msg-assistant > *:last-child { margin-bottom: 0; }

.msg-assistant h1,
.msg-assistant h2,
.msg-assistant h3 {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 24px 0 10px;
  line-height: 1.15;
}
.msg-assistant h1 { font-size: 26px; }
.msg-assistant h2 { font-size: 22px; }
.msg-assistant h3 { font-size: 18px; }
.msg-assistant p { margin: 10px 0; }
.msg-assistant strong { font-weight: 600; color: var(--ink); }
.msg-assistant em { font-style: italic; }

.msg-assistant ul, .msg-assistant ol {
  margin: 10px 0 10px 0;
  padding-left: 22px;
}
.msg-assistant li { margin: 4px 0; }
.msg-assistant li::marker { color: var(--signal); }

.msg-assistant code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--paper-3);
  padding: 1px 6px;
  border: 1px solid var(--rule);
  color: var(--ink);
}
.msg-assistant pre {
  background: var(--ink);
  color: var(--paper-2);
  padding: 14px 16px;
  font-family: var(--font-mono);
  font-size: 13px;
  overflow-x: auto;
  margin: 14px 0;
}
.msg-assistant pre code { background: transparent; border: 0; color: inherit; padding: 0; }

.msg-assistant table {
  /* `separate` (not `collapse`) so border-radius can clip the corners into a
     card — collapsed-border tables ignore radius. */
  border-collapse: separate;
  border-spacing: 0;
  margin: 16px 0;
  font-size: 13px;
  font-family: var(--font-body);
  font-variant-numeric: tabular-nums;   /* sans like ClickPost, but numerics still align */
  width: 100%;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
}
.msg-assistant thead th { background: var(--paper-2); }   /* soft shaded header, ClickPost-style */
.msg-assistant th {
  text-align: left;
  padding: 9px 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: 10.5px;
  color: var(--muted);
  border-bottom: 1px solid var(--rule-2);
}
.msg-assistant td {
  padding: 9px 11px;
  border-bottom: 1px solid var(--rule);   /* hairline solid row dividers */
  color: var(--ink);
}
.msg-assistant tbody tr:last-child td { border-bottom: 0; }
/* Honour markdown column alignment (marked.js emits align="..."). */
.msg-assistant th[align="right"],  .msg-assistant td[align="right"]  { text-align: right; }
.msg-assistant th[align="center"], .msg-assistant td[align="center"] { text-align: center; }
.msg-assistant th[align="left"],   .msg-assistant td[align="left"]   { text-align: left;  }
.msg-assistant tr:hover td { background: var(--paper-2); }
/* While the answer is still streaming, lock the table to fixed column widths so
   each newly revealed row doesn't make the browser recompute every column and
   re-wrap the whole table (the visible "jumping"). The completed table drops the
   `streaming` class and reverts to natural, content-sized columns. */
.msg-assistant.streaming table { table-layout: fixed; }
.msg-assistant.streaming th,
.msg-assistant.streaming td { overflow-wrap: anywhere; }

.msg-assistant blockquote {
  border-left: 3px solid var(--signal);
  padding-left: 14px;
  color: var(--muted);
  margin: 14px 0;
}

.msg-assistant a {
  color: var(--signal);
  text-decoration: none;
}
.msg-assistant a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---------- error banner ---------- */
.error-banner {
  background: var(--paper-2);
  border-left: 2px solid var(--bad);
  color: var(--bad);
  padding: 10px 14px;
  font-family: var(--font-label);
  font-size: 12px;
  margin: 8px 0;
}

/* Usage-limit banner: a neutral (not error-red) accent. */
.error-banner.limit-banner {
  border-left-color: var(--signal);
  color: var(--ink);
}
.limit-banner .limit-msg { margin-bottom: 10px; }

/* "Request more usage" CTA — shared by the limit banner and the /usage card. */
.limit-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.usage-card .limit-actions { margin-top: 16px; }
.limit-cta {
  border: 1px solid var(--signal);
  background: var(--signal);
  color: #fff;
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 6px 14px;
  cursor: pointer;
  border-radius: 0;
  transition: filter 0.12s ease;
}
.limit-cta:hover { filter: brightness(0.92); }
.limit-cta:disabled { opacity: 0.55; cursor: default; }
.limit-status {
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--muted);
}

/* ---------- exhausted-limit notice (sits on the composer) ----------
   Raised by chat.js when the caller's cap is already spent, so the limit is
   known before a question is typed rather than after (see the 429 banner above
   for the after-the-fact case). It shares the composer's own width and sits one
   line above the input: a strip, not a panel — the reader's workspace is the box
   below it. */
.limit-notice {
  position: relative;          /* anchors the ::after attention wash below */
  /* Makes the strip its own stacking context so the wash's `z-index: -1` stays
     inside it. Without this, a negative-z child escapes to the root context and
     paints *under* .composer-wrap's opaque background — i.e. invisibly. */
  isolation: isolate;
  max-width: 980px;
  margin: 0 auto 10px;
  display: flex;
  align-items: baseline;
  /* No column gap: the action follows the message by one word space, so the line
     reads as continuous prose rather than as two separate items. Row gap only
     matters once it wraps on a narrow screen. */
  column-gap: 0;
  row-gap: 4px;
  flex-wrap: wrap;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--muted);
}
.limit-notice[hidden] { display: none; }
/* A single dot is the whole "this is a state, not prose" signal — enough to be
   noticed on top of the composer without a panel's worth of chrome. */
.limit-notice::before {
  content: "";
  flex: 0 0 auto;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--bad);
  transform: translateY(-2px);
  margin-right: 7px;
}
/* While capped, every canned question is a dead end — tapping one only flashes
   this notice — so both places that offer them stand down: the chip rail above
   the box, and the starter cards in the empty state. The strip is then the only
   thing between the reader and the composer. (Follow-up chips are also dropped
   in JS, see showFollowups — hiding them here alone would let them flicker in
   first.) */
.main.is-limited .composer-suggestions,
.main.is-limited .empty-state .suggestion-grid { display: none; }
/* The reason keeps its natural width so the action follows straight after it
   rather than drifting to the far edge of the composer. */
.limit-notice-msg {
  flex: 0 1 auto;
  min-width: 0;
  color: var(--ink-2);
}
/* The action reads as text, not chrome: at this size a filled button would
   outweigh the composer it sits on. No underline — colour and cursor carry the
   affordance, and an underline on a 11.5px line next to the input reads as
   noise. */
.limit-notice .limit-cta {
  flex: 0 0 auto;
  border: 0;
  background: transparent;
  padding: 0;
  font-size: 11.5px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--signal);
  cursor: pointer;
  text-decoration: none;
  transition: color 0.12s ease;
}
.limit-notice .limit-cta:hover { filter: none; color: var(--signal-deep); }
.limit-notice .limit-cta:disabled { opacity: 0.55; cursor: default; }
/* One word space after the message's full stop — not the container's gap, which
   would also push the dot away from the text. The inner gap only shows while the
   button and its "Sending…" status are both present. */
.limit-notice .limit-actions { flex: 0 0 auto; gap: 5px; margin-left: 4px; }
.limit-notice .limit-status { font-size: 11.5px; }

/* Re-assert the notice when a capped reader sends anyway (see flashLimitNotice).
   One pass: a soft highlight behind the line holds for a moment, then settles
   out. Flipping the text red twice was a literal <blink> — this says "this,
   again" without shouting. The wash is a pseudo-element inset *behind* the text
   (z-index -1, no background on the strip itself) so nothing reflows and the
   line stays aligned with the input below. */
@keyframes limit-wash {
  0%   { opacity: 1; }
  35%  { opacity: 1; }
  100% { opacity: 0; }
}
.limit-notice::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -5px -10px;
  border-radius: var(--radius);
  background: rgba(185, 28, 28, 0.11);   /* --bad, barely there */
  opacity: 0;
  pointer-events: none;
}
.limit-notice.nudge::after { animation: limit-wash 0.75s ease-out; }
@media (prefers-reduced-motion: reduce) {
  .limit-notice.nudge::after { animation: none; }
}

/* ---------- composer ---------- */
.composer-wrap {
  border-top: 1px solid var(--rule);
  background: var(--paper);
  padding: 20px 56px 32px;   /* more room beneath the send button so it isn't jammed to the edge */
}
@media (max-width: 720px) { .composer-wrap { padding: 16px 24px 24px; } }

.composer {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: end;
  gap: 18px;
  max-width: 980px;
  margin: 0 auto;
  position: relative;
}

/* Capped: the textarea deliberately stays usable (slash commands are free), so
   only Send is visibly stood down. */
.main.is-limited #send-btn { opacity: 0.45; }
.main.is-limited #input { border-bottom-color: var(--rule-2); }

/* ---------- slash-command palette ---------- */
.slash-menu {
  position: absolute;
  left: 0;
  bottom: calc(100% + 10px);
  width: min(380px, 100%);
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  overflow: hidden;
  z-index: 20;
  display: flex;
  flex-direction: column;
}
/* `display: flex` above would otherwise override the `hidden` attribute's
   UA `display: none`, leaving the empty menu visible as a stray ink bar. */
.slash-menu[hidden] { display: none; }
.slash-item {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 9px 14px;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule);
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
}
.slash-item:last-child { border-bottom: 0; }
.slash-item.active,
.slash-item:hover { background: var(--paper-2); }
.slash-item .slash-name {
  font-family: var(--font-label);
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--ink);
}
.slash-item.active .slash-name { color: var(--signal); }
.slash-item .slash-desc {
  font-size: 12px;
  color: var(--muted);
}

#input {
  width: 100%;
  resize: none;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--ink);
  border-radius: 0;
  padding: 10px 0 12px;
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink);
  outline: none;
  min-height: 44px;
  max-height: 200px;
}
#input::placeholder { color: var(--muted-2); }
#input:focus { border-bottom-color: var(--signal); }

#send-btn {
  background: var(--signal);
  color: var(--paper);
  border: 0;
  padding: 14px 22px;
  font-family: var(--font-label);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  font-weight: 700;
  cursor: pointer;
  border-radius: var(--radius);
  display: inline-flex;
  align-items: center;
  gap: 12px;
  white-space: nowrap;
  transition: background 100ms ease;
}
#send-btn:hover { background: var(--signal-deep); }
#send-btn:disabled { background: var(--muted-2); cursor: wait; }
#send-btn .glyph {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 16px;
  letter-spacing: 0;
}
/* The Send button no longer animates while sending — the single working
   indicator (with rotating logistics words) is the only in-flight animation. */

/* ---------- subtle reveal on first render ---------- */
.app, .login-shell { animation: pageIn 380ms ease both; }
@keyframes pageIn {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ============================ SCHEDULE PAGE ============================ */
/* The chat layout locks html/body overflow so its inner panes scroll.
   The schedule page is a normal scrolling document — undo that. */
html:has(.schedule-shell),
body:has(.schedule-shell) {
  overflow: auto;
  height: auto;
}
.schedule-shell {
  position: relative;
  min-height: 100vh;
  /* No animation here on purpose — pageIn uses transform, which would make
     this element a containing block for descendants and break the rail's
     position: fixed (it would pin to .schedule-shell instead of the viewport). */
}
.schedule-shell .rail {
  position: fixed;
  left: 0;
  top: 0;
  width: var(--rail);
  height: 100vh;
  z-index: 1;
}
.schedule-main {
  /* Center the content column within the area to the RIGHT of the fixed rail
     (not the full viewport): left margin = rail + half the leftover space, so
     the column sits centered in the remaining width and never under the rail. */
  margin-left: calc(var(--rail) + max(0px, (100vw - var(--rail) - 820px) / 2));
  margin-right: auto;
  padding: 24px 56px 80px 56px;
  max-width: 820px;
  /* Override .main's flex/overflow:hidden so this page scrolls naturally. */
  display: block;
  overflow: visible;
  height: auto;
  min-height: 100vh;
}
.schedule-main .main-head {
  margin-bottom: 28px;
  /* .schedule-main already pads 56px on each side, so zero the base
     .main-head horizontal padding to keep the heading aligned with the
     topnav and cards (no double indent), and tighten the top gap. */
  padding: 0 0 18px 0;
}
.rail-title {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 400;          /* match the portal's display headings (was bold h2 700) */
  letter-spacing: -0.01em;
  line-height: 1.15;
  margin: 6px 0 10px 0;
  color: var(--ink);
}
.schedule-card {
  background: rgba(255,255,255,0.55);
  border: 1px solid rgba(12,23,56,0.12);
  padding: 22px 26px;
  margin-bottom: 22px;
}
.schedule-card .eyebrow {
  font-family: var(--font-display, Georgia, serif);
  font-size: 11.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(12,23,56,0.65);
  margin: 0 0 14px 0;
}
.schedule-form .field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 16px;
}
/* `display: flex` above beats the UA [hidden] rule, so re-assert it: a field
   toggled off by the frequency selector (sets the hidden attribute) must hide. */
.schedule-form .field[hidden] { display: none; }
.schedule-form label {
  font-size: 12.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(12,23,56,0.7);
}
.hint-inline {
  text-transform: none;
  letter-spacing: 0;
  font-style: normal;
  color: rgba(12,23,56,0.45);
}
.schedule-form input[type="email"],
.schedule-form select,
.schedule-form textarea {
  font: inherit;
  font-size: 14.5px;
  padding: 10px 12px;
  background: #fdfbf5;
  border: 1px solid rgba(12,23,56,0.18);
  border-radius: var(--radius);
  color: var(--ink, #0c1738);
}
/* Custom dropdown chevron — the native arrow ignores padding-right and jams to
   the edge, so draw our own and reserve room for it. */
.schedule-form select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%2356688f' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}
.schedule-form textarea {
  resize: vertical;
  min-height: 96px;
}
.schedule-form .hint {
  font-size: 12px;
  color: rgba(12,23,56,0.55);
  margin: 4px 0 0 0;
}
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

/* Multi-select "chips" for the guided focus question. (Distinct from the chat
   `.chip` class — named `focus-chip` to avoid that collision.) */
.focus-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.focus-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border: 1px solid rgba(12,23,56,0.18);
  border-radius: 999px;
  background: rgba(255,255,255,0.6);
  font-size: 13px;
  color: var(--ink);
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
  user-select: none;
}
.focus-chip:hover { border-color: rgba(31,59,209,0.45); }
.focus-chip input { margin: 0; accent-color: var(--signal, #1f3bd1); }
/* Tint a chip when its checkbox is checked (modern browsers). */
.focus-chip:has(input:checked) {
  border-color: var(--signal, #1f3bd1);
  background: rgba(31,59,209,0.08);
}

/* Inline text button used for the "skip" / "back" affordances. */
.link-btn {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--signal, #1f3bd1);
  text-decoration: none;
  cursor: pointer;
}
.link-btn:hover { text-decoration: underline; text-underline-offset: 3px; }

/* Consistent "(optional)" tag (used on the Tailor-the-digest heading). */
.optional-tag {
  text-transform: none;
  letter-spacing: 0;
  font-style: normal;
  font-weight: 400;
  color: rgba(12,23,56,0.45);
}
.optional-tag::before { content: "("; }
.optional-tag::after { content: ")"; }

/* Guided "tailor the digest" carousel — one question per slide. */
.tailor-carousel {
  border: 1px solid rgba(12,23,56,0.12);
  border-radius: 8px;
  padding: 16px;
  background: rgba(255,255,255,0.45);
  margin-bottom: 16px;
}
.tailor-slide {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.tailor-slide[hidden] { display: none; }   /* beat the UA/author display rules */
.tailor-dots {
  display: flex;
  gap: 6px;
  margin-bottom: 14px;
}
.tailor-dots [data-dot] {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(12,23,56,0.18);
  transition: background 120ms ease;
}
.tailor-dots [data-dot].is-active { background: var(--signal, #1f3bd1); }
.tailor-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 6px;
}
.tailor-nav-right {
  display: inline-flex;
  align-items: center;
  gap: 14px;
}
/* Cohesive button set for the carousel nav: primary Next, ghost Back, muted Skip. */
.btn-step {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border-radius: 6px;
  padding: 8px 16px;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
/* Primary (Next) */
.btn-step {
  background: var(--signal, #1f3bd1);
  color: #fff;
}
.btn-step:hover { filter: brightness(1.06); }
/* Ghost (Back) */
.btn-step.ghost {
  background: transparent;
  color: rgba(12,23,56,0.75);
  border-color: rgba(12,23,56,0.2);
  filter: none;
}
.btn-step.ghost:hover {
  border-color: rgba(31,59,209,0.5);
  background: rgba(31,59,209,0.05);
  color: var(--ink);
}
/* Muted (Skip) */
.btn-step.muted {
  background: transparent;
  color: rgba(12,23,56,0.5);
  filter: none;
}
.btn-step.muted:hover { color: var(--ink); background: rgba(12,23,56,0.05); }
.subscription-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.subscription-item {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  padding: 14px 0;
  border-bottom: 1px dashed rgba(12,23,56,0.12);
}
.subscription-item:last-child { border-bottom: none; }
.sub-meta { flex: 1; }
.sub-line { font-size: 14px; line-height: 1.45; color: rgba(12,23,56,0.85); }
.sub-when { color: rgba(31,59,209,0.95); font-weight: 500; }
.sub-notes { color: rgba(12,23,56,0.6); margin-top: 4px; }
.sub-meta-small { font-size: 12px; color: rgba(12,23,56,0.5); margin-top: 4px; }
.sub-meta-small .err { color: #b3261e; }
.sub-actions { display: flex; gap: 8px; flex-shrink: 0; align-items: center; }
.btn-ghost.danger { color: #b3261e; }
.sub-actions button[disabled] { opacity: 0.55; cursor: progress; }

/* Inline spinner inside the Send-test button. Hidden by default; revealed
   by the .is-loading class added on submit. */
.sub-actions .spinner {
  display: none;
  width: 12px;
  height: 12px;
  margin-left: 8px;
  vertical-align: middle;
  border: 2px solid rgba(31, 59, 209, 0.25);
  border-top-color: #1f3bd1;
  border-radius: 50%;
  animation: schedule-spin 0.7s linear infinite;
}
.sub-actions button.is-loading .spinner { display: inline-block; }
.sub-actions button.is-loading .btn-label { color: rgba(12, 23, 56, 0.6); }
@keyframes schedule-spin {
  to { transform: rotate(360deg); }
}

/* Full-page busy overlay shown while the test send is running. */
.busy-overlay {
  position: fixed;
  inset: 0;
  background: rgba(244, 241, 234, 0.78);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
  animation: fadeIn 160ms ease both;
}
.busy-overlay[hidden] { display: none; }
.busy-card {
  display: flex;
  align-items: center;
  gap: 18px;
  background: #fdfbf5;
  border: 1px solid rgba(12, 23, 56, 0.18);
  padding: 22px 28px;
  max-width: 460px;
  box-shadow: 0 18px 60px rgba(12, 23, 56, 0.18);
}
.busy-spinner {
  width: 28px;
  height: 28px;
  border: 3px solid rgba(31, 59, 209, 0.18);
  border-top-color: #1f3bd1;
  border-radius: 50%;
  animation: schedule-spin 0.8s linear infinite;
  flex-shrink: 0;
}
.busy-title {
  font-family: var(--font-display, Georgia, serif);
  font-size: 16px;
  color: var(--ink, #0c1738);
  margin-bottom: 4px;
}
.busy-sub {
  font-size: 12.5px;
  color: rgba(12, 23, 56, 0.6);
  line-height: 1.45;
}
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
.flash {
  padding: 10px 14px;
  margin-bottom: 18px;
  font-size: 13.5px;
  border-left: 3px solid #1f3bd1;
  background: rgba(31,59,209,0.06);
}
.flash-err {
  border-left-color: #b3261e;
  background: rgba(179,38,30,0.08);
  color: #7a1f17;
}
@media (max-width: 720px) {
  .schedule-shell .rail {
    position: static;
    width: 100%;
    height: auto;
    border-right: 0;
    border-bottom: 1px solid var(--rule);
  }
  .schedule-main {
    margin-left: 0;
    padding: 28px 22px 60px 22px;
  }
  .field-row { grid-template-columns: 1fr; }
}
