/* ===========================================================================
   Nelo — design system
   ---------------------------------------------------------------------------
   One token layer, two themes. Components never name a colour directly: they
   use the semantic tokens below, so Light and Dark stay in step and a future
   theme is a matter of adding one block rather than touching components.

   Layers, in order:
     1. @font-face   — Manrope, self-hosted (a strict same-origin CSP means no
                       Google Fonts, and self-hosting is faster anyway)
     2. primitives   — the raw palette and scales. Not used by components.
     3. semantics    — what a component actually asks for: --surface, --text-1.
     4. components   — everything else.

   Theme resolution: the <html> element carries data-theme="light|dark". The
   server stamps it from the user's cookie so the first paint is already
   correct, and the client keeps it in sync. When the preference is "system",
   no attribute is set and the prefers-color-scheme block below decides.
   =========================================================================== */

/* ------------------------------------------------------------ 1. Manrope --- */
@font-face {
  font-family: "Manrope";
  src: url("/fonts/Manrope-Regular.ttf") format("truetype");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Manrope";
  src: url("/fonts/Manrope-Medium.ttf") format("truetype");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Manrope";
  src: url("/fonts/Manrope-SemiBold.ttf") format("truetype");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Manrope";
  src: url("/fonts/Manrope-Bold.ttf") format("truetype");
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Manrope";
  src: url("/fonts/Manrope-ExtraBold.ttf") format("truetype");
  font-weight: 800; font-style: normal; font-display: swap;
}

/* --------------------------------------------------------- 2. primitives --- */
:root {
  /* Technology palette. Electric blue leads; indigo, violet and cyan are the
     supporting range for AI surfaces, charts and multi-series data. */
  --blue-50:  #eff5ff;  --blue-100: #dbe8ff; --blue-300: #8bb3ff;
  --blue-500: #2f6bff;  --blue-600: #1d55e0; --blue-400: #5b8cff;
  --indigo-500: #4f46e5; --indigo-400: #6f68ea;
  --violet-500: #7c3aed; --violet-400: #9563f0;
  --cyan-500:  #06b6d4;  --cyan-400: #22cfe8;

  --green-500: #0d9f6e; --green-400: #34d399;
  --amber-500: #c77b06; --amber-400: #fbbf24;
  --red-500:   #dc2f34;  --red-400:  #f87171;

  /* Neutrals. Warm-free greys keep the white reading as white rather than
     beige next to the blues. */
  --grey-0:  #ffffff; --grey-25: #fbfcfd; --grey-50: #f6f8fa;
  --grey-100:#eef1f5; --grey-200:#e3e7ee; --grey-300:#cbd2dd;
  --grey-500:#6b7484; --grey-600:#5b6472; --grey-700:#3d4551;
  --grey-900:#0d1117; --grey-950:#0a0c10;

  /* Type scale. Manrope is geometric and reads small, so the base is a touch
     larger than a Helvetica-family equivalent would be. */
  --font-sans: "Manrope", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --fw-regular: 400; --fw-medium: 500; --fw-semi: 600; --fw-bold: 700; --fw-x: 800;

  --fs-2xs: 10.5px; --fs-xs: 11.5px; --fs-sm: 12.5px; --fs-base: 14px;
  --fs-md: 15px;    --fs-lg: 17px;   --fs-xl: 21px;   --fs-2xl: 27px;  --fs-3xl: 34px;

  --lh-tight: 1.15; --lh-snug: 1.35; --lh-base: 1.55;
  --tracking-tight: -0.021em; --tracking-wide: 0.075em;

  /* Shape and motion */
  --radius-xs: 6px; --radius-sm: 9px; --radius: 13px; --radius-lg: 18px;
  --space: 4px;
  --ease: cubic-bezier(0.32, 0.72, 0, 1);
  --dur: 140ms;
}

/* ---------------------------------------------------------- 3. semantics --- */
/* Light is the default: white page, dark type, hairline borders, colour used
   only where it carries meaning. */
