/* Memkist — web UI styles.
 *
 * This file is the design of record for the member web UI and the tenant
 * control panel. The palette is the marketing site's: deep ink canvas, bone
 * text, sky accent, amber brand mark — dark is the product default, and the
 * light theme is the same design inverted through the tokens, not a second
 * design. The HTML mockups remain the reference for the desktop client and the
 * ops console; they are not the source for colours or geometry here.
 *
 * Three rules for editing this file:
 *   1. No colour, size or spacing literal outside :root. Everything reads from a
 *      token so light and dark stay in step and a change is made once.
 *   2. Colour is used for meaning (state, emphasis), never as decoration.
 *   3. Motion explains a change of state. It is off when the reader asks for
 *      reduced motion.
 *
 * Edges are hairlines: 1px of the bone line colour, an inset top light, and a
 * soft deep shadow — never a solid navy outline, which is what made the old
 * borders read as dated.
 */

:root {
  /* — Memkist palette, copied from the marketing site. — */
  --bg:      #060a12;                 /* ink          */
  --surface: #0b1220;                 /* ink-2        */
  --fg:      #e6edf5;                 /* bone         */
  --muted:   #9fb0c4;                 /* bone-dim     */
  --faint:   #5d6b7e;                 /* muted        */
  --line:    rgba(230, 237, 245, .12);
  --border:  var(--line);
  --accent:      #38bdf8;             /* sky          */
  --accent-deep: #0ea5e9;
  --accent-fg:   #04121c;             /* sky carries dark text               */
  --accent-hover: color-mix(in oklch, var(--accent) 88%, white);
  --fg-solid-hover: color-mix(in oklch, var(--fg) 90%, white);
  --gold: #f59e0b;
  --mark: #fbbf24;                    /* brand mark amber                    */

  --ok:      #6ee7b7;
  --warn:    #f59e0b;
  --danger:  #f87171;
  --info:    #7dd3fc;
  --on-danger: #1b0e0e;

  --accent-soft: color-mix(in oklch, var(--accent) 14%, transparent);
  --fg-soft:     color-mix(in oklch, var(--fg) 6%, transparent);
  --ok-soft:     color-mix(in oklch, var(--ok) 13%, transparent);
  --warn-soft:   color-mix(in oklch, var(--warn) 14%, transparent);
  --danger-soft: color-mix(in oklch, var(--danger) 13%, transparent);
  --info-soft:   color-mix(in oklch, var(--info) 13%, transparent);

  /* — Faces: layered gradients over the base colour, per theme. — */
  --card-face: linear-gradient(180deg, rgba(230, 237, 245, .045), rgba(230, 237, 245, .012));
  --wash:     rgba(230, 237, 245, .045);
  --wash-hi:  rgba(230, 237, 245, .075);
  --table-head: color-mix(in oklch, var(--fg) 3.5%, transparent);
  --row-line: color-mix(in oklch, var(--line) 60%, transparent);
  --row-hover: color-mix(in oklch, var(--accent) 9%, transparent);
  --stage-face: color-mix(in oklch, var(--surface) 72%, transparent);
  --glass: color-mix(in oklch, var(--surface) 82%, transparent);
  --shell-face:
    radial-gradient(900px 480px at 6% -8%, rgba(56, 189, 248, .10), transparent 62%),
    radial-gradient(760px 420px at 98% 104%, rgba(245, 158, 11, .055), transparent 60%),
    var(--bg);
  --auth-face:
    radial-gradient(1000px 640px at 14% 14%, rgba(56, 189, 248, .16), transparent 60%),
    radial-gradient(880px 560px at 86% 94%, rgba(245, 158, 11, .11), transparent 62%),
    var(--bg);
  --grid-dot: rgba(230, 237, 245, .10);
  --brand-tile: #16243a;

  /* — Edges. A hairline, a lit top edge, a deep soft shadow. — */
  --edge: inset 0 1px 0 rgba(255, 255, 255, .05);
  --raise: 0 1px 2px rgba(0, 0, 0, .40);
  --raise-lg: 0 24px 48px -28px rgba(0, 0, 0, .75);
  --glow: 0 10px 26px -12px color-mix(in oklch, var(--accent) 60%, transparent);
  --mark-glow: drop-shadow(0 0 10px rgba(251, 191, 36, .38));
  --hair-card:
    linear-gradient(var(--line), var(--line)) border-box,
    linear-gradient(160deg, rgba(56, 189, 248, .55), rgba(230, 237, 245, .14) 42%, rgba(245, 158, 11, .34)) border-box;

  /* Dark ink sidebar, shared by both themes (the marketing nav is dark too). */
  --ink: #080e1b;
  --ink-fg: #e6edf5;
  --ink-muted: #9fb0c4;
  --ink-line: rgba(230, 237, 245, .10);
  --ink-hover: color-mix(in oklch, var(--fg) 8%, transparent);
  --ink-accent: #38bdf8;
  --ink-accent-soft: color-mix(in oklch, var(--ink-accent) 18%, transparent);

  /* System faces only. No hosted webfont: the image also runs where a CDN is absent. */
  --font-display: "Segoe UI Variable Display", "Segoe UI", -apple-system, BlinkMacSystemFont, Inter, Roboto, Helvetica, Arial, sans-serif;
  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --fs-body: 14.5px;
  --fs-meta: 12px;
  --fs-sm: 13px;
  --fs-title: 20px;
  --fs-display: 30px;

  /* 4px scale. Existing gap names stay so older rules keep resolving. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --gap-xs: var(--space-2);
  --gap-sm: var(--space-3);
  --gap-md: var(--space-4);
  --gap-lg: var(--space-5);

  --radius: 10px;
  --radius-lg: 16px;
  --reading: 100%;
  --sidebar-w: 246px;
  --sidebar-compact: 72px;
  --tabbar-h: 56px;
  --gutter: 14px;

  --dur: 200ms;
  --ease: cubic-bezier(.2, .7, .2, 1);
  --lift: translateY(-1px);

  color-scheme: dark;
}

/* The light theme is the same design read off white paper: ink text, a deeper
   sky so buttons and links still carry contrast, hairlines of ink instead of
   bone. Every other token is inherited from above. */
:root[data-theme="light"] {
  --bg:      #EFF4FA;
  --surface: #FFFFFF;
  --fg:      #0B1220;
  --muted:   #5D6B7E;
  --faint:   #71839b;
  --line:    rgba(11, 18, 32, .13);
  --border:  var(--line);
  --accent:      #0369A1;
  --accent-deep: #075985;
  --accent-fg:   #FFFFFF;
  --accent-hover: color-mix(in oklch, var(--accent) 86%, black);
  --fg-solid-hover: color-mix(in oklch, var(--fg) 90%, black);

  --ok:      #1E6B45;
  --warn:    #C2410C;
  --danger:  #A33B32;
  --info:    #1D6BB5;
  --on-danger: #FFFFFF;

  --card-face: linear-gradient(180deg, #FFFFFF, #FBFDFF);
  --wash:     rgba(11, 18, 32, .030);
  --wash-hi:  rgba(11, 18, 32, .055);
  --table-head: color-mix(in oklch, var(--fg) 3%, transparent);
  --row-hover: color-mix(in oklch, var(--accent) 8%, transparent);
  --stage-face: color-mix(in oklch, var(--surface) 86%, transparent);
  --glass: color-mix(in oklch, var(--surface) 88%, transparent);
  --shell-face:
    radial-gradient(900px 480px at 6% -8%, rgba(14, 165, 233, .09), transparent 62%),
    radial-gradient(760px 420px at 98% 104%, rgba(245, 158, 11, .07), transparent 60%),
    var(--bg);
  --auth-face:
    radial-gradient(1000px 640px at 14% 14%, rgba(14, 165, 233, .14), transparent 60%),
    radial-gradient(880px 560px at 86% 94%, rgba(245, 158, 11, .10), transparent 62%),
    var(--bg);
  --grid-dot: rgba(11, 18, 32, .10);

  --edge: inset 0 1px 0 rgba(255, 255, 255, .85);
  --raise: 0 1px 2px rgba(11, 18, 32, .07);
  --raise-lg: 0 24px 48px -30px rgba(11, 18, 32, .35);
  --glow: 0 10px 24px -14px rgba(3, 105, 161, .55);
  --mark-glow: drop-shadow(0 0 8px rgba(245, 158, 11, .35));
  --hair-card:
    linear-gradient(var(--line), var(--line)) border-box,
    linear-gradient(160deg, rgba(3, 105, 161, .40), rgba(11, 18, 32, .12) 42%, rgba(245, 158, 11, .35)) border-box;

  color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--fg); font-family: var(--font-body); font-size: var(--fs-body); line-height: 1.55; -webkit-font-smoothing: antialiased; }
svg { display: block; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }
p { margin: 0; text-wrap: pretty; }
h1, h2, h3 { margin: 0; text-wrap: balance; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
mark { background: color-mix(in oklch, var(--fg) 16%, transparent); color: var(--fg); border-radius: 3px; padding: 0 2px; }
::selection { background: color-mix(in oklch, var(--accent) 30%, transparent); }

.ic { width: 16px; height: 16px; flex: none; }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.meta { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--muted); }
.eyebrow { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .22em; text-transform: uppercase; color: var(--accent); margin: 0; display: flex; align-items: center; gap: 10px; }
.eyebrow::before { content: ""; width: 22px; height: 1px; background: var(--accent); opacity: .7; flex: none; }
.serif { font-family: var(--font-display); letter-spacing: -.02em; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.grow { flex: 1; min-width: 0; }

/* The brand mark: marketing's amber tile, used wherever the product signs its name. */
.logo { width: 30px; height: 30px; flex: none; border-radius: 8px; filter: var(--mark-glow); }

/* ── window shell ───────────────────────────────────────────────────────────
 * Mobile first: the sidebar is hidden and a bottom tab bar carries Files,
 * Search, Assistant, and More. From 768px the sidebar floats as a rounded ink
 * rail and the stage becomes a single glass card between them.
 */
.win { height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
.app { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr); }
.stage {
  min-width: 0; min-height: 0; display: flex; flex-direction: column;
  background: var(--stage-face), var(--surface);
  border: 1px solid var(--border);
  border-radius: 0;
  overflow: hidden;
}
.titlebar { z-index: 20; height: 50px; flex: none; display: flex; align-items: center; gap: var(--space-3); padding: 0 var(--space-5); border-bottom: 1px solid var(--border); background: color-mix(in oklch, var(--surface) 88%, transparent); backdrop-filter: blur(14px); }
.tb-title { color: var(--muted); font-size: var(--fs-sm); font-family: var(--font-display); }
.tb-brand { display: inline-flex; align-items: center; gap: var(--space-2); font-weight: 600; letter-spacing: -.01em; color: inherit; text-decoration: none; }
.tb-brand .dot, .rail-brand .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--mark); flex: none; box-shadow: 0 0 8px color-mix(in oklch, var(--mark) 60%, transparent); }
.tb-chip { display: inline-flex; align-items: center; gap: 7px; height: 26px; padding: 0 11px; border: 1px solid var(--border); border-radius: 999px; background: var(--wash); font-size: 12.5px; color: var(--muted); }
.tb-chip .pulse { width: 6px; height: 6px; border-radius: 50%; background: var(--info); animation: pulse 1.8s ease-out infinite; }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 color-mix(in oklch, var(--info) 55%, transparent); } 70% { box-shadow: 0 0 0 6px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }

.themeswitch { display: inline-flex; border: 1px solid var(--ink-line); border-radius: 999px; padding: 2px; background: transparent; }
.themeswitch button { display: grid; place-items: center; width: 32px; height: 22px; border: 0; background: transparent; color: var(--ink-muted); border-radius: 999px; }
.themeswitch button:hover { color: var(--ink-fg); background: var(--ink-hover); }
.themeswitch button[aria-pressed="true"] { background: var(--ink-accent-soft); color: var(--ink-accent); }
.themeswitch .ic { width: 13px; height: 13px; }

/* ── app shell ────────────────────────────────────────────────────────────── */
.rail {
  display: none;
  position: relative;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-4) var(--space-3);
  background: linear-gradient(180deg, rgba(230, 237, 245, .05), transparent 140px), var(--ink);
  color: var(--ink-fg);
  border: 1px solid var(--ink-line);
  border-radius: var(--radius-lg);
  overflow: auto;
  box-shadow: var(--edge), var(--raise-lg);
}
.rail-brand { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-2) var(--space-4); color: var(--ink-fg); font-weight: 600; letter-spacing: -.01em; text-decoration: none; }
.rail-brand:hover { text-decoration: none; color: var(--ink-accent); }
.rail-id { padding: var(--space-1) var(--space-2) var(--space-4); margin-bottom: var(--space-2); border-bottom: 1px solid var(--ink-line); }
.rail-id .nm { font-weight: 600; font-size: 14px; letter-spacing: -.01em; color: var(--ink-fg); }
.rail-id .sub { color: var(--ink-muted); font-size: 12.5px; margin-top: 2px; }
.nav-group { display: flex; flex-direction: column; gap: 2px; margin-bottom: var(--space-3); }
.nav-group-label { font-family: var(--font-mono); font-size: 10px; letter-spacing: .18em; text-transform: uppercase; color: var(--faint); padding: var(--space-2) var(--space-2) var(--space-1); }
.nav-marker { position: absolute; top: 0; left: 0; width: 3px; border-radius: 999px; background: linear-gradient(180deg, var(--accent), color-mix(in oklch, var(--accent) 35%, transparent)); pointer-events: none; transform: translateY(0); transition: transform var(--dur) var(--ease), height var(--dur) var(--ease); box-shadow: 0 0 8px color-mix(in oklch, var(--accent) 55%, transparent); }
.rail-foot { margin-top: auto; padding-top: var(--space-4); display: flex; flex-direction: column; gap: var(--space-3); }
.rail-user { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2); border-top: 1px solid var(--ink-line); }
.rail-user .nm { font-size: 13px; font-weight: 500; color: var(--ink-fg); }
.rail-user .sub { color: var(--ink-muted); font-size: 11.5px; }
.rail-only-icon { display: none; }
.rail :focus-visible { outline-color: var(--ink-accent); }

