/* ============================================================
   40 — AI FINANCIAL ASSISTANT
   A chat surface that reads like a report: user turns in a tinted
   bubble, assistant turns as plain prose with a receipt of the
   figures used. Tokens only.

   Width: the panel IS the measure. Prose, receipt hairlines, chips
   and composer all terminate on the same edge — no inner column.
   ============================================================ */

.assistant {
  padding-block: var(--section-y) var(--s-13);
  background: var(--surface-alt);
  border-top: 1px solid var(--c-hairline-soft);
}

/* ---------------- intro ---------------- */

.assistant__intro {
  max-width: 62ch;
  margin-bottom: var(--s-9);
}
.assistant__eyebrow { margin-bottom: var(--s-3); }
.assistant__title { margin-bottom: var(--s-4); }

/* ---------------- panel ---------------- */

.assistant__panel {
  display: flex;
  flex-direction: column;
  max-width: 46rem;
  background: var(--surface);
  border: 1px solid var(--c-hairline);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-sm);
  overflow: hidden;
}

/* Below the two-column threshold the panel IS the measure, so the block
   centres on it. Without this the section inherits the 1240px container
   and, at any width between the panel's 46rem and the 1080px breakpoint
   — 1024px most obviously — the panel sits left in a field of empty
   background. Centred, the margin reads as margin. The cap includes the
   container's own gutters, so the panel still measures a full 46rem. */
@media (max-width: 1079.98px) {
  .assistant__grid { max-width: calc(46rem + var(--gutter) * 2); }
}

/* Wide viewports: the intro becomes the left column and the panel the
   right, so the wide container holds two things instead of one column
   and a field of empty background. */
@media (min-width: 1080px) {
  .assistant__grid {
    display: grid;
    grid-template-columns: minmax(17rem, 22rem) minmax(0, 46rem);
    gap: var(--s-10);
    align-items: start;
    justify-content: space-between;
  }
  .assistant__intro {
    margin-bottom: 0;
    position: sticky;
    top: var(--s-11);
  }
}

/* ---------------- bar ---------------- */

.assistant__bar {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--c-hairline-soft);
  background: linear-gradient(180deg, color-mix(in srgb, var(--c-offwhite) 88%, transparent), transparent);
}

.assistant__mark {
  display: grid;
  place-items: center;
  width: var(--s-7);
  height: var(--s-7);
  flex: none;
  border-radius: var(--r-md);
  color: var(--c-brand);
  background: var(--c-brand-tint);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-brand) 16%, transparent);
}
.assistant__mark svg { width: 20px; height: 20px; }

/* A real heading, so the transcript is a landmark a screen reader can
   jump to — sized down to bar type, not to the h3 scale. */
.assistant__name {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
  line-height: var(--lh-normal);
  letter-spacing: var(--tracking-snug);
  color: var(--text-strong);
  /* The name yields before the bar wraps: one row at every width. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.assistant__status {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  flex: none;
  height: var(--s-6);
  padding-inline: var(--s-3);
  border-radius: var(--r-pill);
  border: 1px solid var(--c-hairline);
  background: var(--surface);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--text-body);
  white-space: nowrap;
  transition: border-color var(--t-fast) var(--ease-out),
              background var(--t-fast) var(--ease-out);
}
.assistant__status:hover {
  background: var(--surface-alt);
  border-color: var(--c-slate-light);
}
.assistant__status-dot {
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--c-slate-light);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-slate-light) 18%, transparent);
}
/* Deepened until the live dot clears 3:1 on the pill (3.46:1 at 55%);
   the slate dot is 4.26:1, so both states read at the same strength. */
.assistant__status[data-mode="ollama"] .assistant__status-dot {
  background: color-mix(in srgb, var(--c-lime) 55%, var(--c-navy));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-lime) 32%, transparent);
}

/* The disclosure the pill opens. Visible text, not a tooltip. */
.assistant__mode-note {
  padding: var(--s-3) var(--s-5);
  border-bottom: 1px solid var(--c-hairline-soft);
  background: var(--surface-alt);
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  color: var(--text-body);
}
.assistant__mode-note[hidden] { display: none; }

/* ---------------- transcript ----------------
   Sizes to its content and only then scrolls, so the panel is never
   half-empty on first load. */

.assistant__transcript {
  flex: 0 1 auto;
  min-height: 0;
  max-height: clamp(16rem, 52vh, 34rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--c-hairline) transparent;
  padding: var(--s-6) var(--s-5);
  display: flex;
  flex-direction: column;
  gap: var(--s-7);
  /* alpha ramp only — softens the hard clip where content meets the bar */
  -webkit-mask-image: linear-gradient(180deg, transparent 0, black var(--s-5), black 100%);
  mask-image: linear-gradient(180deg, transparent 0, black var(--s-5), black 100%);
}
.assistant__transcript::-webkit-scrollbar { width: 10px; }
.assistant__transcript::-webkit-scrollbar-thumb {
  background: var(--c-hairline);
  border-radius: var(--r-pill);
  border: 3px solid var(--surface);
}
.assistant__transcript:focus-visible { outline-offset: -3px; }

