@import url('https://fonts.googleapis.com/css2?family=Geist:wght@300..700&family=Geist+Mono:wght@400;500&family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400&display=swap');

/* Otis admin — design tokens (2026-09 redesign).
 *
 * Warm paper grounds and ink, with the Otis brand colours as the highlights,
 * each with one job:
 *   indigo #4146E5 (--accent)  your controls: primary actions, links, the
 *                              selected nav item / tab / row, focus, charts
 *   violet #7C3AED (--otis)    anything Otis did: its mark and byline, drafts to
 *                              approve, "Otis is handling", suggestions, answers
 *   orange (--signal)          a person is needed — nothing else
 *   green (--ok)               live, bought, success
 * The logo (white sparkles on indigo, --brand) is Otis's mark. Type: Geist for
 * the interface, Geist Mono for numbers/shortcuts/IDs, and Newsreader (serif)
 * for words written by Otis or by shoppers.
 *
 * Every token name from the previous system is kept, so routes that reference
 * var(--accent), var(--bg-subtle) etc. pick up the new look unchanged. The dark
 * theme is opt-in: <html data-theme="dark">, set from the account menu.
 */
:root {
  color-scheme: light;

  /* Grounds */
  --chrome: #111113;          /* the app frame: sidebar and the edge around the panel */
  --canvas: #f3f1ec;          /* paper behind full-window pages (login, blockers, /ops) */
  --bg: #fcfbf9;              /* the inset panel pages render on */
  --bg-subtle: #f6f4f0;
  --bg-muted: #efece6;
  --surface: #ffffff;         /* cards, inputs, popovers */
  --hover: #f4f2ed;           /* list-row hover */
  --selected: #ebebf8;        /* selected list row (an indigo tint) */
  --nav-hover: #eae7e0;
  --nav-active: #e6e2da;
  --kbd-bg: #efece6;

  /* Ink */
  --text: #1c1b18;
  --text-secondary: #57534b;
  --text-muted: #6f6a62;      /* still ≥4.5:1 on --bg and --canvas */
  --text-faint: #8f8a80;      /* decorative only (glyph strokes), never body text */

  /* Lines */
  --border: #e4e0d8;
  --border-subtle: #ece9e3;
  --border-strong: #ddd9d0;

  /* Brand: indigo. --accent is for text, links, marks; --accent-solid for fills under white text. */
  --accent: #4146e5;
  --accent-dark: #3438c7;
  --accent-light: #ebebf8;
  --accent-glow: rgba(65, 70, 229, 0.18);
  --accent-solid: #4146e5;
  --accent-solid-hover: #3438c7;
  --accent-soft: #a8aaf0;     /* secondary data series */

  /* Otis: violet, for what the agent did or wrote. */
  --otis: #7c3aed;
  --otis-light: #f1eaf8;
  --otis-soft: #c2a4f4;       /* dashed "not sent yet" rules */

  /* The logo's colours, the same in both themes: the tile's indigo and the
     sparkles' violet. */
  --brand: #4146e5;
  --otis-mark: #7c3aed;
  --brand-gradient: linear-gradient(180deg, #7c3aed 0%, #4146e5 100%);
  --accent-hover-shadow: none;
  --primary: var(--accent);
  --primary-hover: var(--accent-dark);
  --primary-light: var(--accent-light);

  /* Status. Orange (--amber / --signal) means "a person is needed", nothing else. */
  --green: #3b6e47;
  --green-light: #eaf2ec;
  --ok: #4c9a5b;
  --red: #b3412f;
  --red-light: #f8e7e2;
  --amber: #f07b2e;
  --amber-light: #fbece1;
  --signal: #f07b2e;
  --signal-text: #b04e12;
  --signal-light: #fbece1;

  /* Radius */
  --radius-sm: 5px;
  --radius: 6px;
  --radius-md: 8px;
  --radius-lg: 10px;
  --radius-xl: 14px;
  --radius-pill: 999px;

  /* Shadow (warm, low) */
  --shadow-sm: 0 1px 1px rgba(40, 34, 24, 0.04);
  --shadow-md: 0 4px 14px rgba(40, 34, 24, 0.06), 0 1px 3px rgba(40, 34, 24, 0.04);
  --shadow-lg: 0 24px 60px -16px rgba(28, 27, 24, 0.35), 0 8px 20px -8px rgba(28, 27, 24, 0.2);
  --shadow-panel: 0 0 0 1px var(--border), 0 1px 3px rgba(40, 34, 24, 0.05);
  --ring: 0 0 0 1px var(--border-strong);

  /* Typography */
  --font-display: 'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body: 'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  --font-voice: 'Newsreader', 'Iowan Old Style', Georgia, serif;
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --chrome: #0e0e10;
  --canvas: #121211;
  --bg: #1a1a18;
  --bg-subtle: #1f1e1c;
  --bg-muted: #2a2926;
  --surface: #22211f;
  --hover: #232220;
  --selected: #22233c;
  --nav-hover: #262523;
  --nav-active: #2d2c29;
  --kbd-bg: #2b2a27;

  --text: #edebe6;
  --text-secondary: #b3aea4;
  --text-muted: #948f85;
  --text-faint: #7f7a71;

  --border: #2e2d2a;
  --border-subtle: #2a2926;
  --border-strong: #3b3a35;

  --accent: #9491ff;
  --accent-dark: #b3b1ff;
  --accent-light: #22233c;
  --accent-glow: rgba(148, 145, 255, 0.25);
  --accent-solid: #4f54ee;
  --accent-solid-hover: #5c61f2;
  --accent-soft: #4c4fa8;

  --otis: #b18cff;
  --otis-light: #281f38;
  --otis-soft: #6a4fb0;

  --green: #7dc08a;
  --green-light: #1d2a20;
  --ok: #5db06d;
  --red: #e5836f;
  --red-light: #3a211c;
  --amber: #f08a45;
  --amber-light: #3a2a1f;
  --signal: #f08a45;
  --signal-text: #f2a06a;
  --signal-light: #3a2a1f;

  --shadow-sm: 0 1px 1px rgba(0, 0, 0, 0.25);
  --shadow-md: 0 4px 14px rgba(0, 0, 0, 0.35);
  --shadow-lg: 0 24px 60px -16px rgba(0, 0, 0, 0.6), 0 8px 20px -8px rgba(0, 0, 0, 0.5);
  --shadow-panel: 0 0 0 1px var(--border), 0 1px 3px rgba(0, 0, 0, 0.3);
}

/* Reset */
*, *::before, *::after { box-sizing: border-box; }
html, body, #root { height: 100%; margin: 0; }
body {
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
  background: var(--chrome);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
}
p { margin: 0; }
a { color: inherit; }
::selection { background: var(--accent-solid); color: #fff; }
input::placeholder, textarea::placeholder { color: var(--text-muted); }
/* The hidden attribute wins over a component's own display (a .tc-icon-btn
   is inline-flex, which would otherwise show a hidden one). */
[hidden] { display: none !important; }

/* Shopify App Bridge — hide <ui-title-bar> until App Bridge defines the
   custom element. When we're embedded in Shopify, App Bridge lifts the
   children into the top chrome and this rule no longer matches. When
   we're running standalone (local dev, direct admin URL), the element
   stays undefined and we don't want its inline children rendering as
   loose buttons in the page body. */
ui-title-bar:not(:defined) { display: none; }

/* Subtle scrollbar */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 8px; border: 2px solid var(--bg); }
::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }

