/* ==========================================================================
   base.css — Wave 0 component kit for the new console shell.

   RULES THIS FILE MUST FOLLOW (see task spec / semantic variable contract):
   - Every color reference is one of: --surface, --surface-2, --text,
     --text-muted, --line, --accent, --on-accent, --focus-ring, --good,
     --warn, --crisis, --brand-accent. NEVER a literal hex/rgb/hsl anywhere
     below — this file is grep-gated by check-theme.mjs.
   - Where a translucent variant of a semantic color is needed (scrims,
     shimmer, disabled overlays) we use color-mix(in srgb, var(--X) N%,
     transparent) instead of rgba()/hsla() literals, so no raw color value
     ever appears in this file.
   - --accent/--brand-accent resolution (per-theme, per-org) happens in the
     token stylesheet that defines data-theme/data-mode blocks, NOT here.
     This file only *consumes* var(--accent) etc.
   - Nav STRUCTURE (bottom tab bar vs. left rail) is switched by a body
     class — `nav-compact` or `nav-full` — set by JS via matchMedia at the
     ~640px breakpoint (wired in a later stage). Both layouts are fully
     styled here now, keyed off those two body classes.
   - Class names for toast/modal below are chosen to match what
     app/ui.js actually renders (kcc-toast / kcc-toast show / kcc-toast show
     err from toast(); openModal()/closeModal() toggle a bare element's
     inline display + aria-hidden, so `.kcc-modal-overlay` below supplies
     the *default* (open) display value that reasserts itself once JS
     clears the inline `display:none` override — markup for a closed modal
     must start with an explicit inline `style="display:none"`, same as the
     existing index.html modals).
   - prefers-reduced-motion: every transition/animation declared below lives
     inside a `(prefers-reduced-motion: no-preference)` block, and a single
     catch-all `(prefers-reduced-motion: reduce)` block at the end forces
     `animation:none; transition:none` on every animated surface in this
     file as a belt-and-suspenders backstop.
   ========================================================================== */

/* ---------- reset / base ----------
   Document-level base: this runs regardless of whether a given page wraps its
   content in .kcc-shell (the tool proof-of-concept in Wave 0 does not, since
   the full shell chrome — topbar/rail/tabbar — is wired in a later phase).
   Sets the professional system-font stack (no third-party font request here
   — Google Fonts vs. self-hosting the brand fonts is still an open plan
   question; this stack is dependency-free and reads as clean/professional
   in the interim) plus the base surface/text colors so nothing ever falls
   back to the browser's default serif + 8px margin. */

html {
  color-scheme: light dark;
  /* Root font-size is the anchor for the whole rem-based type/space scale AND for the
     user-facing TEXT-SIZE control (user menu). Comfortable = 100% (the browser default, ~16px);
     Large/Larger scale everything that uses rem up together. Stamped pre-paint on <html> as
     data-textsize by app.html, so there's no flash. */
  font-size: 100%;
}

:root[data-textsize='large'] { font-size: 112.5%; }
:root[data-textsize='larger'] { font-size: 125%; }

/* ==========================================================================
   Design-scale tokens (type / weight / spacing / radius / elevation / motion).
   Colors are NOT here — those live in styles/tokens.css per theme+mode. Every
   value below is unit-based (rem/ms/cubic-bezier) or a mode-aware color-mix,
   so this block adds no literal color to the grep-gated surface.
   ========================================================================== */
:root {
  /* Heading face — warm, surgical: titles / hero / login only (spec §1). Body stays system. */
  --font-heading: 'Fraunces', 'Lora', Georgia, serif;
  --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  /* Type scale + paired line-heights. */
  --fs-display: 1.75rem;   --lh-display: 1.15;
  --fs-title: 1.3125rem;   --lh-title: 1.25;
  --fs-heading: 1.0625rem; --lh-heading: 1.35;
  --fs-body: 1rem;         --lh-body: 1.5;
  --fs-sm: 0.875rem;       --lh-sm: 1.45;
  --fs-label: 0.8125rem;   --lh-label: 1.35;
  --fs-caption: 0.75rem;   --lh-caption: 1.35;
  --fs-micro: 0.6875rem;   --lh-micro: 1.3;

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  /* Spacing — 4px grid. */
  --space-1: 0.25rem;
  --space-1_5: 0.375rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;

  /* Radius. */
  --radius-xs: 0.375rem;
  --radius-sm: 0.5rem;
  --radius-md: 0.625rem;
  --radius-lg: 0.75rem;
  --radius-xl: 1rem;
  --radius-pill: 999px;

  /* Elevation — warm + subtle. Mode-aware: shadow color mixes over --text in light. */
  --shadow-1: 0 1px 2px 0 color-mix(in srgb, var(--text) 8%, transparent);
  --shadow-2: 0 4px 12px -2px color-mix(in srgb, var(--text) 14%, transparent),
    0 2px 4px -2px color-mix(in srgb, var(--text) 10%, transparent);
  --shadow-3: 0 14px 34px -6px color-mix(in srgb, var(--text) 22%, transparent),
    0 4px 10px -4px color-mix(in srgb, var(--text) 14%, transparent);

  /* Motion — barely-there, confirms causality (spec §1). */
  --dur-1: 80ms;
  --dur-2: 140ms;
  --dur-3: 200ms;
  --dur-4: 320ms;
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
}

/* Dark mode: shadows read as a soft dark halo around the (lighter) floating surface, mixed over
   --surface (the dark page color) since there's no darker semantic token. Elevation in dark leans
   mostly on the lifted --surface-2 background + hairline, per spec. */
:root[data-mode='dark'] {
  --shadow-1: 0 1px 2px 0 color-mix(in srgb, var(--surface) 70%, transparent);
  --shadow-2: 0 4px 14px -2px color-mix(in srgb, var(--surface) 82%, transparent),
    0 2px 6px -2px color-mix(in srgb, var(--surface) 72%, transparent);
  --shadow-3: 0 16px 40px -6px color-mix(in srgb, var(--surface) 88%, transparent),
    0 4px 12px -4px color-mix(in srgb, var(--surface) 80%, transparent);
}

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Screen-reader-only utility (visible content stays visible; this is for a11y-only labels). */
.kcc-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Tabular-numerals utility for meters, %, timestamps, counts, hex (spec §1). */
.kcc-tnum {
  font-variant-numeric: tabular-nums;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Shared focus treatment for every interactive element this kit renders.
   --focus-ring is intentionally NOT derived from brand hue (contract), so
   focus stays visible regardless of org accent color. */
.kcc-shell a:focus-visible,
.kcc-shell button:focus-visible,
.kcc-shell input:focus-visible,
.kcc-shell select:focus-visible,
.kcc-shell textarea:focus-visible,
.kcc-shell [tabindex]:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

/* ==========================================================================
   App shell — top bar + content, with either a bottom tab bar (nav-compact)
   or a left rail (nav-full). Both are written now; JS toggles the body
   class in a later stage.
   ========================================================================== */

.kcc-shell {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  background: var(--surface);
  color: var(--text);
}

.kcc-topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  min-height: 3.5rem;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  -webkit-backdrop-filter: saturate(1.4) blur(8px);
  backdrop-filter: saturate(1.4) blur(8px);
  border-bottom: 1px solid var(--line);
}
.kcc-topbar.is-scrolled {
  box-shadow: var(--shadow-1);
}

.kcc-topbar-lead {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}
.kcc-topbar-mid {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
  min-width: 0;
}
.kcc-topbar-actions {
  display: flex;
  align-items: center;
  gap: var(--space-1_5);
  flex: 0 0 auto;
}

/* Brand: logo/monogram + org name (serif).

   `min-width: auto` is load-bearing, not a default left in by accident. This said `min-width: 0`
   until 2026-08-28, which let flex squeeze the whole brand to its padding — 8px — while the mark
   inside it kept its fixed 2rem and simply overflowed. The next item in the lead then laid out on
   top of the monogram: at side-panel width the chosen-role pill painted over the "C" of "LC". The
   org name still ellipsizes under pressure, because `.kcc-brand-name` sets its own `overflow:
   hidden` and so contributes nothing to this minimum. What must give way is the pill, below. */
.kcc-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  text-decoration: none;
  color: var(--text);
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-1);
  min-width: auto;
}
.kcc-brand-mark {
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-sm);
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--accent) 14%, var(--surface-2));
  color: var(--accent);
  font-weight: var(--fw-bold);
  font-size: var(--fs-sm);
}
.kcc-brand-mark .kcc-brand-logo-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.kcc-brand-name {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-heading);
  letter-spacing: 0.005em;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 12rem;
}

/* Workspace-lens switcher (a view lens, not a privilege change). */
.kcc-lens {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1);
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  border: 1px solid var(--line);
}
.kcc-lens-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1_5);
  border: 0;
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-pill);
  cursor: pointer;
  white-space: nowrap;
}
.kcc-lens-btn:hover { color: var(--text); }
.kcc-lens-btn.is-active {
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-1);
}
.kcc-lens-ico { display: inline-flex; font-size: 1.05em; }

/* Chosen-role pill. Present ONLY while a narrowed view is on, and deliberately NOT hidden at the
   compact breakpoint the way the workspace lens is: the Chrome side panel is phone-width, so compact
   is where this gets read, and a console that quietly shows fewer screens with no visible reason is
   the confusion this whole feature exists to end. At that width it takes the organization's name's
   place — the brand mark still links home, and the org name is on the page itself. */