:root,
:root[data-theme="light"] {
  color-scheme: light;

  --page:        var(--grey-0);
  --surface:     var(--grey-0);
  --surface-2:   var(--grey-50);
  --surface-3:   var(--grey-100);
  --surface-sunk:var(--grey-25);
  --hover:       var(--grey-50);

  --line:        var(--grey-200);
  --line-soft:   var(--grey-100);
  --line-strong: var(--grey-300);

  --text-1: var(--grey-900);
  --text-2: var(--grey-600);
  --text-3: var(--grey-500);
  --text-on-accent: #ffffff;

  --accent:       var(--blue-500);
  --accent-hover: var(--blue-600);
  --accent-weak:  var(--blue-50);
  --accent-line:  var(--blue-100);
  --accent-text:  var(--blue-600);

  --ai:        var(--violet-500);
  --ai-weak:   #f5f0ff;
  --ai-line:   #e6dcff;
  /* The one gradient in the system, reserved for Nelo herself. */
  --ai-gradient: linear-gradient(135deg, var(--violet-500), var(--blue-500) 55%, var(--cyan-500));

  --good: var(--green-500); --good-weak: #e7f7f1; --good-line: #c6ece0;
  --warn: var(--amber-500); --warn-weak: #fdf5e3; --warn-line: #f6e4bd;
  --bad:  var(--red-500);   --bad-weak:  #fdefef; --bad-line:  #f8d7d8;

  --chart-1: var(--blue-500);  --chart-2: var(--violet-500);
  --chart-3: var(--cyan-500);  --chart-4: var(--indigo-500);

  /* Light mode earns its depth from borders, not shadow. */
  --shadow-sm: 0 1px 2px rgba(13, 17, 23, 0.04);
  --shadow:    0 1px 3px rgba(13, 17, 23, 0.06), 0 8px 24px rgba(13, 17, 23, 0.05);
  --ring:      0 0 0 3px var(--accent-line);
}

/* Dark is designed, not inverted: the page is a deep neutral, surfaces step
   *up* toward the viewer, and the accents are lifted so they stay legible. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --page:        var(--grey-950);
  --surface:     #12161d;
  --surface-2:   #171c25;
  --surface-3:   #1d232e;
  --surface-sunk:#0d1015;
  --hover:       #1c222c;

  --line:        #262d3a;
  --line-soft:   #1c222c;
  --line-strong: #333c4c;

  --text-1: #e9edf4;
  --text-2: #9aa4b5;
  /* Lifted from #6f7a8b: card subtitles sit on --surface, where that measured
     4.17:1 — under the 4.5 needed for body-size text. */
  --text-3: #808b9d;
  --text-on-accent: #06101f;

  --accent:       var(--blue-400);
  --accent-hover: #7ba4ff;
  --accent-weak:  rgba(91, 140, 255, 0.13);
  --accent-line:  rgba(91, 140, 255, 0.3);
  --accent-text:  var(--blue-400);

  --ai:        var(--violet-400);
  --ai-weak:   rgba(149, 99, 240, 0.14);
  --ai-line:   rgba(149, 99, 240, 0.32);
  --ai-gradient: linear-gradient(135deg, var(--violet-400), var(--blue-400) 55%, var(--cyan-400));

  --good: var(--green-400); --good-weak: rgba(52, 211, 153, 0.13); --good-line: rgba(52, 211, 153, 0.3);
  --warn: var(--amber-400); --warn-weak: rgba(251, 191, 36, 0.13); --warn-line: rgba(251, 191, 36, 0.3);
  --bad:  var(--red-400);   --bad-weak:  rgba(248, 113, 113, 0.13); --bad-line:  rgba(248, 113, 113, 0.32);

  --chart-1: var(--blue-400);  --chart-2: var(--violet-400);
  --chart-3: var(--cyan-400);  --chart-4: var(--indigo-400);

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow:    0 1px 2px rgba(0, 0, 0, 0.5), 0 10px 30px rgba(0, 0, 0, 0.35);
  /* --ring is not redefined: it is built from --accent-line, which is themed
     just above, so the light definition already resolves correctly here. */
}