/* Focus ring */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: 4px;
}

input.searchbar,
input.searchbar:focus,
input.searchbar:focus-visible {
  outline: none !important;
  box-shadow: none !important;
}

.tabular { font-variant-numeric: tabular-nums; }
.mono { font-family: var(--font-mono); }

/* Badge — a small rounded tag. Sentence case: the old uppercase, tracked
   badge read as generic SaaS chrome. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 20px;
  padding: 0 7px;
  border-radius: var(--radius-sm);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1;
  background: var(--bg-muted);
  color: var(--text-secondary);
  white-space: nowrap;
}
.badge-accent  { background: var(--accent-light); color: var(--accent); }
.badge-success { background: var(--green-light); color: var(--green); }
.badge-error   { background: var(--red-light); color: var(--red); }
.badge-warning { background: var(--signal-light); color: var(--signal-text); }

/* Pill — outcome chip in row contexts (Conversations list). Same shape as a
   badge, one step larger. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 22px;
  padding: 0 8px;
  border-radius: var(--radius);
  font-size: 12px;
  font-weight: 500;
  line-height: 1;
  background: var(--bg-muted);
  color: var(--text-secondary);
  white-space: nowrap;
}
.pill-accent  { background: var(--accent-light); color: var(--accent); }
.pill-success { background: var(--green-light); color: var(--green); }
.pill-error   { background: var(--red-light); color: var(--red); }
.pill-warning { background: var(--signal-light); color: var(--signal-text); }

/* Card */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
  /* Name the properties. `all` animates layout ones too, so any later change
     to padding or width would animate unintentionally and risk jank. */
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.card-hover:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.card.\!p-0 { padding: 0; }

/* Button */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 30px;
  padding: 0 12px;
  border-radius: var(--radius);
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 500;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text);
  cursor: pointer;
  transition:
    background-color 0.12s ease,
    border-color 0.12s ease,
    color 0.12s ease,
    box-shadow 0.12s ease;
  text-decoration: none;
  line-height: 1;
  white-space: nowrap;
}
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-primary { background: var(--accent-solid); color: #fff; }
.btn-primary:hover:not(:disabled) { background: var(--accent-solid-hover); color: #fff; }
.btn-secondary {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-sm);
}
.btn-secondary:hover:not(:disabled) { background: var(--bg-subtle); }
.btn-ghost { color: var(--accent); }
.btn-ghost:hover:not(:disabled) { background: var(--accent-light); }
.btn-sm { min-height: 26px; padding: 0 9px; font-size: 12px; }

/* Input */
.input,
.textarea,
.select {
  width: 100%;
  min-height: 32px;
  padding: 6px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  line-height: 1.4;
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.input:focus,
.textarea:focus,
.select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-glow);
}
.textarea {
  resize: vertical;
  min-height: 80px;
  padding: 8px 10px;
  line-height: 1.55;
}

.delta-up { color: var(--green); }
.delta-down { color: var(--red); }

/* Page layout — single canonical width across every admin page. Left-aligned
   on the same 40px gutter as the PageHeader title, so a page's title, its
   description and its content share one left edge at any window width (a
   centred column drifted right of the title once the panel passed 1480px). */
.page-content {
  max-width: 1480px;
  margin: 0;
  padding: 28px 40px 40px;
}

.muted   { color: var(--text-secondary); }
.subtle  { color: var(--text-muted); }

/* Section label — used above grouped card lists. Sentence case. */
.section-label {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
  margin-bottom: 10px;
}