/* ---------------- turns ---------------- */

.assistant__turn { animation: assistant-in var(--t-slow) var(--ease-out) both; }

@keyframes assistant-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

.assistant__turn--user {
  display: flex;
  justify-content: flex-end;
  padding-left: var(--s-8);
}

.assistant__bubble {
  max-width: 40ch;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-lg) var(--r-lg) var(--r-xs) var(--r-lg);
  background: var(--c-brand-tint);
  color: var(--c-navy);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-brand) 12%, transparent);
}

.assistant__prose { color: var(--text-body); }
.assistant__p {
  font-size: var(--fs-sm);
  line-height: var(--lh-relaxed);
}
.assistant__p + .assistant__p { margin-top: var(--s-4); }

/* ---------------- receipt ---------------- */

.assistant__receipt {
  margin: var(--s-5) 0 0;
  border-top: 1px solid var(--c-hairline);
}
.assistant__fact {
  display: flex;
  align-items: baseline;
  gap: var(--s-4);
  padding-block: var(--s-2);
  border-bottom: 1px solid var(--c-hairline-soft);
}
.assistant__fact-label {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  /* the receipt is the trust surface — it gets body contrast, not muted */
  color: var(--text-body);
}
.assistant__fact-value {
  margin: 0;
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  color: var(--text-strong);
  text-align: right;
}

/* ---------------- follow-ups ---------------- */

.assistant__followups {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-top: var(--s-4);
}
.assistant__followup {
  padding: var(--s-1) var(--s-3);
  border-radius: var(--r-pill);
  border: 1px solid var(--c-hairline);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--c-brand);
  transition: background var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out);
}
/* Brand ink on the brand tint is 4.1:1 at 13px — under AA. The pressed
   brand tone clears it on the same fill. */
.assistant__followup:hover {
  background: var(--c-brand-tint);
  border-color: color-mix(in srgb, var(--c-brand) 30%, transparent);
  color: var(--c-brand-press);
}

/* ---------------- thinking ---------------- */

.assistant__turn.is-thinking {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  color: var(--text-body);
  font-size: var(--fs-xs);
}
.assistant__dots { display: inline-flex; gap: var(--s-1); }
.assistant__dots i {
  width: 5px;
  height: 5px;
  border-radius: var(--r-pill);
  background: var(--c-slate-light);
  animation: assistant-pulse 1.15s var(--ease-inout) infinite;
}
.assistant__dots i:nth-child(2) { animation-delay: .16s; }
.assistant__dots i:nth-child(3) { animation-delay: .32s; }

@keyframes assistant-pulse {
  0%, 100% { opacity: .28; transform: translateY(0); }
  40%      { opacity: 1;   transform: translateY(-2px); }
}

/* The dots are the visual state; this is the spoken one. It stays in
   the accessibility tree at all times — visually hidden by default,
   shown as static text when motion is reduced. */
.assistant__thinking-text {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------------- chips ---------------- */

.assistant__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  padding: var(--s-4) var(--s-5) 0;
}

.assistant__chip {
  flex: 0 1 auto;
  min-width: 0;
  min-height: var(--s-8);
  padding: var(--s-2) var(--s-4);
  border-radius: var(--r-pill);
  border: 1px solid var(--c-hairline);
  background: var(--surface);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--text-body);
  text-align: left;
  transition: background var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.assistant__chip:hover {
  background: var(--c-brand-tint);
  border-color: color-mix(in srgb, var(--c-brand) 28%, transparent);
  color: var(--c-brand-press);
  transform: translateY(-1px);
}
.assistant__chip:active { transform: translateY(0); }

/* ---------------- composer ---------------- */

.assistant__composer {
  display: flex;
  align-items: flex-end;
  gap: var(--s-3);
  margin: var(--s-4) var(--s-5) 0;
  padding: var(--s-2) var(--s-2) var(--s-2) var(--s-4);
  border: 1px solid var(--c-hairline);
  border-radius: var(--r-lg);
  background: var(--surface);
  transition: border-color var(--t-fast) var(--ease-out),
              box-shadow var(--t-fast) var(--ease-out);
}
.assistant__composer:focus-within {
  border-color: color-mix(in srgb, var(--c-brand) 45%, transparent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-brand) 12%, transparent);
}

/* max-height is the single source for the textarea cap — the script
   reads it back rather than repeating the number. */