.tabbar {
  flex: none;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  height: var(--tabbar-h);
  background: color-mix(in oklch, var(--ink) 92%, transparent);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--ink-line);
  z-index: 30;
}
.tab {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  min-height: var(--tabbar-h); color: var(--ink-muted); text-decoration: none; font-size: 11px;
  background: transparent; border: 0; position: relative;
}
.tab:hover { color: var(--ink-fg); text-decoration: none; }
.tab[aria-current="page"], .tab[aria-expanded="true"] { color: var(--ink-accent); }
.tab .chip { position: absolute; top: 6px; right: 18%; height: 16px; min-width: 16px; padding: 0 4px; font-size: 10px; }
.more-panel {
  position: fixed; left: var(--space-3); right: var(--space-3); bottom: calc(var(--tabbar-h) + var(--space-2));
  z-index: 40; background: color-mix(in oklch, var(--ink) 96%, transparent); color: var(--ink-fg);
  border: 1px solid var(--ink-line); border-radius: var(--radius-lg);
  padding: var(--space-3); box-shadow: var(--edge), var(--raise-lg);
  backdrop-filter: blur(16px);
  display: flex; flex-direction: column; gap: var(--space-1);
}
.more-panel[hidden] { display: none; }
.more-panel .nav-item { color: var(--ink-muted); }
.more-panel .nav-item:hover { background: var(--ink-hover); color: var(--ink-fg); }
.more-panel .nav-item[aria-current="page"] { background: var(--ink-accent-soft); color: var(--ink-accent); }
.more-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); margin-top: var(--space-2); padding-top: var(--space-3); border-top: 1px solid var(--ink-line); }

.nav-item { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 38px; padding: 0 10px; border: 1px solid transparent; border-radius: var(--radius); background: transparent; color: var(--muted); font-size: 14px; text-align: left; transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease); text-decoration: none; }
.nav-item:hover { background: var(--fg-soft); color: var(--fg); text-decoration: none; }
.nav-item[aria-current="page"] {
  background: linear-gradient(90deg, color-mix(in oklch, var(--accent) 16%, transparent), color-mix(in oklch, var(--accent) 6%, transparent));
  border-color: color-mix(in oklch, var(--accent) 38%, transparent);
  color: var(--fg);
  font-weight: 600;
  box-shadow: var(--edge);
}
.nav-item .count { margin-left: auto; font-family: var(--font-mono); font-size: 11px; color: var(--muted); background: var(--wash); border: 1px solid var(--border); border-radius: 999px; padding: 0 7px; }

.main { flex: 1; min-width: 0; min-height: 0; overflow: auto; padding: var(--space-5) var(--space-5) var(--space-7); animation: rise-in var(--dur) var(--ease); }
.reading { width: min(100%, var(--reading)); margin-inline: auto; }
.reading .head h1 { font-family: var(--font-display); font-size: var(--fs-display); font-weight: 500; letter-spacing: -.02em; }
.search-query .input { min-height: var(--space-7); background: var(--bg); }
.stack { display: flex; flex-direction: column; gap: var(--gap-md); }
.row { display: flex; align-items: center; gap: var(--gap-sm); flex-wrap: wrap; }
.row.tight { gap: var(--gap-xs); }
.head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--gap-md); flex-wrap: wrap; }
.head h1 { font-family: var(--font-display); font-size: var(--fs-display); font-weight: 500; letter-spacing: -.02em; }
.head .sub { color: var(--muted); font-size: 13.5px; margin-top: 5px; max-width: 76ch; }

/* ── cards, tables, controls ──────────────────────────────────────────────── */
.card { background: var(--card-face), var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--edge), var(--raise); }
.card-h { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 14px 18px; border-bottom: 1px solid var(--border); }
.card-h .ttl { font-weight: 600; font-size: 13.5px; letter-spacing: -.005em; }
.card-pad { padding: 18px; }

.btn { display: inline-flex; align-items: center; justify-content: center; gap: 7px; min-height: 36px; padding: 0 15px; border-radius: var(--radius); border: 1px solid transparent; font-size: 13.5px; font-weight: 500; transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease); text-decoration: none; }
.btn:hover { text-decoration: none; }
.btn-primary {
  background: linear-gradient(180deg, var(--accent-hover), var(--accent-deep));
  color: var(--accent-fg);
  box-shadow: var(--glow), var(--edge);
  font-weight: 600;
}
.btn-primary:hover { color: var(--accent-fg); transform: var(--lift); filter: brightness(1.05) saturate(1.06); }
.btn-secondary { background: var(--wash); color: var(--fg); border-color: var(--border); backdrop-filter: blur(8px); }
.btn-secondary:hover { background: var(--wash-hi); }
.btn-ghost { background: transparent; color: var(--muted); padding-inline: 9px; border-color: transparent; }
.btn-ghost:hover { background: var(--wash); color: var(--fg); }
.btn-sm { min-height: 30px; font-size: 12.5px; padding: 0 11px; border-radius: 8px; }
.btn:disabled { opacity: .5; cursor: not-allowed; transform: none; filter: none; }

/* ── upload in progress ───────────────────────────────────────────────────────
 * The upload button triggers a multipart POST that can run for minutes on a
 * big queue; with no state change the page looks frozen and a second click
 * would double-submit. While busy the button carries a spinner and says
 * "Uploading…", keeps full opacity (a half-dimmed spinner reads as broken),
 * and every input that could change the queue is a no-op in script. */
.spinner {
  display: none;
  width: 14px; height: 14px; flex: none;
  border-radius: 50%;
  border: 2px solid color-mix(in oklch, currentColor 35%, transparent);
  border-top-color: currentColor;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.btn.is-uploading { opacity: 1; cursor: progress; }
.btn.is-uploading .spinner { display: block; }
.btn.is-uploading .ic { display: none; }
.dropzone[aria-disabled="true"] { opacity: .55; cursor: default; pointer-events: none; }

.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-family: var(--font-mono); font-size: 10.5px; font-weight: 500; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
.field .hint { color: var(--muted); font-size: 12.5px; }
.input, .select {
  width: 100%; min-height: 38px; padding: 8px 12px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--wash); color: var(--fg); font-size: 14px;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.input::placeholder { color: var(--faint); }
.input:focus, .select:focus {
  outline: none; border-color: color-mix(in oklch, var(--accent) 60%, transparent);
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent) 20%, transparent);
}

.chip { display: inline-flex; align-items: center; gap: 6px; height: 26px; padding: 0 10px; border: 1px solid var(--border); border-radius: 999px; background: var(--wash); font-size: 12px; color: var(--muted); }
.chip[hidden], .field[hidden] { display: none; }
.wf-fields { display: flex; flex-direction: column; gap: var(--space-3); }
.wf-fields .select, .wf-fields .input { width: 100%; }
/* A block of code or a long single-line value (URL, token). A pill `.chip` has a fixed
   height and inline-flex sizing, so multi-line or unbroken content overflows the panel;
   this is the block-shaped alternative that wraps and scrolls instead. */
.codeblock { display: block; box-sizing: border-box; width: 100%; min-width: 0; max-width: 100%; margin: 0; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--wash); color: var(--fg); font-family: var(--font-mono); font-size: 12.5px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; overflow-x: auto; }
/* The MCP page's tool list: name + what it does, so a reader sees the surface at a
   glance. Bounded and definition-list-like, not a table. */
.tool-list { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; }
.tool-list li { display: flex; align-items: baseline; gap: 10px; font-size: 13px; }
.tool-list li code { font-family: var(--font-mono); font-size: 12.5px; color: var(--accent); white-space: nowrap; }
.tool-list li span { color: var(--muted); }
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.tag { display: inline-flex; align-items: center; gap: 5px; min-height: 22px; padding: 2px 9px; border-radius: 999px; font-size: 11px; font-weight: 600; letter-spacing: .02em; border: 1px solid transparent; white-space: nowrap; }
.tag.ok { background: var(--ok-soft); color: var(--ok); border-color: color-mix(in oklch, var(--ok) 30%, transparent); }
.tag.wait { background: var(--wash); color: var(--muted); border-color: var(--border); }
.tag.bad { background: var(--danger-soft); color: var(--danger); border-color: color-mix(in oklch, var(--danger) 30%, transparent); }
.tag.info { background: var(--info-soft); color: var(--info); border-color: color-mix(in oklch, var(--info) 30%, transparent); }
.tag.warn { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in oklch, var(--warn) 30%, transparent); }

