/* The application shell: sidebar, workspace, Preferences, shared page parts.

   The v2.2 baseline (docs/ui/archive/design-system-preview.html, design-system.md),
   rebuilt on the token tiers rather than copied: every colour and type size is
   a semantic role (`--text-muted`, `--type-ui`), never a primitive, which
   `tests/workspace/web/test_tokens.py` enforces. Both themes come from the
   tokens; nothing here is written twice for dark.

   Layout values (238px / 68px sidebar, 36px workspace top padding, 44px
   navigation rows) are the preview's measured ones. */

/* The reading face `--font-serif` names first (Ask's answers, long text). Its
   declaration lived only in the Matter pages' stylesheet, so the shell fell
   back to Georgia or Times (walk, 2026-10-19). Swap, not block: text shows at
   once in the fallback. */
@font-face {
  font-family: "Newsreader";
  src: url("/static/fonts/Newsreader-Variable.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}

:root {
  color-scheme: light;
}

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

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
  }
}

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

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

body.app-body {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-secondary);
  font-family: var(--type-body);
  font-size: var(--type-ui);
  line-height: 1.55;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: var(--space-300);
  top: var(--space-300);
  transform: translateY(-200%);
  z-index: 1001;
  padding: var(--space-200) var(--space-300);
  border-radius: var(--radius-100);
  background: var(--surface-raised);
  color: var(--accent-base);
  font-weight: 650;
}

.skip-link:focus {
  transform: none;
  box-shadow: var(--elevation-overlay);
}

:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

.icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---- Layout ---------------------------------------------------------- */

.app {
  display: grid;
  grid-template-columns: 238px minmax(0, 1fr);
  min-height: 100vh;
}

:root[data-sidebar="collapsed"] .app {
  grid-template-columns: 68px minmax(0, 1fr);
}

.workspace {
  min-width: 0;
  padding: var(--space-900) var(--space-1000) var(--space-1400);
}

.workspace:focus {
  outline: none;
}

/* ---- Sidebar --------------------------------------------------------- */

.sidebar {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-600);
  height: 100vh;
  overflow-y: auto;
  padding: var(--space-600) var(--space-300);
  background: var(--surface-nav);
  border-right: 1px solid var(--border-subtle);
  z-index: 3;
}

.sidebar__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-200);
  min-height: 36px;
}

.sidebar__brand {
  display: flex;
  align-items: center;
  gap: var(--space-250);
  min-width: 0;
  padding: var(--space-150);
  border-radius: var(--radius-200);
  color: var(--text-primary);
  text-decoration: none;
}

.sidebar__mark {
  display: inline-flex;
  color: var(--accent-base);
}

.sidebar__brand-name {
  font-weight: 750;
  letter-spacing: calc(var(--type-tracking-brand) * 1em);
  white-space: nowrap;
}

.icon-button {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  /* an icon alone is a circle, its hover ground too (DS-52) */
  border-radius: var(--radius-full);
  corner-shape: round;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.icon-button:hover {
  background: var(--surface-hover);
  color: var(--text-primary);
}

.sidebar__caption {
  padding: var(--space-100) var(--space-300) var(--space-50);
  color: var(--text-muted);
  font-size: var(--type-label);
  font-weight: 750;
  letter-spacing: calc(var(--type-tracking-label) * 1em);
  text-transform: uppercase;
}

.sidebar__nav {
  display: grid;
  gap: var(--space-100);
}

.sidebar__item {
  display: flex;
  align-items: center;
  gap: var(--space-300);
  width: 100%;
  min-height: 44px;
  padding: var(--space-250) var(--space-300);
  border: 0;
  border-radius: var(--radius-200);
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  font-weight: 550;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--motion-settle) var(--motion-easing-arrive),
    color var(--motion-settle) var(--motion-easing-arrive);
}

.sidebar__item:hover {
  background: var(--surface-hover);
  color: var(--text-primary);
}

.sidebar__item[aria-current="page"] {
  background: var(--surface-selected);
  color: var(--accent-base);
  font-weight: 650;
}