/* First paint for someone on "system" who has not chosen yet. Once a
   preference exists the server stamps data-theme and this stops applying.
   The values are intentionally identical to the block above — this is the
   only duplication in the system, and it buys a flash-free first paint. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) {
    color-scheme: dark;
    --page: var(--grey-950); --surface: #12161d; --surface-2: #171c25;
    --surface-3: #1d232e; --surface-sunk: #0d1015; --hover: #1c222c;
    --line: #262d3a; --line-soft: #1c222c; --line-strong: #333c4c;
    --text-1: #e9edf4; --text-2: #9aa4b5; --text-3: #808b9d;
    --text-on-accent: #06101f;
    --accent: var(--blue-400); --accent-hover: #7ba4ff;
    --accent-weak: rgba(91, 140, 255, 0.13); --accent-line: rgba(91, 140, 255, 0.3);
    --accent-text: var(--blue-400);
    --ai: var(--violet-400); --ai-weak: rgba(149, 99, 240, 0.14); --ai-line: rgba(149, 99, 240, 0.32);
    --ai-gradient: linear-gradient(135deg, var(--violet-400), var(--blue-400) 55%, var(--cyan-400));
    --good: var(--green-400); --good-weak: rgba(52, 211, 153, 0.13); --good-line: rgba(52, 211, 153, 0.3);
    --warn: var(--amber-400); --warn-weak: rgba(251, 191, 36, 0.13); --warn-line: rgba(251, 191, 36, 0.3);
    --bad: var(--red-400); --bad-weak: rgba(248, 113, 113, 0.13); --bad-line: rgba(248, 113, 113, 0.32);
    --chart-1: var(--blue-400); --chart-2: var(--violet-400);
    --chart-3: var(--cyan-400); --chart-4: var(--indigo-400);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 10px 30px rgba(0, 0, 0, 0.35);
  }
}

/* --------------------------------------------------------- 4. components --- */
* { box-sizing: border-box; }

/* The shells below set `display`, which would otherwise beat the `hidden`
   attribute the app uses to switch between sign-in and the deck. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--page);
  color: var(--text-1);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  font-weight: var(--fw-regular);
  line-height: var(--lh-base);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: "ss01", "ss02";
}

/* Theme switching is deliberately NOT animated.
   Chrome does not reliably re-resolve a *transitioned* property when its value
   comes from a custom property that just changed — the element keeps painting
   the old colour indefinitely. Any element with a colour transition therefore
   gets stranded in the previous theme until a reload, which is exactly what
   "switch to dark mode" must never do.
   theme.js sets data-theme-switching for one frame around the change, so every
   transition is off at the moment the tokens flip and back on immediately
   after. Hover and focus transitions are unaffected in normal use. */
:root[data-theme-switching] *,
:root[data-theme-switching] *::before,
:root[data-theme-switching] *::after {
  transition: none !important;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

button, input, select, textarea { font: inherit; color: inherit; font-family: var(--font-sans); }
button { cursor: pointer; }
a { color: var(--accent-text); text-decoration: none; font-weight: var(--fw-medium); }
a:hover { text-decoration: underline; }

:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius-xs); }

h1, h2, h3, h4 { font-weight: var(--fw-semi); letter-spacing: var(--tracking-tight); line-height: var(--lh-snug); margin: 0; }

/* ------------------------------------------------------------------ shell */
.app {
  display: grid;
  /* minmax(0, …) rather than a bare 1fr: a bare fr track has an automatic
     minimum of its content's min-width, so one wide card silently widens the
     whole column past the viewport and drags the top bar out with it. */
  grid-template-columns: minmax(0, 1fr) 428px;
  grid-template-rows: auto 1fr;
  height: 100vh;
  overflow: hidden;
}