.avatar { width: 30px; height: 30px; flex: none; display: grid; place-items: center; border-radius: 50%; background: var(--accent-soft); color: var(--accent); border: 1px solid color-mix(in oklch, var(--accent) 35%, transparent); font-family: var(--font-mono); font-size: 11px; font-weight: 500; }

.notice { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--card-face), var(--surface); font-size: 13.5px; box-shadow: var(--edge); }
.notice.good { border-color: color-mix(in oklch, var(--ok) 35%, var(--border)); background: var(--ok-soft); }
.notice.bad { border-color: color-mix(in oklch, var(--danger) 40%, var(--border)); background: var(--danger-soft); }

/* ── destructive actions ─────────────────────────────────────────────────────
 * Delete/remove buttons read as destructive at a glance: danger colour on hover,
 * never a neutral ghost that deletes a department on a mis-click. */
.btn-danger { background: transparent; color: var(--danger); border-color: color-mix(in oklch, var(--danger) 40%, var(--border)); }
.btn-danger:hover { background: var(--danger); color: var(--on-danger); border-color: var(--danger); }

/* ── notifications page ───────────────────────────────────────────────────────
 * One card per notification: readable body, decision buttons on the card, an
 * unread marker that survives scanning a long list. */
.notification.unread { border-left: 3px solid var(--accent); }
.dot-new { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 8px color-mix(in oklch, var(--accent) 70%, transparent); margin-right: 7px; vertical-align: 2px; }
.notif-body { margin-top: 10px; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--wash); white-space: pre-wrap; overflow-wrap: break-word; font-size: 13.5px; line-height: 1.55; max-width: 72ch; }

/* ── list view tables ────────────────────────────────────────────────────────
 * A table is a table: it fills the card it sits in (an old `display:block` here
 * shrank every list to its content width, which is why lists never matched the
 * window). When a list genuinely cannot shrink — phone widths — the CARD scrolls
 * sideways, so the page itself never gains a horizontal scrollbar. */
.table { display: table; width: 100%; border-collapse: separate; border-spacing: 0; table-layout: auto; font-size: 13.5px; }
.table th { text-align: left; font-weight: 500; }
.table thead th {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--faint); padding: 11px 16px; background: var(--table-head);
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
.table tbody td { padding: 13px 16px; border-bottom: 1px solid var(--row-line); vertical-align: middle; }
.table tbody tr { transition: background var(--dur) var(--ease); }
.table tbody tr:hover td { background: var(--row-hover); }
.table tbody tr:hover td:first-child { border-radius: 9px 0 0 9px; }
.table tbody tr:hover td:last-child { border-radius: 0 9px 9px 0; }
.table tbody tr:last-child td { border-bottom: 0; }
.card:has(> .table), .card-pad:has(> .table) { overflow-x: auto; }
@media (max-width: 640px) { .table thead th { white-space: normal; } }
.fname { font-weight: 600; display: inline-flex; align-items: center; gap: 8px; }
.fname .ic { color: var(--muted); }

/* A sortable header is a link, not a bare word: it reads as the control it is, and the active
   column keeps its direction arrow so the current order is always legible. */
.th-sort {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--faint); text-decoration: none;
  font: inherit; letter-spacing: inherit; text-transform: inherit;
  transition: color var(--dur) var(--ease);
}
.th-sort:hover { color: var(--fg); text-decoration: none; }
.th-sort.active { color: var(--accent); }
.sort-dir { font-size: 12px; color: var(--accent); }
.cell-action { text-align: right; white-space: nowrap; }

/* The page-size control, sized to sit on the card header line. */
.select-sm {
  min-height: 28px; padding: 0 9px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--wash); color: var(--fg); font: inherit; font-size: 12.5px;
}

/* The pager: the count on the left, the controls on the right, both legible. */
.pager {
  display: flex; align-items: center; justify-content: space-between; gap: var(--gap-sm);
  padding: 12px 16px; border-top: 1px solid var(--border);
}
.btn.disabled { pointer-events: none; opacity: .45; }

.empty { padding: 30px 18px; text-align: center; color: var(--muted); font-size: 13px; }
.empty .ttl { color: var(--fg); font-weight: 600; font-size: 14px; margin-bottom: 4px; }

/* ── files drop zone & upload queue ──────────────────────────────────────────
 * A drop target for one or several files, plus the list of what is queued. Colour is
 * used for the drag state only; sizes stay in tokens' family and are not decorative.
 */
.dropzone {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  padding: 28px 18px; border: 1.5px dashed color-mix(in oklch, var(--border) 80%, transparent); border-radius: 12px;
  background: var(--wash); color: var(--muted); text-align: center; cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease), color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.dropzone:hover, .dropzone:focus-visible { border-color: var(--accent); color: var(--fg); outline: none; }
.dropzone.dragover { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); transform: var(--lift); box-shadow: var(--glow); }
.dropzone .ic.big { width: 26px; height: 26px; color: var(--accent); }
.dropzone .dz-title { font-weight: 500; font-size: 14px; color: var(--fg); }
.dropzone .dz-sub { font-size: 12.5px; }

.upload-queue { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; }
.upload-queue li {
  display: flex; align-items: center; gap: 10px; padding: 8px 11px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--wash); font-size: 13px;
}
.upload-queue .q-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.upload-queue .q-size { color: var(--muted); font-family: var(--font-mono); font-size: 12px; white-space: nowrap; }
.upload-queue .q-remove {
  border: 0; background: transparent; color: var(--muted); font-size: 16px; line-height: 1;
  padding: 2px 6px; cursor: pointer; border-radius: var(--radius);
}
.upload-queue .q-remove:hover { background: var(--danger-soft); color: var(--danger); }