/* Stat — paired label + value used in dashboards. */
.stat-label {
  font-size: 12.5px;
  font-weight: 400;
  color: var(--text-secondary);
}
.stat-value {
  font-family: var(--font-body);
  font-weight: 500;
  letter-spacing: -0.025em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.stat-value-md { font-size: 20px; }
.stat-value-lg { font-size: 28px; }
.stat-value-xl { font-size: 40px; }

/* Delta — a plain coloured figure next to a stat, no pill. A fall is shown in
   muted ink rather than red: "down" isn't always bad (average order can fall
   while orders rise). */
.delta {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.delta-positive { color: var(--green); }
.delta-negative { color: var(--text-muted); }
.delta-flat     { color: var(--text-muted); }

/* ── Redesign utilities ──────────────────────────────────────────────────── */

/* Keyboard shortcut chip. */
.tc-kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 5px;
  border-radius: 4px;
  background: var(--kbd-bg);
  box-shadow: inset 0 -1px 0 var(--border-strong);
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 400;
  line-height: 1;
  white-space: nowrap;
}
.btn-primary .tc-kbd { background: rgba(255, 255, 255, 0.16); box-shadow: none; color: #fff; }

/* Words written by Otis (summaries, briefings, reasoning) or quoted from a
   shopper. The serif is the only marker AI text needs. */
.tc-voice {
  font-family: var(--font-voice);
  font-size: 16px;
  line-height: 1.45;
  letter-spacing: -0.003em;
  color: var(--text);
  text-wrap: pretty;
}
.tc-voice-lg { font-size: 20px; }
.tc-quote { font-family: var(--font-voice); font-style: italic; color: var(--text-secondary); }

/* A list row that highlights on hover. */
.tc-row { transition: background-color 0.1s ease; }
.tc-row:hover { background: var(--hover); }
.tc-row[aria-current="true"],
.tc-row[aria-current="page"],
.tc-row.is-selected { background: var(--selected); }

/* Square icon-only button. */
.tc-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background-color 0.1s ease, color 0.1s ease;
}
.tc-icon-btn:hover { background: var(--bg-muted); color: var(--text); }

/* Section heading row: title, optional count, optional link on the right,
   hairline underneath. */
.tc-section-head {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 30px;
  border-bottom: 1px solid var(--border-subtle);
}
.tc-section-head h2,
.tc-section-head h3 { font-size: 13px; font-weight: 600; letter-spacing: 0; }
.tc-section-head .tc-count { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.tc-section-head a { font-size: 12.5px; font-weight: 500; color: var(--accent); text-decoration: none; }
.tc-section-head a:hover { color: var(--accent-dark); }

/* Segmented control. */
.tc-seg {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  border-radius: var(--radius-md);
  background: var(--bg-muted);
}
.tc-seg > button,
.tc-seg > a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 10px;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  font-size: 12px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.tc-seg > button:hover,
.tc-seg > a:hover { color: var(--text); }
.tc-seg > [aria-pressed="true"],
.tc-seg > [aria-current="page"],
.tc-seg > [aria-selected="true"] {
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 0 0 1px var(--border-strong), 0 1px 2px rgba(40, 34, 24, 0.06);
}

/* Thin horizontal meter (bars in "what held shoppers back" etc.). */
.tc-meter {
  display: flex;
  height: 6px;
  border-radius: 3px;
  background: var(--bg-muted);
  overflow: hidden;
}
.tc-meter > span { display: block; border-radius: 3px; background: var(--accent); }
.tc-meter.is-ink > span { background: var(--text); }

/* The app frame (root.tsx): the black edge around the panels. The visible
   viewport's height (dvh), so on a phone the shell never runs under the
   browser's own bars and can't be dragged up by a scrollIntoView. */
.portal-frame {
  display: flex;
  height: 100vh;
  height: 100dvh;
  background: var(--chrome);
}

/* The inset panel every page renders on (see root.tsx). */
.portal-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
  margin: 8px 8px 8px 0;
  border-radius: var(--radius-lg);
  background: var(--bg);
  box-shadow: var(--shadow-panel);
}

/* Pulsing status dot. */
@keyframes status-ping {
  0%   { transform: scale(1);   opacity: 0.6; }
  100% { transform: scale(2.2); opacity: 0; }
}

/* Pulsing dot used inline on the "Active" filter chip. Different
   from .status-dot because it scales a box-shadow ring instead of
   spawning a ::before pseudo-element — works inside flex chips
   without breaking baseline. */
@keyframes tc-live-pulse {
  0%   { box-shadow: 0 0 0 0   rgba(76, 154, 91, 0.5); }
  70%  { box-shadow: 0 0 0 6px rgba(76, 154, 91, 0);   }
  100% { box-shadow: 0 0 0 0   rgba(76, 154, 91, 0);   }
}
@media (prefers-reduced-motion: reduce) {
  [style*="tc-live-pulse"] { animation: none !important; }
}

/* Portal route-transition fade.
   The <main> in root.tsx is keyed on the top-level section; React remounts it
   when you move between sections, triggering this entrance animation. */
@keyframes portal-route-in {
  from { opacity: 0; transform: translateY(3px); }
  to   { opacity: 1; transform: translateY(0); }
}
.portal-main {
  animation: portal-route-in 120ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .portal-main { animation: none !important; }
}

/* Loading skeletons.
   These replaced dimming the whole page to `opacity: 0.6` while a loader ran.
   60% opacity is the convention for DISABLED, so a page fetching data read as
   a page that had stopped working. A skeleton reads as "arriving" instead.

   Sized to the real content's geometry so nothing shifts when data lands. */
@keyframes portal-skeleton-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}
.skeleton {
  background: var(--bg-muted);
  border-radius: var(--radius);
  animation: portal-skeleton-pulse 1.4s ease-in-out infinite;
}
/* A pulse is a poor progress signal on its own: it never resolves, so a stalled
   fetch looks identical to a fast one. It is paired with the TopProgressBar,
   which does track real request state. */
.skeleton-text { height: 12px; }
.skeleton-value { height: 30px; width: 60%; }
.skeleton-row { height: 40px; }
@media (prefers-reduced-motion: reduce) {
  /* Still a placeholder, just a still one — the shape carries the meaning. */
  .skeleton { animation: none !important; }
}
.status-dot {
  position: relative;
  display: inline-flex;
  width: 8px;
  height: 8px;
  flex-shrink: 0;
}
.status-dot::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: currentColor;
  opacity: 0.5;
  animation: status-ping 1.6s cubic-bezier(0, 0, 0.2, 1) infinite;
}
.status-dot::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: currentColor;
}
.status-dot-green { color: var(--ok); }
.status-dot-amber { color: var(--signal); }
.status-dot-red   { color: var(--red); }
.status-dot-gray  { color: var(--text-faint); }
@media (prefers-reduced-motion: reduce) {
  .status-dot::before { animation: none; opacity: 0; }
}

/* ── Mobile topbar (hidden on desktop) ─────────────────────── */
.mobile-topbar {
  display: none;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: var(--bg);
  border-bottom: 1px solid var(--border-subtle);
  flex-shrink: 0;
  position: sticky;
  top: 0;
  z-index: 40;
}
.mobile-overlay { display: none; }

/* Pinned page header (desktop). Keeps the title/tabs/actions — notably the
   Save button — visible while content scrolls under it. Mobile (≤768px) keeps
   the separate .mobile-topbar, so this is desktop-only. */
@media (min-width: 769px) {
  .page-header {
    position: sticky;
    top: 0;
    z-index: 30;
  }
}