/* Consultant off: the deck takes the whole width. Stamped on the server, so
   the chat panel is never painted and then taken away. */
:root[data-consultant="off"] .app { grid-template-columns: minmax(0, 1fr); }
:root[data-consultant="off"] .chat { display: none; }

.topbar {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0 20px;
  height: 62px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  z-index: 10;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: var(--fw-x);
  font-size: var(--fs-lg);
  letter-spacing: var(--tracking-tight);
  white-space: nowrap;
}
.brand .mark {
  width: 26px; height: 26px; border-radius: 8px;
  background: var(--ai-gradient);
  display: grid; place-items: center;
  flex: none;
}
.brand .mark::after {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: #fff; opacity: 0.95;
}
.brand small {
  color: var(--text-3);
  font-weight: var(--fw-medium);
  font-size: var(--fs-sm);
  letter-spacing: 0;
}

.windows { display: flex; gap: 2px; background: var(--surface-2); padding: 3px; border-radius: var(--radius-sm); }
.windows button {
  background: none; border: 0; padding: 6px 13px;
  border-radius: var(--radius-xs);
  color: var(--text-2); font-size: var(--fs-sm); font-weight: var(--fw-medium);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.windows button:hover { color: var(--text-1); background: var(--surface); }
.windows button[aria-pressed="true"] {
  background: var(--accent); color: var(--text-on-accent); font-weight: var(--fw-semi);
}

.spacer { flex: 1; }

.clock {
  font-family: var(--font-mono); font-size: var(--fs-sm);
  color: var(--text-3); font-variant-numeric: tabular-nums;
}

.pill {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 11px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: var(--fs-xs); color: var(--text-2); font-weight: var(--fw-medium);
}
.pill .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-3); flex: none; }
.pill.ok .dot   { background: var(--good); }
.pill.warn .dot { background: var(--warn); }
.pill.bad .dot  { background: var(--bad); }

.icon-btn {
  background: var(--surface); border: 1px solid var(--line); color: var(--text-2);
  width: 34px; height: 34px; border-radius: var(--radius-sm);
  display: grid; place-items: center; flex: none;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.icon-btn:hover { color: var(--accent-text); border-color: var(--accent); background: var(--accent-weak); }
.icon-btn.spinning svg { animation: spin 0.9s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------- theme switch */
.theme-switch {
  display: flex; gap: 2px; padding: 3px;
  background: var(--surface-2); border-radius: var(--radius-sm);
  border: 1px solid var(--line);
}
.theme-switch button {
  background: none; border: 0; padding: 4px 8px; border-radius: var(--radius-xs);
  color: var(--text-3); display: grid; place-items: center;
  transition: color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.theme-switch button:hover { color: var(--text-1); }
.theme-switch button[aria-pressed="true"] {
  background: var(--surface); color: var(--accent-text); box-shadow: var(--shadow-sm);
}

/* ------------------------------------------------------------------- main */
.main { overflow-y: auto; padding: 22px; background: var(--page); }
.main::-webkit-scrollbar, .chat-log::-webkit-scrollbar, .timeline::-webkit-scrollbar { width: 11px; }
.main::-webkit-scrollbar-thumb, .chat-log::-webkit-scrollbar-thumb, .timeline::-webkit-scrollbar-thumb {
  background: var(--line-strong); border-radius: 6px; border: 3px solid var(--page); background-clip: padding-box;
}

/* --------------------------------------------------------------- briefing */
.briefing {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 20px 22px;
  margin-bottom: 24px;
  position: relative;
  overflow: hidden;
}
/* A single hairline of Nelo's gradient — the AI signature, used sparingly. */
.briefing::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--ai-gradient);
}
.briefing-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.briefing-head h2 {
  font-size: var(--fs-xs); text-transform: uppercase;
  letter-spacing: var(--tracking-wide); color: var(--text-3); font-weight: var(--fw-bold);
}
.briefing-body { font-size: var(--fs-md); color: var(--text-1); line-height: var(--lh-base); }
.briefing-body p { margin: 0 0 10px; }
.briefing-body p:last-child { margin-bottom: 0; }
.briefing-body strong { font-weight: var(--fw-bold); color: var(--text-1); }
.briefing-body ul { margin: 8px 0; padding-left: 18px; }
.briefing-body li { margin-bottom: 5px; }

.btn {
  background: var(--surface); border: 1px solid var(--line); color: var(--text-2);
  padding: 7px 14px; border-radius: var(--radius-sm);
  font-size: var(--fs-sm); font-weight: var(--fw-semi);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.btn:hover { color: var(--accent-text); border-color: var(--accent); background: var(--accent-weak); }
.btn:disabled { opacity: 0.5; cursor: default; }
.btn.primary {
  background: var(--accent); border-color: var(--accent); color: var(--text-on-accent);
  font-weight: var(--fw-bold);
}
.btn.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--text-on-accent); }