/* Files is the daily surface: a slim upload strip, a sticky toolbar, then the table. */
.main:has(.files-page) { padding: 0; }
.files-page { display: flex; flex-direction: column; min-height: 100%; }
.files-intro { padding: var(--space-5) var(--space-6) 0; }
.files-inset { margin: var(--space-4) var(--space-6) 0; }
.notice-ic { margin-top: 2px; }
.file-problem { margin-top: var(--space-1); }
.file-problem .reindex-form { display: inline-block; margin-left: 8px; vertical-align: middle; }
.fname-a { color: inherit; text-decoration: none; }
.fname-a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ── file preview page: image left, facts right ────────────────────────────── */
.preview-layout { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--space-4); align-items: start; }
.preview-figure { padding: 1rem; text-align: center; }
.preview-figure img { max-width: 100%; max-height: 68vh; border-radius: 8px; box-shadow: 0 4px 18px rgba(0, 0, 0, 0.18); }
.preview-meta { padding: 1rem; display: flex; flex-direction: column; gap: var(--space-3); }
.preview-meta .btn { align-self: flex-start; }
.meta-list { display: flex; flex-direction: column; gap: 10px; margin: 0; }
.meta-list > div { display: flex; flex-direction: column; gap: 2px; }
.meta-list dt { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; opacity: 0.65; }
.meta-list dd { margin: 0; font-weight: 600; overflow-wrap: anywhere; }
@media (max-width: 900px) { .preview-layout { grid-template-columns: 1fr; } }
.upload-form { padding: var(--space-4) var(--space-6) 0; display: flex; flex-direction: column; gap: var(--space-3); }
.upload-row { display: flex; align-items: stretch; gap: var(--space-3); }
.upload-row .dropzone { flex: 1; }
.upload-row .btn { align-self: center; }
.dropzone-slim {
  flex-direction: row; justify-content: flex-start; text-align: left;
  padding: var(--space-3) var(--space-4); gap: var(--space-3);
}
.dropzone-slim .ic.big { width: 18px; height: 18px; }
.dropzone-slim .dz-copy { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.dropzone-slim .dz-sub { display: none; }
.dropzone-slim.dragover {
  flex-direction: column; align-items: center; text-align: center;
  padding: var(--space-6) var(--space-4);
}
.dropzone-slim.dragover .dz-sub { display: block; }
.upload-form:has(.upload-queue:not([hidden])) .upload-queue { display: flex; }
.upload-meta { display: flex; flex-direction: column; gap: var(--space-1); }
.files-toolbar {
  position: sticky; top: 0; z-index: 4;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap;
  margin-top: var(--space-4);
  padding: var(--space-3) var(--space-6);
  background: color-mix(in oklch, var(--surface) 92%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}
.files-sheet { border-radius: 0; border-inline: 0; border-top: 0; box-shadow: none; }
@media (max-width: 767px) {
  .files-intro, .upload-form, .files-toolbar { padding-inline: var(--space-4); }
  .files-inset { margin-inline: var(--space-4); }
  .upload-row { flex-direction: column; }
  .upload-row .btn { align-self: flex-end; }
}

/* ── assistant ────────────────────────────────────────────────────────────────
 * The one page that owns the viewport: the conversation scrolls and the composer does not.
 * `.app` is a grid whose items do not stretch by default, so a child that wants a definite
 * height has to claim the row explicitly -- and with a definite height the inner `flex: 1`
 * resolves against it rather than against the content, which is what pins the composer.
 */
.main-fixed {
  align-self: stretch;
  min-height: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.chat { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.chat-scroll { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.chat-scroll:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; }
.chat-inner { width: min(100%, calc(var(--reading) + var(--space-7))); margin: 0 auto; padding: var(--space-5) var(--space-6) var(--space-3); display: flex; flex-direction: column; gap: var(--gap-md); }
.chat-inner .head h1 { font-family: var(--font-display); font-size: var(--fs-display); font-weight: 500; letter-spacing: -.02em; }

/* What the page says before anything has been asked. Disappears on the first question. */
.chat-hint { border-top: 1px solid var(--border); padding-top: var(--gap-md); color: var(--muted); font-size: 13.5px; display: flex; flex-direction: column; gap: 6px; }
.chat-hint[hidden] { display: none; }
.chat-hint .eg { font-style: italic; color: var(--fg); }

/* A margin and a page, not speech balloons. The question is a heading and the answer is the
   body, because that is what this product is: a document you interrogate. */
.transcript { display: flex; flex-direction: column; gap: var(--gap-lg); }
.transcript:empty { display: none; }
.turn { display: grid; grid-template-columns: 72px minmax(0, 1fr); gap: var(--space-3); }
.turn-role { padding-top: 2px; }
.turn-parts { min-width: 0; display: flex; flex-direction: column; gap: var(--gap-sm); }
.turn-body { white-space: pre-wrap; line-height: 1.65; }
.turn.you .turn-body { color: var(--muted); font-family: var(--font-display); font-size: var(--fs-title); line-height: 1.35; }
.turn.assistant .turn-body { border-left: 2px solid color-mix(in oklch, var(--accent) 55%, transparent); padding-left: var(--space-4); }

/* What was attached to a message. On the question, not the answer: these are the files the
   reader brought into the conversation, shown beside their words rather than guessed from them. */
.message-attachments { display: flex; flex-wrap: wrap; gap: var(--gap-xs); }
.message-attach { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border: 1px solid var(--border); border-radius: 999px; background: var(--wash); font-size: 12.5px; }
.message-attach .ic { width: 13px; height: 13px; color: var(--muted); flex: none; }

/* The trail from question to answer. A rule down the left says "this is commentary on the answer
   below", the way a margin note does in print. Colour carries the state and nothing else. */
.activity { border-left: 2px solid var(--border); padding-left: 12px; }
.activity-summary { display: flex; align-items: center; gap: 6px; cursor: pointer; color: var(--muted); font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .02em; list-style: none; }
.activity-summary::-webkit-details-marker { display: none; }
.activity-summary::before { content: "▸"; font-size: 9px; }
.activity[open] > .activity-summary::before { content: "▾"; }
.activity-summary:hover { color: var(--fg); }
.activity-steps { margin: 9px 0 0; padding-left: 17px; display: flex; flex-direction: column; gap: 5px; }
.activity-step { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--muted); }
.activity-step .ic { width: 13px; height: 13px; flex: none; }
.activity-step.running { color: var(--accent); }
.activity-step.running .ic { animation: rise-in var(--dur) var(--ease); }
.activity-step.failed { color: var(--danger); }
.activity-note { color: var(--danger); font-size: 12.5px; }

/* What the answer was built from. A card rather than a footnote at the end of the prose: these
   are the files the reader came for, and reaching one should not mean reading the answer again
   to find its name. */
.answer-files { border: 1px solid var(--border); border-radius: 12px; overflow: hidden; background: var(--card-face), var(--surface); }
.answer-files-head { padding: 8px 12px; border-bottom: 1px solid var(--border); background: var(--table-head); font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--faint); }
.answer-file-list { display: flex; flex-direction: column; }
.answer-file { display: flex; align-items: center; gap: 9px; padding: 9px 12px; border-bottom: 1px solid var(--row-line); }
.answer-file:last-child { border-bottom: 0; }
.answer-file > .ic { color: var(--muted); flex: none; }
.answer-file .fname { min-width: 0; overflow-wrap: anywhere; }
.answer-file .meta { margin-left: auto; white-space: nowrap; }
.answer-file .btn { flex: none; }

/* ── the composer ─────────────────────────────────────────────────────────────
 * Pinned to the foot of the window: the one control on this page that must never move.
 */
.composer { flex: none; border-top: 1px solid var(--border); background: var(--card-face), var(--surface); padding: 12px 0 14px; }
.composer-inner { width: min(100%, calc(var(--reading) + var(--space-7))); margin: 0 auto; padding-inline: var(--space-6); }
.composer-row { display: flex; align-items: flex-end; gap: var(--gap-xs); }
.composer-input {
  flex: 1; min-width: 0;
  min-height: 40px; max-height: 168px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--wash);
  color: var(--fg);
  font: inherit;
  line-height: 1.45;
  resize: none;
  overflow-y: auto;
}
.composer-input:focus { outline: none; border-color: color-mix(in oklch, var(--accent) 60%, transparent); box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent) 20%, transparent); }
.composer-note { margin-top: 8px; color: var(--muted); }

/* The paperclip. Sized to the input beside it so the row reads as one control. */
.composer-attach {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px; min-height: 40px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--wash);
  color: var(--muted);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.composer-attach:hover { color: var(--fg); background: var(--wash-hi); }
.composer-attach .ic { width: 16px; height: 16px; }

/* What is being added, and how far along it is. A file is not usable the moment it is sent:
   ingest runs on the worker, so the chip reports the real state rather than implying readiness. */
.attachments { display: flex; flex-wrap: wrap; gap: var(--gap-xs); margin-top: 8px; }
.attachments[hidden] { display: none; }
.attachment { display: inline-flex; align-items: center; gap: 7px; padding: 5px 11px; border: 1px solid var(--border); border-radius: 999px; background: var(--wash); font-size: 12.5px; }
.attachment > .ic { color: var(--muted); flex: none; }
.attachment-name { font-weight: 500; overflow-wrap: anywhere; }
.attachment-state.bad { color: var(--danger); }