/* ── Responsive — tablet (≤ 1024px) ─────────────────────────── */
@media (max-width: 1024px) {
  .page-content > .grid.grid-cols-3,
  .page-content > .grid.grid-cols-4 {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
}

/* ── Responsive — mobile (≤ 768px) ──────────────────────────── */
@media (max-width: 768px) {
  aside.sidebar {
    position: fixed !important;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 200;
    width: 260px !important;
    transform: translateX(-100%);
    /* Closed, it casts no shadow (it would show down the screen's left edge)
       and leaves the tab order once it has slid away. */
    visibility: hidden;
    transition: transform 0.2s ease, visibility 0s linear 0.2s;
    background: var(--canvas);
  }
  aside.sidebar.open {
    transform: translateX(0);
    visibility: visible;
    box-shadow: var(--shadow-lg);
    transition: transform 0.2s ease;
  }
  .mobile-topbar { display: flex; }
  .mobile-overlay {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(28, 27, 24, 0.4);
    z-index: 150;
  }
  .portal-panel { margin: 0; border-radius: 0; box-shadow: none; }
  .page-content { padding: 16px !important; }
  header .page-header-inner {
    /* Same 16px gutter as .page-content on phones. */
    padding: 6px 16px !important;
    gap: 8px !important;
  }
  .page-header-desc { padding: 12px 16px 0 !important; }
  .card { padding: 14px; }
}

/* ── Responsive layout helpers ───────────────────────────────────────────
   The Today dashboard row (Recent conversations + Set-up checklist) and the
   conversation-detail columns (transcript + "what Otis did") set their grid
   template here rather than inline, so the @media rule below can collapse them
   to a single column on mobile (inline styles would otherwise win). */
.tc-dashboard-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* Recent conversations spans the first two of the three columns; the checklist
   takes the third. Kept in CSS (not inline) so the ≤768px rule below can reset
   it to a single full-width row — an inline grid-column: span 2 would create an
   implicit second column on mobile and keep the cards side-by-side. */
.tc-dashboard-main { grid-column: span 2; }
.tc-detail-cols { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); }
/* A tab row with more tabs past an edge fades that edge (useTabRow sets it). */
.tc-tab-row[data-fade="end"] { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent); }
.tc-tab-row[data-fade="start"] { -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 36px), transparent); mask-image: linear-gradient(to left, #000 calc(100% - 36px), transparent); }
.tc-tab-row[data-fade="both"] { -webkit-mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 36px), transparent); mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 36px), transparent); }
/* Tab rows (HeaderTabs / SectionTabs) scroll sideways on overflow instead of
   wrapping onto multiple lines ("stacking") on narrow screens. */
.tc-tab-row {
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.tc-tab-row::-webkit-scrollbar { display: none; }

@media (max-width: 768px) {
  .tc-dashboard-row,
  .tc-detail-cols { grid-template-columns: 1fr; }
  /* Drop the 2-column span so Recent conversations + checklist stack instead of
     sitting side-by-side in a squished 2-up grid. */
  .tc-dashboard-main { grid-column: auto; }
}

/* Tab rows + section sub-menus on phones (James, 2026-08-09): keep labels at
 * their natural size and scroll sideways, with the row bleeding to the screen
 * edges so a half-visible tab signals "there's more this way".
 */
@media (max-width: 640px) {
  .tc-tab-row {
    flex-wrap: nowrap;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    overscroll-behavior-x: contain;
  }
  .tc-tab-row > button,
  .tc-tab-row > a {
    scroll-snap-align: start;
    /* Never shrink: squeezing is precisely what we're avoiding. */
    flex: 0 0 auto;
    white-space: nowrap;
  }
}

/* ── Markdown inside transcript bubbles ──────────────────────────────────
   The conversation transcript renders each message through <Markdown> (marked +
   DOMPurify), mirroring the storefront widget so the merchant sees what the
   shopper saw — links clickable, lists / tables / bold rendered. The wrap rules
   are load-bearing: a long unbroken string (e.g. a checkout URL the agent
   pasted) would otherwise push the bubble off the page. */
.tc-markdown {
  overflow-wrap: anywhere;
  word-break: break-word;
}
.tc-markdown p { margin: 0 0 8px 0; }
.tc-markdown p:last-child { margin-bottom: 0; }
.tc-markdown a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: 500;
  overflow-wrap: anywhere;
}
.tc-markdown strong { font-weight: 600; }
.tc-markdown ul,
.tc-markdown ol { margin: 6px 0 8px; padding-left: 20px; }
.tc-markdown li { margin-bottom: 2px; }
.tc-markdown h1,
.tc-markdown h2,
.tc-markdown h3 { font-size: 14px; font-weight: 600; margin: 8px 0 4px; }
.tc-markdown code {
  background: var(--bg-muted);
  padding: 1px 4px;
  border-radius: 3px;
  font-size: 12.5px;
  font-family: var(--font-mono);
}
.tc-markdown pre {
  background: var(--bg-muted);
  padding: 10px 12px;
  border-radius: var(--radius);
  overflow-x: auto;
  margin: 8px 0;
}
.tc-markdown pre code { background: none; padding: 0; }
.tc-markdown blockquote {
  margin: 8px 0;
  padding-left: 12px;
  border-left: 2px solid var(--border-strong);
  color: var(--text-secondary);
}
.tc-markdown hr { border: none; border-top: 1px solid var(--border-subtle); margin: 8px 0; }
/* Comparison tables can be wide — let them scroll inside the bubble rather than
   stretch it past the page edge. */
.tc-markdown table {
  display: block;
  width: 100%;
  overflow-x: auto;
  border-collapse: collapse;
  margin: 8px 0;
  font-size: 13px;
}
.tc-markdown th,
.tc-markdown td { border: 1px solid var(--border); padding: 6px 8px; text-align: left; }
.tc-markdown th { background: var(--bg-subtle); }
.tc-markdown img { max-width: 100%; height: auto; border-radius: var(--radius-sm); }