.kcc-viewpill {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1_5);
  padding: var(--space-1) var(--space-2);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  cursor: pointer;
  white-space: nowrap;
}
.kcc-viewpill:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
.kcc-viewpill-ico { display: inline-flex; color: var(--accent); }
/* Only bites when something has constrained the pill's width, which happens at the compact
   breakpoint and nowhere else — see the `flex: 0 1 auto` there. A panel dragged narrower than the
   topbar's content then truncates the role name rather than letting the pill slide over the brand or
   shove the icon buttons off the right edge. "Coordina…" is legible; two things drawn on top of each
   other is not. Kept off desktop deliberately: making the pill shrinkable up there let flex collapse
   it to an 18px stub while 200px of the row sat empty (measured at 700px, 2026-08-28). */
.kcc-viewpill-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Breadcrumb page label (body font — serif is reserved for brand + content H1). */
.kcc-crumb {
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 14rem;
}
@media (prefers-reduced-motion: no-preference) {
  .kcc-crumb.is-rising { animation: kcc-rise var(--dur-3) var(--ease-out); }
}
@keyframes kcc-rise {
  from { opacity: 0; transform: translateY(0.35rem); }
  to { opacity: 1; transform: translateY(0); }
}

/* Persistent search entry (opens the ⌘K palette). */
.kcc-search-box {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  width: min(20rem, 100%);
  max-width: 20rem;
  padding: var(--space-1_5) var(--space-3);
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text-muted);
  font: inherit;
  font-size: var(--fs-sm);
  cursor: text;
  text-align: left;
}
.kcc-search-box:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }
.kcc-search-text { flex: 1 1 auto; }
.kcc-search-kbd { margin-left: auto; }
.kcc-search-icon-only { display: none; }

.kcc-kbd {
  font-family: var(--font-body);
  font-size: var(--fs-micro);
  color: var(--text-muted);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-xs);
  padding: 0.05rem 0.35rem;
  line-height: 1.4;
}

/* Row that holds the optional left rail + the main content pane. */
.kcc-body {
  flex: 1 1 auto;
  display: flex;
  min-height: 0; /* allow children to scroll instead of pushing the shell */
}

.kcc-content {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  overflow-y: auto;
  padding: var(--space-4);
}
.kcc-content:focus { outline: none; } /* it's a scroll/focus target (tabindex=-1), not a control */

/* WHY `overflow-y: auto` above scrolls nothing, and what it costs.
   The shell is `min-height: 100dvh`, not `height`, so the flex chain never gets a definite height:
   .kcc-content grows to fit its tool and the DOCUMENT is what scrolls. Measured in the running app —
   the pane's scrollTop cannot be moved off 0. The one mode that does give .kcc-shell a definite
   height, html.kcc-chat-docked, sets `display: none` on this very element. So the declaration has
   never scrolled anything in either mode.
   It is not inert, though. A non-visible overflow makes a box a scroll container, and a scroll
   container is the scrollport every descendant `position: sticky` measures itself against. Binding
   them to a port that never moves is why the call note's rail has carried a sticky rule since it was
   written and has never once stuck: at scrollY 1001 its top measured -651px, and flipping this one
   declaration to `visible` in the live page put it at 8px, exactly its `top: .5rem`.
   Removing it outright is a shell-wide change: because CSS couples the axes, the horizontal clipping
   it currently provides for free would go with it, and a tool with a wide table would hand the
   document a horizontal scrollbar instead of scrolling inside the pane. That is a sweep of every tool,
   not a line. So this opts ONE route out, the call script, which is where a coordinator asked for a
   note that stays in the corner, and which owns its own `overflow-x` already. tools/coordinate/playbook
   adds and removes the class in mount/unmount, the same way app/chatsurface.js drives kcc-chat-docked.
   The shell-wide fix is an item in BACKLOG.md — this is the scoped half of it, not a claim it is done. */
html.kcc-callscript .kcc-content { overflow: visible; }

.kcc-content-inner {
  max-width: 60rem;
  margin: 0 auto;
}
@media (prefers-reduced-motion: no-preference) {
  .kcc-content-inner.is-entering { animation: kcc-tool-enter var(--dur-3) var(--ease-out); }
}
@keyframes kcc-tool-enter {
  from { opacity: 0; transform: translateY(0.375rem); }
  to { opacity: 1; transform: translateY(0); }
}

/* Page head — the H1 (focus target) + short description, above the mounted tool. */
.kcc-page-head { margin-bottom: var(--space-4); }
.kcc-page-head:empty { display: none; }
.kcc-page-title {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-title);
  line-height: var(--lh-title);
  color: var(--text);
  margin: 0;
}
.kcc-page-title:focus { outline: none; } /* moved-to focus target; ring would read as an error */
.kcc-page-desc {
  margin: var(--space-1) 0 0;
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

/* Hybrid welcome header (role-tailored) — serif hero atop the primary tool. */
.kcc-welcome { margin-bottom: var(--space-2); }
.kcc-welcome-title {
  font-family: var(--font-heading);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  color: var(--text);
  margin: 0;
}
.kcc-welcome-title:focus { outline: none; }
.kcc-welcome-sub {
  margin: var(--space-1) 0 0;
  color: var(--text-muted);
  font-size: var(--fs-body);
}
.kcc-welcome-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.kcc-welcome-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.kcc-welcome-nudge { margin-top: var(--space-4); }

/* --- nav-full: left rail --- */
.kcc-rail {
  display: none; /* default: hidden until body.nav-full */
  flex-direction: column;
  flex: 0 0 auto;
  width: 15rem;
  padding: var(--space-3);
  background: var(--surface);
  border-right: 1px solid var(--line);
  overflow-y: auto;
}
body.nav-full .kcc-rail { display: flex; }

/* --- is-rail-thin: the rail as an icon strip --- */
/* Set by shell.setActive() while the current tool declares `rail: 'thin'` in app/registry.js —
   Messages and Dashboard today. A conversation screen is three columns wide on its own (the thread
   list, the thread, and the room panel), and next to it the 15rem labelled nav was the widest column
   while being the least used. Labels and section titles go; each icon keeps its `title`, so hovering
   still names the screen, and the sliding indicator still marks the current one. The shell root
   carries the class rather than the rail because the mobile sheet reuses the same items and must
   keep its labels — this rule reaches only `.kcc-rail`. */
.kcc-shell.is-rail-thin .kcc-rail {
  width: 3.75rem;
  padding: var(--space-3) var(--space-2);
  overflow-x: hidden;
}
.kcc-shell.is-rail-thin .kcc-rail .kcc-nav-section-title {
  /* The section name has no room; a hairline keeps the grouping legible. */
  height: 0;
  padding: 0;
  margin: 0 var(--space-1) var(--space-2);
  border-top: 1px solid var(--line);
  overflow: hidden;
  color: transparent;
}
.kcc-shell.is-rail-thin .kcc-rail .kcc-nav-section:first-child .kcc-nav-section-title { border-top: none; margin-bottom: 0; }
.kcc-shell.is-rail-thin .kcc-rail .kcc-rail-item {
  position: relative;
  justify-content: center;
  gap: 0;
  width: 2.75rem;
  min-height: 2.75rem;
  margin: 0 auto;
  padding: 0;
}
.kcc-shell.is-rail-thin .kcc-rail .kcc-rail-item .kcc-nav-label { display: none; }
.kcc-shell.is-rail-thin .kcc-rail .kcc-rail-item .kcc-nav-ico { font-size: 1.3em; }
.kcc-shell.is-rail-thin .kcc-rail .kcc-rail-item .kcc-nav-lock {
  position: absolute;
  top: 0.3rem;
  right: 0.3rem;
  font-size: 0.7em;
}
/* The same state widens the page. `.kcc-content-inner` is capped at 60rem because a form or a
   settings page reads badly at full width; a three-column conversation screen does not, and at 60rem
   the three of them were sharing 960px — the thread pane came out narrower than the thread list. The
   rail's declaration says "this screen is columns", so it lifts the cap; nothing else does. */
.kcc-shell.is-rail-thin .kcc-content-inner { max-width: none; }
@media (prefers-reduced-motion: no-preference) {
  .kcc-rail { transition: width var(--dur-3) var(--ease-out), padding var(--dur-3) var(--ease-out); }
}

/* Positioned wrapper so the sliding indicator can be absolutely placed against the items. */
.kcc-rail-nav { position: relative; }

.kcc-rail-indicator {
  position: absolute;
  left: 0;
  top: 0;
  width: 3px;
  height: 0;
  border-radius: var(--radius-pill);
  background: var(--accent);
  opacity: 0;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .kcc-rail-indicator { transition: transform var(--dur-3) var(--ease-out), height var(--dur-3) var(--ease-out), opacity var(--dur-2) var(--ease-standard); }
}

.kcc-nav-section + .kcc-nav-section { margin-top: var(--space-3); }
.kcc-nav-section-title {
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 0 var(--space-2) var(--space-1);
}
.kcc-rail-list { display: flex; flex-direction: column; gap: 0.15rem; }

.kcc-rail-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 44px;
  padding: var(--space-2) var(--space-2);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  text-decoration: none;
  background: transparent;
  border: none;
  text-align: left;
  cursor: pointer;
  font: inherit;
  font-size: var(--fs-sm);
}
.kcc-rail-item:hover { background: var(--surface-2); color: var(--text); }
.kcc-rail-item.is-active {
  background: var(--surface-2);
  color: var(--accent);
  font-weight: var(--fw-semibold);
}
.kcc-nav-ico { flex: 0 0 auto; display: inline-flex; font-size: 1.15em; }
.kcc-nav-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kcc-nav-lock { flex: 0 0 auto; display: inline-flex; color: var(--warn); font-size: 0.9em; }
@media (prefers-reduced-motion: no-preference) {
  .kcc-rail-item { transition: background var(--dur-2) var(--ease-standard), color var(--dur-2) var(--ease-standard); }
}