/* ── search results ───────────────────────────────────────────────────────── */
.results { display: flex; flex-direction: column; }
.result { padding: 16px 18px; border-bottom: 1px solid var(--row-line); transition: background var(--dur) var(--ease); }
.result:hover { background: var(--row-hover); }
.result:last-child { border-bottom: 0; }
.result .top { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.result .where { display: inline-flex; align-items: center; gap: 5px; }
.result .section { color: var(--muted); font-size: 12.5px; }
.result .snip { margin-top: 7px; font-size: 13.5px; line-height: 1.6; color: var(--fg); }
.result .snip.none { color: var(--muted); font-style: italic; }

/* The expand affordance. Quiet and inline: the preview and its remainder are one continuous
   passage, and the control should not read as a separate button. */
.snip-toggle {
  border: 0;
  background: transparent;
  padding: 0;
  margin-left: 2px;
  color: var(--accent);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.snip-toggle:hover { text-decoration: underline; }

/* ── sign-in and password pages ─────────────────────────────────────────────
 * An immersive ink stage on the left — the marketing canvas, with its glows and
 * dot grid — and the form floating on a glass card at the right. Wide screens
 * split; narrow screens stack into one column, brand first.
 */
.auth {
  min-height: 100dvh;
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(430px, .8fr);
  background: var(--auth-face);
}
.auth-brand {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-5);
  padding: clamp(30px, 4.5vw, 60px);
  border-right: 1px solid var(--line);
}
/* The dot grid, faded out by a radial mask so it reads as depth, not wallpaper. */
.auth-brand::before {
  content: "";
  position: absolute; inset: 0;
  background-image: radial-gradient(var(--grid-dot) 1px, transparent 1.4px);
  background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(120% 95% at 26% 42%, #000 25%, transparent 78%);
  mask-image: radial-gradient(120% 95% at 26% 42%, #000 25%, transparent 78%);
  pointer-events: none;
}
.auth-brand > * { position: relative; }
.auth-brand .mark { display: flex; align-items: center; gap: var(--space-3); font-weight: 600; font-size: 21px; letter-spacing: -.01em; color: var(--fg); animation: rise-in .6s var(--ease) both; }
.auth-copy { display: flex; flex-direction: column; gap: var(--space-4); animation: rise-in .7s var(--ease) .12s both; }
.auth-copy p { margin: 0; max-width: 17ch; color: var(--fg); font-family: var(--font-display); font-size: clamp(32px, 3.6vw, 54px); font-weight: 300; line-height: 1.08; letter-spacing: -.025em; }
.auth-copy p .hl { color: var(--accent); text-shadow: 0 0 42px rgba(56, 189, 248, .45); }
.auth-strip { display: flex; align-items: center; gap: 14px; font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .26em; text-transform: uppercase; color: var(--faint); }
.auth-strip::before { content: ""; width: 34px; height: 1px; background: linear-gradient(90deg, var(--accent), transparent); }
.auth-panel { display: grid; place-items: center; padding: clamp(24px, 4vw, 48px); }
.signin { width: 100%; max-width: 400px; animation: rise-in .7s var(--ease) .18s both; }
/* The form card wears a gradient hairline: sky into bone into amber, the product's
   three colours tracing the edge. Padding-box/border-box paints it in two layers —
   the interior layer must be OPAQUE, or the border's gradient shows through the
   whole card instead of only the 1px ring. */
.signin .card {
  border: 1px solid transparent;
  border-radius: 18px;
  background:
    linear-gradient(180deg, color-mix(in oklch, var(--surface) 94%, var(--fg)), var(--surface)) padding-box,
    var(--hair-card);
  box-shadow: 0 30px 60px -32px rgba(0, 0, 0, .8), var(--edge);
  backdrop-filter: blur(16px);
}
:root[data-theme="light"] .signin .card {
  background:
    linear-gradient(180deg, #ffffff, #fbfdff) padding-box,
    var(--hair-card);
  box-shadow: 0 30px 60px -34px rgba(11, 18, 32, .45), var(--edge);
}
.signin .card-pad { padding: clamp(26px, 3vw, 36px); }
.signin h1 { font-family: var(--font-display); font-size: 26px; font-weight: 600; letter-spacing: -.02em; margin-top: 14px; }
.signin .sub { color: var(--muted); font-size: var(--fs-sm); margin-top: var(--space-1); margin-bottom: var(--space-5); }
.signin .btn-primary { width: 100%; min-height: 42px; font-size: 14px; }
.signin .fine { color: var(--faint); font-size: 11px; font-family: var(--font-mono); letter-spacing: .05em; text-align: center; margin-top: var(--space-4); }
.auth-alt { margin-top: var(--space-4); text-align: center; }
@media (max-width: 900px) {
  .auth { grid-template-columns: 1fr; }
  .auth-brand { justify-content: flex-start; gap: var(--space-4); padding: var(--space-6) var(--space-5); border-right: 0; border-bottom: 1px solid var(--line); min-height: 0; }
  .auth-copy p { font-size: var(--fs-title); max-width: none; }
  .auth-strip { display: none; }
  .auth-panel { place-items: start center; padding-top: var(--space-6); }
}

@media (min-width: 768px) {
  .app { grid-template-columns: var(--sidebar-compact) minmax(0, 1fr); padding: 12px; gap: 12px; }
  .stage { border-radius: var(--radius-lg); }
  .rail { display: flex; }
  .tabbar { display: none; }
  .more-panel { display: none; }
  .rail-brand, .nav-item, .rail-id, .rail-user { justify-content: center; }
  .rail .nav-label,
  .rail .rail-id .nm,
  .rail .rail-id .sub,
  .rail-user .grow,
  .nav-group-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .rail-only-icon { display: block; }
  .rail .nav-item { position: relative; }
  .rail .chip { position: absolute; top: 6px; right: 10px; margin: 0; width: 8px; height: 8px; min-height: 0; padding: 0; overflow: hidden; color: transparent; }
  .rail-id { border: 0; margin: 0; padding: 0; height: 0; overflow: hidden; }
  .nav-item { padding-inline: 0; }
  .rail-user { flex-direction: column; border-top: 0; }
  .main { padding: var(--space-5) var(--space-4) var(--space-6); }
}

@media (min-width: 1024px) {
  .app { grid-template-columns: var(--sidebar-w) minmax(0, 1fr); padding: var(--gutter); gap: var(--gutter); }
  .rail-brand, .nav-item, .rail-id, .rail-user { justify-content: flex-start; }
  .rail .nav-label,
  .rail .rail-id .nm,
  .rail .rail-id .sub,
  .rail-user .grow,
  .nav-group-label { position: static; width: auto; height: auto; overflow: visible; clip: auto; }
  .rail-only-icon { display: none; }
  .rail .chip { position: static; width: auto; height: 28px; padding: 0 11px; overflow: visible; color: var(--ink-accent); }
  .rail-id { border-bottom: 1px solid var(--ink-line); margin-bottom: var(--space-2); padding-bottom: var(--space-4); }
  .nav-item { padding-inline: 10px; }
  .rail-user { flex-direction: row; border-top: 1px solid var(--ink-line); }
  .main { padding: var(--space-5) var(--space-6) var(--space-7); }
}

/* ── control panel ────────────────────────────────────────────────────────────
 * The admin console shares the design tokens above; only its shell differs, because
 * an administrator's job is different from a member's: they are managing a workspace
 * rather than reading their own files. Two floating panels over the ink canvas —
 * the sidebar rail and the top bar — with the page scrolling between them.
 */
.shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  gap: var(--gutter);
  height: 100dvh;
  padding: var(--gutter);
  overflow: hidden;
  background: var(--shell-face);
}
.side {
  position: relative;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 18px 14px;
  background: linear-gradient(180deg, rgba(230, 237, 245, .05), transparent 140px), var(--ink);
  color: var(--ink-fg);
  border: 1px solid var(--ink-line);
  border-radius: var(--radius-lg);
  box-shadow: var(--edge), var(--raise-lg);
  overflow: auto;
}
.side .who { padding: var(--space-1) var(--space-2) var(--space-4); margin-bottom: var(--space-2); border-bottom: 1px solid var(--ink-line); }
.side .who .nm { font-weight: 600; font-size: 13.5px; color: var(--ink-fg); letter-spacing: -.01em; }
.side .who .sub { color: var(--faint); font-family: var(--font-mono); font-size: 10px; letter-spacing: .18em; text-transform: uppercase; margin-top: 5px; }
.side .thru { margin-top: auto; padding-top: var(--space-4); }
.side-theme { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: var(--space-2); }
.side :focus-visible { outline-color: var(--ink-accent); }
.nav-item[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }
.nav-item[aria-disabled="true"]:hover { background: transparent; color: var(--muted); }

.content { min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: var(--gutter); }
.top {
  z-index: 20; flex: none;
  display: flex; align-items: center; gap: var(--space-3);
  padding: 0 18px; height: 52px;
  border: 1px solid var(--border); border-radius: 14px;
  background: var(--glass);
  backdrop-filter: blur(14px);
  box-shadow: var(--edge), var(--raise);
}
.top .crumb { font-family: var(--font-mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); display: inline-flex; align-items: center; gap: 10px; }
.top .crumb::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--mark); box-shadow: 0 0 9px color-mix(in oklch, var(--mark) 65%, transparent); animation: breathe 3.2s ease-in-out infinite; }
.top .spacer { flex: 1; }
.page { flex: 1; min-height: 0; overflow: auto; padding: 4px 2px var(--space-6); animation: rise-in var(--dur) var(--ease); }
@media (max-width: 767px) {
  .shell { grid-template-columns: minmax(0, 1fr); height: auto; min-height: 100dvh; overflow: visible; padding: var(--space-3); }
  .side { min-height: 0; }
  .page { overflow: visible; padding-inline: 0; }
  .content { gap: var(--space-3); }
}

.metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--gap-md); }
.metric.card { padding: var(--space-4) var(--space-5); }
.page .head h1 { font-family: var(--font-display); font-size: var(--fs-display); font-weight: 500; letter-spacing: -.02em; }
.metric { display: flex; flex-direction: column; gap: 9px; }
.metric .label { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--faint); display: flex; align-items: center; gap: 8px; }
.metric .value { font-family: var(--font-display); font-size: 28px; font-weight: 300; letter-spacing: -.02em; line-height: 1.1; font-variant-numeric: tabular-nums; }
.metric .note { color: var(--muted); font-size: 12.5px; line-height: 1.55; }
.metric .bar { height: 6px; border-radius: 999px; background: var(--wash); overflow: hidden; }
.metric .bar i { display: block; height: 100%; background: linear-gradient(90deg, var(--accent), var(--accent-deep)); }
.metric .bar i.warn { background: var(--warn); }
.metric .bar i.bad { background: var(--danger); }

