/* The application stylesheet. Built from frontend/css by frontend/scripts/build-css.js - edit the layers, not this file. */

/* Trycord design tokens v1.0 */
:root {
  --tc-brand: #FF4D24;
  --tc-brand-hover: #E9431D;
  --tc-brand-strong: #C93618;
  --tc-success: #35B875;
  --tc-warning: #F2B84B;
  --tc-danger: #EF5350;
  --tc-info: #5798F5;
  --tc-font-sans: "Manrope", system-ui, -apple-system, "Segoe UI", sans-serif;
  --tc-font-mono: "JetBrains Mono", "SFMono-Regular", Consolas, monospace;
  --tc-space-1: 4px; --tc-space-2: 8px; --tc-space-3: 12px;
  --tc-space-4: 16px; --tc-space-5: 20px; --tc-space-6: 24px;
  --tc-space-8: 32px; --tc-space-10: 40px; --tc-space-12: 48px;
  --tc-radius-sm: 4px; --tc-radius-md: 8px; --tc-radius-lg: 12px;
  --tc-radius-xl: 16px; --tc-radius-pill: 999px;
  --tc-motion-fast: 140ms; --tc-motion-normal: 180ms;
  --tc-ease: cubic-bezier(.2, 0, 0, 1);
}
:root, [data-theme="dark"] {
  color-scheme: dark;
  --tc-bg: #18191D; --tc-bg-deep: #121317;
  --tc-surface: #22242A; --tc-surface-hover: #2A2C33;
  --tc-border: #30323A; --tc-text: #F4F5F7;
  --tc-text-muted: #A4A7B0; --tc-text-on-brand: #FFFFFF;
  --tc-brand-focus: #FF7A5A;
}
[data-theme="light"] {
  color-scheme: light;
  --tc-bg: #F5F6F8; --tc-bg-deep: #FFFFFF;
  --tc-surface: #FFFFFF; --tc-surface-hover: #ECEEF2;
  --tc-border: #E7E9EE; --tc-text: #202127;
  --tc-text-muted: #666A75; --tc-text-on-brand: #FFFFFF;
  --tc-brand-focus: #C93618;
}

/* ---- tokens.css ---- */

/* The application's semantic layer over the token library.
 *
 * The library (inlined above by build-css.js) owns the palette, the type scale
 * and the timing. This file names the surfaces, the states and the measurements
 * the interface actually uses, so a component never reaches for a raw hex or a
 * magic pixel.
 *
 * Trycord is a workbench: navigation is quiet and structural, the conversation
 * is the most legible thing on screen, and the ember accent marks only what is
 * live, selected or primary.
 *
 * Reader-authored palettes arrive as inline --c-* properties from
 * packages/theme.js. The semantic names below fall back through them, so a
 * custom palette restyles the whole application without a second stylesheet.
 */

:root {
  /* -- measurement --------------------------------------------------------- */
  --rail-w: 68px;
  --context-w: 276px;
  --inspector-w: 336px;
  --stage-w: 1180px;
  --cmdbar-h: 52px;
  --head-h: 54px;
  --composer-max: 300px;
  --content-max: 1040px;
  /* A working surface is not a reading column. A studio - the workspace, the
     settings console, anything with two panes side by side - uses the width
     it is given, up to a point: a workspace squeezed into the width of an
     article is a workspace nobody can work in. */
  --workspace-max: 1760px;

  /* The readable floor. */
  --text-xs: 0.75rem;

  /* -- type ---------------------------------------------------------------- */
  --fs-display: clamp(1.9rem, 1.45rem + 1.7vw, 2.7rem);
  --fs-h1: 1.45rem;
  --fs-h2: 1.15rem;
  --fs-h3: 1rem;
  --fs-body: 0.9375rem;
  --fs-sm: 0.875rem;
  --fs-meta: 0.8125rem;
  --fs-micro: 0.75rem;
  --weight-body: 450;
  --weight-medium: 550;
  --weight-strong: 650;
  --weight-bold: 750;
  --weight-black: 850;
  --tracking-tight: -0.02em;
  --tracking-label: 0.11em;

  /* -- space --------------------------------------------------------------- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 28px;
  --space-8: 40px;
  --space-9: 56px;

  /* -- radii and motion ---------------------------------------------------- */
  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 20px;
  --radius-pill: var(--tc-radius-pill);
  --dur-1: var(--tc-motion-fast);
  --dur-2: var(--tc-motion-normal);
  --dur-3: 300ms;
  --ease: var(--tc-ease);
  --ease-out: cubic-bezier(.16, 1, .3, 1);

  /* -- layering ------------------------------------------------------------
   * The bands, from the page upwards:
   *
   *   nav    the shell's own chrome - the command bar
   *   scrim  the backdrop that dims the page behind a panel
   *   panel  the shell's panels - the place column, the inspector, the
   *          voice dock. One band, so a panel is never above another
   *          panel, and a panel is never above the menus, the toasts or
   *          the dialogs that belong to the reader's attention.
   *   menu   the menus
   *   overlay the sheets and the dialogs
   *   toast  the notices
   *   popover the thing that follows the pointer
   *   modal  the last word
   *
   * A panel that sits above the menus is a panel that covers the menu the
   * reader just opened; a panel above the toasts hides the answer to what
   * they just did. So the panels are one band, and the band is below every
   * one of those.
   */
  --z-nav: 30;
  --z-scrim: 35;
  --z-panel: 40;
  --z-menu: 75;
  --z-overlay: 80;
  --z-toast: 90;
  --z-popover: 100;
  --z-modal: 110;

  --font: var(--tc-font-sans);
  --mono: var(--tc-font-mono);

  /* -- interactive accents -------------------------------------------------- */
  --brand: var(--c-accent, var(--tc-brand));
  --brand-fill: var(--tc-brand-strong);
  --brand-fill-hover: var(--tc-brand);
  --brand-ink: #FFFFFF;
}

/* Density. The attribute lives on <html> and is written by js/prefs.js; the
 * default block is cozy, and the two other arrangements change measurements
 * rather than type, so a row is still a row. The rail's width is part of the
 * arrangement: a dense workspace gives the communities less room. */
:root,
:root[data-density="cozy"] {
  --row-h: 44px;
  --row-pad: 9px 10px;
  --gap-row: 8px;
  --msg-gap: 15px;
  --panel-pad: 16px;
  --section-gap: 24px;
  --rail-w: 68px;
}
:root[data-density="compact"] {
  --row-h: 36px;
  --row-pad: 6px 8px;
  --gap-row: 4px;
  --msg-gap: 10px;
  --panel-pad: 12px;
  --section-gap: 18px;
  --rail-w: 54px;
}
:root[data-density="comfortable"] {
  --row-h: 52px;
  --row-pad: 12px 12px;
  --gap-row: 10px;
  --msg-gap: 20px;
  --panel-pad: 20px;
  --section-gap: 32px;
  --rail-w: 82px;
}

/* Ember - the default dark palette. Charcoal from the canonical library, the
 * ember accent, and nothing else. */
:root,
[data-theme="trycord"],
[data-theme="dark"] {
  color-scheme: dark;
  --app-bg: var(--c-pg, var(--tc-bg-deep));
  --panel: var(--c-base, var(--tc-bg));
  --panel-2: #1D1F24;
  --panel-3: var(--tc-surface);
  --raised: var(--tc-surface);
  --rail-bg: #0E0F12;

  --line: var(--tc-border);
  --line-2: #3A3D46;

  --text-1: var(--c-txt, var(--tc-text));
  --text-2: #B9BDC7;
  --text-3: #8F949F;

  --hover: rgba(244, 245, 247, .06);
  --active: rgba(244, 245, 247, .10);
  --selected: color-mix(in srgb, var(--brand) 16%, transparent);

  --brand-soft: color-mix(in srgb, var(--brand) 13%, transparent);
  --brand-line: color-mix(in srgb, var(--brand) 42%, transparent);
  --focus: var(--tc-brand-focus);

  --danger: var(--tc-danger);
  --success: var(--tc-success);
  --warning: var(--tc-warning);
  --info: var(--tc-info);

  --shadow-1: 0 1px 3px rgba(0, 0, 0, .4);
  --shadow-2: 0 10px 30px -10px rgba(0, 0, 0, .65);
  --shadow-3: 0 26px 70px -18px rgba(0, 0, 0, .78);

  --ember-wash: radial-gradient(120% 80% at 50% 0%, color-mix(in srgb, var(--brand) 22%, transparent), transparent 70%);

  --scrollbar: rgba(255, 255, 255, .12);
  --scrollbar-hover: rgba(255, 255, 255, .20);
}

/* Daylight */
[data-theme="light"] {
  color-scheme: light;
  --app-bg: #F1F2F5;
  --panel: #F7F8FA;
  --panel-2: #FFFFFF;
  --panel-3: #EDEFF3;
  --raised: #FFFFFF;
  --rail-bg: #E8EAEE;

  --line: #E4E6EB;
  --line-2: #D3D6DD;

  --text-1: #1D1E23;
  --text-2: #4B5058;
  --text-3: #666B78;

  --hover: rgba(29, 30, 35, .05);
  --active: rgba(29, 30, 35, .09);
  --selected: rgba(201, 54, 24, .12);

  --brand: var(--c-accent, #C93618);
  --brand-fill: #C93618;
  --brand-fill-hover: #B02F14;
  --brand-soft: rgba(201, 54, 24, .10);
  --brand-line: rgba(201, 54, 24, .38);
  --focus: #B02F14;

  --danger: #B3261E;
  --success: #1B7A4E;
  --warning: #8A5A00;
  --info: #1F5FBF;

  --shadow-1: 0 1px 2px rgba(20, 22, 28, .06);
  --shadow-2: 0 10px 30px -12px rgba(20, 22, 28, .22);
  --shadow-3: 0 28px 60px -20px rgba(20, 22, 28, .28);

  --ember-wash: radial-gradient(120% 80% at 50% 0%, rgba(201, 54, 24, .10), transparent 70%);

  --scrollbar: rgba(20, 22, 28, .16);
  --scrollbar-hover: rgba(20, 22, 28, .26);
}

/* Midnight */
[data-theme="midnight"] {
  color-scheme: dark;
  --app-bg: #0B0E17;
  --panel: #121623;
  --panel-2: #171C2C;
  --panel-3: #1E2436;
  --raised: #262D42;
  --rail-bg: #080B13;

  --line: rgba(190, 210, 255, .085);
  --line-2: rgba(190, 210, 255, .15);

  --text-1: #EAEFFB;
  --text-2: #9AA6C4;
  --text-3: #98A2B8;

  --hover: rgba(190, 210, 255, .06);
  --active: rgba(190, 210, 255, .1);
  --selected: color-mix(in srgb, var(--brand) 18%, transparent);

  --brand-soft: color-mix(in srgb, var(--brand) 16%, transparent);
  --brand-line: color-mix(in srgb, var(--brand) 42%, transparent);
  --focus: var(--tc-brand-focus);

  --danger: #F87171;
  --success: #4ADE9B;
  --warning: #FBBF67;
  --info: #8FB4FF;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, .42);
  --shadow-2: 0 10px 28px -8px rgba(0, 0, 0, .62);
  --shadow-3: 0 26px 64px -18px rgba(0, 0, 0, .76);

  --ember-wash: radial-gradient(120% 80% at 50% 0%, color-mix(in srgb, var(--brand) 24%, transparent), transparent 70%);

  --scrollbar: rgba(190, 210, 255, .15);
  --scrollbar-hover: rgba(190, 210, 255, .24);
}


/* ---- base.css ---- */

/* Base: the font, the reset, and the handful of primitives everything else
 * inherits. Nothing here knows about a component. */

@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("../assets/trycord-assets/fonts/manrope-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("../assets/trycord-assets/fonts/manrope-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("../assets/trycord-assets/fonts/jetbrains-mono-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

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

* { margin: 0; }

html, body { height: 100%; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: 1.5;
  font-weight: var(--weight-body);
  color: var(--text-1);
  background: var(--app-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overscroll-behavior: none;
}

h1, h2, h3, h4, h5, h6 {
  font-weight: var(--weight-bold);
  line-height: 1.18;
  letter-spacing: var(--tracking-tight);
}
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }

/* The label voice: monospace, spaced, upper. It marks a section, a setting name,
   a metric - anything that names a thing rather than speaks. Using the mono for
   it is the one typographic move that separates this client from a template. */
.eyebrow {
  font-family: var(--mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-3);
}
.display {
  font-size: var(--fs-display);
  font-weight: var(--weight-black);
  letter-spacing: var(--tracking-tight);
  line-height: 1.08;
}

a { color: inherit; text-decoration: none; }
a:hover { text-decoration: none; }

button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
button:disabled { cursor: not-allowed; }

img, svg, video, canvas { display: block; max-width: 100%; }
svg { flex: none; }

ul, ol { list-style: none; padding: 0; }

hr { border: 0; border-top: 1px solid var(--line); margin: var(--space, 16px) 0; }

code, kbd, pre, samp { font-family: var(--mono); font-size: 0.9em; }

::placeholder { color: var(--text-3); opacity: 1; }

/* Focus: one ring, everywhere, keyboard-only. */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

::selection { background: var(--brand-soft); color: var(--text-1); }

/* Scrollbars: present when needed, quiet otherwise. */
* { scrollbar-width: thin; scrollbar-color: var(--scrollbar) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--scrollbar);
  border-radius: var(--radius-pill);
  border: 3px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-hover); background-clip: content-box; }

/* -- primitives ---------------------------------------------------------- */

/* The hidden attribute has to win.
 *
 * A component that sets its own display - a grid, a flex box - beats the
 * browser's rule for [hidden], because an author style beats a user-agent one.
 * An element asked to hide therefore stays on screen, still holding its
 * height. The sign-in pages hide the shell this way: without this rule the
 * empty shell keeps the viewport and the page that was meant to stand alone
 * is pushed below it.
 */
[hidden] { display: none !important; }

.app-root { height: 100dvh; }
/* A sign-in or public page is a direct child of <body>, beside the app host. While
   one is up the shell inside the host is hidden, so the host must stop reserving
   the viewport or it would push that page below the fold. */
[data-raw] .app-root { height: auto; }

.muted { color: var(--text-2); }
.subtle { color: var(--text-3); }
.mono { font-family: var(--mono); font-size: 0.86em; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  /* The skip link is chrome, not a notice. It belongs with the command bar
     and the app bar, and not in the band the toasts and the popovers use:
     a link that is above the toasts covers the answer to what the reader
     just did. */
  position: fixed; top: 8px; left: 8px; z-index: var(--z-nav);
  transform: translateY(-200%); background: var(--panel-3); color: var(--text-1);
  padding: 10px 16px; border-radius: var(--radius-sm); box-shadow: var(--shadow-2);
  transition: transform var(--dur-1) var(--ease);
}
.skip-link:focus { transform: translateY(0); }

.stack { display: flex; flex-direction: column; }
.row { display: flex; align-items: center; }
.spacer { flex: 1 1 auto; }
.gap-1 { gap: 4px; } .gap-2 { gap: 8px; } .gap-3 { gap: 12px; } .gap-4 { gap: 16px; }

.text-brand { color: var(--brand); }
.text-danger { color: var(--danger); }
.text-success { color: var(--success); }
.text-warning { color: var(--warning); }

/* The one ember wash, used sparingly behind a mark or a primary banner. */
.ember-wash { background-image: var(--ember-wash); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* The same floor when the reader asked for it in Appearance rather than through
   the OS - one of the two is always the last word, and they say the same thing. */
[data-motion="reduced"], [data-motion="reduced"] *,
[data-motion="reduced"] *::before, [data-motion="reduced"] *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.01ms !important;
  scroll-behavior: auto !important;
}


/* ---- components.css ---- */

/* Components: the shared vocabulary. Every control on every screen is one of
 * these, so a settings page and a conversation agree about what a button is.
 *
 * The language is flat charcoal: surfaces are told apart by one line and one
 * step of tone, not by stacked shadows; a control answers the pointer by
 * changing colour, not by moving. Elevation is reserved for what genuinely
 * floats - menus, dialogs, toasts - and the ember fill appears once per screen,
 * on the primary action. */

/* -- button -------------------------------------------------------------- */
.btn {
  --btn-bg: transparent;
  --btn-fg: var(--text-1);
  --btn-bd: transparent;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 36px; padding: 0 14px;
  border: 1px solid var(--btn-bd); border-radius: var(--radius-md);
  background: var(--btn-bg); color: var(--btn-fg);
  font-size: var(--fs-sm); font-weight: var(--weight-strong); white-space: nowrap;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
    color var(--dur-1) var(--ease), opacity var(--dur-1) var(--ease);
}
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn svg { width: 16px; height: 16px; }

.btn--primary { --btn-bg: var(--brand-fill); --btn-fg: var(--brand-ink); }
.btn--primary:hover:not(:disabled) { --btn-bg: var(--brand-fill-hover); }

.btn--default { --btn-bg: var(--raised); --btn-bd: var(--line-2); }
.btn--default:hover:not(:disabled) { --btn-bg: var(--panel-3); --btn-bd: var(--line-2); }

.btn--ghost, .btn--quiet { --btn-fg: var(--text-2); }
.btn--ghost:hover:not(:disabled), .btn--quiet:hover:not(:disabled) { --btn-bg: var(--hover); --btn-fg: var(--text-1); }

.btn--danger { --btn-fg: var(--danger); --btn-bd: color-mix(in srgb, var(--danger) 42%, transparent); }
.btn--danger:hover:not(:disabled) { --btn-bg: color-mix(in srgb, var(--danger) 12%, transparent); }

.btn--block { width: 100%; }
.btn--sm { height: 28px; padding: 0 10px; font-size: var(--fs-meta); }
.btn--lg { height: 44px; padding: 0 20px; font-size: var(--fs-body); }
.btn--icon { width: 34px; height: 34px; padding: 0; }
.btn--icon.btn--sm { width: 28px; height: 28px; }

.icon-btn {
  width: 32px; height: 32px; flex: none;
  display: inline-grid; place-items: center;
  border-radius: var(--radius-md); color: var(--text-2);
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.icon-btn:hover { background: var(--hover); color: var(--text-1); }
.icon-btn[aria-pressed="true"] { background: var(--brand-soft); color: var(--brand); }

/* -- input --------------------------------------------------------------- */
.input, .textarea, .select {
  width: 100%; min-width: 0;
  padding: 9px 12px;
  background: var(--app-bg);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-md);
  color: var(--text-1);
  font-size: var(--fs-sm);
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.input:hover, .textarea:hover, .select:hover { border-color: color-mix(in srgb, var(--text-3) 55%, transparent); }
.input:focus, .textarea:focus, .select:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}
.textarea { resize: vertical; min-height: 84px; line-height: 1.5; }
.select { appearance: none; padding-right: 32px; background-image: none; }

.field { display: flex; flex-direction: column; gap: 6px; }
.field-label { font-size: var(--fs-meta); font-weight: 600; color: var(--text-2); }
.field-hint { font-size: var(--fs-meta); color: var(--text-3); }
.field-error { font-size: var(--fs-meta); color: var(--danger); }

/* The whole-form answer, next to the submit button: what the server refused. */
.form-error { font-size: var(--fs-sm); color: var(--danger); }
.form-note { font-size: var(--fs-sm); color: var(--text-2); line-height: 1.6; }
.form-stack { display: flex; flex-direction: column; gap: var(--space-3); }
.input--invalid { border-color: color-mix(in srgb, var(--danger) 55%, transparent); }
.input--invalid:focus { border-color: var(--danger); box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 14%, transparent); }