/* ------------------------------------------------------------------ cards */
.group { margin-bottom: 30px; }
.group-head { display: flex; align-items: center; gap: 12px; margin-bottom: 13px; }
.group-head h3 {
  font-size: var(--fs-xs); text-transform: uppercase;
  letter-spacing: var(--tracking-wide); color: var(--text-3); font-weight: var(--fw-bold);
}
.group-head .rule { flex: 1; height: 1px; background: var(--line-soft); }

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(238px, 1fr));
  gap: 13px;
  /* Each card takes its natural height — otherwise one card with a breakdown
     stretches every neighbour in its row into a wall of empty space. A card
     reading "Orders taken: 0" pulled to 380px is worse than a ragged edge. */
  align-items: start;
  /* Small cards backfill the gaps the wide ones leave. */
  grid-auto-flow: dense;
}

/* A card carrying a ranked list is a different object from a stat tile, and
   sharing one column width serves neither: the tile wastes the space and the
   list grows tall and truncates its labels. Give the list width instead of
   height and the ragged column that produces mostly goes away.

   Only once there is room for two columns — below that the grid is one card
   wide and a span of 2 would push the deck past the viewport. */
@media (min-width: 900px) {
  .card.wide { grid-column: span 2; }
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 15px 17px;
  display: flex; flex-direction: column; gap: 7px;
  min-height: 116px;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.card:hover { border-color: var(--line-strong); box-shadow: var(--shadow-sm); }
.card.primary { border-color: var(--accent-line); background: var(--accent-weak); }
.card.warn { border-color: var(--warn-line); background: var(--warn-weak); }
.card.critical { border-color: var(--bad-line); background: var(--bad-weak); }

.card-title {
  font-size: var(--fs-sm); color: var(--text-2); font-weight: var(--fw-semi);
  display: flex; align-items: center; gap: 6px;
}
.card-value {
  font-size: var(--fs-2xl); font-weight: var(--fw-x);
  letter-spacing: var(--tracking-tight); line-height: var(--lh-tight);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
  color: var(--text-1);
}
/* A product or customer name is a label, not a figure — it should not shout
   the way a currency total does. */
.card-value.as-text { font-size: var(--fs-lg); font-weight: var(--fw-bold); }
.card.critical .card-value { color: var(--bad); }
.card-sub { font-size: var(--fs-sm); color: var(--text-3); margin-top: auto; font-weight: var(--fw-regular); }

.trend {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2px 8px; border-radius: 999px;
  font-size: var(--fs-xs); font-weight: var(--fw-bold); font-variant-numeric: tabular-nums;
  background: var(--surface-3); color: var(--text-2);
}
.trend.good { background: var(--good-weak); color: var(--good); }
.trend.bad  { background: var(--bad-weak);  color: var(--bad); }

.card-row { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }

.spark { display: block; width: 100%; height: 28px; margin-top: 2px; }

.breakdown { margin-top: 9px; display: flex; flex-direction: column; gap: 6px; }
.breakdown-row { display: grid; grid-template-columns: 1fr auto; gap: 8px; font-size: var(--fs-sm); align-items: center; }
.breakdown-row .label { color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.breakdown-row .val { color: var(--text-1); font-variant-numeric: tabular-nums; font-weight: var(--fw-semi); }
.breakdown-bar { grid-column: 1 / -1; height: 3px; background: var(--surface-3); border-radius: 2px; overflow: hidden; }
.breakdown-bar i { display: block; height: 100%; background: var(--chart-1); border-radius: 2px; }

.card-items { margin-top: 9px; display: flex; flex-direction: column; gap: 6px; }
.card-item {
  font-size: var(--fs-sm); padding: 7px 9px; border-radius: var(--radius-xs);
  background: var(--surface-2); border-left: 2px solid var(--line-strong);
}
.card-item.critical { border-left-color: var(--bad); }
.card-item.warn { border-left-color: var(--warn); }
.card-item .t { color: var(--text-1); font-weight: var(--fw-medium); }
.card-item .s { color: var(--text-3); font-size: var(--fs-xs); }

.as-of {
  display: block; font-size: var(--fs-2xs); color: var(--text-3);
  font-family: var(--font-mono); margin-top: 3px;
}

/* --------------------------------------------------------------- timeline */
.timeline-wrap { margin-top: 8px; }
.timeline-controls { display: flex; gap: 9px; margin-bottom: 11px; flex-wrap: wrap; align-items: center; }
.timeline-controls input, .timeline-controls select {
  background: var(--surface); border: 1px solid var(--line); color: var(--text-1);
  padding: 8px 11px; border-radius: var(--radius-sm); font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
}
.timeline-controls input { flex: 1; min-width: 170px; }
.timeline-controls input::placeholder { color: var(--text-3); font-weight: var(--fw-regular); }
.timeline-controls input:focus, .timeline-controls select:focus {
  outline: none; border-color: var(--accent); box-shadow: var(--ring);
}

.timeline {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); max-height: 470px; overflow-y: auto;
}
.event {
  display: grid; grid-template-columns: 64px 1fr auto; gap: 13px;
  padding: 10px 15px; border-bottom: 1px solid var(--line-soft);
  align-items: baseline; font-size: var(--fs-sm);
}
.event:last-child { border-bottom: 0; }
.event:hover { background: var(--hover); }
.event .time { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-3); }
.event .body .t { color: var(--text-1); font-weight: var(--fw-medium); }
.event .body .s { color: var(--text-3); font-size: var(--fs-xs); font-weight: var(--fw-regular); }
.event .amt { font-variant-numeric: tabular-nums; font-weight: var(--fw-bold); white-space: nowrap; }
.event .amt.pos { color: var(--good); }
.event .amt.neg { color: var(--text-2); }
.event.critical { background: var(--bad-weak); }
.event.warn .body .t::before { content: "▲ "; color: var(--warn); font-size: 9px; }