.sidebar__bottom {
  margin-top: auto;
}

.sidebar__note {
  /* The footer under Preferences (DS-48): space above, none below. */
  margin: var(--space-300) 0 0;
  padding: 0 var(--space-300);
  color: var(--text-muted);
  font-size: var(--type-label);
}

.sidebar__preferences[aria-expanded="true"] {
  background: var(--surface-hover);
  color: var(--text-primary);
}

/* Collapsed: icons only. The labels leave the layout but stay as the links'
   `title`, and the nav keeps its accessible names through the visible-label
   spans being hidden only visually. */
:root[data-sidebar="collapsed"] .sidebar {
  padding-inline: var(--space-250);
}

:root[data-sidebar="collapsed"] .sidebar__head {
  flex-direction: column;
  gap: var(--space-300);
}

:root[data-sidebar="collapsed"] .sidebar__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

:root[data-sidebar="collapsed"] .sidebar__item {
  justify-content: center;
  padding-inline: 0;
}

:root[data-sidebar="collapsed"] .sidebar__caption,
:root[data-sidebar="collapsed"] .sidebar__note {
  display: none;
}

/* ---- Signing in (pages/auth.html, api/auth.py) -----------------------
   Home's hero (home.css) under the product's mark, centred on the page; no
   sidebar. Only the layout around the hero is defined here. */

.auth {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: var(--space-600);
  min-height: 100vh;
  padding: var(--space-800) var(--space-400);
}

.auth__brand {
  display: flex;
  align-items: center;
  gap: var(--space-250);
  margin: 0;
  color: var(--text-primary);
  font-weight: 650;
}

.auth__mark {
  display: inline-flex;
  color: var(--text-primary);
}

.auth__hero {
  width: 100%;
  max-width: 760px;
}

.auth__title {
  max-width: 16ch;
}

.auth__action {
  text-decoration: none;
}

/* ---- Preferences popover -------------------------------------------- */

.preferences {
  position: fixed;
  z-index: 1000;
  width: 292px;
  padding: var(--space-500);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-300);
  background: var(--surface-raised);
  color: var(--text-secondary);
  box-shadow: var(--elevation-overlay);
}

.preferences[hidden] {
  display: none;
}

.preferences__title {
  margin: 0 0 var(--space-400);
  color: var(--text-primary);
  font-size: var(--type-normal);
  font-weight: 700;
}

.preferences__group {
  display: grid;
  gap: var(--space-250);
  margin: 0;
  padding: 0;
  border: 0;
}

.preferences__legend {
  margin-bottom: var(--space-300);
  padding: 0;
  font-weight: 650;
}

.preferences__option {
  display: flex;
  align-items: center;
  gap: var(--space-250);
  cursor: pointer;
}

.preferences__option input {
  accent-color: var(--accent-base);
}

.preferences__note {
  margin: var(--space-450) 0 0;
  color: var(--text-muted);
  font-size: var(--type-meta);
}

/* Who is signed in, and signing out (api/identity.py, api/auth.py): the first
   group of the popover, above Appearance, so the sidebar keeps its places. */
.preferences__account {
  display: grid;
  gap: var(--space-250);
  margin: 0 0 var(--space-500);
  padding: 0 0 var(--space-500);
  border-bottom: 1px solid var(--border-subtle);
}

.preferences__who {
  display: grid;
  margin: 0;
}

.preferences__name {
  color: var(--text-primary);
  font-weight: 650;
  overflow-wrap: anywhere;
}

.preferences__email {
  color: var(--text-muted);
  font-size: var(--type-small);
  overflow-wrap: anywhere;
}

.preferences__account form {
  margin: 0;
}

/* ---- Shared page parts ---------------------------------------------- */

.page {
  max-width: 1080px;
}

.eyebrow {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--type-label);
  font-weight: 750;
  letter-spacing: calc(var(--type-tracking-label) * 1em);
  text-transform: uppercase;
}

.page__header {
  margin-bottom: var(--space-700);
}