.checkbox { display: flex; align-items: flex-start; gap: 10px; font-size: var(--fs-sm); cursor: pointer; }
.checkbox input { width: 16px; height: 16px; margin-top: 2px; accent-color: var(--brand-fill); cursor: pointer; }

.switch {
  position: relative; width: 40px; height: 24px; flex: none;
  border-radius: var(--radius-pill); background: var(--panel-3);
  border: 1px solid var(--line-2);
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.switch::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px;
  border-radius: 50%; background: var(--text-2);
  transition: transform var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.switch[aria-checked="true"] { background: var(--brand-fill); border-color: transparent; }
.switch[aria-checked="true"]::after { transform: translateX(16px); background: #fff; }

.segmented { display: inline-flex; padding: 3px; gap: 2px; background: var(--panel-3); border-radius: var(--radius-md); }
.segmented-item {
  padding: 5px 12px; border-radius: var(--radius-sm);
  font-size: var(--fs-meta); font-weight: 600; color: var(--text-2);
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.segmented-item:hover { color: var(--text-1); }
.segmented-item[aria-selected="true"] { background: var(--raised); color: var(--text-1); box-shadow: var(--shadow-1); }

/* -- surfaces ------------------------------------------------------------ */
.panel-title {
  font-family: var(--mono); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-3);
}

.settings-field {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 10px 0;
}
.settings-field-text { min-width: 0; }
.settings-field-label { font-size: var(--fs-sm); font-weight: 600; }
.settings-field-desc { margin-top: 2px; font-size: var(--fs-meta); color: var(--text-3); }
.settings-field-ctl { flex: none; display: flex; align-items: center; gap: 8px; }

.badge {
  display: inline-flex; align-items: center; gap: 5px; height: 20px; padding: 0 8px;
  border-radius: var(--radius-pill); font-size: var(--fs-micro); font-weight: 700;
  background: var(--panel-3); color: var(--text-2);
}
.badge--brand { background: var(--brand-soft); color: var(--brand); }
.badge--danger { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); }
.badge--success { background: color-mix(in srgb, var(--success) 14%, transparent); color: var(--success); }
.badge--warning { background: color-mix(in srgb, var(--warning) 16%, transparent); color: var(--warning); }
/* A state the server has not answered yet. It is not a warning: nothing is
   wrong, nothing is known, and the badge says so without claiming otherwise. */
.badge--muted { background: var(--panel-3); color: var(--text-3); }

.count-badge {
  min-width: 20px; height: 20px; padding: 0 6px; border-radius: var(--radius-pill);
  background: var(--brand-fill); color: #fff; font-size: var(--fs-micro); font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
}

/* -- avatar -------------------------------------------------------------- */
.avatar {
  --avatar-size: 38px;
  position: relative; width: var(--avatar-size); height: var(--avatar-size); flex: none;
  border-radius: 50%; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 650; color: #fff; font-size: max(var(--text-xs), calc(var(--avatar-size) * .38));
  user-select: none;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar--rounded { border-radius: 32%; }
.avatar--xs { --avatar-size: 22px; }
.avatar--sm { --avatar-size: 28px; }
.avatar--md { --avatar-size: 38px; }
.avatar--lg { --avatar-size: 52px; }
.avatar--xl { --avatar-size: 88px; }

.avatar-dot {
  position: absolute; right: -1px; bottom: -1px; width: 30%; height: 30%;
  min-width: 10px; min-height: 10px; border-radius: 50%;
  /* The ring reads against whatever the avatar sits on; a surface can name the
     colour it lays the avatar against. */
  border: 2px solid var(--avatar-ring, var(--panel)); box-sizing: content-box;
}
.avatar-dot[data-presence="online"] { background: var(--success); }
.avatar-dot[data-presence="idle"] { background: var(--warning); }
.avatar-dot[data-presence="dnd"] { background: var(--danger); }
.avatar-dot[data-presence="offline"] { background: var(--text-3); }

.banner { background-size: cover; background-position: center; background-color: var(--panel-3); }

/* -- menu ---------------------------------------------------------------- */
.menu {
  position: fixed; z-index: var(--z-menu);
  min-width: 204px; max-height: min(420px, calc(100vh - 24px)); overflow-y: auto;
  /* Scrolling the menu must not scroll the page behind it. A scroll that
     reaches the document is a scroll of the window, and the window's scroll
     closes the menu - so a menu whose items overflowed could be neither
     scrolled nor left open. */
  overscroll-behavior: contain;
  scrollbar-width: thin;
  padding: 5px; background: var(--raised);
  border: 1px solid var(--line-2); border-radius: var(--radius-md);
  box-shadow: var(--shadow-3);
  animation: menu-in var(--dur-1) var(--ease-out);
}
@keyframes menu-in { from { opacity: 0; transform: translateY(-3px); } }
.menu-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 7px 9px; border-radius: var(--radius-sm);
  font-size: var(--fs-sm); font-weight: 500; color: var(--text-1); text-align: left;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.menu-item:hover, .menu-item:focus-visible { background: var(--hover); }
.menu-item svg { width: 16px; height: 16px; color: var(--text-2); }
.menu-item--danger { color: var(--danger); }
.menu-item--danger svg { color: var(--danger); }
.menu-item[aria-disabled="true"] { opacity: .45; pointer-events: none; }
.menu-sep { height: 1px; background: var(--line); margin: 5px 6px; }
.menu-label {
  padding: 7px 9px 4px; font-family: var(--mono); font-size: var(--fs-micro);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-3);
  display: flex; align-items: center; gap: 8px;
}
.menu-lead { display: inline-flex; flex: none; }
.menu-headtext { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.menu-headname { color: var(--text-2); }
.menu-sub {
  font-family: var(--font); font-size: var(--fs-micro); letter-spacing: normal;
  text-transform: none; color: var(--text-3);
}

/* -- dialog -------------------------------------------------------------- */
.dialog {
  width: 100%; max-width: 460px; margin: auto;
  background: var(--raised);
  border: 1px solid var(--line-2); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3); animation: dialog-in var(--dur-2) var(--ease-out);
  overflow: hidden;
}
@keyframes dialog-in { from { opacity: 0; transform: translateY(8px) scale(.985); } }
.dialog--wide { max-width: 640px; }
.dialog-head { display: flex; align-items: flex-start; gap: 12px; padding: 18px 18px 0 20px; }
.dialog-head-text { flex: 1; min-width: 0; }
.dialog-title { font-size: var(--fs-h2); font-weight: var(--weight-bold); }
.dialog-sub { margin-top: 5px; color: var(--text-2); font-size: var(--fs-sm); }
.dialog-close {
  width: 30px; height: 30px; flex: none; display: grid; place-items: center;
  border-radius: var(--radius-sm); color: var(--text-3);
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.dialog-close:hover { background: var(--hover); color: var(--text-1); }
.dialog-body { padding: 16px 20px; display: flex; flex-direction: column; gap: 14px; }
.dialog-foot {
  padding: 13px 20px; display: flex; gap: 10px; justify-content: flex-end;
  border-top: 1px solid var(--line); background: var(--panel);
}

/* -- empty state --------------------------------------------------------- */
.empty {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 8px; padding: 48px 24px; color: var(--text-2); margin: auto; max-width: 420px;
}
.empty-icon {
  width: 52px; height: 52px; display: grid; place-items: center; margin-bottom: 4px;
  border-radius: var(--radius-lg); background: var(--panel-3); color: var(--text-3);
}
.empty-icon svg { width: 24px; height: 24px; }
.empty-title { font-size: 1.02rem; font-weight: var(--weight-bold); color: var(--text-1); }
.empty-text { font-size: var(--fs-sm); color: var(--text-2); }

/* -- overlay ------------------------------------------------------------- */
.overlay {
  position: fixed; inset: 0; z-index: var(--z-overlay);
  display: flex; align-items: center; justify-content: center; padding: 20px;
  background: rgba(6, 6, 8, .58);
  backdrop-filter: blur(4px);
  animation: overlay-in var(--dur-2) var(--ease);
  overflow-y: auto;
}
@keyframes overlay-in { from { opacity: 0; } }
[data-theme="light"] .overlay { background: rgba(28, 30, 36, .38); }

/* -- toasts -------------------------------------------------------------- */
.toasts {
  position: fixed; z-index: var(--z-toast); bottom: 20px; right: 20px;
  display: flex; flex-direction: column; gap: 8px; max-width: min(360px, calc(100vw - 32px));
}
.toast {
  display: flex; align-items: flex-start; gap: 10px; padding: 11px 12px;
  background: var(--raised); border: 1px solid var(--line-2);
  border-left: 3px solid var(--text-3);
  border-radius: var(--radius-md); box-shadow: var(--shadow-2);
  font-size: var(--fs-sm);
  animation: toast-in var(--dur-2) var(--ease-out);
}
.toast--success { border-left-color: var(--success); }
.toast--error { border-left-color: var(--danger); }
.toast--info { border-left-color: var(--info); }
.toast--brand { border-left-color: var(--brand); }
.toast-text { flex: 1; }
.toast-close {
  padding: 2px; border-radius: var(--radius-xs); color: var(--text-3);
  transition: color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.toast-close:hover { color: var(--text-1); background: var(--hover); }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } }

/* -- spinner ------------------------------------------------------------- */
.spinner {
  width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--line-2); border-top-color: var(--brand);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }


/* ---- shell.css ---- */

/* The workspace shell.
 *
 * The workbench is a grid with named areas, so the layout cannot drift from the
 * regions it lays out: the command bar across the top, then the communities
 * rail, the open place's column and the stage. The inspector, the backdrop and
 * the dock float, because a floating thing that took a grid cell would move the
 * whole workspace instead of covering part of it.
 *
 * Everything here renders from semantic tokens only - no raw hex, no shadow
 * recipe the token layer has not agreed to first. */

.ws {
  display: grid;
  grid-template-rows: var(--cmdbar-h) minmax(0, 1fr);
  /* The column's width is a length and not `auto`, so the grid can be
     animated: the column glides out of the way and the stage takes its room
     as it goes, rather than the whole thing snapping from one shape to
     another. */
  grid-template-columns: var(--rail-w) var(--context-w) minmax(0, 1fr);
  grid-template-areas:
    "cmd cmd cmd"
    "rail column stage";
  height: 100dvh;
  min-height: 0;
  position: relative;
  overflow: hidden;
  background: var(--app-bg);
  transition: grid-template-columns var(--dur-2) var(--ease-out);
}

/* The column, closed.
 *
 * The reader asked for it out of the way, so it goes out of the way - but it
 * goes smoothly, and it fades as it goes, because a thing that vanishes
 * between one frame and the next reads as a fault rather than as a choice. */