.tag {
  display: inline-block; padding: 1px 6px; border-radius: var(--radius-xs);
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: var(--fs-2xs); color: var(--text-3); font-family: var(--font-mono);
  text-transform: uppercase; letter-spacing: 0.04em; margin-right: 7px;
}

/* ------------------------------------------------------------------- chat */
.chat {
  display: flex; flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--line);
  overflow: hidden;
}
.chat-head { display: flex; align-items: center; gap: 10px; padding: 15px 17px; border-bottom: 1px solid var(--line); }
.chat-head h2 { font-size: var(--fs-lg); font-weight: var(--fw-x); letter-spacing: var(--tracking-tight); }
.chat-head .sub { font-size: var(--fs-xs); color: var(--text-3); font-weight: var(--fw-medium); }

.wake-indicator {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 17px; font-size: var(--fs-sm); color: var(--text-3);
  background: var(--surface-2); border-bottom: 1px solid var(--line);
  font-weight: var(--fw-medium);
}
.wake-indicator.listening { color: var(--accent-text); background: var(--accent-weak); }
.wake-indicator.awake { color: var(--ai); background: var(--ai-weak); }
.wake-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-3); flex: none; }
.wake-indicator.listening .wake-dot { background: var(--accent); animation: pulse 1.6s ease-in-out infinite; }
.wake-indicator.awake .wake-dot { background: var(--ai); animation: pulse 0.85s ease-in-out infinite; }
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.3; transform: scale(1.4); }
}
.wake-indicator code {
  font-family: var(--font-mono); background: var(--surface-3);
  padding: 1px 6px; border-radius: var(--radius-xs); color: var(--accent-text);
  font-size: var(--fs-xs);
}