/* --- nav-compact: bottom tab bar --- */
.kcc-tabbar {
  display: none; /* default: hidden until body.nav-compact */
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 20;
  align-items: stretch;
  justify-content: space-around;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  -webkit-backdrop-filter: saturate(1.4) blur(8px);
  backdrop-filter: saturate(1.4) blur(8px);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
body.nav-compact .kcc-tabbar { display: flex; }

/* Reserve room so tabbar-fixed content doesn't hide the last bit of content. */
body.nav-compact .kcc-content {
  padding-bottom: calc(var(--space-4) + 3.5rem + env(safe-area-inset-bottom, 0px));
}

/* --- is-navless: the shell with nothing in its nav --- */
/* Set by shell.js when this person's composition resolves to no tools at all — a guest today, and
   any composition an org narrows to nothing tomorrow. The rail and the tab bar are not rendered, so
   the only thing left to undo is the room the fixed tab bar reserved beneath the content: 3.5rem of
   blank space under a screen with no bar below it, which reads as a page that failed to finish. */
body.nav-compact .kcc-shell.is-navless .kcc-content {
  padding-bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
}

/* Sliding underline indicator (signature motion, mirrors the rail bar). */
.kcc-tab-indicator {
  position: absolute;
  top: 0;
  left: 0;
  height: 3px;
  width: 0;
  border-radius: var(--radius-pill);
  background: var(--accent);
  opacity: 0;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .kcc-tab-indicator { transition: transform var(--dur-3) var(--ease-out), width var(--dur-3) var(--ease-out), opacity var(--dur-2) var(--ease-standard); }
}

.kcc-tab-item {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.15rem;
  padding: var(--space-2) var(--space-1) calc(var(--space-2) + 0.1rem);
  min-height: 3.5rem;
  background: transparent;
  border: none;
  color: var(--text-muted);
  font: inherit;
  font-size: var(--fs-micro);
  font-weight: var(--fw-medium);
  cursor: pointer;
}
.kcc-tab-ico { font-size: 1.35rem; display: inline-flex; flex: 0 0 auto; }
.kcc-tab-item.is-active { color: var(--accent); }

/* Five slots at 360px is ~72px each, so a label must survive ~68px of usable width. Two things make
   that work rather than hoping: `navLabel` in app/registry.js shortens the few names that cannot fit
   ("Network health" -> "Health"), and anything still too long ellipsizes on ONE line instead of
   wrapping — a wrapped label grows the bar's height, which in a fixed bottom bar silently eats the
   content padding calculated against 3.5rem and clips the last row of every screen. */
.kcc-tab-label {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: 1.15;
}
/* The bar's items are real destinations now, so a tier lock can appear on one. Small and quiet — it
   is a fact about the screen, not a call to action. */
.kcc-tab-item .kcc-nav-lock {
  position: absolute;
  top: 0.35rem;
  right: 0.55rem;
  font-size: 0.7rem;
  opacity: 0.75;
}
.kcc-tab-item { position: relative; }

/* ==========================================================================
   Buttons
   ========================================================================== */

.kcc-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.55rem 1rem;
  border-radius: 0.5rem;
  border: 1px solid transparent;
  font: inherit;
  font-weight: 600;
  font-size: 0.9rem;
  cursor: pointer;
  white-space: nowrap;
}

.kcc-btn:disabled {
  cursor: not-allowed;
  /* translucent variant of --text-muted, no literal color values */
  color: color-mix(in srgb, var(--text-muted) 70%, transparent);
  border-color: var(--line);
  background: var(--surface-2);
}

.kcc-btn-primary {
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--accent);
}

.kcc-btn-primary:hover:not(:disabled) {
  /* slightly recessed accent on hover, still no literal color */
  background: color-mix(in srgb, var(--accent) 88%, var(--text));
}

.kcc-btn-secondary {
  background: var(--surface-2);
  color: var(--text);
  border-color: var(--line);
}

.kcc-btn-secondary:hover:not(:disabled) {
  background: color-mix(in srgb, var(--surface-2) 85%, var(--text));
}

.kcc-btn-danger {
  background: var(--surface-2);
  color: var(--crisis);
  border-color: var(--crisis);
}

.kcc-btn-danger:hover:not(:disabled) {
  background: color-mix(in srgb, var(--surface-2) 80%, var(--crisis));
}

/* ==========================================================================
   Form inputs
   ========================================================================== */

.kcc-field {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-bottom: 0.9rem;
}

.kcc-field-label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-muted);
}

.kcc-field-hint {
  font-size: 0.75rem;
  color: var(--text-muted);
}

.kcc-input,
.kcc-select,
.kcc-textarea {
  width: 100%;
  padding: 0.55rem 0.7rem;
  border-radius: 0.5rem;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  font: inherit;
}

.kcc-input::placeholder,
.kcc-textarea::placeholder {
  color: var(--text-muted);
}

.kcc-input:disabled,
.kcc-select:disabled,
.kcc-textarea:disabled {
  background: var(--surface-2);
  color: var(--text-muted);
}

.kcc-textarea {
  resize: vertical;
  min-height: 5rem;
}

.kcc-field.has-error .kcc-input,
.kcc-field.has-error .kcc-select,
.kcc-field.has-error .kcc-textarea {
  border-color: var(--crisis);
}

.kcc-field-error {
  font-size: 0.75rem;
  color: var(--crisis);
}

/* ==========================================================================
   Toast — must match app/ui.js exactly:
   toast() sets className to "kcc-toast" (hidden), "kcc-toast show"
   (visible/ok), or "kcc-toast show err" (visible/error).
   ========================================================================== */

.kcc-toast {
  position: fixed;
  left: 50%;
  bottom: 1.25rem;
  z-index: 50;
  max-width: min(90vw, 22rem);
  padding: 0.65rem 1rem;
  border-radius: 0.6rem;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--line);
  border-left: 3px solid var(--good);
  box-shadow: none;
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 0.5rem);
  pointer-events: none;
}

.kcc-toast.show {
  visibility: visible;
  opacity: 1;
  transform: translate(-50%, 0);
}

.kcc-toast.show.err {
  border-left-color: var(--crisis);
}

@media (prefers-reduced-motion: no-preference) {
  .kcc-toast {
    transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
  }
}

/* ==========================================================================
   Modal / overlay
   openModal(el)/closeModal() only toggle inline display + aria-hidden on a
   bare element, so the *stylesheet* default below is the OPEN appearance;
   markup must start with an inline style="display:none" to be closed.
   ========================================================================== */

.kcc-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  /* scrim: translucent --text over --surface, no rgba()/hex literal */
  background: color-mix(in srgb, var(--text) 55%, transparent);
}

.kcc-modal-overlay[aria-hidden='true'] {
  display: none;
}

.kcc-modal {
  width: 100%;
  max-width: 30rem;
  max-height: min(90vh, 40rem);
  overflow-y: auto;
  /* A dialog taller than its box (Records' partner form is ~900px in a 640px box) is scrolled to its
     end constantly. Without this, that last wheel notch chains to the page and moves the list behind
     it. The scroll lock covers this too; both, because contain also holds on the pointer-over-scrim
     case and on engines where the lock is weaker. */
  overscroll-behavior: contain;
  border-radius: 0.75rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--line);
  padding: 1.25rem;
}

.kcc-modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.75rem;
}

.kcc-modal-title {
  font-weight: 700;
  color: var(--text);
}

.kcc-modal-close {
  background: transparent;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font: inherit;
  font-size: 1.1rem;
  line-height: 1;
  padding: 0.2rem;
}

.kcc-modal-close:hover {
  color: var(--text);
}

.kcc-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 1rem;
}

@media (prefers-reduced-motion: no-preference) {
  .kcc-modal {
    animation: kcc-modal-in 0.16s ease;
  }

  @keyframes kcc-modal-in {
    from {
      opacity: 0;
      transform: translateY(0.5rem);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }
}

/* ==========================================================================
   Card
   ========================================================================== */

.kcc-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 0.75rem;
  padding: 1rem;
}

.kcc-card + .kcc-card {
  margin-top: 0.75rem;
}

.kcc-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.6rem;
}

.kcc-card-title {
  font-weight: 700;
  color: var(--text);
}