.ws[data-nav="hidden"] { grid-template-columns: var(--rail-w) 0px minmax(0, 1fr); }
.ws[data-nav="hidden"] .context {
  opacity: 0;
  pointer-events: none;
}

/* -- the arrangement --------------------------------------------------------
 * The reader chooses which regions of the workspace are shown. The choice is a
 * word list on the shell root, so the stylesheet answers "is this region here"
 * with one selector and the shell hides nothing by hand. */
.ws:not([data-regions~="rail"]) { --rail-w: 0px; }
.ws:not([data-regions~="rail"]) .rail { display: none; }
.ws:not([data-regions~="column"]) .context { display: none; }

/* -- the command bar ------------------------------------------------------ */

.cmdbar {
  grid-area: cmd;
  display: flex; align-items: center; gap: 10px;
  padding: 0 12px 0 10px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  z-index: var(--z-nav);
}

.cmdbar-nav { display: none; margin-left: -2px; }

/* The panel control in the command bar: it is offered only when the page on
 * screen has a panel behind it. */
.cmdbar-panel { flex: none; }

.cmdbar-omni {
  display: flex; align-items: center; gap: 9px;
  width: min(560px, 100%);
  height: 34px; padding: 0 10px;
  border: 1px solid var(--line-2); border-radius: var(--radius-md);
  background: var(--app-bg); color: var(--text-3); font-size: var(--fs-sm);
  transition: border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease),
    background var(--dur-1) var(--ease);
}
.cmdbar-omni:hover { border-color: var(--brand-line); color: var(--text-2); background: var(--panel); }
.cmdbar-omni svg { flex: none; }
.cmdbar-omni-label { flex: 1; min-width: 0; text-align: left; }
.cmdbar-kbd {
  flex: none; padding: 1px 6px; border: 1px solid var(--line-2); border-radius: var(--radius-xs);
  background: var(--panel-3); color: var(--text-3);
  font-family: var(--mono); font-size: var(--fs-micro);
}

.spacer { flex: 1; }

.cmdbar-alerts { display: flex; align-items: center; }
.cmdbar-bell .count-badge { margin-left: -6px; min-width: 17px; height: 17px; font-size: 10px; }

/* -- the connection chip -------------------------------------------------- */

.connection {
  display: none; align-items: center; gap: 7px;
  height: 26px; padding: 0 10px; border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--warning) 14%, transparent);
  color: var(--warning);
  font-size: var(--fs-meta); font-weight: var(--weight-strong);
}
.connection[data-state="offline"], .connection[data-state="reconnecting"] { display: inline-flex; }
.connection[data-state="offline"] {
  background: color-mix(in srgb, var(--danger) 14%, transparent);
  color: var(--danger);
}
.connection .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

/* -- the communities rail ------------------------------------------------- */

.rail {
  grid-area: rail;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 10px 0;
  background: var(--rail-bg);
  border-right: 1px solid var(--line);
  overflow-y: auto; overflow-x: hidden;
}
.rail-list { display: flex; flex-direction: column; align-items: center; gap: 8px; width: 100%; }
.rail-item {
  position: relative; width: 46px; height: 46px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--radius-lg);
  color: var(--text-2);
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.rail-item:hover { background: var(--hover); color: var(--text-1); }

/* The active mark gets the ember bar on the rail's own edge - the one place in
 * navigation where the accent is unconditional, because it answers "where". */
.rail-item::before {
  content: ""; position: absolute; left: -11px; top: 50%;
  width: 3px; height: 6px; transform: translateY(-50%);
  border-radius: var(--radius-pill); background: var(--text-3);
  opacity: 0;
  transition: height var(--dur-1) var(--ease), opacity var(--dur-1) var(--ease),
    background var(--dur-1) var(--ease);
}
.rail-item:hover::before { opacity: .55; }
.rail-item.is-active::before { opacity: 1; height: 22px; background: var(--brand); }

.rail-home img { width: 26px; height: 26px; object-fit: contain; display: block; }
.brand-fallback {
  width: 26px; height: 26px; display: grid; place-items: center;
  font-weight: var(--weight-black); color: var(--brand);
}
.rail-community .avatar { width: 38px; height: 38px; }
.rail-divider { width: 26px; height: 1px; background: var(--line); margin: 2px 0; }

/* The communities that live on another instance, in a section of their own.
   A community of this instance is here; a community on another one is a
   reference, and the reader is told which it is. */
.rail-divider--federated { margin-top: var(--space-3); }
.rail-list--federated { padding-top: var(--space-1); }
.rail-community--federated { position: relative; }
.rail-community--federated .avatar {
  border: 1px dashed var(--line-2);
  border-radius: var(--radius-sm);
}
.rail-community--federated.is-joined .avatar { border-style: solid; }
.rail-add { border: 1px dashed var(--line-2); color: var(--text-3); }
.rail-add:hover { border-color: var(--brand-line); color: var(--brand); }

/* -- the place column ----------------------------------------------------- */

.context {
  grid-area: column;
  position: relative;
  display: flex; flex-direction: column; min-width: 0;
  width: 100%;
  overflow: hidden;
  background: var(--panel);
  border-right: 1px solid var(--line);
  /* The fade that goes with the glide. The movement is the grid's; this is
     the column's own. */
  transition: opacity var(--dur-2) var(--ease-out);
}
.ws[data-column="off"] .context { display: none; }

.context-head {
  flex: none; display: flex; align-items: center;
  min-height: var(--head-h); padding: 0 8px 0 10px;
}
.context-identity { display: flex; align-items: center; gap: 6px; width: 100%; min-width: 0; }
.context-identity-link {
  display: flex; align-items: center; gap: 9px; flex: 1; min-width: 0;
  padding: 5px 6px; border-radius: var(--radius-md);
  font-weight: var(--weight-strong); color: var(--text-1);
  transition: background var(--dur-1) var(--ease);
}
.context-identity-link:hover { background: var(--hover); }
.context-brand {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 5px 6px; border-radius: var(--radius-md);
  color: var(--text-1); font-weight: var(--weight-strong);
  transition: background var(--dur-1) var(--ease);
}
.context-brand:hover { background: var(--hover); }
.context-brand img { width: 22px; height: 22px; object-fit: contain; display: block; }
.context-actions { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.context-mark-fallback {
  width: 28px; height: 28px; flex: none; display: grid; place-items: center;
  border-radius: 30%; background: var(--panel-3); color: var(--text-3);
}

.context-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 4px 8px 10px; }
.context-empty {
  padding: 10px 8px; color: var(--text-3);
  font-size: var(--fs-meta); line-height: 1.55;
}
/* The row of create controls at the end of a community's column. */
.context-actions-row {
  display: flex; gap: 6px; padding: 8px 8px 4px; flex-wrap: wrap;
}
.context-foot { flex: none; border-top: 1px solid var(--line); padding: 8px; }

.nav-group { display: flex; flex-direction: column; gap: 2px; }
.nav-head {
  display: flex; align-items: center; gap: 4px;
  padding-right: 4px;
}
.nav-head .nav-label { flex: 1; min-width: 0; }
.nav-label {
  padding: 14px 8px 5px;
  font-family: var(--mono); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-3);
}
/* The control on a category heading. Quiet until the heading is pointed at or
   the control itself is reached by keyboard, so the column stays a column
   and not a wall of buttons. */
.nav-add {
  display: inline-flex; align-items: center; justify-content: center;
  /* The mark is small and quiet, and the target is not: a control that is
     twenty pixels square is hard to hit with a mouse and impossible with a
     finger. */
  width: 26px; height: 26px; padding: 0; margin-bottom: 3px;
  border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--text-3); cursor: pointer;
  opacity: 0;
  transition: opacity var(--dur-1) var(--ease), background var(--dur-1) var(--ease),
    color var(--dur-1) var(--ease);
}
.nav-group:hover .nav-add,
.nav-add:focus-visible { opacity: 1; }
.nav-add:hover { background: var(--hover); color: var(--text-1); }
.nav-add:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
@media (hover: none) {
  /* A touch screen has no hover, so the control is always there - and a finger
     needs a target it can hit without aiming. */
  .nav-add { opacity: 1; width: 44px; height: 44px; }
}
.nav-item {
  display: flex; align-items: center; gap: 10px;
  min-height: 34px; padding: 0 8px;
  border-radius: var(--radius-md);
  color: var(--text-2); font-size: var(--fs-sm); font-weight: var(--weight-medium);
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.nav-item svg { flex: none; color: var(--text-3); transition: color var(--dur-1) var(--ease); }
.nav-item > .truncate { min-width: 0; flex: 1; }
.nav-item:hover { background: var(--hover); color: var(--text-1); }
.nav-item.is-active {
  background: var(--selected); color: var(--text-1); font-weight: var(--weight-strong);
}
.nav-item.is-active svg { color: var(--brand); }
.nav-item--channel { min-height: 32px; gap: 8px; }
.nav-item--dm { gap: 9px; }

/* The people in a voice channel, shown under the channel. A member should be
   able to see who is in a room before they join it, so the room carries its
   own faces rather than asking for them one at a time. */
.nav-room { display: block; }
.nav-room__people {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 2px 0 6px 26px;
}
.nav-room__person {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  font-size: var(--fs-sm);
  color: var(--text-2);
}
.nav-room__person .avatar { flex: 0 0 auto; }

/* A row being dragged, and a row that would take it. The dragged row dims and
 * the row under the pointer says it would take it. */
.nav-item[data-dragging], .nav-label[data-dragging] { opacity: .45; }
.nav-item[data-dropping], .nav-label[data-dropping] {
  outline: 1px dashed var(--brand); outline-offset: -2px;
}
.nav-label[data-dragging] { cursor: grabbing; }
.nav-muted { margin-left: auto; display: inline-flex; color: var(--text-3); }
.nav-dot { margin-left: auto; width: 7px; height: 7px; border-radius: 50%; background: var(--brand); flex: none; }
.nav-sep { height: 1px; background: var(--line); margin: 8px 6px; }
.dm-stack { display: inline-flex; flex: none; }
.dm-stack .avatar { outline: 2px solid var(--panel); }
.dm-stack .avatar + .avatar { margin-left: -8px; }

.account-button {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 6px 8px; border-radius: var(--radius-md); text-align: left;
  transition: background var(--dur-1) var(--ease);
}
.account-button:hover { background: var(--hover); }
.account-id { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.account-name { font-size: var(--fs-sm); font-weight: var(--weight-strong); color: var(--text-1); }
.account-sub { font-size: var(--fs-micro); color: var(--text-3); }
.account-button > svg { flex: none; color: var(--text-3); }

/* A column can be resized by dragging its edge or by nudging the grip with the
 * keyboard; the grip is a separator to assistive technology, not decoration. */
.grip {
  position: absolute; top: 0; bottom: 0; width: 9px; z-index: 2;
  cursor: col-resize; touch-action: none;
}
.grip--column { right: -5px; }
.grip--inspector { left: -5px; }
.grip--stage { right: -5px; }
.grip::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: 4px; width: 1px;
  background: var(--brand-line); opacity: 0;
  transition: opacity var(--dur-1) var(--ease);
}
.grip:hover::after, .grip[data-dragging]::after, .grip:focus-visible::after { opacity: 1; }

/* -- the stage ------------------------------------------------------------ */

.stage { grid-area: stage; display: flex; min-width: 0; min-height: 0; position: relative; }
.screen {
  display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0;
  /* The reading column has a width the reader chooses; wider than the stage
     and it simply fills it. */
  max-width: var(--stage-w);
  margin-inline: auto;
}

.stage-head {
  flex: none; display: flex; align-items: center; gap: 12px;
  min-height: var(--head-h); padding: 0 16px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}
.stage-head-inner { display: flex; align-items: center; gap: 12px; width: 100%; min-width: 0; }
.stage-head-content { flex: 1; display: flex; align-items: center; gap: 10px; min-width: 0; }
.stage-head-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.stage-head-icon { flex: none; display: grid; place-items: center; color: var(--text-3); }
.stage-head-title {
  font-size: 0.98rem; font-weight: var(--weight-strong);
  letter-spacing: var(--tracking-tight); color: var(--text-1);
}
.stage-head-sub { font-size: var(--fs-micro); color: var(--text-3); }
.stage-head-actions { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.context-toggle[aria-expanded="true"] { background: var(--selected); color: var(--brand); }

.stage-body {
  flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden;
  display: flex; flex-direction: column;
}
.stage-body:focus { outline: none; }

/* -- the composer ---------------------------------------------------------
 * The form is the shell's; the controls inside it belong to the conversation
 * that fills the slot. */

.composer-slot {
  flex: none; position: relative; z-index: 4;
  padding: 0 16px 14px;
  background: var(--app-bg);
}
.composer-slot[hidden] { display: none; }
.composer {
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px;
  background: var(--panel);
  border: 1px solid var(--line-2); border-radius: var(--radius-md);
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
}
.composer:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }

/* -- the inspector -------------------------------------------------------- */

.inspector {
  position: absolute; top: 0; right: 0; bottom: 0; z-index: var(--z-panel);
  width: min(var(--inspector-w), calc(100vw - var(--rail-w)));
  max-width: 92vw;
  display: flex; flex-direction: column; min-height: 0;
  background: var(--panel);
  border-left: 1px solid var(--line-2);
  box-shadow: var(--shadow-2);
  animation: panel-in var(--dur-2) var(--ease-out);
}
@keyframes panel-in { from { opacity: 0; transform: translateX(14px); } }
.inspector[hidden] { display: none; }

.inspector-head {
  flex: none; display: flex; align-items: center; gap: 8px;
  min-height: var(--head-h); padding: 8px 8px 8px 10px;
  border-bottom: 1px solid var(--line);
}
.inspector-tabs {
  flex: 1; min-width: 0;
  display: inline-flex; gap: 2px; padding: 2px;
  background: var(--panel-3); border-radius: var(--radius-md);
}
.inspector-tab {
  display: flex; align-items: center; gap: 6px; min-width: 0;
  padding: 5px 10px; border-radius: var(--radius-sm);
  color: var(--text-2); font-size: var(--fs-meta); font-weight: var(--weight-strong);
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.inspector-tab:hover { color: var(--text-1); }
.inspector-tab.is-active { background: var(--raised); color: var(--text-1); box-shadow: var(--shadow-1); }
.inspector-close { flex: none; }
.inspector-body { flex: 1; min-height: 0; overflow-y: auto; }
.inspector-loading { display: grid; place-items: center; padding: 40px 20px; }
.inspector-note { padding: 24px 18px; color: var(--text-2); font-size: var(--fs-sm); line-height: 1.55; }

/* -- the dock ------------------------------------------------------------- */

.dock {
  position: fixed; left: calc(var(--rail-w) + 16px); bottom: 16px; z-index: var(--z-panel);
  width: min(430px, calc(100vw - var(--rail-w) - 32px));
  background: var(--raised);
  border: 1px solid var(--line-2); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  animation: dock-in var(--dur-2) var(--ease-out);
}
@keyframes dock-in { from { opacity: 0; transform: translateY(10px); } }
.dock[hidden] { display: none; }

/* -- the scrim ------------------------------------------------------------ */

.scrim {
  display: none; position: absolute; inset: 0; z-index: var(--z-scrim);
  background: color-mix(in srgb, var(--tc-bg-deep) 72%, transparent);
  animation: overlay-in var(--dur-2) var(--ease);
}

/* -- the command palette -------------------------------------------------- */

.overlay--top { align-items: flex-start; padding-top: min(13vh, 116px); }
.dialog--palette { max-width: 580px; margin: 0 auto; }
.palette { display: flex; flex-direction: column; min-height: 0; max-height: min(560px, 70vh); }
.palette-input-row {
  flex: none; display: flex; align-items: center; gap: 10px;
  padding: 14px 16px; border-bottom: 1px solid var(--line);
}
.palette-input-row svg { flex: none; color: var(--text-3); }
.palette-input {
  flex: 1; min-width: 0;
  background: none; border: 0; outline: none;
  color: var(--text-1); font-size: var(--fs-h3);
}
.palette-input::placeholder { color: var(--text-3); }
.palette-results { flex: 1; min-height: 72px; overflow-y: auto; padding: 8px; }
.palette-group + .palette-group { margin-top: 4px; }
.palette-group-label {
  padding: 9px 10px 4px;
  font-family: var(--mono); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-3);
}
.palette-item {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 38px;
  padding: 0 10px; border-radius: var(--radius-md);
  color: var(--text-2); font-size: var(--fs-sm); text-align: left;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.palette-item svg { flex: none; color: var(--text-3); }
.palette-item.is-active { background: var(--selected); color: var(--text-1); }
.palette-item.is-active svg { color: var(--brand); }
.palette-item-label { flex: 1; min-width: 0; }
.palette-item-hint { flex: none; max-width: 45%; color: var(--text-3); font-size: var(--fs-meta); }
.palette-note { padding: 18px 12px; color: var(--text-3); font-size: var(--fs-sm); }

/* -- narrow windows -------------------------------------------------------
 * On a desk the column is a column. On a narrow window it draws over the stage
 * instead, opened from the command bar and closed by the backdrop or Escape;
 * the inspector does the same. The line matches the media query in shell.js. */
/* The width below which the place column draws over the stage. It is the
   same number as NARROW_WIDTH in frontend/js/shell.js, and the check in
   frontend/tests/layout.test.js says so - a threshold in one place and not
   the other is a sidebar that is visible in one half of the application and
   not the other. */
@media (max-width: 860px) {
  .cmdbar-nav { display: inline-grid; }
  .context {
    position: absolute; top: var(--cmdbar-h); bottom: 0; left: var(--rail-w);
    /* Above the scrim, not below it.
       The scrim is there to close the column when the reader taps outside
       it, and it is drawn over the page - so a column underneath it could
       not be touched at all: the column appeared, and every one of its
       links did nothing. The column is a drawer here, and a drawer is
       above the thing that dims it. */
    z-index: var(--z-panel);
    width: min(var(--context-w), calc(100vw - var(--rail-w)));
    box-shadow: var(--shadow-3);
    /* The drawer slides the whole way in, rather than a little: a drawer
       that only shifts a few pixels reads as a fault rather than as a
       drawer opening. */
    transform: translateX(-100%); opacity: 0; visibility: hidden;
    transition: transform var(--dur-2) var(--ease-out), opacity var(--dur-2) var(--ease-out),
      visibility var(--dur-2);
  }
  .ws[data-nav="overlay"] .context { transform: none; opacity: 1; visibility: visible; }
  .ws[data-nav="overlay"] .scrim,
  .ws[data-context="open"] .scrim { display: block; }
  .grip--column { display: none; }
}

/* A line in a list of choices, as the move dialog draws them. */
.row--button {
  width: 100%; text-align: left; cursor: pointer;
  border-radius: var(--radius-sm); color: var(--text-1);
}
.row--button:hover { background: var(--hover); }
.row-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }


/* ---- features.css ---- */

/* The workspace pages.
 *
 * Everything the stage shows, built from the kit in frontend/js/ui/page.js:
 * the pagehead strip, cards and their rows, memos, counted facts, the deck,
 * the three honest states, and the small surfaces the first feature pages own
 * (chips, finder, join code). One section per builder - when a class here has
 * no emitter, or an emitter has no class here, that is the bug this layering
 * exists to expose.
 *
 * Colours come from tokens.css only; no raw values are allowed in this layer. */

/* -- layout ----------------------------------------------------------------- */

.fold { display: flex; flex-direction: column; gap: var(--space-6); max-width: var(--content-max); width: 100%; }
/* A working surface. It uses the width it is given, because a workspace with
   a list and an editor beside it is not a reading column - and a reading
   column's width in the middle of a wide screen is what made the workspace
   look compressed. */
.fold--wide { max-width: none; }
.fold--tight { gap: var(--space-3); }
.fold--airy { gap: var(--space-8); }

.deck { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: var(--space-5); align-items: start; }
@media (max-width: 1100px) { .deck { grid-template-columns: 1fr; } }

.actionline { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.pagerline { display: flex; justify-content: center; padding: var(--space-2) 0 0; }

/* -- the pagehead ------------------------------------------------------------- */

.pagehead { display: flex; align-items: flex-start; gap: var(--space-4); flex-wrap: wrap; }
.pagehead-main { flex: 1; min-width: 220px; }

/* The identity of a community.
   The mark, the name, and what the community is for - the community's own
   words, and only when it has said them. */
.community-identity { display: inline-flex; align-items: center; gap: var(--space-2); }
.community-identity--link { text-decoration: none; color: inherit; }
.community-identity--link:hover .community-identity__name { text-decoration: underline; }
.community-identity__mark { display: inline-grid; place-items: center; }
.community-identity__words { display: inline-flex; flex-direction: column; min-width: 0; }
.community-identity__name {
  font-size: var(--fs-sm); font-weight: var(--weight-strong); color: var(--text-1);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.community-identity__about {
  font-size: var(--fs-micro); color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.pagehead-kicker {
  margin: 0 0 6px;
  font-size: var(--fs-micro);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-3);
}

.pagehead-title { margin: 0; font-size: var(--fs-h1); font-weight: var(--weight-black); letter-spacing: var(--tracking-tight); }
.pagehead-lede { margin: 6px 0 0; color: var(--text-2); font-size: var(--fs-body); max-width: 68ch; }
.pagehead-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

/* -- cards --------------------------------------------------------------------- */

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: clip;
}

.card--flat { background: transparent; }
.card--dashed { background: transparent; border-style: dashed; border-color: var(--line-2); }

.cardhead {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  /* The head wraps. A title long enough to crowd the tools used to push them
     out of the card, and the card clips its overflow, so the button was
     simply gone - and the note beside it was drawn on top of the title. */
  flex-wrap: wrap;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
}

.cardhead-glyph { color: var(--text-3); display: grid; place-items: center; flex: none; }
/* The label may shrink, so a long title truncates instead of pushing the
   tools out of the card. The title is a heading, so the whole of it is in
   the accessibility tree even when it is drawn short. */
.cardhead-label {
  margin: 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--fs-body); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight);
}
.cardhead-note {
  margin-left: auto; min-width: 0; font-size: var(--fs-micro); color: var(--text-3); text-align: right;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cardhead-tools { display: flex; align-items: center; gap: var(--space-2); flex: none; margin-left: auto; }
.cardhead-note + .cardhead-tools { margin-left: 0; }

.cardbody { padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-3); }
.cardbody--tight { padding: var(--space-3) var(--space-4); }
.cardbody--flush { padding: 0; gap: 0; }