.assistant__input {
  flex: 1 1 auto;
  min-width: 0;
  height: var(--s-8);
  max-height: var(--s-13);
  padding-block: var(--s-2);
  border: 0;
  background: none;
  outline: none;
  resize: none;
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--text-strong);
  scrollbar-width: thin;
}
.assistant__input::placeholder { color: var(--text-body); }

.assistant__send {
  display: grid;
  place-items: center;
  width: var(--s-8);
  height: var(--s-8);
  flex: none;
  border-radius: var(--r-md);
  background: var(--c-brand);
  color: var(--c-white);
  transition: background var(--t-fast) var(--ease-out),
              opacity var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.assistant__send svg { width: 18px; height: 18px; }
.assistant__send:hover:not(:disabled) { background: var(--c-brand-hover); transform: translateY(-1px); }
.assistant__send:active:not(:disabled) { background: var(--c-brand-press); transform: none; }
.assistant__send:disabled {
  background: var(--c-hairline-soft);
  color: var(--text-body);
  cursor: not-allowed;
}

/* ---------------- note ---------------- */

.assistant__note {
  padding: var(--s-4) var(--s-5) var(--s-5);
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  color: var(--text-body);
}
.assistant__note code {
  font-size: var(--fs-xs);
  color: var(--text-strong);
}

/* ---------------- narrow ---------------- */

@media (max-width: 720px) {
  .assistant { padding-block: var(--s-10) var(--s-11); }
  .assistant__panel { border-radius: var(--r-lg); }
  .assistant__bar,
  .assistant__transcript { padding-inline: var(--s-4); }
  /* The bar carries three fixed-width things and no room to spare. Tighten
     its own chrome — gaps and the pill's padding — so "Pyncht Assistant"
     and "Analysis engine" both print in full instead of one ellipsising.
     Type sizes and the padding that aligns the bar with the transcript
     below it are untouched. */
  .assistant__bar { gap: var(--s-2); }
  .assistant__status { gap: var(--s-1); padding-inline: var(--s-2); }
}

/* Below 400px the bar is still 7px short of holding both strings. The mark
   is the only thing there carrying no information — it is aria-hidden
   ornament — so it goes rather than the product name getting ellipsised. */
@media (max-width: 400px) {
  .assistant__mark { display: none; }
  .assistant__note,
  .assistant__mode-note { padding-inline: var(--s-4); }
  .assistant__composer { margin-inline: var(--s-4); }
  .assistant__turn--user { padding-left: var(--s-5); }
  .assistant__bubble { max-width: 100%; }
  .assistant__fact { gap: var(--s-3); }

  /* Wrapped, these four questions take two rows here and three below
     440px, pushing the composer under the fold on a phone. One
     horizontally scrolling row keeps the input on screen.
     overflow-x forces overflow-y to compute to auto, which would clip
     the focus ring off the bottom edge of a chip — the padding below
     is that ring (2px outline at 3px offset), not decoration.

     The scrollbar is hidden, so the fade IS the affordance: without it
     the fourth chip is simply invisible with nothing saying it exists.
     The trailing padding is the fade's own lane, so at the end of the
     scroll the last chip sits clear of it and reads at full strength. */
  .assistant__chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    padding-inline: var(--s-4) var(--s-7);
    padding-bottom: var(--s-2);
    scroll-padding-inline: var(--s-4) var(--s-7);
    -webkit-mask-image: linear-gradient(90deg, black calc(100% - var(--s-6)), transparent 100%);
    mask-image: linear-gradient(90deg, black calc(100% - var(--s-6)), transparent 100%);
  }
  .assistant__chips::-webkit-scrollbar { display: none; }
  .assistant__chip {
    flex: 0 0 auto;
    white-space: nowrap;
  }
  /* …and taken back off the composer, so the rhythm is unchanged. */
  .assistant__composer { margin-top: var(--s-2); }
}

/* ---------------- touch targets ----------------
   Sizes above are tuned for a pointer. On touch the same controls
   need 44px of finger, so grow the box without changing the type. */

@media (pointer: coarse) {
  .assistant__chip,
  .assistant__followup { min-height: 44px; }
  .assistant__send { width: 44px; height: 44px; }
  /* The pill is a real button now, so it takes a real finger. */
  .assistant__status { height: 44px; }
  .assistant__bar { padding-block: var(--s-2); }
  /* The textarea is the primary control on the panel and was the one
     thing left at 40px. min-height, not height: the autosize script sets
     an inline height from scrollHeight, and min-height outranks it. */
  .assistant__input { min-height: 44px; }
}

/* ---------------- reduced motion ---------------- */

@media (prefers-reduced-motion: reduce) {
  .assistant__turn { animation: none; }
  .assistant__dots { display: none; }
  .assistant__thinking-text {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip-path: none;
  }
}