.kcc-card-subtitle {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.kcc-card.is-raised {
  background: var(--surface-2);
}

/* Status dot for cards that show availability/urgency (good/warn/crisis). */
.kcc-status-dot {
  display: inline-block;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 999px;
  background: var(--good);
  flex: 0 0 auto;
}

.kcc-status-dot.is-warn {
  background: var(--warn);
}

.kcc-status-dot.is-crisis {
  background: var(--crisis);
}

/* ==========================================================================
   Loading state — skeleton + spinner
   ========================================================================== */

.kcc-skeleton {
  display: block;
  border-radius: 0.4rem;
  background: linear-gradient(
    90deg,
    var(--surface-2) 25%,
    color-mix(in srgb, var(--surface-2) 60%, var(--line)) 37%,
    var(--surface-2) 63%
  );
  background-size: 200% 100%;
  color: transparent; /* so skeletons can wrap placeholder text without showing it */
}

.kcc-skeleton.kcc-skeleton-text {
  height: 0.8em;
  margin: 0.2em 0;
}

.kcc-skeleton.kcc-skeleton-line {
  height: 1rem;
  width: 100%;
}

.kcc-skeleton.kcc-skeleton-block {
  height: 5rem;
  width: 100%;
}

.kcc-skeleton.kcc-skeleton-avatar {
  height: 2.5rem;
  width: 2.5rem;
  border-radius: 999px;
}

@media (prefers-reduced-motion: no-preference) {
  .kcc-skeleton {
    animation: kcc-skeleton-shimmer 1.4s ease-in-out infinite;
  }

  @keyframes kcc-skeleton-shimmer {
    0% {
      background-position: 200% 0;
    }
    100% {
      background-position: -200% 0;
    }
  }
}

.kcc-spinner {
  display: inline-block;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 999px;
  border: 2px solid var(--line);
  border-top-color: var(--accent);
  vertical-align: middle;
}

.kcc-spinner.is-lg {
  width: 2rem;
  height: 2rem;
  border-width: 3px;
}

@media (prefers-reduced-motion: no-preference) {
  .kcc-spinner {
    animation: kcc-spin 0.7s linear infinite;
  }

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

/* ==========================================================================
   Buttons — sizes, ghost, icon-button, block, active press, loading
   (additive to the base .kcc-btn / primary / secondary / danger above).
   ========================================================================== */
.kcc-btn { border-radius: var(--radius-sm); }
/* `.kcc-btn` sets display:inline-flex, which OUTRANKS the user-agent `[hidden] { display: none }` —
   so `button.hidden = true` on any button in this app silently did nothing. Caught live on the
   side-panel pairing screen, where the "Get a fresh code" button stayed visible from first paint.
   Same per-component form the other [hidden] rules in this file use. */
.kcc-btn[hidden] { display: none; }
.kcc-btn:active:not(:disabled) { transform: scale(0.98); }
.kcc-btn-sm { padding: var(--space-1_5) var(--space-3); font-size: var(--fs-label); }
.kcc-btn-lg { padding: var(--space-3) var(--space-5); font-size: var(--fs-body); min-height: 44px; }
.kcc-btn-block { width: 100%; }
.kcc-btn-ghost { background: transparent; color: var(--text-muted); border-color: transparent; }
.kcc-btn-ghost:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }
.kcc-btn.is-loading { position: relative; color: transparent !important; pointer-events: none; }
.kcc-btn.is-loading::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1.1em;
  height: 1.1em;
  margin: -0.55em 0 0 -0.55em;
  border-radius: var(--radius-pill);
  border: 2px solid color-mix(in srgb, var(--on-accent) 45%, transparent);
  border-top-color: var(--on-accent);
}
@media (prefers-reduced-motion: no-preference) {
  .kcc-btn { transition: background var(--dur-2) var(--ease-standard), transform var(--dur-1) var(--ease-standard), border-color var(--dur-2) var(--ease-standard); }
  .kcc-btn.is-loading::after { animation: kcc-spin 0.7s linear infinite; }
}

/* Icon-only button (≥44px tap target). */
.kcc-iconbtn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  font: inherit;
  font-size: 1.15rem;
}
.kcc-iconbtn:hover { background: var(--surface-2); color: var(--text); }
/* The Messages button. One button since 2026-08-31 — there were two, a bell and a speech-bubble,
   landing on two different screens, and the one that looked most like "messages" was the one that did
   not open the Messages screen. The icon goes from muted to full-strength when something is waiting. */
.kcc-messages.has-unread { color: var(--text); }

/* The live-call chip. A coordinator mid-call can be on any screen in the console — Messages, the
   directory, a record — and before this existed there was nothing on those screens to say a call was
   still open, or any way back to it that did not go through the menu. It renders ONLY while a call is
   parked in app/callsession.js, so it needs no role or tier gate: no call, no chip. */
.kcc-livecall {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  height: 2.25rem;
  padding: 0 0.6rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
  color: var(--text);
  font: inherit;
  font-size: var(--fs-micro);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.kcc-livecall:hover { background: color-mix(in srgb, var(--accent) 20%, var(--surface)); }
.kcc-livecall svg { color: var(--accent); font-size: 1rem; flex: 0 0 auto; }
/* Narrow screens keep the chip but drop its words — the dot of colour beside the phone is what has
   to survive, because it is the only thing telling someone a call is still open. */
@media (max-width: 40rem) {
  .kcc-livecall-text { display: none; }
  .kcc-livecall { padding: 0 0.5rem; }
}

.kcc-count-badge {
  position: absolute;
  top: 0.35rem;
  right: 0.35rem;
  min-width: 1.05rem;
  height: 1.05rem;
  padding: 0 0.25rem;
  border-radius: var(--radius-pill);
  background: var(--crisis);
  color: var(--on-accent);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-variant-numeric: tabular-nums;
}
.kcc-count-badge[hidden] { display: none; }

/* ==========================================================================
   Avatar
   ========================================================================== */
.kcc-avatar {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--accent) 16%, var(--surface-2));
  color: var(--accent);
  font-weight: var(--fw-bold);
  font-size: var(--fs-sm);
}
.kcc-avatar-lg { width: 2.75rem; height: 2.75rem; font-size: var(--fs-body); }
.kcc-avatar-btn { width: 2.75rem; height: 2.75rem; border: 1px solid var(--line); cursor: pointer; }
.kcc-avatar-btn:hover { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }

/* ==========================================================================
   User menu (dropdown)
   ========================================================================== */
.kcc-usermenu-wrap { position: relative; }
.kcc-menu {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 60;
  width: 18rem;
  max-width: calc(100vw - 1.5rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  padding: var(--space-3);
}
:root[data-mode='dark'] .kcc-menu { background: var(--surface-2); }
.kcc-menu[hidden] { display: none; }
.kcc-menu-id { display: flex; gap: var(--space-2); align-items: center; padding-bottom: var(--space-2); }
.kcc-menu-id-text { min-width: 0; display: flex; flex-direction: column; }
.kcc-menu-id-name { font-weight: var(--fw-semibold); color: var(--text); }
.kcc-menu-id-email { font-size: var(--fs-caption); color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kcc-menu-group { padding: var(--space-2) 0; }
.kcc-menu-group-title { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin-bottom: var(--space-1_5); }
.kcc-menu-sep { height: 1px; background: var(--line); margin: var(--space-1) 0; }
.kcc-menu-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 44px;
  padding: var(--space-2);
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-sm);
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-align: left;
}
.kcc-menu-item:hover { background: var(--surface-2); }
.kcc-menu-item-danger { color: var(--crisis); }
.kcc-swatch-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.kcc-swatch {
  width: 1.75rem;
  height: 1.75rem;
  border-radius: var(--radius-pill);
  border: 2px solid var(--line);
  cursor: pointer;
  padding: 0;
  background: linear-gradient(135deg, var(--kcc-swatch-b) 0 50%, var(--kcc-swatch-a) 50% 100%);
}
.kcc-swatch.is-active { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent); }

/* Role-view picker rows inside the user menu (only rendered for someone holding more than one role).
   Reuses .kcc-menu-item wholesale; this adds the two-line label, the tick, and a chosen state. */
.kcc-menu-item-fill { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.kcc-menu-item-label { color: var(--text); }
.kcc-menu-item-sub { font-size: var(--fs-caption); color: var(--text-muted); }
.kcc-menu-item-check { flex: 0 0 auto; display: inline-flex; color: var(--accent); }
.kcc-menu-item.is-active { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.kcc-menu-item.is-active .kcc-menu-item-label { font-weight: var(--fw-semibold); }
@media (prefers-reduced-motion: no-preference) {
  .kcc-menu { animation: kcc-pop var(--dur-2) var(--ease-out); }
  .kcc-menu-item, .kcc-swatch { transition: background var(--dur-2) var(--ease-standard), border-color var(--dur-2) var(--ease-standard); }
}
@keyframes kcc-pop {
  from { opacity: 0; transform: translateY(-0.25rem) scale(0.98); }
  to { opacity: 1; transform: none; }
}

/* ==========================================================================
   Segmented control (light/dark + text-size in the menu; reusable)
   ========================================================================== */
.kcc-seg { display: flex; border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; }
.kcc-seg-btn {
  flex: 1 1 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1_5);
  min-height: 40px;
  padding: var(--space-1_5) var(--space-2);
  border: 0;
  background: var(--surface);
  color: var(--text-muted);
  font: inherit;
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  cursor: pointer;
}
.kcc-seg-btn + .kcc-seg-btn { border-left: 1px solid var(--line); }
.kcc-seg-btn:hover { background: var(--surface-2); color: var(--text); }
.kcc-seg-btn.is-active { background: var(--accent); color: var(--on-accent); }

/* ==========================================================================
   Chip / Badge (positive-achievement flavor)
   ========================================================================== */
.kcc-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.7rem;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--line);
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
}
.kcc-chip-good { background: color-mix(in srgb, var(--good) 14%, var(--surface)); color: color-mix(in srgb, var(--good) 72%, var(--text)); border-color: color-mix(in srgb, var(--good) 40%, var(--line)); }
.kcc-chip-warn { background: color-mix(in srgb, var(--warn) 14%, var(--surface)); color: color-mix(in srgb, var(--warn) 72%, var(--text)); border-color: color-mix(in srgb, var(--warn) 40%, var(--line)); }
.kcc-chip-accent { background: color-mix(in srgb, var(--accent) 12%, var(--surface)); color: color-mix(in srgb, var(--accent) 78%, var(--text)); border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }

.kcc-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.2rem 0.6rem;
  border-radius: var(--radius-pill);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  background: color-mix(in srgb, var(--good) 15%, var(--surface));
  color: color-mix(in srgb, var(--good) 70%, var(--text));
  border: 1px solid color-mix(in srgb, var(--good) 35%, var(--line));
}
.kcc-badge-warn { background: color-mix(in srgb, var(--warn) 15%, var(--surface)); color: color-mix(in srgb, var(--warn) 70%, var(--text)); border-color: color-mix(in srgb, var(--warn) 35%, var(--line)); }
.kcc-badge-neutral { background: var(--surface-2); color: var(--text-muted); border-color: var(--line); }

/* ==========================================================================
   Switch (toggle). Markup contract:
   <label class="kcc-switch"><input type="checkbox"><span class="kcc-switch-track"></span><span class="kcc-switch-thumb"></span></label>
   ========================================================================== */
.kcc-switch { position: relative; display: inline-block; width: 2.75rem; height: 1.5rem; flex: 0 0 auto; }
.kcc-switch input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; margin: 0; cursor: pointer; }
.kcc-switch-track { position: absolute; inset: 0; border-radius: var(--radius-pill); background: var(--surface-2); border: 1px solid var(--line); }
.kcc-switch-thumb { position: absolute; top: 50%; left: 0.2rem; width: 1.05rem; height: 1.05rem; border-radius: var(--radius-pill); background: var(--surface); box-shadow: var(--shadow-1); transform: translateY(-50%); }
.kcc-switch input:checked ~ .kcc-switch-track { background: var(--accent); border-color: var(--accent); }
.kcc-switch input:checked ~ .kcc-switch-thumb { transform: translate(1.2rem, -50%); }
@media (prefers-reduced-motion: no-preference) {
  .kcc-switch-track, .kcc-switch-thumb { transition: background var(--dur-2) var(--ease-standard), transform var(--dur-2) var(--ease-out); }
}

/* ==========================================================================
   Meter (bar + ring). Bar drives width inline; ring drives --kcc-ring (0-100).
   ========================================================================== */
.kcc-meter { height: 0.5rem; border-radius: var(--radius-pill); background: var(--surface-2); overflow: hidden; }
.kcc-meter-fill { height: 100%; width: 0; border-radius: var(--radius-pill); background: var(--accent); }
.kcc-meter-fill.is-good { background: var(--good); }
.kcc-meter-fill.is-warn { background: var(--warn); }
@media (prefers-reduced-motion: no-preference) {
  .kcc-meter-fill { transition: width var(--dur-4) var(--ease-out); }
}
.kcc-meter-ring {
  width: 3rem;
  height: 3rem;
  border-radius: var(--radius-pill);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: conic-gradient(var(--accent) calc(var(--kcc-ring, 0) * 1%), var(--surface-2) 0);
}
.kcc-meter-ring::before { content: ''; width: 2.2rem; height: 2.2rem; border-radius: var(--radius-pill); background: var(--surface); }

/* ==========================================================================
   Banner (inline notice / gentle nudge)
   ========================================================================== */
/* Platform view-as bar — full-bleed, first child of .kcc-shell, ABOVE the topbar (which shows the
   VIEWED practice's brand, so the disclaimer must come first). Warn tone deliberately: this is a
   state the operator must not forget they are in.
   flex:0 0 auto so it shrinks .kcc-body rather than giving the document a scrollbar — .kcc-content is
   the scroll container. Colours are built the same way .kcc-banner-warn builds its tone, so the
   contrast gate holds across all 6 themes x light/dark. Semantic tokens only. */
.kcc-viewasbar {
  flex: 0 0 auto;
  /* Column, because the bar now holds two rows: the always-visible disclosure, and the
     collapsed practice/person switcher underneath it. */
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: color-mix(in srgb, var(--warn) 16%, var(--surface));
  border-bottom: 1px solid color-mix(in srgb, var(--warn) 34%, var(--line));
  color: var(--text);
  font-size: var(--fs-sm);
}
.kcc-viewasbar-row { display: flex; align-items: center; gap: var(--space-2); }
.kcc-viewasbar-ico { flex: 0 0 auto; display: inline-flex; color: var(--warn); }
.kcc-viewasbar-text { flex: 1 1 auto; min-width: 0; }
.kcc-viewasbar-exit,
.kcc-viewasbar-btn {
  flex: 0 0 auto;
  font: inherit;
  font-weight: var(--fw-semibold);
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 0.25rem 0.6rem;
  cursor: pointer;
}
.kcc-viewasbar-exit:hover,
.kcc-viewasbar-btn:hover:not(:disabled) { background: var(--surface-2); }
.kcc-viewasbar-btn:disabled { opacity: 0.55; cursor: default; }
.kcc-viewasbar-picker {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.kcc-viewasbar-picker[hidden] { display: none; }
.kcc-viewasbar-lbl {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  min-width: 0;
}
.kcc-viewasbar-sel {
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 400;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 0.25rem 0.4rem;
  max-width: 16rem;
}
.kcc-viewasbar-note { flex: 1 1 12rem; min-width: 0; font-size: var(--fs-caption); color: var(--text-muted); }
@media (max-width: 640px) {
  .kcc-viewasbar-row { align-items: flex-start; flex-wrap: wrap; }
  .kcc-viewasbar-lbl, .kcc-viewasbar-sel { width: 100%; max-width: none; }
}

.kcc-banner {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  padding: var(--space-3);
  border-radius: var(--radius-md);
  border: 1px solid var(--line);
  background: var(--surface-2);
}
/* Same trap as `.kcc-btn[hidden]` above: `.kcc-banner` sets display:flex, which outranks the UA
   `[hidden] { display: none }`, so every banner rendered with the attribute — the Messages
   send-failure notice, its de-identification coach, the Directory nudge, the shared composer's
   coach — painted as an empty coloured box with a lone icon in it from first paint. Caught live on
   the unified Messages tab, where a team thread has no coach at all and still showed the box. */
.kcc-banner[hidden] { display: none; }
.kcc-banner-ico { flex: 0 0 auto; color: var(--accent); margin-top: 0.1rem; display: inline-flex; }
.kcc-banner-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.15rem; }
.kcc-banner-title { font-weight: var(--fw-semibold); color: var(--text); }
.kcc-banner-text { color: var(--text-muted); font-size: var(--fs-sm); }
.kcc-banner-close { flex: 0 0 auto; width: 2rem; height: 2rem; font-size: 1rem; }
.kcc-banner-info { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); border-color: color-mix(in srgb, var(--accent) 28%, var(--line)); }
.kcc-banner-info .kcc-banner-ico { color: var(--accent); }
.kcc-banner-good { background: color-mix(in srgb, var(--good) 10%, var(--surface)); border-color: color-mix(in srgb, var(--good) 30%, var(--line)); }
.kcc-banner-good .kcc-banner-ico { color: var(--good); }
.kcc-banner-warn { background: color-mix(in srgb, var(--warn) 12%, var(--surface)); border-color: color-mix(in srgb, var(--warn) 32%, var(--line)); }
.kcc-banner-warn .kcc-banner-ico { color: var(--warn); }
.kcc-banner-crisis { background: color-mix(in srgb, var(--crisis) 10%, var(--surface)); border-color: color-mix(in srgb, var(--crisis) 30%, var(--line)); }
.kcc-banner-crisis .kcc-banner-ico { color: var(--crisis); }

/* ==========================================================================
   State block (loading/empty/error/offline/forbidden) — one shared pattern.
   ========================================================================== */
.kcc-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-2);
  padding: var(--space-6) var(--space-4);
  max-width: 28rem;
  margin: var(--space-5) auto;
}
.kcc-state-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.25rem;
  height: 3.25rem;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--accent) 12%, var(--surface-2));
  color: var(--accent);
  font-size: 1.5rem;
}
.kcc-state-title { font-family: var(--font-heading); font-weight: var(--fw-semibold); font-size: var(--fs-title); color: var(--text); margin: 0; }
.kcc-state-body { color: var(--text-muted); margin: 0; }
.kcc-state-actions { margin-top: var(--space-2); }

/* ==========================================================================
   Tooltip / "what's this?" helper. Contract: a small button.kcc-whatsthis or
   any element.kcc-tooltip carrying data-tip="one friendly sentence".
   Suppressed on touch (no hover) so it never gets stuck open on a tap.
   ========================================================================== */
