/* WAE — mobile first. The target is an iPhone Home Screen icon, so everything
   is sized for a thumb and safe area insets are respected. */

/* Ecoori brand teal #2C7083, sampled from the live ecoori.com stylesheet on
   20 August 2026, with #7BB4BD as its lighter tone. The backgrounds are tinted
   towards the brand rather than painted flat in it, so answer text keeps its
   contrast — a full #2C7083 page would drop body copy to about 4:1. */
:root {
  --brand: #2c7083;
  --brand-light: #7bb4bd;

  --bg: #f2f8f9;
  --fg: #102b33;
  --muted: #56777f;
  --line: #d3e4e8;
  --accent: #2c7083;
  --accent-fg: #ffffff;
  --chip: #e2eff2;
  --error: #b91c1c;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #071b21;
    --fg: #e6f1f3;
    --muted: #8db0b8;
    --line: #14343d;
    --accent: #7bb4bd;
    --accent-fg: #062026;
    --chip: #0e2830;
    --error: #fca5a5;
  }
}

* { box-sizing: border-box; }

/* The [hidden] attribute must actually hide things.
 *
 * The browser hides [hidden] with an attribute selector, specificity 0-1-0.
 * Every layout rule below that targets an id — #chat, #signedOut — beats it at
 * 1-0-0, so show() could set .hidden on a section and the section would stay on
 * screen. Measured on the first production deploy: a signed-out visitor saw the
 * sign-in panel AND the whole chat view stacked beneath it, because #chat
 * carries display:flex. Nothing on localhost caught it, since every test there
 * was already signed in.
 */
[hidden] { display: none !important; }

/* The app fills the viewport exactly: header, then a scrolling thread, then a
   composer pinned to the bottom. Only the thread scrolls, so the composer stays
   put when the keyboard opens and the page never rubber-bands as a whole.

   100dvh, not 100vh: on iOS Safari 100vh is the height with the toolbars
   HIDDEN, so a composer positioned against it sits below the fold until the
   user scrolls. dvh follows the toolbars as they collapse. */
html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 17px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           0 env(safe-area-inset-left);
  -webkit-text-size-adjust: 100%;

  display: flex;
  flex-direction: column;
  height: 100dvh;
  overflow: hidden;
}

header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding: 1rem 1.25rem; border-bottom: 1px solid var(--line);
  flex: none;
}

h1 { font-size: 1.15rem; margin: 0; letter-spacing: .04em; }

/* The signed-out panel is the one screen that is not a thread. */
#signedOut { padding: 1.25rem; max-width: 42rem; margin: 0 auto; width: 100%; }

#chat {
  flex: 1;
  min-height: 0;          /* or the thread refuses to scroll inside the flex */
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 42rem;
  margin: 0 auto;
}

.lead { font-size: 1.05rem; }
.fine { color: var(--muted); font-size: .85rem; }

textarea {
  width: 100%; padding: .85rem; font: inherit; border-radius: 12px;
  border: 1px solid var(--line); background: transparent; color: inherit;
  resize: vertical;
}
textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

button {
  font: inherit; border-radius: 999px; cursor: pointer; padding: .7rem 1.25rem;
  border: 1px solid var(--line); background: transparent; color: inherit;
  /* 44px is the iOS minimum comfortable tap target. */
  min-height: 44px;
}

.primary {
  background: var(--accent); color: var(--accent-fg); border-color: var(--accent);
  width: 100%; margin-top: .75rem; font-weight: 600;
}

.ghost { color: var(--muted); }

.chips { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1.5rem; }

.chip {
  background: var(--chip); border-color: transparent; font-size: .85rem;
  padding: .5rem .9rem; text-align: left; color: var(--muted);
}

.answer { font-size: 1.05rem; margin: .5rem 0 1.5rem; }

.cite {
  display: inline-block; margin: 0 .12rem; padding: 0 .4rem;
  border-radius: 999px; background: var(--chip); color: var(--muted);
  font-size: .72rem; text-decoration: none; vertical-align: .08em;
}

.sources { list-style: none; padding: 0; margin: .75rem 0 0; }
.sources li { padding: .5rem 0; border-top: 1px solid var(--line); font-size: .9rem; }
.sources a { color: inherit; }
.marker { color: var(--muted); font-size: .75rem; }

summary { cursor: pointer; color: var(--muted); font-size: .9rem; }

.stage { font-size: 1.05rem; margin: 1rem 0 .25rem; }
.error { color: var(--error); }

.spinner {
  width: 26px; height: 26px; border-radius: 50%;
  border: 2px solid var(--line); border-top-color: var(--accent);
  animation: spin 900ms linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 3s; }
}