.page__title {
  margin: var(--space-350) 0 var(--space-250);
  color: var(--text-primary);
  font-size: var(--type-page);
  font-weight: 750;
  line-height: 1.15;
  letter-spacing: calc(var(--type-tracking-title) * 1em);
}

.page__lede {
  max-width: 62ch;
  margin: 0;
  color: var(--text-muted);
  font-size: var(--type-text);
}

/* THE COMPOSER (DS-15): floating and well rounded, with a small round send
   button inside it -- the shape current assistants' inputs share. 24px corners
   (owner, 2026-10-15: 12px read as dated), so a one-line composer reads as a
   pill and a grown one stays soft. */
.composer {
  display: flex;
  align-items: center;
  gap: var(--space-200);
  max-width: 760px;
  min-height: 52px;
  padding: var(--space-200) var(--space-200) var(--space-200) var(--space-400);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-500);
  background: var(--surface-raised);
}

/* The send button: the primary button made round (design-system review,
   2026-10-24) -- an arrow in a circle of the controls' floor,
   `--control-min-height`, named for screen readers by its aria-label. It lifts
   on hover as `.button--primary` does, and while there is nothing to send it
   is faded, not greyed, with the ordinary cursor ("disabled is faded, not
   hidden", controls.css). */
.composer__send {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--control-min-height);
  height: var(--control-min-height);
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  corner-shape: round;
  background: var(--accent-base);
  color: var(--text-inverse);
  cursor: pointer;
}

.composer__send .icon {
  width: 18px;
  height: 18px;
  stroke-width: 2.2;
}

.composer__send:hover:not(:disabled) {
  box-shadow: var(--elevation-subtle);
}

.composer__send:disabled {
  opacity: 0.4;
  cursor: default;
}

.composer__send:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

/* Stop takes the send button's place while an answer runs: the same circle,
   a square, and the page's text colour so it does not read as "send again". */
.composer__send--stop {
  background: var(--text-primary);
  color: var(--surface-raised);
}

.composer__send--stop .icon {
  fill: currentColor;
}

.composer__send--stop:hover:not(:disabled) {
  background: var(--text-secondary);
}

/* KEYBOARD FOCUS IS THE SHARED RING (section 4), on the whole box while its
   field has focus: the field itself draws none, since its edge is the box's.
   The send button keeps its own ring, so only the field's focus is matched. */
.composer:has(.composer__input:focus-visible) {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

.composer__icon {
  display: inline-flex;
  color: var(--text-muted);
}

.composer__input {
  flex: 1;
  min-width: 0;
  min-height: 40px;
  padding: var(--space-250) var(--space-50);
  border: 0;
  background: transparent;
  color: var(--text-primary);
  font: inherit;
}

.composer__input::placeholder {
  color: var(--text-muted);
}

.composer__input:focus-visible {
  outline: none;
}

/* Buttons and inputs are the design system's (`foundations/controls.css`,
   linked before this file); the shell does not define them a second time. */

.composer--compact {
  margin-bottom: var(--space-600);
}

.page__hint {
  max-width: 760px;
  margin: 0;
  color: var(--text-muted);
}

.results {
  max-width: 760px;
}

.results__count {
  color: var(--text-muted);
  font-weight: 400;
}

/* The things of one concept (plan cb3d1 task 19). */
.collection {
  max-width: 760px;
}

.pager__link {
  color: var(--accent-base);
  text-underline-offset: 3px;
}

/* A thing's dependencies, by level (plan 84625 task 23). */
.thing-deps { margin-top: var(--space-700); }
.thing-deps__title { margin: 0; font-size: var(--type-section); font-weight: 650; }

/* The lacking filter (plan 84625 task 23): one row of label, relation and
   button, wrapping on a narrow screen. */
.collection__filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-200) var(--space-300);
  margin: var(--space-400) 0;
  font-size: var(--type-small);
  color: var(--text-secondary);
}
.collection__select { width: auto; max-width: 100%; }
.collection__clear { font-size: var(--type-small); color: var(--text-secondary); }
.collection__clear:hover { color: var(--text-primary); }