.kcc-whatsthis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.2rem;
  height: 1.2rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  cursor: help;
  padding: 0;
  vertical-align: middle;
}
.kcc-whatsthis:hover, .kcc-whatsthis:focus-visible { color: var(--text); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.kcc-tooltip { position: relative; }
@media (hover: hover) {
  .kcc-whatsthis, .kcc-tooltip[data-tip] { position: relative; }
  .kcc-whatsthis[data-tip]:hover::after,
  .kcc-whatsthis[data-tip]:focus-visible::after,
  .kcc-tooltip[data-tip]:hover::after,
  .kcc-tooltip[data-tip]:focus-visible::after {
    content: attr(data-tip);
    position: absolute;
    bottom: calc(100% + 0.5rem);
    left: 50%;
    transform: translateX(-50%);
    width: max-content;
    max-width: 16rem;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--line);
    box-shadow: var(--shadow-2);
    font-size: var(--fs-caption);
    font-weight: var(--fw-regular);
    line-height: 1.4;
    text-align: left;
    white-space: normal;
    z-index: 70;
  }
}

/* ==========================================================================
   Command palette (⌘K)
   ========================================================================== */
.kcc-palette-backdrop {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 12vh var(--space-4) var(--space-4);
  background: color-mix(in srgb, var(--text) 45%, transparent);
}
.kcc-palette-backdrop[hidden] { display: none; }
.kcc-palette {
  width: 100%;
  max-width: 34rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  overflow: hidden;
}
:root[data-mode='dark'] .kcc-palette { background: var(--surface-2); }
.kcc-palette-search { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-3); border-bottom: 1px solid var(--line); }
.kcc-palette-ico { color: var(--text-muted); display: inline-flex; }
.kcc-palette-input { flex: 1 1 auto; border: 0; background: transparent; color: var(--text); font: inherit; font-size: var(--fs-body); min-width: 0; }
.kcc-palette-input:focus { outline: none; }
.kcc-palette-results { max-height: 22rem; overflow-y: auto; padding: var(--space-2); }
.kcc-palette-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2);
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-align: left;
}
.kcc-palette-item:hover, .kcc-palette-item.is-sel { background: var(--surface-2); }
.kcc-palette-item.is-sel { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 40%, transparent); }
.kcc-palette-item-ico { color: var(--text-muted); display: inline-flex; font-size: 1.1em; }
.kcc-palette-item-text { display: flex; flex-direction: column; min-width: 0; }
.kcc-palette-item-label { font-size: var(--fs-sm); color: var(--text); }
.kcc-palette-item-ws { font-size: var(--fs-caption); color: var(--text-muted); }
.kcc-palette-empty { padding: var(--space-4); color: var(--text-muted); text-align: center; font-size: var(--fs-sm); }
.kcc-palette-foot { display: flex; align-items: center; gap: var(--space-1_5); padding: var(--space-2) var(--space-3); border-top: 1px solid var(--line); color: var(--text-muted); font-size: var(--fs-caption); }
@media (prefers-reduced-motion: no-preference) { .kcc-palette { animation: kcc-pop var(--dur-3) var(--ease-out); } }

/* ==========================================================================
   Mobile nav sheet (bottom "More/Menu")
   ========================================================================== */
.kcc-sheet-backdrop {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: color-mix(in srgb, var(--text) 45%, transparent);
}
.kcc-sheet-backdrop[hidden] { display: none; }
.kcc-sheet {
  width: 100%;
  max-width: 32rem;
  max-height: 80vh;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-top-left-radius: var(--radius-xl);
  border-top-right-radius: var(--radius-xl);
  padding: var(--space-4);
  padding-bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
}
:root[data-mode='dark'] .kcc-sheet { background: var(--surface-2); }
.kcc-sheet-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-3); }
.kcc-sheet-title { font-family: var(--font-heading); font-size: var(--fs-heading); font-weight: var(--fw-semibold); color: var(--text); }
@media (prefers-reduced-motion: no-preference) { .kcc-sheet { animation: kcc-sheet-up var(--dur-4) var(--ease-out); } }
@keyframes kcc-sheet-up { from { transform: translateY(100%); } to { transform: none; } }

/* ==========================================================================
   Coach-mark tour (minimal runner)
   ========================================================================== */
.kcc-tour { position: fixed; inset: 0; z-index: 90; pointer-events: none; }
.kcc-tour[hidden] { display: none; }
.kcc-tour-ring {
  position: fixed;
  border: 2px solid var(--accent);
  border-radius: var(--radius-md);
  box-shadow: 0 0 0 9999px color-mix(in srgb, var(--text) 55%, transparent);
  pointer-events: none;
}
.kcc-tour-card {
  position: fixed;
  width: min(20rem, calc(100vw - 1.5rem));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  padding: var(--space-4);
  pointer-events: auto;
}
:root[data-mode='dark'] .kcc-tour-card { background: var(--surface-2); }
.kcc-tour-step { font-size: var(--fs-caption); color: var(--text-muted); }
.kcc-tour-title { font-family: var(--font-heading); font-size: var(--fs-heading); font-weight: var(--fw-semibold); color: var(--text); margin: var(--space-1) 0; }
.kcc-tour-body { color: var(--text-muted); font-size: var(--fs-sm); margin: 0 0 var(--space-3); }
.kcc-tour-actions { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.kcc-tour-actions-right { display: flex; gap: var(--space-2); }
@media (prefers-reduced-motion: no-preference) { .kcc-tour-ring { transition: top var(--dur-3) var(--ease-out), left var(--dur-3) var(--ease-out), width var(--dur-3) var(--ease-out), height var(--dur-3) var(--ease-out); } }

/* ==========================================================================
   Card variants — interactive lift + feature (serif + icon tile)
   ========================================================================== */
.kcc-card-interactive { cursor: pointer; }
.kcc-card-interactive:hover { border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); box-shadow: var(--shadow-1); }
.kcc-card-feature { display: flex; gap: var(--space-3); align-items: flex-start; }
.kcc-card-feature .kcc-card-title { font-family: var(--font-heading); }
.kcc-feature-tile {
  flex: 0 0 auto;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--accent) 12%, var(--surface-2));
  color: var(--accent);
  font-size: 1.3rem;
}
@media (prefers-reduced-motion: no-preference) {
  .kcc-card-interactive { transition: border-color var(--dur-2) var(--ease-standard), box-shadow var(--dur-2) var(--ease-standard), transform var(--dur-2) var(--ease-standard); }
  .kcc-card-interactive:hover { transform: translateY(-1px); }
}

/* ==========================================================================
   Drawer (right panel desktop / bottom sheet mobile)
   ========================================================================== */
.kcc-drawer-backdrop {
  position: fixed;
  inset: 0;
  z-index: 75;
  display: flex;
  justify-content: flex-end;
  background: color-mix(in srgb, var(--text) 45%, transparent);
}
.kcc-drawer-backdrop[hidden] { display: none; }
.kcc-drawer {
  width: min(24rem, 100%);
  height: 100%;
  overflow-y: auto;
  background: var(--surface);
  border-left: 1px solid var(--line);
  box-shadow: var(--shadow-3);
  padding: var(--space-4);
}
:root[data-mode='dark'] .kcc-drawer { background: var(--surface-2); }
@media (max-width: 640px) {
  .kcc-drawer-backdrop { align-items: flex-end; }
  .kcc-drawer { width: 100%; height: auto; max-height: 85vh; border-left: 0; border-top: 1px solid var(--line); border-top-left-radius: var(--radius-xl); border-top-right-radius: var(--radius-xl); }
}
@media (prefers-reduced-motion: no-preference) { .kcc-drawer { animation: kcc-drawer-in var(--dur-4) var(--ease-out); } }
@keyframes kcc-drawer-in { from { transform: translateX(4%); opacity: 0; } to { transform: none; opacity: 1; } }

/* ==========================================================================
   Toast — elevation + warn kind + icon slot (component additions; app/ui.js
   still drives show/err; warn/icon classes are available for later use).
   ========================================================================== */
.kcc-toast { box-shadow: var(--shadow-2); }
.kcc-toast.show.warn { border-left-color: var(--warn); }
.kcc-toast-ico { margin-right: var(--space-2); }

/* ==========================================================================
   Live theme morph — one-time cross-fade pulse when appearance changes.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  :root[data-theme-morph] .kcc-shell,
  :root[data-theme-morph] .kcc-shell * {
    transition: background-color var(--dur-4) var(--ease-standard), color var(--dur-4) var(--ease-standard), border-color var(--dur-4) var(--ease-standard) !important;
  }
}

/* ==========================================================================
   Responsive topbar (compact ≤640: lens + wide search + breadcrumb give way
   to the bottom tab bar + an icon-only search entry).
   ========================================================================== */