.chat-log { flex: 1; overflow-y: auto; padding: 17px; display: flex; flex-direction: column; gap: 15px; }

.msg { display: flex; flex-direction: column; gap: 5px; max-width: 100%; }
.msg .who {
  font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: var(--tracking-wide);
  color: var(--text-3); font-weight: var(--fw-bold);
}
.msg .bubble {
  padding: 11px 14px; border-radius: var(--radius); font-size: var(--fs-base);
  background: var(--surface-2); border: 1px solid var(--line);
  overflow-wrap: anywhere; line-height: var(--lh-base);
}
/* Nelo's own replies carry a hint of her colour so the conversation reads at
   a glance as two voices. */
.msg.assistant .bubble { border-left: 2px solid var(--ai-line); }
.msg.user .bubble { background: var(--accent-weak); border-color: var(--accent-line); }
.msg .bubble p { margin: 0 0 8px; }
.msg .bubble p:last-child { margin-bottom: 0; }
.msg .bubble strong { font-weight: var(--fw-bold); }
.msg .bubble ul { margin: 6px 0; padding-left: 18px; }
.msg .bubble code {
  font-family: var(--font-mono); font-size: var(--fs-sm);
  background: var(--surface-3); padding: 1px 5px; border-radius: var(--radius-xs);
}

/* An action Nelo carried out, shown inline so the change is accounted for. */
.action-note {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: var(--fs-xs); font-weight: var(--fw-semi);
  color: var(--ai); background: var(--ai-weak);
  border: 1px solid var(--ai-line); border-radius: 999px;
  padding: 3px 11px; align-self: flex-start;
}
.action-note::before { content: "✓"; font-weight: var(--fw-bold); }

.confirm-row { display: flex; gap: 8px; margin-top: 4px; }

.trace { font-size: var(--fs-2xs); color: var(--text-3); font-family: var(--font-mono); }
.trace span {
  background: var(--surface-2); border: 1px solid var(--line-soft);
  padding: 1px 6px; border-radius: var(--radius-xs); margin-right: 4px;
}

.thinking { display: flex; gap: 5px; padding: 8px 0; }
.thinking i { width: 6px; height: 6px; border-radius: 50%; background: var(--ai); animation: bounce 1.2s ease-in-out infinite; }
.thinking i:nth-child(2) { animation-delay: 0.15s; }
.thinking i:nth-child(3) { animation-delay: 0.3s; }
@keyframes bounce { 0%, 60%, 100% { opacity: 0.25; } 30% { opacity: 1; } }

.suggestions { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 17px 13px; }
.suggestions button {
  background: var(--surface); border: 1px solid var(--line); color: var(--text-2);
  padding: 6px 12px; border-radius: 999px; font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.suggestions button:hover { color: var(--accent-text); border-color: var(--accent); background: var(--accent-weak); }

.composer {
  display: flex; gap: 9px; padding: 13px 17px 17px;
  border-top: 1px solid var(--line); align-items: flex-end;
}
.composer textarea {
  flex: 1; background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius-sm); padding: 10px 13px; resize: none;
  font-size: var(--fs-base); max-height: 140px; min-height: 42px;
  font-weight: var(--fw-regular);
}
.composer textarea::placeholder { color: var(--text-3); }
.composer textarea:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
.composer .icon-btn { width: 42px; height: 42px; }
.composer .icon-btn.active { color: var(--ai); border-color: var(--ai); background: var(--ai-weak); }