.cardfoot {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 12px 16px;
  border-top: 1px solid var(--line);
}

.cardfoot--end { justify-content: flex-end; }

/* -- rows ---------------------------------------------------------------------- */

.cardrow {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--space-3);
  padding: 11px 16px;
  border-bottom: 1px solid var(--line);
  width: 100%;
  text-align: left;
}

.cardrow:last-child { border-bottom: 0; }

.cardrow--link {
  background: transparent;
  border-left: 0;
  border-right: 0;
  border-top: 0;
  cursor: pointer;
  color: inherit;
  font: inherit;
  transition: background var(--dur-1) var(--ease);
}

.cardrow--link:hover { background: var(--hover); }
.cardrow--link:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.cardrow--active { background: var(--selected); }
.cardrow--unread { background: color-mix(in srgb, var(--brand) 5%, transparent); }
.cardrow--unread .cardrow-title { font-weight: var(--weight-bold); color: var(--text-1); }

.cardrow-lead { display: grid; place-items: center; color: var(--text-3); }
.cardrow-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cardrow-title { font-size: var(--fs-body); font-weight: var(--weight-strong); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cardrow-sub { font-size: var(--fs-sm); color: var(--text-3); line-height: 1.5; }
.cardrow-side { display: flex; align-items: center; gap: var(--space-2); color: var(--text-3); }
.cardrow-meta { font-size: var(--fs-micro); color: var(--text-3); flex: none; }

.cardrow-list { display: flex; flex-direction: column; }

.unread-dot {
  width: 9px;
  height: 9px;
  border-radius: var(--radius-pill);
  background: var(--brand);
  display: inline-block;
}

/* -- memos ---------------------------------------------------------------------- */

.memo-list { display: flex; flex-direction: column; gap: var(--space-2); }

.memo {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-left-width: 3px;
  border-radius: var(--radius-md);
  background: var(--panel-2);
}

.memo-glyph { flex: none; color: var(--text-3); margin-top: 1px; }
.memo--success .memo-glyph { color: var(--success); }
.memo--info .memo-glyph { color: var(--info, var(--text-3)); }
.memo--warning { border-left-color: var(--warning); }
.memo--warning .memo-glyph { color: var(--warning); }
.memo--danger { border-left-color: var(--danger); }
.memo--danger .memo-glyph { color: var(--danger); }

.memo-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.memo-top { display: flex; align-items: baseline; gap: var(--space-2); }
.memo-title { font-size: var(--fs-sm); font-weight: var(--weight-bold); }
.memo-stamp { margin-left: auto; font-size: var(--fs-micro); color: var(--text-3); flex: none; }
.memo-text { margin: 0; font-size: var(--fs-sm); color: var(--text-2); line-height: 1.55; }
.memo-actions { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-1); }

/* -- facts ----------------------------------------------------------------------- */

.factline {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  overflow: clip;
}

.factcell { background: var(--panel); padding: 12px 15px; display: flex; flex-direction: column; gap: 2px; }
.factnum { font-size: var(--fs-h2); font-weight: var(--weight-black); letter-spacing: var(--tracking-tight); }
.factlabel { font-size: var(--fs-micro); color: var(--text-3); }

/* -- the three states -------------------------------------------------------------- */

.holdline {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 18px 4px;
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.faultline {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-3) 4px;
  color: var(--danger);
  font-size: var(--fs-sm);
}

.faultline-text { flex: 1; min-width: 0; }

.blank {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  text-align: center;
  padding: var(--space-7) var(--space-4);
}

.blank-glyph {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: var(--radius-pill);
  background: var(--panel-3);
  color: var(--text-3);
}

.blank-title { margin: var(--space-1) 0 0; font-size: var(--fs-body); font-weight: var(--weight-bold); color: var(--text-1); }
.blank-text { margin: 0; font-size: var(--fs-sm); color: var(--text-3); max-width: 46ch; }
.blank-action { margin-top: var(--space-1); }

/* -- filter chips -------------------------------------------------------------------- */

.chips { display: inline-flex; gap: 6px; }

.chip {
  border: 1px solid var(--line-2);
  background: transparent;
  color: var(--text-2);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: var(--weight-strong);
  border-radius: var(--radius-pill);
  padding: 5px 14px;
  cursor: pointer;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}

.chip:hover { background: var(--hover); color: var(--text-1); }
.chip--on { background: var(--brand-fill); border-color: var(--brand-fill); color: var(--brand-ink); }
.chip--quiet { background: var(--panel-3); border-color: var(--line-2); color: var(--text-3); }
.chip--on:hover { background: var(--brand-fill-hover); color: var(--brand-ink); }
.chip:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* -- the finder ----------------------------------------------------------------------- */

.finder-input { width: 100%; }

/* -- the join code ---------------------------------------------------------------------- */

.joincode {
  font-family: var(--mono);
  font-size: var(--fs-sm);
  letter-spacing: 0.06em;
  background: var(--panel-3);
  border: 1px dashed var(--line-2);
  border-radius: var(--radius-md);
  padding: 10px 14px;
  color: var(--text-2);
  overflow-wrap: anywhere;
}

/* == conversations ===================================================================
 * The message timeline and the composer slot it ends in. Rows give the reader a
 * person, a moment, and the actions for that row; a continued row drops the
 * repetition but keeps its shape on the grid. Nothing here is raw colour: the
 * tokens carry the surface. */

.convo-page { display: flex; flex-direction: column; height: 100%; min-height: 0; overflow: hidden; }
.convo-host { height: 100%; min-height: 0; display: flex; flex-direction: column; }
.convo-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: var(--gap-md); }

.convo { display: flex; flex-direction: column; gap: 2px; padding-bottom: var(--gap-sm); }

.day-sep {
  display: flex; align-items: center; gap: 12px;
  margin: 14px 0 6px; color: var(--text-3);
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
}
.day-sep::before, .day-sep::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.day-sep > span { flex: none; }

.msg {
  display: grid; grid-template-columns: 40px 1fr; gap: 10px;
  padding: 3px 8px; border-radius: var(--radius-md);
}
.msg:hover, .msg:focus-within { background: var(--hover); }

/* A message under a finger that is swiping it.
   It moves with the finger, so the reader can see what is about to happen
   and can let go of it. */
.msg.is-swiping { transition: none; will-change: transform; }
.msg.is-swiping .msg-rail { transition: transform var(--dur-1) var(--ease); }
.msg--continued { margin-top: 0; }
.msg--own .msg-author { color: var(--brand); }
.msg--pending { opacity: 0.72; }
.msg--standalone { padding: 8px; outline: none; }

.msg-rail { position: relative; }
.msg--continued .msg-rail { visibility: hidden; height: 0; }

/* Density changes the composition and not only the measurements: a compact
 * workspace drops the face beside each message, because the name is already
 * on the line above it. */
:root[data-density="compact"] .msg-rail { display: none; }
:root[data-density="compact"] .msg--continued .msg-rail { display: none; }

.msg-main { position: relative; min-width: 0; }

.msg-meta { display: flex; align-items: baseline; gap: 8px; min-height: 18px; }
.msg-author { font-weight: 700; font-size: var(--fs-sm); color: var(--text-1); }
.msg-stamp { font-size: var(--fs-xs); color: var(--text-3); }
.msg-edited { font-size: var(--fs-xs); color: var(--text-3); font-style: italic; }
/* A message this device could not open. It is not an error in the message and
   it is not empty: the text is in the envelope, and this device does not have
   the key. */
.msg-unreadable {
  font-size: var(--fs-sm);
  color: var(--text-3);
  font-style: italic;
}
.msg-pinflag { color: var(--text-3); display: inline-flex; vertical-align: middle; }
.msg-sending { font-size: var(--fs-xs); color: var(--text-3); font-style: italic; }