body.nav-compact .kcc-lens { display: none; }
body.nav-compact .kcc-search-box { display: none; }
body.nav-compact .kcc-crumb { display: none; }
body.nav-compact .kcc-search-icon-only { display: inline-flex; }
body.nav-compact .kcc-brand-name { max-width: 42vw; }
body.nav-compact .kcc-shell.has-view .kcc-brand-name { display: none; }
/* Trading the org name for the pill (line above) is not enough on its own. Measured at 375px on the
   live console: the lead needed 159px and had 143px, so flex took the difference out of the brand,
   and the pill drew over the monogram. These four rules buy back exactly that difference, cheapest
   first, and none of them shrinks a touch target below 44px.
     1. The pill's user glyph is decoration — the role name is the whole message — so it goes here.
     2. A 12px gap either side of the middle group is desktop spacing; 6px at panel width.
     3. `.kcc-topbar-mid` holds only the breadcrumb and the search box, and this width already hides
        both. An empty `flex: 1 1 auto` box is not free: it absorbs the row's slack, which is why
        tightening the gaps alone changed nothing. Removing it also removes one gap.
     4. Pill padding, last, because it is the one that costs legibility.
   The role name then renders in full at 375px with 6px to spare. Below that width the pill is the
   one item allowed to give way — at this breakpoint the middle group is gone, so it is the only
   thing left that can, and the alternative is the icon buttons walking off the right edge. A panel
   dragged to 320px does degrade: measured there, the pill gets 34px and reads "C…", ambiguous
   between Clinician and Coordinator. That is the accepted floor, not an oversight — the four icon
   buttons alone are 200px of the 296px available, and every way to buy the pill more room costs
   either a 44px touch target or a control the reader can still reach. The full name stays in the
   button's aria-label and title, and tapping it opens the menu that names the current view. */
body.nav-compact .kcc-viewpill-ico { display: none; }
body.nav-compact .kcc-topbar { gap: var(--space-1_5); }
body.nav-compact .kcc-shell.has-view .kcc-topbar-mid { display: none; }
body.nav-compact .kcc-viewpill {
  flex: 0 1 auto;
  min-width: 0;
  padding: var(--space-1) var(--space-1_5);
}

/* The per-workspace tool strip that lived here (added 2026-08-03) was DELETED on 2026-08-04, not
   disabled. It existed only because the bottom bar held workspaces and could therefore reach a
   workspace's first tool and nothing else; the bar now holds real screens, so a second nav row had
   nothing left to do. It also never fit: a four-tool clinician strip measured 486px of content in a
   360px viewport, so one of the four sat off-screen. Full reasoning at navDestinations() in
   app/registry.js. Removing it returns ~53px of a 700px panel to content. */

/* The toast sits 1.25rem from the bottom, which in compact mode is INSIDE the fixed tab bar — and at
   z-index 50 against the bar's 20, so it covers a nav label rather than sliding under it. In the
   Chrome side panel that is every save and every sign-in hiding a navigation destination (verified
   2026-08-03: "Signed in." sat squarely on top of "Network"). Same 3.5rem the content padding above
   already reserves for the bar, so the two stay in step. */
body.nav-compact .kcc-toast { bottom: calc(1.25rem + 3.5rem + env(safe-area-inset-bottom, 0px)); }

/* ==========================================================================
   Login screen (spec §4) — centered branded card + brand-tinted radial wash
   ========================================================================== */
.kcc-login-screen {
  position: relative;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}
.kcc-login-wash {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(120% 80% at 50% -10%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 60%);
}
.kcc-login-main { position: relative; z-index: 1; width: 100%; display: flex; justify-content: center; }
.kcc-login-card {
  width: 100%;
  max-width: 26rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-2);
  padding: var(--space-6) var(--space-5);
  text-align: center;
  display: flex;
  flex-direction: column;
}
:root[data-mode='dark'] .kcc-login-card { background: var(--surface-2); }
.kcc-login-brand { display: flex; justify-content: center; margin-bottom: var(--space-3); }
.kcc-login-logo { width: 3.5rem; height: 3.5rem; object-fit: cover; border-radius: var(--radius-md); }
.kcc-login-monogram {
  width: 3.5rem;
  height: 3.5rem;
  border-radius: var(--radius-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--accent) 16%, var(--surface-2));
  color: var(--accent);
  font-family: var(--font-heading);
  font-weight: var(--fw-bold);
  font-size: var(--fs-title);
}
.kcc-login-org { font-family: var(--font-heading); font-weight: var(--fw-semibold); font-size: var(--fs-display); line-height: var(--lh-display); color: var(--text); margin: 0; }
.kcc-login-headline { font-size: var(--fs-heading); font-weight: var(--fw-semibold); color: var(--text); margin: var(--space-3) 0 0; }
.kcc-login-sub { color: var(--text-muted); font-size: var(--fs-sm); margin: var(--space-1) 0 var(--space-4); }
.kcc-login-card .kcc-field { text-align: left; }
.kcc-login-card .kcc-btn-block { margin-top: var(--space-2); }
/* The one question the invitation card asks — see renderInvite in app/main.js. Left-aligned inside a
   centred card on purpose: it is a sentence to read rather than a heading, and centred prose in a
   26rem column breaks in the wrong places. The row wraps because "I'd rather not say" plus two other
   answers does not fit on one line at 380px, which is the width this is read at. */
.kcc-invite-rel { text-align: left; color: var(--text); font-size: var(--fs-sm); line-height: var(--lh-sm); margin: 0 0 var(--space-2); }
.kcc-invite-answers { display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: flex-start; margin-bottom: var(--space-2); }
.kcc-invite-answers button[aria-pressed='true'] { border-color: var(--accent); color: var(--accent); }
.kcc-invite-own { margin-bottom: var(--space-3); text-align: left; }
.kcc-login-secure { display: flex; align-items: center; justify-content: center; gap: var(--space-1_5); margin-top: var(--space-4); color: var(--text-muted); font-size: var(--fs-caption); }
.kcc-login-secure svg { flex: 0 0 auto; }

/* Side-panel pairing code. Read aloud or copied across to another window, often in a narrow panel, so
   it is deliberately large with wide letter-spacing — a mistyped character reads as "the feature is
   broken". word-break keeps it inside the ~320px the side panel can be dragged down to. */
.kcc-pair-code {
  margin: var(--space-3) 0 var(--space-2);
  padding: var(--space-3) var(--space-2);
  border: 1px dashed var(--line);
  border-radius: var(--radius-md);
  background: var(--surface-2);
  color: var(--text);
  font-size: var(--fs-title);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.12em;
  text-align: center;
  word-break: break-all;
}

/* ==========================================================================
   Reduced motion — backstop for every animated surface above. Even if a
   future edit adds a transition/animation outside a no-preference block,
   this catch-all still neutralizes it for users who asked for less motion.
   ========================================================================== */

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

/* ==========================================================================
   Team chat surface (app/chatsurface.js)

   The whole point of this block is that the widget's height is never a `vh`
   number. It used to be `min-height: 55vh` inside a card in the scrolling
   content pane, which ignored the topbar, the toolstrip, the card chrome and
   the bottom tab bar — so in the ~700px Chrome side panel the page scrolled
   AND the widget's message list scrolled, nested, inside ~385px. Here the
   panel is a three-row flex column: head and foot are `flex: 0 0 auto`, the
   stage is `flex: 1 1 auto; min-height: 0`, and it therefore takes exactly
   what is left. `min-height: 0` is load-bearing — without it a flex child
   refuses to shrink below its content and the outer scroll comes straight
   back.

   Two shapes, one surface. Compact (the side panel, and any narrow window):
   edge-to-edge, no radius, covering the tab bar deliberately — while you are
   in a conversation, the conversation IS the app, and Close is the way back.
   Full (desktop): a centered dialog over a scrim, roomy but not stretched, so
   a chat column is not 1600px wide.
   ========================================================================== */

/* ONE element, two modes. It is appended once as a flex child of .kcc-body and never moves — see the
   comment block in app/chatsurface.js for why moving it is not an option (re-parenting a node that
   contains an iframe reloads it, costing the conversation and any half-typed message on every
   expand/collapse). Only these classes change. */
.kcc-chatsurface { display: flex; }
.kcc-chatsurface[hidden] { display: none; }

/* --- docked: this screen's content. A plain flex child, so the flex row does the measuring and there
   is no rect maths to drift. --- */
.kcc-chatsurface.is-docked {
  position: static;
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
}
/* The content pane steps aside while the chat is the screen. Set and reverted by applyMode(). */
html.kcc-chat-docked .kcc-content { display: none; }
/* .kcc-tabbar is position:FIXED, so .kcc-body extends underneath it and a docked chat would put its
   footer — the "chat not loading? call …" line — entirely behind the tab bar, and hide the bottom
   57px of the conversation where there is no footer. Measured at 360x700 before this rule: tab bar
   643-700, footer 665-700, fully covered. Reserve the same room .kcc-content already reserves, and
   deliberately with the same expression so the two cannot drift apart. The EXPANDED surface is above
   the tab bar (z-index 78 vs 20) and covers it on purpose, so this applies to docked only. */
body.nav-compact .kcc-chatsurface.is-docked {
  padding-bottom: calc(3.5rem + env(safe-area-inset-bottom, 0px));
}

/* A docked chat needs the content pane to have a REAL height, and at desktop width it did not.
   `.kcc-shell` is `min-height: 100dvh`, so it grows with its content; `.kcc-rail` declares
   `overflow-y: auto` but a flex item's default `min-height: auto` refuses to shrink below its content,
   so a long rail stretched `.kcc-body` and the whole PAGE scrolled instead of the rail. Measured at
   1280x820 as an 18-tool admin: `.kcc-body` 968px in an 820px viewport — and that is true UNDOCKED
   too, on every tool. It is a pre-existing bug and it is NOT fixed here: making the shell exactly
   viewport-height globally would change every screen and deserves its own verification pass.
   Scoped to the docked chat instead, which is the one surface whose whole point is filling the pane
   exactly, and reverted the moment it undocks. */