/* ---------------------------------------------------------------- install

   The iOS Add to Home Screen sheet. iOS fires no beforeinstallprompt and shows
   no install banner, so a PWA that does not ask stays a browser tab. The sheet
   sits above the Safari toolbar and points down at the Share button, which is
   where iOS 15 and later put it. */

.sheet {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: calc(12px + env(safe-area-inset-bottom));
  z-index: 20;

  padding: 16px 16px 12px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--chip);
  box-shadow: 0 8px 32px rgba(16, 43, 51, 0.18);

  animation: rise 280ms ease-out;
}

@keyframes rise {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}

.sheetTitle {
  margin: 0 0 6px;
  font-weight: 600;
}

.sheetBody {
  margin: 0 0 4px;
  color: var(--fg);
}

/* The iOS share glyph, drawn rather than relying on an emoji that renders
   differently on every OS version. */
.shareGlyph {
  display: inline-block;
  width: 13px;
  height: 16px;
  vertical-align: -3px;
  border: 1.5px solid var(--accent);
  border-top: none;
  border-radius: 2px;
  position: relative;
}

.shareGlyph::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -8px;
  width: 1.5px;
  height: 10px;
  margin-left: -0.75px;
  background: var(--accent);
}

.shareGlyph::after {
  content: "";
  position: absolute;
  left: 50%;
  top: -8px;
  width: 6px;
  height: 6px;
  margin-left: -3px;
  border-left: 1.5px solid var(--accent);
  border-top: 1.5px solid var(--accent);
  transform: rotate(45deg);
}

/* Points down at the toolbar. Motion is small and slow on purpose: this sits
   on screen while someone reads, and a fast bounce is hard to read past. */
.pointer {
  width: 0;
  height: 0;
  margin: 8px auto 4px;
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  border-top: 10px solid var(--accent);
  animation: nudge 1.6s ease-in-out infinite;
}

@keyframes nudge {
  0%, 100% { transform: translateY(0); opacity: 0.85; }
  50%      { transform: translateY(5px); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .sheet { animation: none; }
  .pointer { animation: none; }
}

.sheet .ghost {
  width: 100%;
  margin-top: 4px;
}

/* ---------------------------------------------------------------- actions

   The four buttons under every answer, and the banners around a shared one. */

.actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin: 16px 0 12px;
}

.actions .ghost {
  width: 100%;
  margin: 0;
}

.actions .ghost[disabled] {
  opacity: 0.45;
}

/* #openSourceBtn is an anchor rather than a button — see index.html for why —
   so it needs the box model the bare `button` rule gives the other three. */
.actions a.ghost {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: .7rem 1.25rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: inherit;
  text-decoration: none;
}

/* An anchor cannot be [disabled]; it is marked aria-disabled and made inert. */
.actions a.ghost[aria-disabled="true"] {
  opacity: 0.45;
  pointer-events: none;
}

/* The share-includes-the-answer toggle. Deliberately wordy: the whole point is
   that someone reads the consequence before they turn it on, and a bare label
   saying "Include answer" would not tell anyone that customer pricing is about
   to go into a group chat. */
.toggle {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin: 0 0 12px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--muted);
}

.toggle input {
  flex: none;
  width: 20px;
  height: 20px;
  margin: 1px 0 0;
  accent-color: var(--accent);
}

.banner {
  margin: 0 0 14px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 10px;
  background: var(--chip);
  font-size: 14px;
  line-height: 1.5;
}

/* The in-app browser warning sits above everything, because if it applies then
   nothing below it is going to work. */
.banner.warn {
  margin: 12px;
  border-left-color: var(--error);
}

.banner.warn .ghost {
  display: block;
  width: 100%;
  margin-top: 10px;
}

/* Feedback for Copy, which otherwise gives no sign it did anything. */
#actionStatus:empty {
  display: none;
}

/* Keeps the closing punctuation attached to the citation chip before it, so a
   line never starts with a lone comma. Applied to the last chip of a run only;
   see render() for why. */
.citeGroup {
  white-space: nowrap;
}

/* The chip carries .12rem of margin on both sides so a run of them does not
   collide. Inside a citation group the right margin would sit between the chip
   and the comma that belongs to the sentence, reading as "[D1] ," rather than
   "[D1],". */
.citeGroup .cite {
  margin-right: 0;
}

/* ---------------------------------------------------------------- thread

   Message bubbles. Questions right and tinted with the brand, answers left on
   the page background — the arrangement every messenger uses, so nobody has to
   learn which side is which. */