.grid2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--gap-md); align-items: start; }
@media (max-width: 1000px) { .grid2 { grid-template-columns: 1fr; } }

.list { display: flex; flex-direction: column; }
.list .item { display: flex; align-items: center; gap: var(--gap-sm); padding: 12px 16px; border-bottom: 1px solid var(--row-line); }
.list .item:last-child { border-bottom: 0; }

.soon { display: flex; flex-direction: column; gap: 10px; }
.soon .item { display: flex; align-items: flex-start; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--row-line); }
.soon .item:last-child { border-bottom: 0; }
.soon .what { font-weight: 500; font-size: 13.5px; }
.soon .why { color: var(--muted); font-size: 12.5px; margin-top: 2px; }

.inline-form { display: flex; align-items: flex-end; gap: var(--gap-xs); }
.inline-form .field { min-width: 140px; }
.select-sm { min-height: 32px; padding: 4px 8px; font-size: 13px; }

/* ── ink nav + motion primitives ─────────────────────────────────────────────
 * The sidebar is ink in both themes. Motion is the rise on a newly painted page,
 * the drop-zone lift, the row hover, and the accent already used by a running
 * assistant step.
 */
@keyframes rise-in {
  from { opacity: 0; transform: translateY(var(--space-2)); }
  to { opacity: 1; transform: none; }
}
@keyframes breathe {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklch, var(--mark) 45%, transparent); }
  50% { box-shadow: 0 0 10px 2px color-mix(in oklch, var(--mark) 30%, transparent); }
}

.rail, .side {
  color: var(--ink-fg);
  border-color: var(--ink-line);
}
.rail .rail-id,
.rail .rail-user,
.side .who,
.side .thru .rail-user { border-color: var(--ink-line); }
.rail .rail-id .nm,
.rail .rail-user .nm,
.side .who .nm,
.side .brand .tx,
.side .rail-user .nm { color: var(--ink-fg); }
.rail .rail-id .sub,
.rail .rail-user .sub,
.side .who .sub,
.side .rail-user .sub,
.side .meta { color: var(--ink-muted); }
.rail .nav-item,
.side .nav-item { color: var(--ink-muted); }
.rail .nav-item:hover,
.side .nav-item:hover { background: var(--ink-hover); color: var(--ink-fg); }
.rail .nav-item[aria-current="page"],
.side .nav-item[aria-current="page"] {
  background: linear-gradient(90deg, color-mix(in oklch, var(--accent) 20%, transparent), color-mix(in oklch, var(--accent) 7%, transparent));
  color: var(--ink-fg);
  border-color: color-mix(in oklch, var(--accent) 40%, transparent);
  font-weight: 600;
  box-shadow: var(--edge);
}
.rail .nav-item .count,
.side .nav-item .count,
.rail .chip { color: var(--ink-muted); background: color-mix(in oklch, var(--fg) 6%, transparent); border-color: var(--ink-line); }
.rail .chip { background: var(--ink-accent-soft); border-color: transparent; color: var(--ink-accent); }
.rail .avatar,
.side .avatar { background: var(--ink-accent-soft); color: var(--ink-accent); border-color: color-mix(in oklch, var(--ink-accent) 35%, transparent); }
.rail .btn-ghost,
.side .btn-ghost,
.more-panel .btn-ghost { color: var(--ink-muted); }
.rail .btn-ghost:hover,
.side .btn-ghost:hover,
.more-panel .btn-ghost:hover { background: var(--ink-hover); color: var(--ink-fg); }
.side .themeswitch { background: transparent; border-color: var(--ink-line); }
.side .themeswitch button { color: var(--ink-muted); }
.side .themeswitch button:hover { color: var(--ink-fg); background: var(--ink-hover); }
.side .themeswitch button[aria-pressed="true"] { background: var(--ink-accent-soft); color: var(--ink-accent); }