/* Live conversation typing indicator (ADR-150) */
.tc-typing-dots {
  display: inline-flex;
  gap: 4px;
  padding: 10px 14px;
  background: var(--bg-muted);
  border-radius: 12px;
}
.tc-typing-dots span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-faint);
  animation: tc-dot 1.2s infinite ease-in-out;
}
.tc-typing-dots span:nth-child(2) { animation-delay: 0.15s; }
.tc-typing-dots span:nth-child(3) { animation-delay: 0.3s; }
@keyframes tc-dot {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.5; }
  30% { transform: translateY(-4px); opacity: 1; }
}

/* ── Sidebar (components/Sidebar.tsx) ────────────────────────────────────── */
/* The sidebar is black in both themes (the cream panel sits in a black frame),
   so it redefines the tokens for everything inside it — nav items, search,
   counts, the status card and the account menu all follow. Brand colour stays
   in small doses: the selected item's icon, the counts, the "N new" tag. */
aside.sidebar {
  color-scheme: dark;
  /* Same black as the frame around the panel (root.tsx), in both themes. */
  --canvas: var(--chrome);
  --bg: #1b1b1f;
  --bg-subtle: #18181c;
  --bg-muted: #1b1b1f;
  --surface: #1e1e23;
  --hover: #202026;
  --nav-hover: #1d1d22;
  --nav-active: #2a2a31;
  --kbd-bg: #28282e;
  --text: #f0f0f2;
  --text-secondary: #b9b9c2;
  --text-muted: #8e8f98;
  --text-faint: #5d5e66;
  --border: #2a2a30;
  --border-subtle: #232328;
  --border-strong: #34343b;
  --accent: #a5a3ff;
  --accent-light: rgba(165, 163, 255, 0.14);
  --otis: #c4a8ff;
  --otis-light: rgba(196, 168, 255, 0.15);
  --signal: #f08a45;
  --signal-text: #f5a46e;
  --ok: #5db06d;
  --shadow-md: 0 10px 28px rgba(0, 0, 0, 0.55);
  color: var(--text);
}
aside.sidebar .tc-nav-item[aria-current="page"] { background: rgba(255, 255, 255, 0.09); color: #fff; }
aside.sidebar .tc-nav-item[aria-current="page"] > svg { color: var(--accent); }
aside.sidebar .tc-nav-item.is-parent-active { color: #fff; }
aside.sidebar .tc-nav-item.is-parent-active > svg { color: var(--accent); }
@keyframes tc-nav-sub-in {
  from { opacity: 0; transform: translateY(-2px); }
  to   { opacity: 1; transform: none; }
}
.tc-nav-sub { animation: tc-nav-sub-in 140ms ease-out; }
@media (prefers-reduced-motion: reduce) {
  .tc-nav-sub { animation: none; }
}
.tc-nav-item {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 28px;
  padding: 0 8px;
  border-radius: var(--radius);
  color: var(--text-secondary);
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.1s ease;
}
.tc-nav-item:hover { background: var(--nav-hover); }
.tc-nav-item > svg { flex-shrink: 0; color: var(--text-muted); }
.tc-nav-item[aria-current="page"] { background: var(--accent-light); color: var(--accent); }
.tc-nav-item[aria-current="page"] > svg { color: var(--accent); }
.tc-nav-item.is-parent-active { color: var(--text); }
.tc-nav-sub {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 0 0 3px 15px;
  padding-left: 8px;
  border-left: 1px solid var(--border-strong);
}
.tc-nav-sub .tc-nav-item { height: 26px; font-weight: 400; }
.tc-nav-sub .tc-nav-item[aria-current="page"] { font-weight: 500; }
.tc-nav-count { margin-left: auto; font-size: 12px; font-weight: 400; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.tc-nav-count.is-signal { display: inline-flex; align-items: center; gap: 5px; font-weight: 600; color: var(--signal-text); }
.tc-nav-count.is-signal::before { content: ''; width: 6px; height: 6px; border-radius: 3px; background: var(--signal); }
aside.sidebar.is-collapsed .tc-nav-label,
aside.sidebar.is-collapsed .tc-nav-count,
aside.sidebar.is-collapsed .tc-nav-sub,
aside.sidebar.is-collapsed .tc-nav-group-label,
aside.sidebar.is-collapsed .tc-hide-collapsed { display: none !important; }
aside.sidebar.is-collapsed .tc-nav-item { justify-content: center; padding: 0; }

/* ── Command palette (components/CommandPalette.tsx) ─────────────────────── */
@keyframes tc-palette-in {
  from { opacity: 0; transform: translateY(-4px) scale(0.99); }
  to   { opacity: 1; transform: none; }
}
.tc-palette { animation: tc-palette-in 110ms ease-out; }
@media (prefers-reduced-motion: reduce) {
  .tc-palette { animation: none; }
}
@media (max-width: 640px) {
  .tc-hide-narrow { display: none; }
}

/* Header / section tabs (PageHeader.tabStyle). The inline style sets the
   resting background, so hover needs !important to show through. */
.tc-tab:hover:not([aria-selected="true"]):not([aria-current="page"]) {
  background: var(--hover) !important;
  color: var(--text) !important;
}
.tc-meter.is-signal > span { background: var(--signal); }
.tc-nav-count.is-otis { display: inline-flex; align-items: center; gap: 5px; font-weight: 600; color: var(--otis); }
.tc-nav-count.is-otis::before { content: ''; width: 7px; height: 7px; border-radius: 50%; border: 1.5px dashed var(--otis); box-sizing: border-box; }

/* Collapsed rail: Conversations' counts are hidden, so an orange dot on its
   icon says someone needs a person. */
.tc-nav-item { position: relative; }
.tc-rail-dot { display: none; }
aside.sidebar.is-collapsed .tc-rail-dot {
  display: block;
  position: absolute;
  top: 5px;
  right: 11px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--signal);
  box-shadow: 0 0 0 2px var(--canvas);
}
/* In the rail the sub-items are hidden, so the section itself shows as selected. */
aside.sidebar.is-collapsed .tc-nav-item.is-parent-active { background: rgba(255, 255, 255, 0.09); }

/* The Otis wordmark (components/OtisLogo.tsx): ink lettering on light
   grounds, white lettering on the black sidebar and in the dark theme. */
.otis-wordmark img { display: block; width: 100%; height: 100%; }
.otis-wordmark .otis-wordmark-white { display: none; }
:root[data-theme="dark"] .otis-wordmark .otis-wordmark-ink,
aside.sidebar .otis-wordmark .otis-wordmark-ink { display: none; }
:root[data-theme="dark"] .otis-wordmark .otis-wordmark-white,
aside.sidebar .otis-wordmark .otis-wordmark-white { display: block; }

/* ── Select (components/ui.tsx) — in place of the native <select> popup ── */
.tc-select { display: inline-flex; min-width: 0; max-width: 100%; vertical-align: middle; }
.tc-select-trigger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 32px;
  padding: 0 8px 0 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  line-height: 1.2;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.tc-select-trigger:hover:not(:disabled) { border-color: var(--text-faint); }
.tc-select-trigger:focus-visible,
.tc-select-trigger[aria-expanded="true"] {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-glow);
}
.tc-select-trigger:disabled { opacity: 0.55; cursor: not-allowed; }
.tc-select.is-sm .tc-select-trigger { min-height: 28px; padding: 0 6px 0 9px; font-size: 12.5px; }
.tc-select-value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tc-select-value.is-placeholder { color: var(--text-muted); }
.tc-select-chevron { flex-shrink: 0; color: var(--text-muted); transition: transform 0.12s ease; }
.tc-select-trigger[aria-expanded="true"] .tc-select-chevron { transform: rotate(180deg); }
.tc-select-menu {
  position: fixed;
  z-index: 350;
  box-sizing: border-box;
  padding: 4px;
  overflow-y: auto;
  border-radius: var(--radius-md);
  background: var(--surface);
  box-shadow: 0 0 0 1px var(--border), var(--shadow-md);
  outline: none;
}
.tc-select-group { padding: 8px 8px 4px; font-size: 12px; color: var(--text-muted); }
.tc-select-option {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  min-height: 30px;
  box-sizing: border-box;
  padding: 7px 10px 7px 8px;
  border-radius: var(--radius);
  color: var(--text);
  font-size: 13px;
  line-height: 1.3;
  cursor: pointer;
  user-select: none;
}
.tc-select-option[data-active="true"] { background: var(--bg-muted); }
.tc-select-option[aria-selected="true"] { font-weight: 500; }
.tc-select-option[aria-disabled="true"] { color: var(--text-muted); cursor: default; }
.tc-select-check { width: 14px; height: 16px; flex-shrink: 0; display: inline-flex; align-items: center; color: var(--accent); }
.tc-select-hint { display: block; margin-top: 1px; font-size: 12px; font-weight: 400; color: var(--text-muted); }
.tc-select.is-mono .tc-select-value,
.tc-select-menu.is-mono .tc-select-option { font-family: var(--font-mono); font-size: 12.5px; }

/* ── Otis for the merchant: its own screen in the black frame ─────────────
   components/OtisPanel.tsx. Docked beside the page panel from 1180px (the
   dock grows and the page makes room), over the page below that, full screen
   on a phone. Open/closed is <html data-otis-panel>, set before first paint
   by the boot script in root.tsx and kept in step by the panel. */
.otis-dock {
  flex-shrink: 0;
  width: 0;
  overflow: hidden;
  transition: width 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
html[data-otis-panel="open"] .otis-dock { width: 408px; }
.otis-panel {
  box-sizing: border-box;
  width: 400px;
  height: calc(100% - 16px);
  margin: 8px 8px 8px 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background:
    radial-gradient(120% 90px at 50% 0, color-mix(in srgb, var(--otis-light) 70%, transparent), transparent),
    var(--bg);
  box-shadow: var(--shadow-panel);
  opacity: 0;
  transform: translateX(28px);
  visibility: hidden;
  transition: opacity 180ms ease, transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1), visibility 0s linear 240ms;
}
html[data-otis-panel="open"] .otis-panel {
  opacity: 1;
  transform: none;
  visibility: visible;
  transition: opacity 180ms ease 40ms, transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@media (max-width: 1179px) {
  html[data-otis-panel="open"] .otis-dock { width: 0; }
  .otis-dock { overflow: visible; }
  .otis-panel {
    position: fixed;
    top: 8px;
    right: 8px;
    bottom: 8px;
    z-index: 140;
    height: auto;
    width: min(400px, calc(100vw - 16px));
    margin: 0;
    opacity: 1;
    transform: translateX(calc(100% + 16px));
    box-shadow: var(--shadow-panel), var(--shadow-lg);
  }
}
@media (max-width: 768px) {
  .otis-panel { inset: 0; width: 100%; border-radius: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .otis-dock, .otis-panel, html[data-otis-panel="open"] .otis-panel { transition: none !important; }
}

.op-head { height: 48px; flex-shrink: 0; display: flex; align-items: center; gap: 10px; padding: 0 8px 0 16px; }
.op-head > svg { flex-shrink: 0; }
.op-head-name { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.op-head-title { font-size: 13.5px; font-weight: 600; line-height: 17px; }
.op-head-sub { font-size: 11.5px; line-height: 15px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.op-thread { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 8px 16px 14px; display: flex; flex-direction: column; gap: 18px; }
.op-intro { display: flex; flex-direction: column; gap: 16px; padding-top: 6px; }
.op-intro-line { font-size: 16.5px; line-height: 1.45; color: var(--text); }
.op-skills { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; border-radius: var(--radius-md); background: var(--surface); box-shadow: 0 0 0 1px var(--border); }
.op-skills li { display: grid; grid-template-columns: 26px minmax(0, 1fr); column-gap: 10px; row-gap: 6px; padding: 11px 12px; }
.op-skills li + li { border-top: 1px solid var(--border-subtle); }
.op-skill-icon { width: 26px; height: 26px; border-radius: var(--radius); display: inline-flex; align-items: center; justify-content: center; background: var(--bg-muted); color: var(--text-secondary); }
.op-skill-icon.is-shop { background: color-mix(in srgb, var(--accent) 11%, transparent); color: var(--accent); }
.op-skill-icon.is-help { background: var(--bg-muted); color: var(--text-secondary); }
.op-skill-icon.is-change { background: var(--otis-light); color: var(--otis); }
.op-skill-text { display: flex; flex-direction: column; min-width: 0; }
.op-skill-text b { font-size: 13px; font-weight: 600; line-height: 17px; }
.op-skill-text span { font-size: 12px; line-height: 16px; color: var(--text-muted); }
.op-skill-try { grid-column: 2; justify-self: start; max-width: 100%; padding: 0; border: 0; background: none; color: var(--accent); font: inherit; font-size: 12.5px; line-height: 1.4; text-align: left; cursor: pointer; }
.op-skill-try:hover { text-decoration: underline; text-underline-offset: 2px; }

.op-suggest { display: flex; flex-direction: column; gap: 6px; }
.op-suggest-label { font-size: 12px; color: var(--text-muted); }
.op-suggest-btn { display: flex; align-items: center; gap: 8px; width: 100%; min-height: 32px; padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface); color: var(--text); font: inherit; font-size: 12.5px; line-height: 1.4; text-align: left; cursor: pointer; transition: border-color 0.1s ease, background-color 0.1s ease; }
.op-suggest-btn:hover { border-color: var(--border-strong); background: var(--bg-subtle); }
.op-suggest-btn > svg { flex-shrink: 0; color: var(--text-muted); }
.op-suggest-btn.is-change > svg { color: var(--otis); }
.op-follow { padding-top: 2px; }

.op-q { align-self: flex-end; max-width: 88%; padding: 7px 11px; border-radius: 11px 11px 3px 11px; background: var(--bg-muted); font-size: 13px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; scroll-margin-top: 12px; }
.op-a { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.op-byline { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--text-muted); }
.op-byline b { color: var(--otis); font-weight: 500; }
.op-skill-tag { height: 18px; padding: 0 6px; border-radius: var(--radius-pill); background: var(--bg-muted); color: var(--text-secondary); font-size: 11px; line-height: 18px; }
.op-skill-tag.is-change { background: var(--otis-light); color: var(--otis); }
.op-text { font-size: 15.5px; line-height: 1.5; }
.op-thinking-note { font-size: 12px; }
.op-thinking-note::before { content: "· "; }
.op-thinking-lines { display: flex; flex-direction: column; gap: 7px; }

.op-figures { margin: 0; display: grid; gap: 1px; border-radius: var(--radius-md); overflow: hidden; background: var(--border-subtle); box-shadow: 0 0 0 1px var(--border); }
.op-figure { background: var(--surface); padding: 9px 11px; min-width: 0; }
.op-figure dt { font-size: 11.5px; color: var(--text-muted); line-height: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.op-figure dd { margin: 3px 0 0; font-family: var(--font-mono); font-size: 16px; font-weight: 500; line-height: 20px; font-variant-numeric: tabular-nums; }
.op-figure dd span { display: block; margin-top: 1px; font-family: var(--font-body); font-size: 11.5px; font-weight: 400; color: var(--text-muted); line-height: 15px; }

.op-items { list-style: none; margin: 0; padding: 0; border-radius: var(--radius-md); background: var(--surface); box-shadow: 0 0 0 1px var(--border); overflow: hidden; }
.op-items li + li { border-top: 1px solid var(--border-subtle); }
.op-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px 8px 11px; color: var(--text); text-decoration: none; }
.op-item:hover { background: var(--bg-subtle); }
.op-item > svg { flex-shrink: 0; color: var(--text-muted); }
.op-item-dot { width: 7px; height: 7px; flex-shrink: 0; border-radius: 50%; background: var(--border-strong); }
.op-item-dot.is-signal { background: var(--signal); }
.op-item-dot.is-otis { background: transparent; box-shadow: inset 0 0 0 1.5px var(--otis); }
.op-item-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.op-item-label { font-size: 12.5px; line-height: 17px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.op-item-detail { font-size: 12px; line-height: 16px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.op-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.op-steps li { display: flex; gap: 10px; align-items: flex-start; }
.op-steps .tc-voice { font-size: 15px; line-height: 1.45; }
.op-step-n { flex-shrink: 0; width: 19px; height: 19px; margin-top: 1px; border-radius: 50%; background: var(--otis-light); color: var(--otis); font-family: var(--font-mono); font-size: 11px; font-weight: 500; line-height: 19px; text-align: center; }

.op-change { display: flex; flex-direction: column; gap: 10px; padding: 12px; border-radius: var(--radius-md); background: var(--surface); box-shadow: 0 0 0 1px color-mix(in srgb, var(--otis) 30%, var(--border)), 0 0 0 4px color-mix(in srgb, var(--otis-light) 55%, transparent); }
.op-change[data-status="applied"], .op-change[data-status="undone"] { box-shadow: 0 0 0 1px var(--border); }
.op-change-head { display: flex; align-items: center; gap: 8px; min-width: 0; }
.op-change-head > svg { flex-shrink: 0; color: var(--otis); }
.op-change-title { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; line-height: 17px; }
.op-change-where { flex-shrink: 0; font-size: 12px; color: var(--text-muted); text-decoration: none; }
.op-change-where:hover { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.op-change-rows { margin: 0; display: flex; flex-direction: column; gap: 6px; }
.op-change-row { display: grid; grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.4fr); gap: 10px; align-items: baseline; }
.op-change-row dt { font-size: 12px; color: var(--text-muted); line-height: 16px; }
.op-change-row dd { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; font-size: 12.5px; line-height: 17px; }
.op-change-row dd > svg { color: var(--text-muted); flex-shrink: 0; }
.op-change-from { color: var(--text-muted); text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--text-muted) 60%, transparent); }
.op-change[data-status="undone"] .op-change-from { text-decoration: none; color: var(--text); }
.op-change[data-status="undone"] .op-change-to { color: var(--text-muted); text-decoration: line-through; }
.op-change-to { font-weight: 500; }
.op-change-note { font-size: 12px; line-height: 1.45; color: var(--text-secondary); }
.op-change-error { font-size: 12px; line-height: 1.45; color: var(--red); }
.op-change-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.op-change-actions .btn { text-decoration: none; }
.op-change-done { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: space-between; }
.op-change-ok { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: 500; color: var(--ok); }
.op-change-undone { font-size: 12.5px; color: var(--text-secondary); }
.op-change-foot { font-size: 11.5px; color: var(--text-muted); }

.op-sources { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.op-sources-label { font-size: 12px; color: var(--text-muted); margin-right: 2px; }
.op-chip { display: inline-flex; align-items: center; gap: 6px; height: 24px; max-width: 100%; padding: 0 8px; border-radius: var(--radius); background: var(--surface); box-shadow: 0 0 0 1px var(--border); color: var(--text); font-size: 12px; text-decoration: none; transition: box-shadow 0.1s ease, background-color 0.1s ease; }
.op-chip:hover { box-shadow: 0 0 0 1px var(--border-strong); background: var(--bg-subtle); }
.op-chip > svg { flex-shrink: 0; color: var(--text-muted); }
.op-chip > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.op-chip-n { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-muted); }
.op-links { display: flex; flex-wrap: wrap; gap: 6px; }
.op-links .btn { text-decoration: none; }
.op-basis { font-size: 12px; color: var(--text-muted); line-height: 1.45; }
.op-link { padding: 0; border: 0; background: none; color: var(--accent); font: inherit; font-size: 12px; cursor: pointer; }
.op-link:hover { text-decoration: underline; text-underline-offset: 2px; }
.op-fallback { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; border-radius: var(--radius-md); background: var(--bg-subtle); box-shadow: inset 0 0 0 1px var(--border-subtle); }
.op-fallback p { font-size: 12.5px; color: var(--text-secondary); line-height: 1.5; }

.op-composer { flex-shrink: 0; padding: 8px 12px 12px; }
.op-composer-box { border: 1px solid var(--border-strong); border-radius: var(--radius-md); background: var(--surface); transition: border-color 0.12s ease, box-shadow 0.12s ease; }
.op-composer-box:focus-within { border-color: var(--otis); box-shadow: 0 0 0 3px color-mix(in srgb, var(--otis) 16%, transparent); }
.op-composer textarea { display: block; box-sizing: border-box; width: 100%; min-height: 42px; max-height: 168px; resize: none; border: 0; border-radius: var(--radius-md); background: transparent; padding: 11px 12px 2px; color: var(--text); font: inherit; font-size: 13px; line-height: 1.5; }
.op-composer textarea:focus, .op-composer textarea:focus-visible { outline: none; }
.op-composer-foot { display: flex; align-items: center; gap: 8px; padding: 4px 6px 6px 8px; }
.op-context { display: inline-flex; align-items: center; gap: 6px; height: 22px; max-width: 60%; padding: 0 3px 0 8px; border: 0; border-radius: var(--radius-pill); background: var(--bg-muted); color: var(--text-secondary); font: inherit; font-size: 11.5px; white-space: nowrap; overflow: hidden; }
.op-context-dot { width: 6px; height: 6px; flex-shrink: 0; border-radius: 50%; background: var(--otis); }
.op-context button { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--text-muted); cursor: pointer; }
.op-context button:hover { background: var(--border-strong); color: var(--text); }
.op-context.is-off { padding: 0 8px 0 6px; gap: 4px; background: transparent; box-shadow: inset 0 0 0 1px var(--border); color: var(--text-muted); cursor: pointer; }
.op-context.is-off:hover { color: var(--text); box-shadow: inset 0 0 0 1px var(--border-strong); }
.op-composer-hint { flex: 1; min-width: 0; display: inline-flex; justify-content: flex-end; align-items: center; gap: 3px; }

/* The sidebar's "Ask Otis" row: a nav row that toggles the Otis panel. */
.tc-ask-otis { width: 100%; border: 0; background: transparent; font: inherit; text-align: left; cursor: pointer; }
/* Open: a violet wash (Otis), not the grey of the page you're on. */
aside.sidebar .tc-ask-otis[aria-pressed="true"] { background: var(--otis-light); color: #fff; }

/* ── Touch screens (phones, tablets): targets a thumb can hit ──────────────
   The admin is dense for a mouse. On a touch screen every control is at
   least 40px (tabs, segments and chips 34–36px, in their scrolling rows),
   text fields use 16px type (anything smaller and iOS zooms the page when
   you tap into it), and keyboard hints go, with no keyboard to press them on.
   The tab strip sets its size inline (PageHeader tabStyle), hence !important. */
@media (pointer: coarse) {
  .btn { min-height: 40px; padding: 0 14px; font-size: 13.5px; }
  .btn-sm { min-height: 36px; padding: 0 12px; font-size: 13px; }
  .tc-icon-btn { width: 40px; height: 40px; }
  .tc-tab { height: 36px !important; padding: 0 12px !important; font-size: 13.5px !important; }
  .tc-seg > button,
  .tc-seg > a { height: 34px; padding: 0 12px; font-size: 13px; }
  .tc-select-trigger { min-height: 40px; font-size: 14px; }
  .tc-select.is-sm .tc-select-trigger { min-height: 36px; font-size: 13.5px; }
  .tc-select-option { min-height: 44px; align-items: center; font-size: 15px; }
  /* Switches (config-form.tsx) draw inline at 30×18: a phone-sized switch,
     with a tap area past its edges. */
  .tc-switch { width: 40px !important; height: 24px !important; }
  .tc-switch > span { top: 4px !important; left: 4px !important; width: 16px !important; height: 16px !important; }
  .tc-switch[aria-checked="true"] > span { left: 20px !important; }
  .tc-switch::after { content: ""; position: absolute; inset: -10px -6px; }
  /* A section head's action link ("Open", "View all"): a taller tap area. */
  .tc-section-head a { padding: 10px 0; margin: -10px 0; }
  .input, .select { min-height: 40px; }
  /* !important: many fields set a smaller size inline, and those would still zoom. */
  .input, .textarea, .select, textarea,
  input:not([type]), input[type="text"], input[type="email"], input[type="search"],
  input[type="url"], input[type="tel"], input[type="number"], input[type="password"] { font-size: 16px !important; }
  .tc-kbd, .tc-palette-keys { display: none !important; }
  aside.sidebar .tc-nav-item { height: 40px; }
  aside.sidebar .tc-nav-sub .tc-nav-item { height: 36px; }
}