.msg-text { white-space: pre-wrap; overflow-wrap: anywhere; color: var(--text-1); margin: 0; }
.msg-replying {
  display: flex; align-items: center; gap: 6px; margin: 2px 0;
  color: var(--text-3); font-size: var(--fs-xs);
}
.msg-replying-name { color: var(--text-2); font-weight: 600; }

.msg-attachments { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.msg-image {
  max-width: min(360px, 100%); max-height: 280px;
  border-radius: var(--radius-md); border: 1px solid var(--line-2);
}

/* The text block a message carries: text, replies, attachments and reactions
   stacked under one author line. */
.msg-content { display: flex; flex-direction: column; gap: 4px; min-width: 0; }

/* Inline content inside a message. Links take the brand accent; a mention or a
   #channel gets a soft brand wash instead of looking like a dead word. */
.msg-link { color: var(--brand); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; overflow-wrap: anywhere; }
.mention { color: var(--brand); background: color-mix(in srgb, var(--brand) 10%, transparent); padding: 1px 4px; border-radius: var(--radius-sm); font-weight: var(--weight-bold); }

/* The non-image attachment row's leading glyph column. */
.msg-file-glyph { display: grid; place-items: center; flex: none; color: var(--text-3); }

/* The emoji face of a reaction chip: sized to the chip, not the author text. */
.msg-reaction-emoji { line-height: 1; font-size: var(--fs-sm); }

/* Composer furniture: the two icon buttons flanking the field, and the strip
   that names an open reply, edit or attachment. */
.iconbtn {
  display: grid; place-items: center; width: 36px; height: 36px; flex: none;
  border: 1px solid transparent; border-radius: var(--radius-md);
  background: transparent; color: var(--text-2); cursor: pointer;
}
.iconbtn:hover { background: var(--hover); border-color: var(--line-2); color: var(--text-1); }
.composer-context-note {
  display: inline-flex; align-items: center; gap: 6px; min-width: 0;
  color: var(--text-2); font-size: var(--fs-xs);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* An upload in flight: how far it has got, and how to stop it. */
.upload-bar {
  display: inline-block; width: 90px; height: 4px; flex: none;
  border-radius: var(--radius-pill); background: var(--panel-3); overflow: hidden;
}
.upload-bar-fill {
  display: block; height: 100%; width: 0;
  background: var(--brand); border-radius: var(--radius-pill);
  transition: width var(--dur-1) var(--ease);
}

/* A file dragged over the composer. */
.composer.is-dropping {
  outline: 2px dashed var(--brand-line);
  outline-offset: 2px;
}

/* Discover's public communities land on a grid of cards. */
.cardgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--space-4); }

/* Settings and community-config list bodies: a stack of rows in place. */
.rowlist { display: flex; flex-direction: column; }

/* A row's circular lead chip. */
.role-dot {
  display: grid; place-items: center; width: 28px; height: 28px; flex: none;
  border-radius: 50%; background: var(--panel-3); color: var(--text-2);
}
.role-dot--invite { background: color-mix(in srgb, var(--brand) 12%, transparent); color: var(--brand); }

/* A role that carries a colour, and the things that draw it.
   The colour is set on the element as --role-colour, so one rule draws the
   dot, the name and the chip, and a role with no colour keeps the
   interface's own. */
.role-dot--role { background: var(--role-colour, var(--panel-3)); }
.role-dot--sm { width: 16px; height: 16px; }

.role-name { color: var(--role-colour, currentColor); }
.role-separator { color: var(--text-3); }

.role-chips { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.role-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 2px 8px 2px 4px; border-radius: 999px;
  background: var(--panel-2); color: var(--text-2);
  font-size: var(--fs-micro); line-height: 1.4;
}

/* The colour picker in the role editor. */
.role-colour { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.role-colour__swatches { display: flex; flex-wrap: wrap; gap: 8px; }
.role-colour__swatch {
  width: 28px; height: 28px; padding: 0;
  border: 2px solid transparent; border-radius: 50%;
  background: var(--role-colour, var(--panel-3));
  cursor: pointer;
}
.role-colour__swatch.is-chosen { border-color: var(--text-1); }
.role-colour__hex { width: 10rem; }

/* The settings item's label column, distinct from the control column. */
.settings-item-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

/* An unlabeled lead paragraph in a page body. */
.lede { margin: 0; color: var(--text-2); max-width: 65ch; line-height: 1.6; }
.msg-file {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 12px; border: 1px solid var(--line-2); border-radius: var(--radius-md);
  background: var(--panel-2); color: var(--text-1); text-decoration: none;
  max-width: 100%;
}
.msg-file:hover { background: var(--hover); }
.msg-file--image { padding: 0; border: 0; background: none; display: block; max-width: 100%; }
.msg-file--image:hover { background: none; }
.msg-file-name { font-weight: 600; overflow-wrap: anywhere; }
.msg-file-size { color: var(--text-3); font-size: var(--fs-xs); }

.msg-embeds { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }

/* -- the arrangement --------------------------------------------------------- */
.layout-regions { display: flex; flex-direction: column; gap: var(--space-3); }
.layout-widths { display: flex; align-items: center; gap: 12px; }
.layout-width { flex: 1; min-width: 0; accent-color: var(--brand); }
.layout-value { color: var(--text-3); font-size: var(--fs-micro); font-variant-numeric: tabular-nums; }

/* -- the member roster --------------------------------------------------------
 * The same roster is drawn on the members page and in the inspector beside a
 * channel, so it has one set of rules. */
.channel-row .cardrow-sub, .category-row .cardrow-sub { white-space: normal; }
.member-panel { display: flex; flex-direction: column; gap: 10px; }
.member-head { display: flex; align-items: center; gap: 10px; }
.member-search { flex: 1; min-width: 0; }
.member-count { color: var(--text-3); font-size: var(--fs-micro); font-variant-numeric: tabular-nums; }
.member-list { border-top: 1px solid var(--line); }
.member-row .cardrow-meta { min-width: 68px; text-align: right; }
.member-presence { color: var(--text-3); }
.member-presence[data-presence="online"] { color: var(--success); }
.member-presence[data-presence="idle"] { color: var(--warning); }
.member-presence[data-presence="dnd"] { color: var(--danger); }
.member-more { display: flex; justify-content: center; padding: 10px 0; }

/* -- link previews -----------------------------------------------------------
 * A preview is a card: a picture or a player when the page had one, and the
 * page's own words when it did not. The site is named by a tile of its first
 * letter rather than by a favicon - a favicon is a request to an arbitrary
 * host on behalf of every reader who opens the channel. */
.embed-card {
  display: flex; flex-direction: column; gap: 8px;
  max-width: 520px;
  border: 1px solid var(--line-2); border-left: 3px solid var(--brand);
  border-radius: var(--radius-md); padding: 10px; background: var(--panel-2);
}
.embed-card:hover { border-color: var(--line-3); }
.embed-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.embed-site { display: flex; align-items: center; gap: 7px; margin: 0; }
.embed-tile {
  display: grid; place-items: center;
  width: 20px; height: 20px; flex: none;
  border-radius: var(--radius-sm);
  background: var(--panel-3); color: var(--text-2);
  font-size: var(--fs-xs); font-weight: var(--weight-bold); text-transform: uppercase;
}
.embed-site-name {
  font-size: var(--fs-xs); color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.embed-title {
  display: block; color: var(--text-1); font-weight: 600; text-decoration: none;
  overflow-wrap: anywhere;
}
.embed-title:hover { color: var(--brand); }
.embed-text {
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; margin: 0; color: var(--text-2); font-size: var(--fs-sm);
}
.embed-host { margin: 0; font-size: var(--fs-xs); color: var(--text-3); }
.embed-original {
  align-self: flex-start; margin-top: 2px;
  font-size: var(--fs-xs); color: var(--brand); text-decoration: none;
}
.embed-original:hover { text-decoration: underline; }
.embed-media {
  display: block; padding: 0; border: 0; background: none; cursor: zoom-in;
  border-radius: var(--radius-md); overflow: hidden; max-width: 100%;
}
.embed-media:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
/* The space is reserved before the picture arrives.
   Without it the message jumps when the preview loads, and the reader is
   reading one thing while the page moves under them. The picture is fitted
   inside the box rather than stretched, so a portrait one is centred in it
   rather than distorted. */
.embed-image {
  display: block; width: 100%; max-width: min(420px, 100%);
  aspect-ratio: 16 / 10; max-height: 320px;
  object-fit: contain; border-radius: var(--radius-md); border: 1px solid var(--line-2);
  background: var(--panel-3);
}
.embed-video {
  display: block; width: 100%; max-width: 480px; aspect-ratio: 16 / 9;
  border-radius: var(--radius-md); border: 1px solid var(--line-2); background: var(--panel-3);
}
/* A preview the server could not describe is the link and nothing else. */
.embed-plain {
  align-self: flex-start; margin-top: 4px;
  color: var(--brand); font-size: var(--fs-sm); overflow-wrap: anywhere;
}

/* -- the lightbox ------------------------------------------------------------
 * An image opened from a message, read large, with the other images of the
 * message a keypress away. */
.dialog--lightbox { max-width: min(1100px, 94vw); width: 94vw; background: transparent; }
.dialog--lightbox .dialog-body { padding: 0; }
.lightbox { display: flex; flex-direction: column; gap: 8px; }
/* The frame holds the picture and scrolls when the picture is read at its own
   size. Nothing is cut off: the picture is the one thing in a message that
   cannot be shrunk without losing what it says. */
.lightbox-frame {
  display: flex; justify-content: center;
  max-height: 74vh; overflow: auto;
  border-radius: var(--radius-md); background: var(--panel-3);
}
.lightbox-frame.is-zoomed { justify-content: flex-start; }
.lightbox-image {
  display: block; max-width: 100%; max-height: 74vh; margin: 0 auto;
  object-fit: contain; border-radius: var(--radius-md); background: var(--panel-3);
}
.lightbox-frame.is-zoomed .lightbox-image {
  max-width: none; max-height: none; margin: 0; border-radius: 0;
}
.lightbox-bar { display: flex; align-items: center; gap: 10px; }
.lightbox-caption {
  flex: 1; min-width: 0; margin: 0; color: var(--text-2); font-size: var(--fs-sm);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lightbox-count { color: var(--text-3); font-size: var(--fs-xs); font-variant-numeric: tabular-nums; }
.lightbox-zoom {
  display: grid; place-items: center; width: 36px; height: 36px; flex: none;
  border: 1px solid var(--line-2); border-radius: var(--radius-md);
  background: var(--panel-2); color: var(--text-2);
}
.lightbox-zoom:hover { background: var(--hover); color: var(--text-1); }
.lightbox-zoom[aria-pressed="true"] { background: var(--brand-fill); color: var(--brand-ink); }
.lightbox-close, .lightbox-nav {
  display: grid; place-items: center; width: 36px; height: 36px; flex: none;
  border: 1px solid var(--line-2); border-radius: var(--radius-md);
  background: var(--panel-2); color: var(--text-2);
}
.lightbox-close:hover, .lightbox-nav:hover { background: var(--hover); color: var(--text-1); }
.lightbox-nav { position: absolute; top: 50%; transform: translateY(-50%); }
.lightbox-nav--prev { left: 8px; }
.lightbox-nav--next { right: 8px; }

.msg-reactions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.msg-reaction {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: 999px;
  border: 1px solid var(--line-2); background: var(--panel-2);
  color: var(--text-2); font-size: var(--fs-sm);
}
.msg-reaction:hover { border-color: var(--line-3); }
.msg-reaction--mine { border-color: var(--brand); color: var(--brand); background: var(--brand-soft); }
.msg-reaction--flat:hover { border-color: var(--line-2); }
.msg-reaction-count { font-variant-numeric: tabular-nums; }

.msg-thread-badge {
  display: inline-flex; align-items: center; gap: 7px; margin-top: 6px;
  padding: 4px 12px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--line-2); background: var(--panel-2); color: var(--text-2);
}
.msg-thread-badge:hover { border-color: var(--brand); color: var(--brand); }
.msg-thread-badge__count { font-weight: 800; font-variant-numeric: tabular-nums; }
.msg-thread-badge-label { font-size: var(--fs-xs); }

.msg-tools {
  position: absolute; top: -14px; right: 10px;
  display: none; gap: 4px; padding: 3px;
  background: var(--panel); border: 1px solid var(--line-2); border-radius: var(--radius-md);
  box-shadow: var(--shadow-1);
}
.msg:hover .msg-tools, .msg:focus-within .msg-tools { display: inline-flex; }
.msg--standalone .msg-tools { display: none; }
.toolbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--text-3); cursor: pointer;
}
.toolbtn:hover { background: var(--hover); color: var(--text-1); }

.msg-waiting { display: inline-flex; vertical-align: middle; margin-left: 8px; }

.typingline {
  display: flex; align-items: center; gap: 8px;
  min-height: 22px; padding: 2px 18px 0;
  color: var(--text-3); font-size: var(--fs-xs);
}
.typingline[hidden] { display: none; }
.typing-dots { letter-spacing: 2px; color: var(--brand); }

.thread-flow { display: flex; flex-direction: column; gap: 12px; min-height: 200px; }
.thread-note { color: var(--text-3); font-size: var(--fs-sm); margin: 0; }
.thread-replies { display: flex; flex-direction: column; gap: 2px; min-height: 120px; max-height: 46vh; overflow-y: auto; }
.thread-replies .msg { padding-right: 12px; }
.thread-composer { margin-top: 4px; }

.pin-row { display: flex; }
.pin-row-main { min-width: 0; flex: 1 1 auto; }

/* -- the conversation composer ---------------------------------------------------- */

.composer-context {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px; border-bottom: 1px solid var(--line);
  color: var(--text-2); font-size: var(--fs-sm);
}
.composer-context[hidden] { display: none; }
.composer-context-name { color: var(--text-1); font-weight: 700; }
.composer-context-text { color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.composer-row { display: flex; align-items: flex-end; gap: 8px; }
.composer-input {
  flex: 1 1 auto; resize: none; max-height: 300px;
  background: transparent; border: 0; color: var(--text-1);
  font: inherit; line-height: 1.45;
}
.composer-input:focus { outline: none; }
.composer-send { align-self: flex-end; }
.composer .form-error { margin: 0; padding: 0 2px; }

/* == the waves the column and the context read ===================================== */

.rowtools { display: inline-flex; align-items: center; gap: 6px; }
.chip--warn { border-color: var(--warning); color: var(--warning); }
.chip--danger { border-color: var(--danger); color: var(--danger); }
.badge--count {
  min-width: 20px; padding: 2px 7px; border-radius: 999px;
  background: var(--brand-fill); color: var(--brand-ink);
  font-size: var(--fs-xs); font-weight: 800; text-align: center;
  font-variant-numeric: tabular-nums;
}
.anticipation-line { color: var(--text-3); }

/* == profile ====================================================================== */

.profile { display: flex; flex-direction: column; gap: var(--gap-md); }
.profile-banner { border-radius: var(--radius-lg); max-height: 180px; min-height: 96px; width: 100%; object-fit: cover; border: 1px solid var(--line-2); }
.profile-main { display: flex; gap: 14px; align-items: flex-start; }
.profile-nameblock { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1 1 auto; }
.profile-name { font-size: var(--fs-xl); font-weight: 800; color: var(--text-1); margin: 0; }
.profile-status { color: var(--text-2); margin: 0; }
.profile-relation { color: var(--text-3); font-size: var(--fs-sm); margin: 0; }
/* The roles, each in the colour the community gave it. A role with no colour
   keeps the interface's own, so it is never the brand by accident. */
.profile-roles { color: var(--text-2); font-size: var(--fs-sm); font-weight: 600; margin: 0; }

/* == settings surfaces ============================================================== */

.settings-profile-top { display: flex; align-items: center; gap: 14px; }
/* The cropper: the picture, and the part of it the reader chose.
   The shade is the picture with the chosen part cut out of it, so the
   choice is visible rather than described. */
.cropper {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-md);
  background: var(--panel-3);
  touch-action: none;
  user-select: none;
}
.cropper__image { display: block; max-width: 100%; }
.cropper__shade {
  position: absolute; inset: 0;
  background: rgba(0, 0, 0, .58);
  pointer-events: none;
}
.cropper__selection {
  position: absolute;
  border: 2px solid var(--brand);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .5);
  cursor: move;
  touch-action: none;
}
.cropper__handle {
  position: absolute;
  right: -7px; bottom: -7px;
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 2px solid var(--brand);
  background: var(--panel-1);
  cursor: nwse-resize;
}