@media (prefers-reduced-motion: reduce) {
  .main,
  .page,
  .dropzone,
  .table tbody tr,
  .nav-item,
  .btn,
  .composer-attach,
  .auth-brand .mark,
  .auth-copy,
  .signin,
  .tb-chip .pulse,
  .top .crumb::before {
    animation: none;
    transition: none;
  }
  /* The spinner stops moving but stays visible: the state is carried by the
     ring and the "Uploading…" label, not by motion. */
  .btn .spinner { animation: none; border-top-color: currentColor; }
  .dropzone.dragover { transform: none; }
  .btn-primary:hover { transform: none; }
}

/* ── Knowledge graph (the KB view) ─────────────────────────────────────────
 * The picture owns the page: the canvas fills the viewport below the page head,
 * and search, the details panel, and the legend float ON it. Depth is drawn in
 * SVG: glossy radial-gradient nodes (stops coloured from tokens, so both themes
 * shade correctly), scale and opacity by distance, edges faded with depth.
 * Every colour still comes from a token — no literals outside :root.
 */
.main.graph-full { display: flex; flex-direction: column; overflow: hidden; }
.graph-page {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  padding: 0 var(--space-5) var(--space-4);
}
.graph-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-4);
  padding-top: var(--space-4);
}
.graph-stage {
  position: relative;
  flex: 1;
  min-height: 380px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 8%, color-mix(in oklch, var(--accent) 7%, transparent), transparent 70%),
    var(--surface);
}
.graph-svg { width: 100%; height: 100%; display: block; touch-action: none; cursor: grab; }
.graph-svg:active { cursor: grabbing; }
.graph-vignette { fill: transparent; pointer-events: none; }
.graph-svg .graph-edge { stroke: var(--border); fill: none; }
.graph-svg .graph-edge.mention { stroke: var(--ink-accent); stroke-dasharray: 5 4; }
.graph-svg .graph-edge.dimmed { stroke-opacity: 0.05 !important; }
.graph-svg .graph-node { cursor: grab; outline: none; }
.graph-svg .graph-node:active { cursor: grabbing; }
.graph-svg .graph-node.dimmed { opacity: 0.14 !important; }
.graph-svg .graph-node:focus-visible .node-shape { stroke: var(--accent); stroke-width: 2.5; }
.graph-svg .graph-node.active .node-shape { stroke: var(--fg); stroke-width: 2; }
.graph-svg .node-shape {
  stroke: color-mix(in oklch, var(--fg) 22%, transparent);
  stroke-width: 0.5;
  filter: drop-shadow(0 4px 5px color-mix(in oklch, var(--fg) 30%, transparent));
}
/* Glossy spheres: the gradient stops take their colours from the same tokens
   the legend dots use, mixed brighter at the highlight and deeper at the rim. */
.grad-stop.grad-hi.k-person { stop-color: color-mix(in oklch, var(--info) 45%, white); }
.grad-stop.grad-lo.k-person { stop-color: color-mix(in oklch, var(--info) 78%, black); }
.grad-stop.grad-hi.k-organization { stop-color: color-mix(in oklch, var(--accent) 40%, white); }
.grad-stop.grad-lo.k-organization { stop-color: color-mix(in oklch, var(--accent) 78%, black); }
.grad-stop.grad-hi.k-location { stop-color: color-mix(in oklch, var(--ok) 45%, white); }
.grad-stop.grad-lo.k-location { stop-color: color-mix(in oklch, var(--ok) 78%, black); }
.grad-stop.grad-hi.k-convention { stop-color: color-mix(in oklch, var(--ink-accent) 55%, white); }
.grad-stop.grad-lo.k-convention { stop-color: color-mix(in oklch, var(--ink-accent) 70%, var(--ink)); }
.grad-stop.grad-hi.k-concept { stop-color: color-mix(in oklch, var(--warn) 45%, white); }
.grad-stop.grad-lo.k-concept { stop-color: color-mix(in oklch, var(--warn) 78%, black); }
.graph-svg .graph-label {
  fill: var(--muted);
  font-size: 11px;
  font-family: var(--font-body);
  text-anchor: middle;
  pointer-events: none;
  paint-order: stroke;
  stroke: var(--surface);
  stroke-width: 2.5px;
}
.graph-searchbar {
  position: absolute;
  top: var(--space-4);
  left: var(--space-4);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: min(380px, 62%);
  padding: var(--space-2) var(--space-3);
  background: color-mix(in oklch, var(--surface) 88%, transparent);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--raise-lg);
  backdrop-filter: blur(6px);
  z-index: 6;
}
.graph-panel {
  position: absolute;
  top: var(--space-4);
  right: var(--space-4);
  width: min(360px, 42%);
  max-height: calc(100% - 7rem);
  overflow: auto;
  box-shadow: var(--raise-lg);
  z-index: 5;
}
.graph-legend {
  position: absolute;
  left: var(--space-4);
  bottom: var(--space-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: color-mix(in oklch, var(--surface) 88%, transparent);
  border: 1px solid var(--border);
  border-radius: 12px;
  backdrop-filter: blur(6px);
  z-index: 6;
}
.legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--fs-meta);
  color: var(--muted);
}
.legend-dot { width: 11px; height: 11px; border-radius: 50%; display: inline-block; }
.legend-dot.k-person { background: var(--info); }
.legend-dot.k-organization { background: var(--accent); }
.legend-dot.k-location { background: var(--ok); }
.legend-dot.k-convention { background: var(--ink-accent); border-radius: 2px; }
.legend-hint {
  border-left: 1px solid var(--border);
  padding-left: var(--space-3);
  font-style: italic;
}
.graph-docs { list-style: none; margin: 0 0 var(--space-3); padding: 0; display: grid; gap: var(--space-2); }
.graph-doc {
  display: grid;
  gap: 2px;
  padding: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.graph-related { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.graph-fallback {
  position: absolute;
  inset: var(--space-4);
  padding: var(--space-4);
  display: grid;
  gap: var(--space-3);
  align-content: start;
  background: var(--surface);
  overflow: auto;
  z-index: 7;
}
.graph-fallback ul { margin: 0; padding-left: var(--space-5); display: grid; gap: var(--space-1); }
@media (max-width: 980px) {
  .graph-panel { width: min(320px, 56%); }
  .graph-searchbar { width: min(300px, 58%); }
  .legend-hint { display: none; }
}

/* The graph head's select paints itself everywhere the theme does: on some
   platforms a native select box ignores author colours and leaves a white pill
   on a dark page. appearance:none hands the painting to the tokens, and the
   chevron is drawn by the wrapper. */
.select-wrap { position: relative; display: inline-flex; }
.select-wrap::after {
  content: ""; position: absolute; right: 10px; top: 50%; width: 7px; height: 7px;
  border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
  transform: translateY(-70%) rotate(45deg); pointer-events: none;
}
.select-wrap .select-sm { appearance: none; -webkit-appearance: none; padding-right: var(--space-6); }

/* ── native select popups ───────────────────────────────────────────────────
 * The option list is painted on its own layer: with a translucent select
 * background, Chromium paints that layer white while the option text inherits
 * our light colour — invisible words. So every select is painted OPAQUE from
 * the same tokens, and its options are painted explicitly per theme. The
 * closed control reads the same as the old wash (surface tinted by 4.5% of the
 * foreground is what the wash composited to over a card anyway).
 * These rules sit at the end of the file so they win the equal-specificity
 * rules above; `select.input` carries the element+class weight it needs to
 * beat the plain `.input` rule. */
select, .select, .select-sm, select.input { background: color-mix(in oklch, var(--surface) 95.5%, var(--fg)); }
select option, .select option, .select-sm option { background-color: var(--surface); color: var(--fg); }