.thread {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 1rem 1rem 0.5rem;
  scroll-behavior: smooth;
}

.opening { padding: 1rem 0 0; }

.msg {
  display: flex;
  margin: 0 0 14px;
}

.msg.mine { justify-content: flex-end; }
.msg.theirs { justify-content: flex-start; }

.bubble {
  max-width: 88%;
  padding: 12px 14px;
  border-radius: 18px;
  border: 1px solid var(--line);
  background: var(--bg);
  /* Long file names and tracking numbers must not push the thread sideways. */
  overflow-wrap: anywhere;
}

.msg.mine .bubble {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
  border-bottom-right-radius: 6px;
  white-space: pre-wrap;   /* a typed question keeps its own line breaks */
}

.msg.theirs .bubble {
  background: var(--chip);
  border-bottom-left-radius: 6px;
}

.bubble.failed { border-color: var(--error); }

.bubble .answer { margin: 0; }

.bubble .meta { margin: 10px 0 0; }

.bubble .sourcesBox { margin-top: 10px; }

/* An answer bubble is wider than a question: it carries citations, a sources
   drawer and four buttons, and squeezing those to 88% wastes the screen. */
.msg.theirs .bubble { max-width: 96%; }

/* The working indicator, three dots the way a messenger shows typing. */
.working { display: flex; align-items: center; gap: 10px; }

.dots { display: inline-flex; gap: 4px; }

.dots i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--muted);
  animation: blink 1.4s infinite both;
}

.dots i:nth-child(2) { animation-delay: .2s; }
.dots i:nth-child(3) { animation-delay: .4s; }

@keyframes blink {
  0%, 80%, 100% { opacity: .25; }
  40% { opacity: 1; }
}

.working .stage { font-size: .9rem; color: var(--muted); margin: 0; }

@media (prefers-reduced-motion: reduce) {
  .thread { scroll-behavior: auto; }
  .dots i { animation: none; opacity: .6; }
}

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

.composer {
  flex: none;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  background: var(--bg);
}

.composer textarea {
  flex: 1;
  width: auto;
  margin: 0;
  padding: 11px 14px;
  border-radius: 22px;
  min-height: 44px;
  max-height: 160px;
  overflow-y: auto;
  resize: none;
  line-height: 1.4;
}

.send {
  flex: none;
  width: 44px;
  min-height: 44px;
  padding: 0;
  border-radius: 50%;
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
  font-size: 1.1rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

.send:disabled { opacity: .45; }

/* The action bar sits inside an answer bubble now, so it needs less air than
   it did as a standalone block, and the status line shares its last row. */
.bubble .actions {
  grid-template-columns: 1fr 1fr;
  margin: 12px 0 0;
}

.bubble .actions .status { grid-column: 1 / -1; margin: 0; }

/* ---------------------------------------------------------------- settings */

.headerRight { display: flex; align-items: center; gap: .5rem; }

.icon {
  width: 44px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
}

.settings {
  flex: none;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--chip);
}

.settings .toggle { margin: 0; }

/* The share-includes-the-answer toggle. Deliberately wordy: the whole point is
   that someone reads the consequence before they turn it on, and a bare label
   saying "Include answer" would not tell anyone that customer pricing is about
   to go into a group chat. */
.toggle {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-size: 14px;
  line-height: 1.45;
  color: var(--muted);
}

.toggle input {
  flex: none;
  width: 20px;
  height: 20px;
  margin: 1px 0 0;
  accent-color: var(--accent);
}

/* Inside a bubble the four actions are secondary to the answer, so they are
   sized down from the standalone buttons they started as. At full size they
   dominated every message in the thread, and "Open CRM row" wrapped onto two
   lines. */
.bubble .actions .ghost {
  font-size: .85rem;
  padding: .45rem .6rem;
  min-height: 38px;
  white-space: nowrap;
}

/* ---------------------------------------------------------------- citations

   Hidden until asked for. JK: "citation, please do not provide at first. if
   ask, then provide."

   The markers are still generated and still in the text — they are what keeps
   the answer honest, and the sources list is built from them. This only stops
   them interrupting the sentence on first read. Opening the sources drawer
   reveals them, which is the "if ask" part; the setting makes that permanent. */

.cite { display: none; }

.bubble.showCites .cite,
body.citesAlways .cite {
  display: inline-block;
}

/* With the chips hidden the nowrap group has nothing left to protect, and an
   empty inline-block would otherwise leave a gap before the full stop. */
.citeGroup { white-space: normal; }

.bubble.showCites .citeGroup,
body.citesAlways .citeGroup {
  white-space: nowrap;
}