/* The mark that says a bot is a bot. A reader should not have to guess
   whether they are talking to a person, and the mark is used wherever a
   bot's name is shown: in a message, in a member list, in a conversation
   list and on a profile. */
.botflag {
  font-size: var(--fs-micro);
  font-weight: 800;
  letter-spacing: .06em;
  color: var(--text-3);
  border: 1px solid var(--line-2);
  border-radius: 4px;
  padding: 0 4px;
  line-height: 1.5;
}

.settings-banner { max-height: 140px; width: 100%; object-fit: cover; border-radius: var(--radius-md); border: 1px solid var(--line-2); }

/* The picture and the cover on the profile page.
   The chosen picture is shown in the same place as the one that is up, so
   the reader sees what they picked rather than the old face until the
   server has answered. */
.settings-profile-face { display: grid; place-items: center; }
.settings-profile-face .avatar-img {
  width: 88px; height: 88px; border-radius: 32%; object-fit: cover;
  display: block;
}
.settings-profile-cover.is-empty { display: none; }

.settings-image-field { display: flex; flex-direction: column; gap: 10px; }
.settings-image-tools { display: flex; align-items: center; gap: 10px; }
.settings-image-field .form-error { margin: 0; }

.settings-item {
  display: grid; grid-template-columns: 1fr auto auto; gap: 12px; align-items: center;
  padding: 12px 0; border-bottom: 1px solid var(--line);
}
.settings-item:last-child { border-bottom: 0; }
.settings-item--pending { background: var(--warn-soft, var(--panel-3)); border-radius: var(--radius-md); }
.settings-item-label { margin: 0; font-weight: 700; font-size: var(--fs-sm); display: flex; gap: 8px; align-items: center; }
.settings-note { margin: 2px 0 0; color: var(--text-3); font-size: var(--fs-xs); max-width: 52ch; }
.settings-item-control { min-width: 220px; }
.settings-item-actions { display: inline-flex; }

.cfg-layout { display: grid; grid-template-columns: 220px 1fr; gap: var(--gap-md); align-items: start; }
.cfg-nav { display: flex; flex-direction: column; gap: 2px; }
.cfg-nav__item {
  display: block; width: 100%; text-align: left;
  padding: 9px 12px; border: 0; border-radius: var(--radius-md);
  background: transparent; color: var(--text-2); cursor: pointer;
  font: inherit; font-weight: 600;
}
.cfg-nav__item:hover { background: var(--hover); color: var(--text-1); }
.cfg-nav__item.active { background: var(--brand-soft); color: var(--brand); }
.cfg-nav__item:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.cfg-stage { min-height: 200px; }

/* -- the mail console -------------------------------------------------------------- */

.cfg-mail { display: flex; flex-direction: column; gap: 14px; padding: 16px; border: 1px solid var(--line-2); border-radius: var(--radius-lg); background: var(--panel-2); }
.cfg-mail__status { margin: 0; color: var(--text-2); }
.cfg-mail__modes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.cfg-mail__mode {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px; text-align: left;
  padding: 12px; border-radius: var(--radius-md);
  border: 1px solid var(--line-2); background: var(--panel);
  color: var(--text-2); cursor: pointer; font: inherit;
}
.cfg-mail__mode:hover { border-color: var(--line-3); }
.cfg-mail__mode.active { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.cfg-mail__mode strong { color: var(--text-1); }
.cfg-mail__mode.active strong { color: var(--brand); }
.cfg-mail__mode-summary { font-size: var(--fs-xs); color: var(--text-3); }
.cfg-mail__detail { display: flex; flex-direction: column; gap: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
.cfg-mail__detail-text { margin: 0; color: var(--text-2); }
.cfg-mail__detail-note { color: var(--text-3); font-style: italic; }
.cfg-mail__detail-actions { display: flex; gap: 8px; align-items: center; }
.cfg-mail__to { max-width: 280px; }

/* -- the client choices ------------------------------------------------------------ */

.theme-row { display: flex; gap: 12px; flex-wrap: wrap; }
.theme-choice {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 10px 14px; border-radius: var(--radius-md);
  border: 1px solid var(--line-2); background: var(--panel-2);
  color: var(--text-1); cursor: pointer; font: inherit; font-weight: 600;
}
.theme-choice:hover { border-color: var(--line-3); }
.theme-choice.is-current { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.theme-swatch { position: relative; width: 26px; height: 26px; border-radius: 50%; border: 1px solid var(--line-2); background: var(--panel); overflow: hidden; }
/* Each chip carries its target theme as an attribute, so the token block for
 * that theme scopes into the chip and the preview shows the real colours of
 * the thing it names - the split reads surface left, accent right. */
.theme-swatch::after {
  content: ''; position: absolute; right: 4px; top: 4px; width: 9px; height: 9px;
  border-radius: 999px; background: var(--brand);
}

/* The custom palette row and its status. */
.palette-row { display: flex; gap: var(--space-3); align-items: end; flex-wrap: wrap; }
.palette-field {
  display: grid; gap: 6px; font-size: var(--fs-sm); color: var(--text-2);
}
.palette-field input[type="color"] {
  width: 46px; height: 46px; padding: 2px; border-radius: var(--radius-md);
  border: 1px solid var(--line-2); background: var(--panel-2); cursor: pointer;
}
.palette-row-side { display: grid; gap: var(--space-2); justify-items: start; }
.palette-guide { margin: 0; color: var(--text-2); font-size: var(--fs-sm); line-height: 1.55; }
.palette-status { margin: 0; min-height: 1.2em; font-size: var(--fs-sm); }
.palette-status:empty { display: none; }
.ok-line { color: var(--success); }
.warn-line { color: var(--danger); }
.card-note { margin: 0 0 8px; color: var(--text-2); font-size: var(--fs-sm); }
.density-row { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.density-row .btn.is-current { border-color: var(--brand); color: var(--brand); }
.input--color { appearance: none; -webkit-appearance: none; }


.recovery-codes {
  font-family: var(--mono); font-size: var(--fs-sm);
  padding: 12px; border: 1px dashed var(--line-2); border-radius: var(--radius-md);
  background: var(--panel-3); color: var(--text-1);
  overflow-x: auto;
}
.recovery-codes + .auth-qr { margin-top: 10px; }

/* A published key or token: the same dashed mono block, named for what it holds. */
.keyblock {
  font-family: var(--mono); font-size: var(--fs-xs);
  padding: 10px 12px; border: 1px dashed var(--line-2); border-radius: var(--radius-md);
  background: var(--panel-3); color: var(--text-1);
  overflow-x: auto; white-space: pre-wrap; word-break: break-all;
  margin: 0;
}

/* The action strip that closes a working form: buttons pushed to the start edge. */
.formfoot { display: flex; justify-content: flex-end; gap: var(--space-3); }
.auth-qr { width: 180px; height: 180px; border-radius: var(--radius-md); border: 1px solid var(--line-2); background: var(--panel); }

/* -- the voice dock ------------------------------------------------------------
 * One floating panel that follows a voice session from page to page: the room
 * it names, the people audible in it, and the three acts that matter. Idle it
 * costs nothing; live it carries nothing the session has not said for itself. */

/* A disclosure.
   The details are there for the person who wants them and out of the way for
   the person who does not. */
.details { border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--panel-2); }
.details__summary {
  cursor: pointer; padding: var(--space-3) var(--space-4);
  font-size: var(--fs-sm); font-weight: var(--weight-strong); color: var(--text-2);
  list-style: none;
}
.details__summary::-webkit-details-marker { display: none; }
.details__summary::before { content: '\203A'; display: inline-block; margin-right: 8px; transition: transform var(--dur-1) var(--ease); }
.details[open] .details__summary::before { transform: rotate(90deg); }
.details__body { padding: 0 var(--space-4) var(--space-4); }

.voice-dock { display: grid; gap: var(--space-3); padding: var(--space-4); }
.voice-dock__top { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
.voice-dock__lead { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.voice-dock__glyph { display: inline-flex; color: var(--brand); }
/* The state of the connection, in a word.
   The colour is the only difference between the states, so the word is
   always there beside it. */
.voice-dock__state {
  font-size: var(--fs-micro); color: var(--text-3);
  padding: 2px 8px; border-radius: 999px; border: 1px solid var(--line);
}
.voice-dock__state[data-state="connected"] { color: var(--brand); border-color: var(--brand-line); }
.voice-dock__state[data-state="reconnecting"] { color: var(--warning); border-color: var(--warning); }
.voice-dock__state[data-state="failed"] { color: var(--danger); border-color: var(--danger); }

.voice-dock__title {
  font-weight: var(--weight-strong); color: var(--text-1);
  font-size: var(--fs-md); letter-spacing: var(--tracking-tight);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.voice-dock__peers { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2) var(--space-3); }
.voice-dock__peer { position: relative; display: inline-flex; border-radius: 999px; }
.voice-dock__peer.is-speaking { box-shadow: 0 0 0 2px var(--brand); }
.voice-dock__peerflag {
  position: absolute; right: -3px; bottom: -3px; display: inline-flex;
  padding: 2px; border-radius: 999px; background: var(--raised); color: var(--text-2);
  border: 1px solid var(--line-2);
}
.voice-dock__status { grid-column: 1 / -1; }

/* A screen somebody is sharing.
   The picture is carried peer to peer, so this is the stream the browser
   sent rather than a picture of the dock's own. */
.voice-dock__screens { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.voice-dock__screenwrap { display: grid; gap: 4px; }
.voice-dock__screen {
  width: 220px; max-width: 100%; aspect-ratio: 16 / 9;
  object-fit: contain; background: var(--panel-3);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.voice-dock__screenwho { font-size: var(--fs-micro); color: var(--text-3); }

/* The devices.
   The microphone and the speaker the reader chose, and the one speaker
   there is when there is only one. */
.voice-dock__devices { display: grid; gap: var(--space-2); }
.voice-dock__device { display: grid; gap: 4px; font-size: var(--fs-micro); color: var(--text-3); }
.voice-dock__devicelabel { font-weight: var(--weight-strong); color: var(--text-2); }
.voice-dock__devicehint { margin: 0; font-size: var(--fs-micro); color: var(--text-3); }
.voice-dock__note {
  margin: 0; color: var(--text-2); font-size: var(--fs-sm); line-height: 1.55;
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
}
.dock-link {
  margin-left: var(--space-2);
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--brand); text-decoration: underline; font: inherit; font-size: var(--fs-sm);
}
.voice-dock__controls { display: flex; align-items: center; gap: var(--space-2); justify-content: flex-end; }
.dock-btn {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--panel-2); border: 1px solid var(--line-2); color: var(--text-1);
  cursor: pointer;
}
.dock-btn--round { width: 38px; height: 38px; border-radius: 999px; }
.dock-btn--round:hover { background: var(--hover); }
.dock-btn--round.is-off { color: var(--danger); border-color: var(--danger); }
.dock-btn--round.is-off:hover { background: var(--panel-2); }

/* -- the voice room --------------------------------------------------------------
 * The channel page of a voice room: who is in it, the way in, and the honest
 * limits of the instance. The speaking glow is a ring, not a shadow show. */

.voice-room { display: grid; gap: var(--space-4); align-content: start; }
.voice-room__gate { display: grid; gap: var(--space-3); align-content: start; }
.voice-room__roster {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 1px;
}
.voice-room__row {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
}
.voice-room__row.is-speaking .voice-room__name { color: var(--brand); font-weight: var(--weight-strong); }
.voice-room__row.is-speaking { box-shadow: inset 2px 0 0 var(--brand); }
.voice-room__row--preview { opacity: 0.92; }
.voice-room__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-1); }
.voice-room__row-side { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--text-2); }
.voice-room__muteflag { display: inline-flex; color: var(--text-2); }
.voice-room__controls {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--space-2);
}
.voice-room__controls .btn.is-off { color: var(--danger); }
.voice-room__note { margin: 0; color: var(--text-2); font-size: var(--fs-sm); line-height: 1.55; }

/* -- the remade front doors ------------------------------------------------- */
/*
 * The content pages the reader lands on: the greeting hero, the two-column
 * board, places and quick paths as cards rather than rows, people tiles,
 * request cards, the day-rail inbox, the studio rail for the settings and
 * administration. Colours from tokens only; one block per new kit area.
 */

/* -- hero -------------------------------------------------------------------- */
/* The greeting strip is the sanctioned pagehead wearing one class. The date
 * kicker, the shout that names the day or the page, and the honest sentence
 * keep the same skeleton as every other strip; the brand rail beside the
 * title is what makes these front doors read louder than the rest. */

.pagehead.hero { align-items: flex-end; padding: var(--space-6) 0 var(--space-1); gap: var(--space-5); }
.pagehead.hero .pagehead-main { min-width: 0; }
.pagehead.hero .pagehead-kicker {
  margin: 0;
  font-size: var(--fs-meta);
  font-weight: var(--weight-strong);
  letter-spacing: 0.06em;
}
.pagehead.hero .pagehead-title {
  font-size: var(--fs-display);
  line-height: 1.08;
  letter-spacing: -0.02em;
  padding-left: var(--space-2);
  border-left: 4px solid var(--brand);
}
.pagehead.hero .pagehead-lede { margin-top: var(--space-1); color: var(--text-2); max-width: 56ch; }
.pagehead.hero .pagehead-actions { padding-bottom: var(--space-1); }

/* -- the board --------------------------------------------------------------- */
/* Homepage grid: one wide column for what came in, one narrow for the places
 * the reader keeps and the fast paths. Both collapse on their own when the
 * viewport does. */

.board {
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
}
.board-col { display: flex; flex-direction: column; gap: var(--space-5); min-width: 0; }
.board-col--wide { min-height: 240px; }
.board-col--side .card { min-width: 0; overflow: hidden; }
@media (max-width: 1000px) {
  .board { grid-template-columns: minmax(0, 1fr); }
}

/* -- places ------------------------------------------------------------------ */
/* Communities as cards: the mark, the name, the count, and a quiet arrow. */

.placelist { display: flex; flex-direction: column; }
.placecard {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border-bottom: 1px solid var(--line);
  color: inherit;
  text-decoration: none;
  transition: background var(--dur-1) ease;
  min-width: 0;
}
.placecard:last-child { border-bottom: 0; }
.placecard:hover { background: var(--hover); }
.placecard-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.placecard-name {
  color: var(--text-1);
  font-size: var(--fs-sm);
  font-weight: var(--weight-strong);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.placecard-meta { color: var(--text-3); font-size: var(--fs-micro); }
.placecard-go { color: var(--text-3); display: grid; place-items: center; transition: color var(--dur-1) ease, transform var(--dur-1) ease; }

/* The places that live on another instance. A community of this instance is
   here; a community on another one is a reference, and the section says so. */
.places-heading {
  margin: var(--space-3) 0 var(--space-1);
  padding: 0 var(--space-3);
  font-family: var(--mono); font-size: var(--fs-micro);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-3);
}
.placecard--federated .avatar { border: 1px dashed var(--line-2); }
.placecard:hover .placecard-go { color: var(--brand); transform: translateX(2px); }

/* -- quick paths ------------------------------------------------------------- */

/* The quick paths.
   As many columns as the space allows and no more: a fixed pair of columns
   in a narrow column gave every tile about half the width it needed, and
   "Direct messages" became "Direct ...". */
.quickgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-2);
  padding: var(--space-3);
}
.quickcard {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--panel);
  color: inherit;
  text-decoration: none;
  min-width: 0;
  transition: border-color var(--dur-1) ease, background var(--dur-1) ease;
}
.quickcard:hover { border-color: var(--brand-line); background: var(--hover); }
.quickcard-glyph { display: grid; place-items: center; color: var(--text-2); }
.quickcard:hover .quickcard-glyph { color: var(--brand); }
.quickcard-label {
  flex: 1; min-width: 0;
  color: var(--text-1); font-size: var(--fs-sm); font-weight: var(--weight-medium);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.quickcard-go { color: var(--text-3); display: grid; place-items: center; }

/* -- the studio rail --------------------------------------------------------- */
/* Settings and administration: the door list beside the page, grouped the way
 * the registry groups them, current door marked. Collapses to a horizontal
 * strip above the page on narrow screens. */

.studio {
  display: grid;
  grid-template-columns: minmax(0, 240px) minmax(0, 1fr);
  gap: var(--space-6);
  align-items: start;
  /* A studio is a working surface, not an article: it is allowed to be wide.
     The reading width is for the things a person reads, and a workspace with
     a list and an editor beside it is not one of them. */
  max-width: var(--workspace-max);
  width: 100%;
}
.studionav {
  position: sticky;
  top: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel);
}
@media (max-width: 1000px) {
  .studio { grid-template-columns: minmax(0, 1fr); }
  .studionav { position: static; display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .studionav-group { grid-column: 1 / -1; }
}
.studionav-group {
  margin: var(--space-3) 0 var(--space-1);
  font-size: var(--fs-micro);
  font-weight: var(--weight-strong);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-3);
}
.studionav-group:first-child { margin-top: 0; }
.studionav-link {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  color: var(--text-2);
  text-decoration: none;
  font-size: var(--fs-sm);
  min-width: 0;
  transition: background var(--dur-1) ease, color var(--dur-1) ease;
}
.studionav-link:hover { background: var(--hover); color: var(--text-1); }
.studionav-link--active { background: var(--selected); color: var(--brand); font-weight: var(--weight-strong); }
.studionav-link svg { flex: none; opacity: 0.85; }
.studionav-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.studio-stage { min-width: 0; max-width: none; }