/* `vh` first, `dvh` as an enhancement. With `dvh` alone and no fallback, a browser that does not know
   the unit drops the whole declaration — and then the docked chat's ancestor has no definite height,
   so the stage (`flex: 1 1 auto; min-height: 0`) collapses to ZERO and the conversation is invisible
   with nothing to scroll. That is a plausible reading of "on some browsers the chat section is
   hidden", and it costs one extra rule to make impossible. `dvh` is still preferred where supported
   because it tracks a mobile browser's collapsing toolbars, which `vh` does not. */
html.kcc-chat-docked .kcc-shell { height: 100vh; }
@supports (height: 100dvh) {
  html.kcc-chat-docked .kcc-shell { height: 100dvh; }
}
html.kcc-chat-docked .kcc-rail { min-height: 0; }

/* --- expanded: a takeover. --- */
.kcc-chatsurface.is-expanded {
  position: fixed;
  inset: 0;
  z-index: 78; /* above the nav sheet (70); below the command palette (80) and the tour (90) */
}

.kcc-chatsurface-panel {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  color: var(--text);
}

.kcc-chatsurface-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  min-height: 3rem;
  border-bottom: 1px solid var(--line);
}
.kcc-chatsurface-title {
  font-family: var(--font-heading);
  font-size: var(--fs-heading);
  font-weight: var(--fw-semibold);
  color: var(--text);
}

/* The widget's home. `min-height: 0` is what lets it shrink to the space available.

   `overflow-y: auto`, NOT `hidden`, and this is the single most important line in this file.
   The GoHighLevel widget's height is a FIXED PIXEL NUMBER it declares on its own shadow `:host`
   (measured 2026-08-04: 592px, up to 660px with its branding row) and it does not adapt to this box.
   We now push a height onto it from JS — see fitWidget() in app/chatsurface.js — but that is an
   override of someone else's component, and it can stop working without warning: a widget version
   that renames its variables, a stale cached bundle, a measurement taken before layout exists.
   `hidden` turned every one of those futures into "the composer is off-screen and the browser refuses
   to scroll to it", which is exactly what was reported. `auto` turns them into "scroll down a bit".
   The overflow stays REACHABLE. Verified: at a 640px surface the widget overflowed by 17px and at
   560px by 97px, with scrollHeight > clientHeight in both cases and no way to reach it. */
.kcc-chatsurface-stage {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
/* `.kcc-chatsurface-hint` is gone with the row it styled (2026-08-04). It was the "use your work
   email" line, and like the phone footer before it, a static row in a fixed-height surface pays for
   itself out of the message area. */
/* Whichever mechanism the practice uses, it fills the stage: an iframe embed, or the container the
   GoHighLevel loader renders into. */
.kcc-chatsurface-host,
.kcc-chatsurface-frame {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  border: 0;
  display: block;
}
.kcc-chatsurface-loading { display: block; padding: var(--space-4); }

/* There is deliberately no `.kcc-chatsurface-foot` any more. A permanent footer inside a surface whose
   height is fixed by the viewport can only take its pixels from the message area — in the Chrome side
   panel it covered the conversation, and on one clinician's account left no room to type. Removed
   2026-08-04; reasoning at app/chatsurface.js. */
.kcc-chatsurface-actions { display: flex; align-items: center; gap: var(--space-1_5); flex: 0 0 auto; }
/* `[hidden]` is only `display: none` in the UA stylesheet, so ANY class that sets display beats it —
   and `.kcc-iconbtn` sets `display: inline-flex`. applyMode() toggles the attribute on these two
   buttons and it was being ignored: the Close X stayed visible in docked mode, where there is nothing
   to close. Specificity 0,2,0 here, so the attribute wins without `!important`. */
.kcc-chatsurface-actions [hidden] { display: none; }

/* The onboarding checklist is a body-level section (`#kcc-setup`), a sibling of `.kcc-shell` rather
   than content, so hiding the content pane does not hide it and it lands on top of a docked
   conversation. On the Team chat screen the conversation is the point; the checklist is a nudge that
   still shows on every other screen. */
html.kcc-chat-docked #kcc-setup { display: none; }

/* Background must not scroll under any overlay that takes over the screen. Applied through
   setScrollLock(key, wanted) in app/ui.js, which is KEYED so nested overlays release independently —
   closing the palette over an open chat does not unlock the page early.

   Real callers, all verified wired: the shared kcc-modal (Records, Roster, Programs, Profile
   actions), the expanded chat surface, the "Go to" sheet, the command palette, the plan tool's
   premium preview, and both message composers. This class previously had NO callers at all while
   chatsurface.js toggled a `kcc-chat-locked` class that had NO rule here — so nothing was locked.
   test/scroll-lock.test.mjs now fails if a toggled kcc-* class has no rule in this file. */
html.kcc-scroll-locked, html.kcc-scroll-locked body { overflow: hidden; }

/* --- full (desktop): a centered dialog rather than a full-bleed takeover --- */
@media (min-width: 40rem) {
  .kcc-chatsurface.is-expanded {
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    /* scrim: translucent --text over --surface, no rgba()/hex literal */
    background: color-mix(in srgb, var(--text) 55%, transparent);
  }
  .kcc-chatsurface.is-expanded .kcc-chatsurface-panel {
    flex: 0 0 auto;
    width: min(38rem, 100%);
    /* Same reasoning as .kcc-shell above: a `dvh` inside min() takes the whole declaration down with
       it, and here that leaves `height` unset on a `flex: 0 0 auto` panel — which then sizes to its
       content, i.e. the header alone. The chat would simply not be there. */
    height: min(88vh, 46rem);
    border: 1px solid var(--line);
    border-radius: 0.75rem;
    overflow: hidden;
    box-shadow: var(--shadow-2);
  }
  @supports (height: 100dvh) {
    .kcc-chatsurface.is-expanded .kcc-chatsurface-panel { height: min(88dvh, 46rem); }
  }
  /* Docked at desktop width the chat fills the content pane, so it needs the pane's own left edge
     rather than a dialog's border. */
  .kcc-chatsurface.is-docked { border-left: 1px solid var(--line); }
}

/* Opacity only — NOT the translateY(0.5rem) the other overlays in this file use, and that is a
   correctness point rather than a taste one. Measured at 360x700: the panel is exactly viewport-sized,
   so an 8px transform put its footer at y=708 in a 700px viewport, clipping the "chat not loading?
   phone" row — the one row someone reads precisely when the widget is failing. A dialog smaller than
   the viewport can afford to slide; a full-bleed surface cannot, because there is nowhere to slide
   from. A fade also reads better here: nothing is arriving from somewhere, the screen is changing. */
@media (prefers-reduced-motion: no-preference) {
  .kcc-chatsurface.is-expanded .kcc-chatsurface-panel { animation: kcc-chatsurface-in var(--dur-3) var(--ease-out); }
  @keyframes kcc-chatsurface-in {
    from { opacity: 0; }
    to { opacity: 1; }
  }
}

/* The home screen's "Message my team" call to action (messageTeamAction() in app/main.js).

   It is a primary button and the first thing in the actions row, because until now the only route to
   team chat from a home screen was an unlabelled speech-bubble icon in the topbar — a reasonable
   second affordance and a poor first one. Nothing on the screen said where to reach a person.

   `is-unread` is added when there is actually something waiting, and is deliberately quiet: the label
   already changes to "2 new messages", so the ring is reinforcement, not the message. No new colour
   token — a ring in --accent, which every theme already defines. */
.kcc-welcome-cta.is-unread {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent);
}

/* ── POP-OUT: the same app, with the furniture taken out ─────────────────────────────────────
   Drew, 2026-08-31: "on the messages... on the care console allow them to open up the chat on
   onother browser (small button) and for it to sync".

   A second window is for putting a conversation beside the work it is about — a chart, a form,
   another tab. Everything that is navigation in the main window is furniture in that one: the
   topbar names an app you are already in, the rail and the tabbar go places a 460px window has no
   room for, and a person who navigated away inside it would be stranded in a chrome-less app with
   no way back. So the chrome is hidden, and main.js clears `data-popout` on every route change, so
   the moment anything navigates the window becomes an ordinary one again rather than a trap.

   This is CSS rather than a second HTML page on purpose. A pop-out page of its own would be a
   second copy of the boot sequence, the session read, the theme resolution and the tool mount —
   four things that would drift apart within a month, and the conversation is the one surface where
   drifting apart means two people looking at different text. One app, one route, less furniture.

   `--space-0` is not a token here deliberately: padding: 0 is the absence of the token, not a new
   size on the scale. */
:root[data-popout="1"] .kcc-topbar,
:root[data-popout="1"] .kcc-rail,
:root[data-popout="1"] .kcc-tabbar { display: none; }
:root[data-popout="1"] .kcc-content { padding: 0; }
/* The shell is min-height:100dvh (see the note at .kcc-content), so in a small window the tool must
   be told to fill it rather than to take 72vh of a viewport that is already the conversation. */
:root[data-popout="1"] .kcc-shell { min-height: 100dvh; }
