/* Growing with OCBC — one light, calm look. No framework, no webfont: every
   byte here is served from this repo. */

:root {
  --bg: #f4f6f8;
  --surface: #ffffff;
  --line: #e2e6ea;
  --ink: #1b1f24;
  --ink-soft: #5b6570;
  --brand: #d8232a;
  --accent: #4a5560; /* replaced per persona once a chat opens */
  --radius: 12px;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
}

/* --- masthead ----------------------------------------------------------- */

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  padding: 18px 28px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.masthead-titles {
  flex: 1 1 auto;
  min-width: 0;
}

.masthead-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.masthead-status {
  font-size: 13px;
  white-space: nowrap;
}

.masthead-status.error {
  color: var(--brand);
}

@media (max-width: 600px) {
  .masthead {
    padding: 14px 16px;
    gap: 12px;
  }

  .masthead-titles {
    flex-basis: 100%;
  }

  .masthead-actions {
    width: 100%;
    justify-content: flex-start;
  }
}

.wordmark {
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--brand);
  border: 2px solid var(--brand);
  border-radius: 6px;
  padding: 4px 8px;
  font-size: 15px;
}

.masthead h1 {
  margin: 0;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.masthead-sub {
  margin: 2px 0 0;
  font-size: 14px;
  color: var(--ink-soft);
}

main {
  flex: 1;
  min-height: 0;
  display: flex;
  justify-content: center;
  padding: 32px 24px;
}

main > section {
  width: 100%;
  max-width: 860px;
  min-height: 0;
}

/* --- persona cards ------------------------------------------------------ */

.section-title {
  margin: 0 0 20px;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink-soft);
  letter-spacing: 0.02em;
}

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 18px;
}

.card {
  appearance: none;
  text-align: left;
  font: inherit;
  color: inherit;
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 3px solid var(--card-accent, var(--accent));
  border-radius: var(--radius);
  padding: 22px 20px 24px;
  cursor: pointer;
  transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease;
}

.card:hover,
.card:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(27, 31, 36, 0.08);
  outline: none;
  border-color: var(--card-accent, var(--accent));
  border-top-color: var(--card-accent, var(--accent));
}

.card-initial {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--card-accent, var(--accent));
  color: #fff;
  font-weight: 600;
  font-size: 18px;
  margin-bottom: 14px;
}

.card-name {
  font-size: 18px;
  font-weight: 600;
  margin: 0 0 6px;
}

.card-tagline {
  margin: 0 0 18px;
  font-size: 14px;
  color: var(--ink-soft);
}

.card-cta {
  font-size: 13px;
  font-weight: 600;
  color: var(--card-accent, var(--accent));
}

.status {
  margin: 18px 2px 0;
  font-size: 14px;
  color: var(--ink-soft);
}

.status[hidden] { display: none; }

/* --- chat --------------------------------------------------------------- */

#chat {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

#chat[hidden] { display: none; }

.chat-bar {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  border-top: 3px solid var(--accent);
}

.who {
  flex: 1;
  min-width: 0;
}

/* Both lines truncate. The tagline always did; the name did not, and as an
   inline element inside a `.who` that flexes to zero it was drawn straight over
   the controls beside it — visible in a browser at 375px, invisible to every
   harness this project has had until now. */