/* -- stats ------------------------------------------------------------------- */

.statstrip { display: flex; gap: var(--space-3); flex-wrap: wrap; }
.stat {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--panel);
  min-width: 0;
}
.stat-value {
  font-size: var(--fs-h2);
  font-weight: var(--weight-black);
  color: var(--brand);
  letter-spacing: -0.01em;
}
.stat-label {
  font-size: var(--fs-micro);
  color: var(--text-2);
  letter-spacing: 0.02em;
}

/* -- people tiles ------------------------------------------------------------ */

.peoplegrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: var(--space-3); padding: var(--space-3); }
.friendtile {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--panel);
  color: inherit;
  text-decoration: none;
  min-width: 0;
  transition: border-color var(--dur-1) ease, transform var(--dur-1) ease;
}
.friendtile:hover { border-color: var(--brand-line); transform: translateY(-1px); }
.friendtile-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.friendtile-name {
  color: var(--text-1);
  font-size: var(--fs-sm);
  font-weight: var(--weight-strong);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.friendtile-sub {
  color: var(--text-3);
  font-size: var(--fs-micro);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.friendtile-tools { display: flex; gap: var(--space-1); opacity: 0.6; transition: opacity var(--dur-1) ease; }
.friendtile:hover .friendtile-tools { opacity: 1; }

/* icon buttons inside tiles keep a fixed square house */
.iconbtn--tile { width: 30px; height: 30px; padding: 0; display: grid; place-items: center; }

/* -- request cards ----------------------------------------------------------- */

.requestlist { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-3); }
.requestcard {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--brand-line);
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--brand) 6%, var(--panel));
  min-width: 0;
}
@media (max-width: 720px) { .requestcard { flex-wrap: wrap; } }
.requestcard-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.requestcard-name { color: var(--text-1); font-size: var(--fs-sm); font-weight: var(--weight-strong); }
.requestcard-sub { color: var(--text-3); font-size: var(--fs-micro); }
.requestcard-actions { display: flex; gap: var(--space-2); flex: none; }

/* -- the inbox feed ---------------------------------------------------------- */

.feedlist { display: flex; flex-direction: column; max-width: var(--content-max); width: 100%; }
.feedday {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-5) 0 var(--space-1);
}
.feedday:first-child { margin-top: 0; }
.feedday::after { content: ''; flex: 1; height: 1px; background: var(--line); }
.feedday-label {
  font-size: var(--fs-micro);
  font-weight: var(--weight-strong);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* -- row meta pair ----------------------------------------------------------- */
/* A small time beside the unread bubble on conversation rows. */

.rowmeta-pair { display: inline-flex; align-items: center; gap: var(--space-2); }
.rowstamp { font-size: var(--fs-micro); color: var(--text-3); white-space: nowrap; }
.cardrow-meta .rowmeta-pair { align-items: center; }

/* -- the search bar ---------------------------------------------------------- */

.searchbar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--raised);
  max-width: var(--content-max);
  width: 100%;
  transition: border-color var(--dur-1) ease;
}
.searchbar:focus-within { border-color: var(--brand-line); }
.searchbar-glyph { display: grid; place-items: center; color: var(--text-3); }
.searchbar .input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: 0;
  padding: var(--space-1) 0;
  box-shadow: none;
}
.searchbar .input:focus-visible { outline: none; }

/* -- anchor offset ----------------------------------------------------------- */

.anchor { scroll-margin-top: var(--space-6); }

/* -- the page editor --------------------------------------------------------- */
/* One block of a page body, and the two ways of writing the same body. The
   editor is a working surface: the blocks are stacked, each one named, and
   the tools sit at the right of the name. */

.pageblock {
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--panel);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.pageblock-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.pageblock-kind {
  font-family: var(--mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-3);
}
.pageblock-body { display: flex; flex-direction: column; gap: var(--space-2); }
.pageblock-row { display: flex; gap: var(--space-2); align-items: flex-start; }
.pageblock-row > .input, .pageblock-row > .select { flex: 1 1 0; min-width: 0; }
.pageblock-row > .select { flex: 0 0 140px; }
.pageblock-items { display: flex; flex-direction: column; gap: var(--space-2); }
.pageblock-item { display: flex; gap: var(--space-2); align-items: center; }
.pageblock-item > .input { flex: 1 1 auto; min-width: 0; }

.icon-btn--sm { width: 26px; height: 26px; }

.page-source {
  font-family: var(--mono);
  font-size: var(--fs-sm);
  line-height: 1.6;
  min-height: 320px;
}

/* The preview is the server's own rendering of the body, shown in the reading
   column a visitor gets. */
.page-preview {
  max-width: 62ch;
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--text-2);
}
.page-preview:empty { display: none; }
.page-preview h2 { color: var(--text-1); margin: var(--space-6) 0 var(--space-2); }
.page-preview h3 { color: var(--text-1); margin: var(--space-5) 0 var(--space-2); }
.page-preview p { margin: 0 0 var(--space-3); }
.page-preview p.lede { color: var(--text-2); font-size: var(--fs-body); }
.page-preview ul, .page-preview ol { padding-left: var(--space-5); margin: 0 0 var(--space-3); }
.page-preview li { margin-bottom: var(--space-1); }
.page-preview a { color: var(--brand); text-decoration: underline; text-underline-offset: 2px; }
.page-preview blockquote {
  margin: var(--space-4) 0;
  padding: var(--space-2) var(--space-4);
  border-left: 3px solid var(--brand-line);
}
.page-preview pre {
  background: var(--panel-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  overflow-x: auto;
}
/* The blocks the server's renderer emits for the newer block types. The
   picture, the table and the quotation's attribution each carry a class the
   renderer puts there, so the preview and the published page can be told
   apart from ordinary prose. */
.page-preview figure.page-image { margin: var(--space-4) 0; }
.page-preview figure.page-image img {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-md);
  border: 1px solid var(--line);
}
.page-preview footer.page-quote-source {
  color: var(--text-3);
  font-size: var(--fs-meta);
  margin-top: var(--space-2);
}
.page-preview table.page-table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--space-4) 0;
  font-size: var(--fs-sm);
}
.page-preview table.page-table caption {
  text-align: left;
  color: var(--text-3);
  font-size: var(--fs-meta);
  padding-bottom: var(--space-2);
}
.page-preview table.page-table th,
.page-preview table.page-table td {
  border: 1px solid var(--line);
  padding: var(--space-2) var(--space-3);
  text-align: left;
  vertical-align: top;
}
.page-preview table.page-table th {
  background: var(--panel-3);
  color: var(--text-1);
  font-weight: var(--weight-semibold);
}
.page-preview pre.page-code code { font-family: var(--mono); font-size: var(--fs-sm); }

/* The table editor's grid. A real table, so the columns line up; the rule is
   what makes it look like an editor rather than a spreadsheet. */
.pageblock-table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--space-2) 0;
  font-size: var(--fs-sm);
}
.pageblock-table th,
.pageblock-table td {
  border: 1px solid var(--line);
  padding: var(--space-2);
  vertical-align: top;
}
.pageblock-table th { background: var(--panel-3); color: var(--text-1); font-weight: var(--weight-semibold); }
.pageblock-table th .input, .pageblock-table td .input { width: 100%; }
.page-preview .draft-note {
  background: var(--panel-3);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  margin: var(--space-4) 0;
}

/* The comparison of a draft against the published page. */
.pagediff {
  font-family: var(--mono);
  font-size: var(--fs-meta);
  line-height: 1.6;
  max-height: 60vh;
  overflow: auto;
}
.pagediff-line { display: flex; gap: var(--space-2); white-space: pre-wrap; }
.pagediff-mark { flex: none; width: 1ch; color: var(--text-3); }
.pagediff-text { min-width: 0; }
.pagediff-line--added { background: color-mix(in srgb, var(--success) 12%, transparent); }
.pagediff-line--removed { background: color-mix(in srgb, var(--danger) 12%, transparent); }
.pagediff-line--added .pagediff-mark { color: var(--success); }
.pagediff-line--removed .pagediff-mark { color: var(--danger); }

/* == search, collections, themes, incidents and reports ======================
 *
 * The surfaces of the 3.0 release: the search panel with its filter bar, the
 * collections a reader saves things into, the theme packages an operator
 * imports, the incident timeline and the cross-instance reports. Colours from
 * tokens only; one block per kit area.
 */

/* -- the search panel -------------------------------------------------------- */

.search-bar { display: flex; gap: var(--space-3); align-items: center; }
.search-input { flex: 1; }
.search-note { margin: 0 0 var(--space-2); color: var(--text-3); font-size: var(--fs-xs); }
.search-results { display: flex; flex-direction: column; }
.search-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
}
.search-main { min-width: 0; }
.search-side { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }
@media (max-width: 1000px) {
  .search-layout { grid-template-columns: minmax(0, 1fr); }
}
.search-hit { align-items: start; }
.search-hit-glyph { display: inline-flex; color: var(--text-3); }

/* The conversation a search hit came from.
   The lines around the hit, so the reader can see the exchange the hit was
   part of without leaving the search. The hit itself is not repeated: the
   reader has just read it. */
.search-context {
  display: flex; flex-direction: column; gap: 2px;
  margin-top: 6px; padding-left: 10px;
  border-left: 2px solid var(--line);
}
.search-context__line { display: flex; gap: 8px; min-width: 0; }
.search-context__who {
  flex: 0 0 auto; max-width: 14ch;
  color: var(--text-3); font-size: var(--fs-micro);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.search-context__text {
  color: var(--text-3); font-size: var(--fs-micro);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.saved-row, .history-row { cursor: pointer; }

/* -- the filter bar ---------------------------------------------------------- */

.filter-bar { display: grid; gap: var(--space-3); position: relative; }
.filter-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.filter-chips:empty { display: none; }
.filter-chip {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: 3px 6px 3px 10px; border-radius: var(--radius-pill);
  background: var(--brand-soft); border: 1px solid var(--brand-line);
  color: var(--brand); font-size: var(--fs-xs); font-weight: var(--weight-medium);
}
.filter-chip-text { font-family: var(--mono); }
.filter-chip-remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; padding: 0;
  border: 0; border-radius: 50%;
  background: transparent; color: inherit; cursor: pointer;
}
.filter-chip-remove:hover { background: color-mix(in srgb, var(--brand) 22%, transparent); }
.filter-chip-remove:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
.filter-row { display: flex; gap: var(--space-2); align-items: center; }
.filter-field { width: min(320px, 100%); font-family: var(--mono); }
.filter-note { margin: 0; min-height: 1.2em; color: var(--text-3); font-size: var(--fs-xs); }
.filter-note.is-warn { color: var(--danger); }
.filter-suggestions {
  list-style: none; margin: 0; padding: var(--space-1);
  display: grid; gap: 2px;
  border: 1px solid var(--line-2); border-radius: var(--radius-md);
  background: var(--raised); box-shadow: var(--shadow-2);
}
.filter-suggestion { list-style: none; }
.filter-suggestion-button {
  display: grid; grid-template-columns: auto auto 1fr; gap: var(--space-2);
  align-items: baseline; width: 100%; text-align: left;
  padding: var(--space-2) var(--space-3);
  border: 0; border-radius: var(--radius-sm);
  background: transparent; color: inherit; cursor: pointer; font: inherit;
}
.filter-suggestion-button:hover { background: var(--hover); }
.filter-suggestion-button:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.filter-suggestion-key { font-family: var(--mono); color: var(--brand); font-weight: var(--weight-strong); }
.filter-suggestion-label { font-size: var(--fs-sm); color: var(--text-1); }
.filter-suggestion-value { font-family: var(--mono); font-size: var(--fs-xs); color: var(--text-2); }
.filter-suggestion-hint { font-size: var(--fs-xs); color: var(--text-3); grid-column: 1 / -1; }

/* -- the collections --------------------------------------------------------- */

.collection-layout {
  display: grid;
  /* The list is a panel of a sensible width and the thing beside it takes
     the rest. Proportional columns gave the list two fifths of the screen -
     a list of document titles two fifths of the screen wide, with the editor
     squeezed into what was left. */
  grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
}
.collection-layout > * { min-width: 0; }
@media (max-width: 1000px) {
  .collection-layout { grid-template-columns: minmax(0, 1fr); }
}
.collection-list, .collection-detail { display: flex; flex-direction: column; }
.collection-row { cursor: pointer; }
.collection-item-glyph { display: inline-flex; color: var(--text-3); }
.collection-item { align-items: start; }
.collection-link { color: var(--brand); }
.collection-head {
  display: flex; align-items: start; justify-content: space-between;
  gap: var(--space-4); padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--line); margin-bottom: var(--space-3);
}
.collection-head-main { min-width: 0; }
.collection-title { margin: 0; font-size: var(--fs-h3); font-weight: var(--weight-strong); }
.collection-meta { margin: 2px 0 0; color: var(--text-3); font-size: var(--fs-xs); }
.collection-head-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.collection-add { margin-top: var(--space-3); }
.collection-pick { width: 100%; text-align: left; }