.pager {
  display: flex;
  align-items: baseline;
  gap: var(--space-400);
  margin-top: var(--space-400);
  font-size: var(--type-meta);
}

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

/* The Ontology lens (plan cb3d1 task 22): hierarchies, broad to narrow. */
.ontology {
  max-width: 1200px;
}

.state-panel {
  max-width: 760px;
  margin-top: var(--space-600);
  padding: var(--space-450) var(--space-500);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-300);
  background: var(--surface-sunk);
}

.state-panel__title {
  margin: 0 0 var(--space-150);
  color: var(--text-primary);
  font-weight: 650;
}

.state-panel__marker {
  color: var(--text-muted);
}

.state-panel__body {
  margin: 0;
  color: var(--text-muted);
}

/* ---- Shared controls: hidden, disclosure, working ---------------------- */

/* What a script hides stays hidden. A control's own `display` (the buttons,
   the composer's send) would otherwise win over the `hidden` attribute. One
   rule here rather than one per feature (Ask carried its own until task 52). */
[hidden] {
  display: none !important;
}

/* A disclosure: native <details>, a summary that reads as a control, and one
   chevron that says open or closed. Shared since task 52 (owner, 2026-10-15:
   no second pattern per feature); Ask's progress log uses it, and the
   Inspector's and Explore's sections are to follow. The summary is a flex row,
   so a feature can put a status, a mark or a count in it. */
.disclosure > summary {
  display: flex;
  align-items: center;
  gap: var(--space-200);
  list-style: none;
  cursor: pointer;
}

.disclosure > summary::-webkit-details-marker {
  display: none;
}

.disclosure > summary::after {
  content: "";
  flex: none;
  width: var(--space-150);
  height: var(--space-150);
  margin-left: var(--space-100);
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-1px) rotate(-45deg);
}

.disclosure[open] > summary::after {
  transform: translateY(-2px) rotate(45deg);
}

.disclosure > summary:focus-visible {
  border-radius: var(--radius-100);
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

/* Still working (DS-19): a small ring that turns while an answer is being
   worked on. Decorative -- the status text beside it says what is happening --
   and still under reduced motion (motion.css zeroes `--motion-working`). */
.working {
  flex: none;
  width: var(--space-300);
  height: var(--space-300);
  border: 2px solid var(--border-subtle);
  border-top-color: var(--accent-base);
  border-radius: 50%;
  corner-shape: round;
  animation: working var(--motion-working) var(--motion-easing-steady) infinite;
}

/* ---- Forced colours ------------------------------------------------- */

/* Backgrounds are dropped in forced-colours mode, so the current place and
   the composer focus need an outline that survives. */
@media (forced-colors: active) {
  .sidebar__item[aria-current="page"] {
    outline: 2px solid CanvasText;
    outline-offset: -2px;
  }

  .composer:has(.composer__input:focus-visible) {
    outline: 2px solid Highlight;
  }
}

/* ---- Narrow screens -------------------------------------------------- */

@media (max-width: 760px) {
  .app,
  :root[data-sidebar="collapsed"] .app {
    grid-template-columns: 68px minmax(0, 1fr);
  }

  .sidebar {
    padding-inline: var(--space-250);
  }

  .sidebar__head {
    flex-direction: column;
    gap: var(--space-300);
  }

  .sidebar__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  .sidebar__item {
    justify-content: center;
    padding-inline: 0;
  }

  .sidebar__caption,
  .sidebar__note,
  .sidebar__collapse {
    display: none;
  }

  .workspace {
    padding: var(--space-600) var(--space-400) var(--space-1000);
  }
}

/* The answer of a Source data or Query page sits below its header like any
   page's answer (plan 84625 task 30). */
.page > .answer { margin-top: var(--space-600); }

/* A caption inside the nav (D46 1: "Behind the data") sets its group apart. */
.sidebar__group { margin-top: var(--space-400); }