/* ------------------------------------------------------------------ login */
.login-shell { display: grid; place-items: center; height: 100vh; padding: 20px; background: var(--page); }
.login {
  width: 100%; max-width: 392px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 32px; box-shadow: var(--shadow);
}
.login .brand { margin-bottom: 6px; font-size: var(--fs-xl); }
.login p.lede { margin: 0 0 24px; color: var(--text-3); font-size: var(--fs-sm); font-weight: var(--fw-medium); }
.login label { display: block; font-size: var(--fs-sm); color: var(--text-2); margin-bottom: 6px; font-weight: var(--fw-semi); }
.login input {
  width: 100%; background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius-sm); padding: 11px 13px; margin-bottom: 15px; font-size: var(--fs-base);
}
.login input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
.login .btn { width: 100%; padding: 12px; }
.login .err {
  background: var(--bad-weak); border: 1px solid var(--bad-line);
  color: var(--bad); padding: 10px 13px; border-radius: var(--radius-sm);
  font-size: var(--fs-sm); margin-bottom: 15px; font-weight: var(--fw-medium);
}
.login .qr { text-align: center; margin-bottom: 16px; }
.login .qr img { width: 184px; height: 184px; background: #fff; padding: 9px; border-radius: var(--radius-sm); border: 1px solid var(--line); }
.login .secret {
  font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--text-2);
  background: var(--surface-2); padding: 9px; border-radius: var(--radius-xs);
  word-break: break-all; text-align: center; margin-bottom: 15px; border: 1px solid var(--line);
}

.empty { padding: 44px 20px; text-align: center; color: var(--text-3); font-size: var(--fs-sm); }
.muted { color: var(--text-3); }

.toast {
  position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%);
  background: var(--surface); border: 1px solid var(--line);
  color: var(--text-1);
  padding: 11px 17px; border-radius: var(--radius-sm);
  font-size: var(--fs-sm); font-weight: var(--fw-medium);
  box-shadow: var(--shadow); z-index: 100;
}
.toast.bad { border-color: var(--bad-line); color: var(--bad); background: var(--bad-weak); }

/* ------------------------------------------------------------- responsive */
@media (max-width: 1100px) {
  .app { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr auto; }
  .chat { border-left: 0; border-top: 1px solid var(--line); max-height: 45vh; }
  .topbar { flex-wrap: wrap; height: auto; padding: 10px 14px; gap: 10px; }

  /* Six window buttons do not fit a phone. `min-width: 0` is the load-bearing
     part: a flex item defaults to min-width:auto and would refuse to shrink
     below its content, dragging the whole bar wider than the screen. */
  .windows { order: 3; flex: 1 1 100%; min-width: 0; overflow-x: auto; scrollbar-width: none; }
  .windows::-webkit-scrollbar { display: none; }
  .windows button { flex: none; white-space: nowrap; }

  /* The brand is nowrap, so a flexible box would let it paint over the clock
     instead of shrinking. Pin it, and drop what a phone has no room for. */
  .brand { flex: none; }
  .brand small { display: none; }
  .clock { display: none; }          /* the status pill already carries the sync time */
  .spacer { flex: 1 1 0; min-width: 0; }
  .pill { flex: 0 1 auto; min-width: 0; overflow: hidden; }
  .pill span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  .main { padding: 14px; }
  .cards { grid-template-columns: repeat(auto-fill, minmax(152px, 1fr)); }
  .card-value { font-size: var(--fs-xl); }
  .event { grid-template-columns: 50px 1fr; }
  .event .amt { grid-column: 2; }
}