.who strong {
  display: block;
  font-size: 15px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.who span {
  display: block;
  font-size: 13px;
  color: var(--ink-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The cluster gives way, but only through the chip. It was `flex: none`, which
   is `0 0 auto` — it could not shrink at all, so a chip as wide as whatever
   `UPSTREAM_MODEL` happened to say had nowhere to go but through the panel
   edge, at any viewport width. See the model chip below. */
.tools {
  display: flex;
  align-items: center;
  gap: 14px;
  flex: 0 1 auto;
  min-width: 0;
}

/* The three controls keep their size. Trading a clipped id for a wrapped
   "New chat" would be a bad bargain: a clipped id is still readable and still
   recoverable, and a two-line button is just broken. */
.tools > :not(.chip) { flex: none; }

.toggle {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  color: var(--ink-soft);
  cursor: pointer;
  user-select: none;
}

.toggle input { accent-color: var(--accent); margin: 0; }

.link-button,
.ghost-button {
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  border-radius: 8px;
  background: none;
}

.link-button {
  border: none;
  padding: 4px 2px;
  color: var(--ink-soft);
  /* The chat bar's other unpinned item. Left shrinkable it would absorb its
     share of a long model id and wrap "← Personas" — the one control on this
     screen a viewer who is lost actually needs. */
  flex: none;
}

.link-button::before { content: "\2190\00a0"; }

.ghost-button {
  border: 1px solid var(--line);
  padding: 6px 12px;
  color: var(--ink);
}

.link-button:hover { color: var(--ink); }

/* `:not(:disabled)` because of the download control (phase 0021), which is
   disabled until a record has landed. Without it the one ghost button on this
   page that can be unavailable would still light up in `--accent` under the
   cursor — a control announcing itself as pressable and then refusing. */
.ghost-button:not(:disabled):hover { border-color: var(--accent); color: var(--accent); }

/* The page already decided what unavailable looks like, at `.composer
   button:disabled`. Copied rather than re-invented: DESIGN.md's Spacing section
   says to take the nearest neighbour, and this is a page with no scale to
   consult. */
.ghost-button:disabled {
  opacity: 0.45;
  cursor: default;
}

/* --- the model chip (phase 0019) ----------------------------------------- */
/* A readout, not a control — so it deliberately does **not** wear
   `.ghost-button`, which DESIGN.md offers as the default clothes for a new
   chat-bar control. A bordered pill sitting between two bordered buttons reads
   as a third button that does not respond, and the only thing on this page it
   could be mistaken for pressing is a model switcher, which does not exist.

   It wears the `.toggle`'s clothes instead: 13px, `--ink-soft`, the same 7px
   internal gap. That is the cluster's established borderless idiom, it adds no
   token and no colour, and it is the narrowest of the three shapes available —
   which matters, because the bar is already tight (see the responsive note at
   the foot of this file). `--ink` and 600 on the qualifier because it is a
   label, and because it is the word that has to be read first. */

/* It is a flex row of its own so the id can be clipped without the qualifier
   being clipped with it. `min-width: 0` is the load-bearing declaration: a flex
   item will not shrink below its content without it, and every rule under it
   would be inert. The chip is the only thing in the bar allowed to give way,
   because it is the only thing whose width `.env` decides — the panel measured
   a 68-character id at 512px and 96px of overflow at 1440, which is a projector
   width, not a phone one. */
.chip {
  display: flex;
  align-items: center;
  /* An explicit `min-width` is what lets a flex item shrink at all — the
     default is `auto`, which is the item's own content and is why the chip
     pushed instead of giving way. A **length** rather than `0` because the two
     halves of that are separate requirements: the chip must be able to shrink
     (criterion 8) and it must never be the thing that disappears (criterion 9),
     and `0` satisfies the first by failing the second — measured at 375px, the
     chip collapsed to nothing. `6rem` is `.figure`'s own floor for a column
     that has to stay readable, which is the nearest neighbour this page has. */
  min-width: 6rem;
  font-size: 13px;
  color: var(--ink-soft);
  white-space: nowrap;
}

.chip[hidden] { display: none; }

/* 7px, the toggle's own internal gap. There is also a literal space between the
   two elements in the markup, which flex layout discards but the DOM keeps: it
   is why the chip's `textContent` reads "LLM <id>" and not the two run
   together, so selecting the chip to paste the id somewhere — the one thing an
   operator will actually do with it — hands them a whole one. (This comment
   quoted a real id once. Criterion 1's grep caught it, which is the whole
   reason that grep exists.) */
.chip-label {
  flex: none;
  margin-right: 7px;
  font-weight: 600;
  color: var(--ink);
}

/* Clips, and says so. `overflow: hidden` is a paint-time effect only — the whole
   id stays in `textContent` for selection and in the `title` for hover, so a
   clipped chip is shortened, never wrong. */
.chip-value {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --- the customer panel (phase 0015) ------------------------------------- */
/* A testing affordance living inside a demo: quiet, tabular, and not there at
   all until someone asks for it. It sits between the chat bar and the
   transcript, and scrolls on its own so thirteen figures cannot push the
   conversation off the screen. */

.customer {
  padding: 12px 20px 14px;
  background: #fbfcfd;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  max-height: 34vh;
  overflow-y: auto;
}

.customer[hidden] { display: none; }

.customer-headline {
  margin: 0 0 8px;
  font-weight: 600;
  color: var(--accent);
}

.customer-note {
  margin: 0;
  color: var(--ink-soft);
}

.figure {
  display: grid;
  grid-template-columns: minmax(9rem, 1fr) minmax(6rem, auto) minmax(0, 2fr);
  gap: 2px 16px;
  padding: 6px 0;
  border-top: 1px solid var(--line);
}

.figure-label { color: var(--ink-soft); }

.figure-value {
  font-weight: 600;
  /* Digits line up column-wise, which is most of what makes eleven money
     amounts scannable rather than merely present. */
  font-variant-numeric: tabular-nums;
}

.figure-basis {
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}

/* Narrowed window: the three parts stack rather than squeeze, the same way the
   persona cards reflow to one column. */
@media (max-width: 680px) {
  .figure { grid-template-columns: 1fr; }
}

.messages {
  flex: 1;
  min-height: 340px;
  max-height: 58vh;
  overflow-y: auto;
  padding: 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.msg {
  max-width: 76%;
  padding: 11px 15px;
  border-radius: var(--radius);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.msg.user {
  align-self: flex-end;
  background: var(--accent);
  color: #fff;
  border-bottom-right-radius: 4px;
}

.msg.avatar {
  align-self: flex-start;
  background: #f1f4f7;
  border-bottom-left-radius: 4px;
}

.msg.notice {
  align-self: center;
  max-width: 100%;
  background: #fdf1f1;
  color: #94202a;
  font-size: 14px;
}

.opener {
  margin: auto;
  text-align: center;
  color: var(--ink-soft);
  font-size: 14px;
  max-width: 380px;
}

/* The three dots that stand in for the reply until its first token lands. */
.msg.pending::after {
  content: "\00b7\00b7\00b7";
  letter-spacing: 2px;
  color: var(--ink-soft);
}

.composer {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  padding: 14px 20px 18px;
  border-top: 1px solid var(--line);
}

.composer textarea {
  flex: 1;
  font: inherit;
  color: inherit;
  resize: none;
  max-height: 140px;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fbfcfd;
}

.composer textarea:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--surface);
}

.composer button {
  font: inherit;
  font-weight: 600;
  font-size: 15px;
  color: #fff;
  background: var(--accent);
  border: none;
  border-radius: var(--radius);
  padding: 11px 22px;
  cursor: pointer;
}

.composer button:disabled {
  opacity: 0.45;
  cursor: default;
}

/* --- the access key panel (phase 0014) ----------------------------------- */
/* Only rendered when the API has refused a request, so it is the whole page
   when it appears: one field, one button, one line of explanation. */

.keygate {
  display: flex;
  gap: 12px;
  align-items: center;
  max-width: 420px;
}

.keygate input {
  flex: 1;
  font: inherit;
  color: inherit;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.keygate input:focus {
  outline: none;
  border-color: var(--brand);
}

.keygate button {
  font: inherit;
  font-weight: 600;
  color: #fff;
  background: var(--brand);
  border: none;
  border-radius: var(--radius);
  padding: 11px 22px;
  cursor: pointer;
}

#key-status {
  margin-top: 12px;
  color: var(--brand);
}