/* -- the cross-instance reports ----------------------------------------------- */

.federation-row { align-items: start; }
.federation-glyph { display: inline-flex; color: var(--text-3); }
.disclosure {
  display: grid; gap: var(--space-2);
  padding: var(--space-4); border: 1px solid var(--line-2);
  border-radius: var(--radius-md); background: var(--panel-2);
}
.disclosure-title { margin: 0; font-size: var(--fs-sm); font-weight: var(--weight-strong); color: var(--text-1); }
.disclosure-list { margin: 0; padding-left: var(--space-5); color: var(--text-2); font-size: var(--fs-sm); line-height: 1.6; }
.disclosure-holder:empty { display: none; }

/* -- the incident timeline ---------------------------------------------------- */

.incident-timeline { display: grid; gap: var(--space-4); }
.incident {
  display: grid; gap: var(--space-1);
  padding: var(--space-4); border: 1px solid var(--line);
  border-left: 3px solid var(--brand-line);
  border-radius: var(--radius-md); background: var(--panel-2);
}
.incident-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
.incident-status {
  display: inline-flex; align-items: center;
  padding: 2px 9px; border-radius: var(--radius-pill);
  background: var(--panel-3); color: var(--text-2);
  font-size: var(--fs-xs); font-weight: var(--weight-strong);
}
.incident-status[data-tone="warning"] { background: color-mix(in srgb, var(--warning) 16%, transparent); color: var(--warning); }
.incident-status[data-tone="success"] { background: color-mix(in srgb, var(--success) 14%, transparent); color: var(--success); }
.incident-status[data-tone="info"] { background: var(--brand-soft); color: var(--brand); }
.incident-time { color: var(--text-3); font-size: var(--fs-xs); }
.incident-title { margin: 0; font-size: var(--fs-h3); font-weight: var(--weight-strong); }
.incident-summary { margin: 0; color: var(--text-2); line-height: 1.6; }
.incident-body { margin: 0; color: var(--text-3); line-height: 1.6; }
.incident-row { align-items: start; }
.incident-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }

/* -- the language ------------------------------------------------------------- */

.language-row { cursor: pointer; }
.language-glyph { display: inline-flex; color: var(--text-3); }
.language-sample { margin: 0; color: var(--text-2); }

/* -- the theme packages ------------------------------------------------------- */

.theme-change {
  display: grid; grid-template-columns: 100px 1fr; gap: var(--space-3);
  align-items: center; padding: var(--space-2) 0;
  border-bottom: 1px solid var(--line);
}
.theme-change:last-child { border-bottom: 0; }
.theme-change-label { color: var(--text-2); font-size: var(--fs-sm); }
.theme-change-pair { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.theme-change-swatch {
  display: inline-block; width: 18px; height: 18px;
  border-radius: var(--radius-xs); border: 1px solid var(--line-2);
}
.theme-change-value { font-family: var(--mono); font-size: var(--fs-xs); color: var(--text-2); }
.theme-preview { display: grid; gap: var(--space-3); }
.theme-preview-holder:empty { display: none; }
.theme-problems { margin: 0; padding-left: var(--space-5); color: var(--danger); font-size: var(--fs-sm); line-height: 1.6; }
.theme-changes { display: grid; }
.theme-package { font-family: var(--mono); font-size: var(--fs-xs); }
.theme-tokens { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.theme-token { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--fs-xs); color: var(--text-2); }
.theme-row-item { align-items: start; }

/* -- the template picker ------------------------------------------------------ */

.template-list { display: flex; flex-direction: column; }
.template-item {
  display: flex; align-items: start; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-3) 0; border-bottom: 1px solid var(--line);
}
.template-item:last-child { border-bottom: 0; }
.template-item-main { display: grid; gap: 2px; min-width: 0; }
.template-item-name { font-size: var(--fs-sm); font-weight: var(--weight-strong); color: var(--text-1); }
.template-item-shortcut { font-family: var(--mono); font-size: var(--fs-xs); color: var(--brand); }
.template-item-body { font-size: var(--fs-xs); color: var(--text-3); overflow-wrap: anywhere; }
.template-item-actions { display: flex; gap: var(--space-2); flex: none; }


/* ---- entry.css ---- */

/* The outside of the workspace.
 *
 * Two surfaces mount directly into <body> without the shell, and this layer is
 * the only place their presentation lives: the gates a visitor meets before
 * any session exists, and the public documents a reader can open signed out.
 * Both are deliberately quiet - one centered column, charcoal, the ember
 * hairline as the single flourish - because a checkpoint is not a billboard.
 *
 * Colours come from tokens.css only; no raw values are allowed in this layer. */

/* -- shared ground ----------------------------------------------------------- */

.auth-page,
.pub-page {
  min-height: 100vh;
  background:
    var(--ember-wash),
    var(--app-bg);
  color: var(--text-1);
  display: flex;
  flex-direction: column;
}

/* -- the gates ---------------------------------------------------------------- */

.auth-page {
  align-items: center;
  justify-content: flex-start;
  padding: var(--space-8) var(--space-4);
  overflow-y: auto;
}

/* The two panes.
   The form is on the left, where the eye goes first, and the panel that
   says what this is is on the right. On a narrow screen there is one pane:
   the form, and the panel becomes a line above it. */
.auth-panes {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
  width: min(100%, 1000px);
  margin: auto;
  align-items: center;
}

.auth-pane { min-width: 0; }

/* The panel. */
.auth-pane--brand {
  position: relative;
  overflow: clip;
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  background: var(--panel);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-2);
  isolation: isolate;
}

/* The ember behind the panel, drifting. It is the one piece of movement on
   a screen where somebody is about to type a password, so it is slow, it is
   behind everything, and it stops for a reader who has asked for less
   movement. */
.auth-pane--brand::before {
  content: '';
  position: absolute;
  inset: -30%;
  z-index: -1;
  background:
    radial-gradient(38% 42% at 18% 22%, color-mix(in srgb, var(--brand) 30%, transparent), transparent 70%),
    radial-gradient(42% 38% at 82% 78%, color-mix(in srgb, var(--brand) 18%, transparent), transparent 72%);
  filter: blur(12px);
  animation: gate-drift 22s ease-in-out infinite alternate;
}

@keyframes gate-drift {
  from { transform: translate3d(-3%, -2%, 0) scale(1); }
  to { transform: translate3d(4%, 3%, 0) scale(1.08); }
}

/* The panes arrive rather than being there. */
@keyframes gate-pane-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

.auth-pane--form { animation: gate-pane-in 420ms var(--ease-out) both; }
.auth-pane--brand { animation: gate-pane-in 420ms var(--ease-out) 90ms both; }

.auth-brand { display: flex; flex-direction: column; gap: var(--space-4); }
.auth-brand-mark { display: flex; align-items: center; gap: var(--space-3); }
.auth-brand-img { display: block; }
.auth-brand-name {
  font-size: var(--fs-xl);
  font-weight: 800;
  letter-spacing: var(--tracking-tight, -0.01em);
  color: var(--text-1);
}
.auth-brand-line {
  margin: 0;
  max-width: 34ch;
  color: var(--text-2);
  font-size: var(--fs-sm);
  line-height: 1.6;
}
.auth-brand-instance {
  display: inline-flex; align-items: center; gap: var(--space-2);
  margin: 0;
  padding: var(--space-2) var(--space-3);
  width: fit-content;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-pill);
  background: var(--panel-2);
  color: var(--text-1);
  font-size: var(--fs-sm);
  font-weight: var(--weight-medium);
}
.auth-brand-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--brand);
}

@media (min-width: 860px) {
  /* Two panes, side by side. The form is the one the reader came for, so it
     takes the side the eye reaches first. */
  .auth-panes { grid-template-columns: minmax(0, 420px) minmax(0, 1fr); }
  .auth-pane--form { order: 1; }
  .auth-pane--brand { order: 2; }
  .auth-page { padding: var(--space-8); }
  .gate-card { margin: 0; }
}

@media (max-width: 859px) {
  /* One pane: the form, and the panel as a line above it. A thumb does not
     need a picture, and a narrow screen does not have room for one. */
  .auth-pane--brand {
    padding: var(--space-4);
    border-radius: var(--radius-md);
  }
  .auth-brand { flex-direction: row; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
  .auth-brand-line { display: none; }
  .auth-brand-name { font-size: var(--fs-lg); }
}

@media (prefers-reduced-motion: reduce) {
  /* A reader who has asked for less movement gets none of it. */
  .auth-pane--form,
  .auth-pane--brand { animation: none; }
  .auth-pane--brand::before { animation: none; }
}

.gate-card {
  position: relative;
  width: min(100%, 400px);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-6) var(--space-6) var(--space-6);
  box-shadow: var(--shadow-2);
  margin: auto;
  overflow: clip;
}

/* The one flourish: the ember hairline across the top edge. */
.gate-card::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: var(--brand);
}

.gate-mark {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
  color: var(--text-2);
  font-size: var(--fs-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tight);
  text-decoration: none;
}

.gate-mark:hover { color: var(--text-1); }
.gate-mark-img { display: block; width: 30px; height: 30px; }

.gate-title {
  margin: 0;
  font-size: var(--fs-h1);
  font-weight: var(--weight-black);
  letter-spacing: var(--tracking-tight);
}

.gate-lede { margin: var(--space-2) 0 0; color: var(--text-2); font-size: var(--fs-sm); line-height: 1.6; }

/* The instance an account would be created on, named on the form itself. */
.gate-instance {
  margin: var(--space-4) 0 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--panel);
  color: var(--text-2);
  font-size: var(--fs-meta);
  line-height: 1.5;
}
.gate-instance-name { color: var(--text-1); font-weight: var(--weight-strong); word-break: break-all; }
.gate-instance a { color: var(--brand); }

.gate-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-5);
}

.gate-form [aria-busy='true'] { opacity: .85; }

.gate-alt {
  margin: var(--space-5) 0 0;
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.gate-alt a { color: var(--text-2); font-weight: var(--weight-medium); text-decoration: underline; text-underline-offset: 2px; }
.gate-alt a:hover { color: var(--text-1); }

.gate-note { margin: var(--space-5) 0 0; font-size: var(--fs-sm); color: var(--text-2); }

.gate-choices { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-4); }

.gate-secret {
  display: block;
  font-family: var(--mono);
  font-size: var(--fs-body);
  padding: 10px 14px;
  background: var(--panel-3);
  border: 1px dashed var(--line-2);
  border-radius: var(--radius-md);
  letter-spacing: .05em;
  overflow-wrap: anywhere;
  user-select: all;
  text-align: center;
}

/* -- the public documents ------------------------------------------------------ */

.pub-page { align-items: stretch; }

.sheet-top {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--panel) 60%, transparent);
}

.sheet-return {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-2);
  font-size: var(--fs-sm);
  font-weight: var(--weight-medium);
  text-decoration: none;
  border-radius: var(--radius-sm);
  padding: 4px 6px;
  margin-left: -6px;
}

.sheet-return:hover { color: var(--text-1); background: var(--hover); }
.sheet-return:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.sheet-name { margin-left: auto; font-size: var(--fs-micro); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-3); }

.sheet-body {
  flex: 1;
  display: flex;
  justify-content: center;
  padding: var(--space-7) var(--space-4);
  overflow-y: auto;
}

/* The document itself: one narrow reading column. */
.paper { width: min(100%, 640px); display: flex; flex-direction: column; }

.paper-kicker {
  margin: 0 0 var(--space-2);
  font-size: var(--fs-micro);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--text-3);
}

.paper-title { margin: 0; font-size: var(--fs-display); font-weight: var(--weight-black); letter-spacing: var(--tracking-tight); }
.paper-lede { margin: var(--space-3) 0 0; color: var(--text-2); font-size: var(--fs-body); max-width: 58ch; line-height: 1.65; }
.paper .actionline { margin-top: var(--space-5); }
.paper-note { margin: var(--space-5) 0 0; padding-top: var(--space-3); border-top: 1px solid var(--line); font-size: var(--fs-sm); color: var(--text-3); }

/* -- accepting the documents ------------------------------------------------- */
/* The acceptance control on the registration form: the checkbox, the links to
   the two documents, and the versions that are being accepted.
   It is a block of its own rather than a line at the bottom of a long form,
   because it is the one control on the form a reader cannot do without. */

.gate-legal-block {
  display: flex; flex-direction: column; gap: var(--space-2);
  margin: 0 0 var(--space-4); padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line-2); border-radius: var(--radius-md);
  background: var(--panel-2);
}
.gate-legal-block.is-accepted { border-color: color-mix(in srgb, var(--success) 40%, var(--line-2)); }
.gate-legal-heading {
  margin: 0; font-size: var(--fs-sm); font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-3);
}
.gate-legal-lede { margin: 0; font-size: var(--fs-sm); color: var(--text-2); line-height: 1.55; }
.gate-legal { align-items: flex-start; margin-top: var(--space-1); color: var(--text-1); line-height: 1.5; }
.gate-legal a { color: var(--brand); text-decoration: underline; text-underline-offset: 2px; }
.gate-legal-text { display: flex; flex-direction: column; gap: 2px; }
.gate-legal-title { font-weight: var(--weight-medium); }
.gate-legal-meta { color: var(--text-3); font-size: var(--fs-meta); }
.gate-legal-version.is-missing { color: var(--warning); }
.gate-legal-state { font-weight: var(--weight-medium); }
.gate-legal-block.is-accepted .gate-legal-state { color: var(--success); }

/* The reason the button is closed. A disabled control with no reason is the
   control everybody works around. */
.gate-submit-note { margin: var(--space-2) 0 0; font-size: var(--fs-meta); color: var(--text-3); text-align: center; }
