@layer base {
/* Reset & Variables.
   Design tokens live in tokens/ — see docs/dev/web/design-system.md §3. Only
   layout constants that are not part of a scale belong here. */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* The line above also zeroes the browser's own `margin: auto` on <dialog>
   and on a [popover], which is the whole of how a modal dialog (showModal())
   or a popover is centred: without it either sits in the top-left corner.
   Give it back, here beside the reset that took it, so every dialog and
   popover is centred without asking (METIS-pub#610). */
dialog, [popover] { margin: auto; }

:root {
  --toolbar-h: 33px;
}

html { font-size: 14px; }
html, body {
  height: 100%;
}

body {
  font-family: var(--font);
  color: var(--text);
  background: var(--bg);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  height: 100%;
  padding-left: var(--sidenav-w);
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }

/* Form elements */
/* Browsers do not inherit the page's font into form controls, so every
   button, text box, dropdown and text area was drawn in the browser's own
   face (Arial, or monospace in a text area). This hands them the page's
   typeface (--font, so the per-app --font-ui exceptions follow). Only the
   family: `font: inherit` would also hand them the body's size and line
   height, which the rules below and each component set themselves
   (METIS-pub#539). */
button, input, select, textarea {
  font-family: inherit;
}

textarea, input[type="text"], input[type="email"], input[type="date"],
input[type="number"], input[type="password"], input[type="search"],
input[type="url"], select {
  padding: var(--space-xs);
  box-sizing: border-box;
}

textarea {
  padding: var(--space-sm);
}

/* ── Sidenav ── */
:root {
  --sidenav-w: 48px;
  --sidenav-expanded-w: 210px;
}

.sidenav {
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--sidenav-expanded-w);
  box-shadow: var(--elev-2);
  z-index: 500;
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: visible;
  transition: width var(--dur-base) var(--ease-out);
}

/* Environment tint — left border stripe */
.sidenav-env-dev { border-left: 3px solid var(--nav-env-dev); }
.sidenav-env-dev-prod-db { border-left: 3px solid #e57373; }

/* Focus group — the focus selector + the pages it scopes, visually bound
   together with a left accent stripe so it's clear which items focus affects. */
/* Scope wrapper: the left accent line runs from Focus through all Apps */
.sidenav-focus-scope {
  border-left: 2px solid var(--accent);
  margin: 6px 0;
}
/* All items inside the scope lose 2px left padding to offset the stripe */
.sidenav-focus-scope .sidenav-item { padding-left: 10px; }

.sidenav-focus-group {
  position: relative;
}
/* Group head (top of the rail): focus holon logo on the left, with a right
   column holding the "eye + Focus" heading above the dropdown chip. */
.sidenav-focus-group__head {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  /* No horizontal padding: the logo fills the full collapsed-rail width. The
     right column carries its own right padding (only shown when expanded). */
  padding: 8px 0;
  min-height: 32px;
}
/* Right column (expanded only): eye+label heading stacked over the dropdown. */
.sidenav-focus-col {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1 1 auto;
  min-width: 0;
  padding-right: 12px;
}
.sidenav-focus-heading {
  display: flex;
  align-items: center;
  gap: 8px;
}
.sidenav-focus-eye {
  /* 70% of the 24px nav-icon size. */
  width: 17px;
  height: 17px;
  flex-shrink: 0;
  color: var(--accent);
  opacity: 0.85;
}
.sidenav-focus-col .toggle-focus {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
}
/* Focus holon logo: sized to fill the full collapsed-rail width (46px) and kept
   fixed when the sidenav expands, so it never resizes. Links to the holon. */
.sidenav-focus-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  flex-shrink: 0;
}
.sidenav-focus-logo img {
  width: 46px;
  height: 46px;
  border-radius: var(--radius-md);
  object-fit: cover;
  display: block;
}
.sidenav-focus-logo .toggle-focus__badge {
  width: 46px;
  height: 46px;
  border-radius: var(--radius-md);
  font-size: var(--text-xl);
}
.sidenav-focus-logo svg {
  width: 46px;
  height: 46px;
  color: var(--accent);
}
/* "All" (no focus): globe reads smaller than a holon logo. */
.sidenav-focus-logo--all svg {
  width: 34px;
  height: 34px;
}
/* The chip's own leading avatar is redundant now the icon sits outside it. */
.sidenav-focus-group .toggle-focus__avatar {
  display: none;
}
.sidenav-focus-heading-label {
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-light);
  white-space: nowrap;
  opacity: 1;
  transition: opacity var(--dur-fast) var(--ease-out) 0.06s;
}
.sidenav-focus-group .toggle-focus {
  display: flex;
  width: 100%;
  min-width: 0;
  opacity: 1;
  transition: opacity var(--dur-fast) var(--ease-out) 0.06s;
}
.sidenav-focus-group .toggle-focus__menu {
  position: fixed;
  left: 0;
  right: auto;
  top: 80px; /* overridden by JS; fallback keeps it below the head */
}
/* Focus chip in the sidenav: full-width, reads as a chip, and lights up with a
   tinted background + accent border on hover so it's clearly interactive. */
.sidenav-focus-group .toggle-btn--focus {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--surface);
  color: var(--text);
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.sidenav-focus-group .toggle-btn--focus:hover,
.sidenav-focus-group.is-open .toggle-btn--focus,
.sidenav-focus-group .toggle-focus.open .toggle-btn--focus {
  background: var(--accent-ring);
  border-color: var(--accent);
  box-shadow: var(--elev-1);
}
.sidenav-focus-group .toggle-focus__label {
  flex: 1;
  min-width: 0;
  text-align: left;
  font-weight: 600;
}
/* Logo/badge shown inside the chip (current focus) */
.toggle-focus__avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: var(--accent);
}
.toggle-focus__avatar img {
  width: 20px;
  height: 20px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  display: block;
}
.toggle-focus__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  font-weight: 700;
  flex-shrink: 0;
}
/* Logos inside the dropdown menu items */
.toggle-focus__item {
  display: flex !important;
  align-items: center;
  gap: 8px;
}
.toggle-focus__item-logo {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  object-fit: cover;
  display: block;
}
.toggle-focus__item-logo--all {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
}
.toggle-focus__item-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Keep .sidenav-logo for any remaining usages */
.sidenav-logo {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px;
  border-bottom: 1px solid var(--border-light);
  text-decoration: none;
  color: var(--text);
  flex-shrink: 0;
  white-space: nowrap;
}
.sidenav-logo:hover { background: var(--border-light); }
.sidenav-logo-icon { width: 24px; height: 24px; flex-shrink: 0; }
.sidenav-logo-label { font-size: var(--text-base); font-weight: 600; color: var(--text-muted); }
.sidenav-logo-holon { border-radius: var(--radius); object-fit: contain; }
.sidenav-logo-edit {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--radius);
  color: var(--text-muted);
  text-decoration: none;
  margin-right: 6px;
}
.sidenav-logo-edit:hover {
  color: var(--accent);
  background: var(--border-light);
}

/* Pinned head — the focus selector and Search.
   Outside .sidenav-items on purpose: a control that scopes the whole rail
   should not scroll away from the things it scopes, and keeping it out of the
   scroll container is what lets .sidenav stay overflow:visible so the focus
   dropdown can escape the 48px rail. */
.sidenav-head {
  flex-shrink: 0;
  padding: 4px 0;
}

/* Items container — the only band that scrolls.
   It used to be overflow:hidden, which did not scroll the overflow, it clipped
   it: on a 13" laptop eight of twenty rows were unreachable by any gesture, and
   which app disappeared depended on ShellNavGroup.order. */
.sidenav-items {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 4px 0;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.sidenav-items::-webkit-scrollbar { width: 6px; }
.sidenav-items::-webkit-scrollbar-track { background: transparent; }
.sidenav-items::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: var(--radius-sm);
}

/* Bottom fade, only when the list actually overflows — data-overflow is set by
   a ResizeObserver in sidenav.js. Always-on, it would soften the last item in
   the common case where everything fits. */
.sidenav-items[data-overflow="true"] {
  mask-image: linear-gradient(to bottom, var(--text) calc(100% - 12px), transparent);
}

/* Footer */
.sidenav-footer {
  border-top: 1px solid var(--border-light);
  padding: 4px 0;
  flex-shrink: 0;
  /* visible, not hidden: the user menu opens out of the rail, beside it. */
  overflow: visible;
  position: relative;
}

/* Individual item */
.sidenav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 12px;
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  font-family: var(--font);
  font-size: var(--text-md);
  border: none;
  background: none;
  cursor: pointer;
  width: 100%;
  text-align: left;
  line-height: 1.4;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
/* Primary nav rows (Activity, Calendar, People, Orgs) sit tighter together —
   they have no App heading separating them. */
.sidenav-focus-scope > .sidenav-item,
.sidenav-app-group--primary .sidenav-item { padding-top: 5px; padding-bottom: 5px; }

.sidenav-item:hover { background: var(--border-light); color: var(--text); }
.sidenav-item.sidenav-active { background: var(--border-light); color: var(--text); }
.sidenav-item.sidenav-active .sidenav-icon { opacity: 0.85; }

/* Wrap: sidenav item with an edit/action link (visible only when expanded) */
.sidenav-item-wrap {
  display: flex;
  align-items: center;
  overflow: hidden;
  white-space: nowrap;
}
.sidenav-item-wrap .sidenav-item { flex: 1; min-width: 0; }
.sidenav-item-edit {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--radius);
  color: var(--text-muted);
  text-decoration: none;
  margin-right: 6px;
}
.sidenav-item-edit:hover {
  color: var(--accent);
  background: var(--border-light);
}

/* Icons within items */
.sidenav-icon {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  opacity: 0.45;
  transition: opacity var(--dur-base) var(--ease-out);
  display: block;
}
.sidenav-item:hover .sidenav-icon { opacity: 0.8; }
.sidenav-static-icon { filter: opacity(0.45); }
.sidenav-item:hover .sidenav-static-icon { filter: opacity(0.8); }

/* Labels — faded out on the collapsed rail, which the trailing block does. */
.sidenav-label {
  opacity: 1;
  transition: opacity var(--dur-fast) var(--ease-out) 0.06s;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Divider */
.sidenav-divider {
  height: 1px;
  background: var(--border-light);
  margin: 6px 12px;
  flex-shrink: 0;
}

/* App groups: named app + collapsible sub-items */
.sidenav-app-group {
  display: flex;
  flex-direction: column;
}

/* App tint — an app's block in the rail carries its own colour, so which app
   you are looking at is legible even on the collapsed 48px rail where the
   labels are hidden. Generic mechanism, one token pair per app: the shell
   tags each group with data-app-group="<slug>" and the owning app (or
   tokens/apps.css, for apps using platform primitives) sets the tint.
   Untinted apps default to transparent and look exactly as before.

   Colour only. The rail's geometry stays identical in every app — navigation
   has to feel the same shape wherever you are. */
.sidenav-app-group[data-app-group] {
  background: var(--app-nav-bg, transparent);
  transition: background var(--transition-base);
}

.sidenav-app-group[data-app-group]:hover {
  background: var(--app-nav-bg-hover, var(--app-nav-bg, transparent));
}

/* Items inside a tinted group need their own hover to stay legible against the
   tint rather than the rail's white. */
.sidenav-app-group[data-app-group] .sidenav-item:hover,
.sidenav-app-group[data-app-group] .sidenav-item.sidenav-active {
  background: var(--app-nav-item-active, var(--border-light));
}
/* Sub-items: shown only while the group is open. One open group at a time is
   what keeps the rail's height bounded as apps get registered. */
.sidenav-app-items {
  display: flex;
  flex-direction: column;
}
.sidenav-app-group[data-app-group]:not([data-open]) > .sidenav-app-items {
  display: none;
}

/* App section heading — a disclosure button wearing the .sidenav-item
   treatment, so the row reads and behaves like every other row in the rail. */
.sidenav-app-heading {
  padding: 15px 12px 2px 10px;
  color: var(--text);
}
.sidenav-app-heading .sidenav-icon {
  flex-shrink: 0;
  opacity: 1;
}
.sidenav-app-label {
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  flex: 1;
  min-width: 0;
}

/* An app group's backdrop fades up when the rail expands. The value pair is
   the app's own (registered in its nav.css); which of the two applies is this
   file's answer, so the shell still learns no app slug and the three app
   stylesheets no longer each carry their own copy of "is the rail expanded?"
   — three copies that had already drifted, all missing :focus-within. */
.sidenav [data-app-group] {
  --sidenav-app-backdrop: var(--sidenav-app-backdrop-expanded);
}

/* Expanded: the disclosure chevron, rotated when the group is open. Collapsed
   it becomes a dot meaning "there is more inside" — the trailing block does
   that. One element, because it is one affordance.

   The heading itself stays a click target on the collapsed rail: on a device
   with no hover a tap is the only pointer there is, and a `pointer-events: none`
   here made every app group unreachable on a tablet (issue 241). */
.sidenav-app-chevron {
  flex-shrink: 0;
  width: 7px;
  height: 7px;
  margin-right: 5px;
  border-radius: 0;
  background: none;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  opacity: 0.45;
  transition: transform var(--dur-fast) var(--ease-out),
              opacity var(--dur-fast) var(--ease-out);
}
.sidenav-app-group[data-open] .sidenav-app-chevron {
  transform: rotate(45deg);
}
/* An open group has its rows on show; the dot would be saying it twice. */
.sidenav-app-group[data-open] .sidenav-app-chevron { opacity: 0.7; }

/* ── Footer: the signed-in person, and the menu behind them ──────────────
   One row instead of four, which is where two or three of the rail's rows came
   back from. It also returns the "who am I signed in as" signal the old brand
   row used to carry. */
.sidenav-user { position: relative; }

.sidenav-user__trigger { gap: 10px; }

.sidenav-user__avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  flex-shrink: 0;
}
.sidenav-user__avatar img {
  width: 24px;
  height: 24px;
  border-radius: var(--radius-full);
  object-fit: cover;
  display: block;
}
/* Reuses the focus selector's initials badge — same fallback, same treatment. */
.sidenav-user__badge {
  width: 24px;
  height: 24px;
  border-radius: var(--radius-full);
  background: var(--accent-ring);
  color: var(--text);
}
.sidenav-user__generic {
  width: 22px;
  height: 22px;
  color: var(--text-light);
}
.sidenav-user__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The menu slides out beside the rail, anchored to the bottom, above the
   content area — so it is legible whether the rail is collapsed or expanded. */
.sidenav-user__menu {
  position: absolute;
  left: 100%;
  bottom: 0;
  margin-left: 6px;
  min-width: 200px;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--elev-2);
  z-index: 600;
  display: flex;
  flex-direction: column;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-out);
}
.sidenav-user__menu[data-open] {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
}

.sidenav-user__link {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 6px 8px;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-muted);
  font-family: var(--font);
  font-size: var(--text-md);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.sidenav-user__link:hover,
.sidenav-user__link:focus-visible,
.sidenav-user__link.sidenav-active {
  background: var(--border-light);
  color: var(--text);
}

/* Legacy user info row — links to settings */
.sidenav-user-info { }
.sidenav-user-photo {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}
.sidenav-user-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--text-muted);
  flex-shrink: 0;
}
.sidenav-username { font-size: var(--text-base); color: var(--text-muted); }
.sidenav-logout-form { margin: 0; }

/* Layout */
.main {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: var(--space-md);
  box-sizing: border-box;
  position: relative;
}

/* App mark — the owning app's mark on the pages it owns. Rendered from the
   contribution registry; absent on platform routes and on any app that
   registers no brand.

   It renders in the page-header icon slot (crm/partials/_page_icon.html),
   inline with the page's own heading and selectors: it reads as page furniture
   rather than as a banner above the page. There is deliberately no shell-level
   fallback into <main> — a stray first child lands wherever the page's own
   layout puts it, which on the detail grid is the top-right corner. A page
   without a header slot shows no mark until it grows one.

   Register the bare mark, not a lockup: at this size a wordmark is unreadable,
   and the app's name is already carried by its nav group. */
.app-mark {
  flex-shrink: 0;
  line-height: 0;
}

.app-mark img {
  /* Height-driven so any app's mark keeps its own aspect ratio. Half again the
     34px section icon it sits beside: a mark carries the app's identity and
     reads as undersized at icon parity. */
  height: 51px;
  width: auto;
  display: block;
}

.app-mark a {
  display: inline-block;
  transition: opacity var(--transition-fast);
}

.app-mark a:hover { opacity: 0.75; }

/* ── The one place "collapsed" is declared ─────────────────────────────────
   Everything above styles the expanded rail; this narrows it.

   One selector, because the condition used to be written out by hand in
   thirteen and they had drifted: the width rule said hover-or-preview while
   the app heading's pointer-events rule said hover-or-preview-or-focus-within,

   :focus-within now drives the *width* too, which it did not before — it only
   reached the chevron and the heading. That is deliberate (the old comment on
   the heading rule already claimed a keyboard user got the expansion), and it
   has a visible consequence on a mouse: clicking an app heading focuses the
   <button>, so the rail stays open over the page after the pointer leaves,
   until focus moves on. Clicking anywhere else closes it.
   so a keyboard user got a clickable control inside a 48px rail — and a tablet
   user, with neither hover nor a way to widen the rail, could not reach any
   app's nav at all (issue 241). Adding a state (a pin, a media query, another
   preview) is one edit here. web/app/tests_sidenav.py fails if a second copy
   appears in any stylesheet under metis_apps/ — the three app nav.css files
   each carried their own gate and had already drifted, so the test reads the
   whole tree rather than this file alone.

   It must stay the last sidenav rule: it ties on specificity with rules like
   .sidenav-app-group[data-open] .sidenav-app-chevron — :not() takes its most
   specific argument — and source order is what decides a tie. !important is
   not the fix for that (CLAUDE.md); a losing rule here is in the wrong place.
   ───────────────────────────────────────────────────────────────────────── */
.sidenav:not(:hover, :focus-within, .sidenav--preview-open) {
  width: var(--sidenav-w);
  box-shadow: none;

  & .sidenav-label,
  & .sidenav-focus-heading-label { opacity: 0; }

  /* A scrollbar in a 48px rail is noise. */
  & .sidenav-items { scrollbar-width: none; }
  & .sidenav-items::-webkit-scrollbar { width: 0; }

  /* Would steal width from the item it sits beside. */
  & .sidenav-item-edit { display: none; }

  /* The whole right column goes, leaving the logo alone on the 48px rail —
     the eye heading is inside that column, so nothing of the focus group but
     the logo shows here.

     display, not visibility: a hidden-but-laid-out column still sizes to its
     46px logo plus gap and padding, which overflows the rail by about 22px.
     That is invisible today only because .sidenav is overflow: visible, so it
     becomes a visible artefact the moment anything in that chain clips.

     .open survives both rules: its dropdown is position: fixed, so the pointer
     moving onto the menu leaves the rail and the chip must not vanish under
     it. */
  & .sidenav-focus-group .toggle-focus:not(.open) { display: none; opacity: 0; }
  & .sidenav-focus-group__head:not(:has(.toggle-focus.open)) .sidenav-focus-col {
    display: none;
  }

  & [data-app-group] {
    --sidenav-app-backdrop: var(--sidenav-app-backdrop-collapsed);
  }

  /* Collapsed, the affordance is a dot: "there is more inside". */
  & .sidenav-app-chevron {
    border-radius: var(--radius-full);
    background: currentColor;
    border: 0;
    width: 10px;
    height: 10px;
    margin-right: 2px;
    transform: none;
  }
}

/* Decorative page motif — the owning app's artwork, pinned to the bottom-left
   corner of the viewport. Opt-in: only apps that register backdrops get one,
   and the asset arrives as an inline --app-page-motif on <body> (§4.6).

   A fixed pseudo-element of .main, painted with mix-blend-mode: multiply.
   Multiply is what makes this work at all: the motifs are photographs of black
   ink on white paper, so the paper multiplies away to nothing and only the ink
   lands. Two earlier attempts — a fixed div below the content layer, then a
   dimmed background-image — were both invisible in practice, because dimming
   ink to 8% on a white page leaves a whisper of grey that reads as nothing.
   Multiply lets the ink stay strong enough to see while text under it only
   darkens rather than being veiled.

   Anchored to the content edge, not the window edge: the sidenav is fixed and
   would cover a motif at left: 0. Sized off the viewport so it reads as a
   corner flourish at any window size rather than a picture someone placed. */
[data-app-motif] .main::after {
  content: "";
  position: fixed;
  /* One size, used for both dimensions and for the bleed, so the motif keeps
     its square aspect and the crop stays proportional at every window width. */
  --app-motif-size: min(39vw, 494px);
  --app-motif-bleed: calc(var(--app-motif-size) * -0.1);
  /* Bleeding a tenth off the anchored edge and the bottom makes it read as a
     crop of something larger rather than a stamp placed in the corner.

     Which corner is the app's call — motif artwork is often weighted to one
     side of its frame, and the wrong corner crowds the content column. The
     default hugs the content edge beside the rail; an app switches sides from
     its own theme by setting the three --app-motif-* tokens together. Geometry
     stays here: an app picks a corner, it does not re-declare the element. */
  left: var(--app-motif-left, calc(var(--sidenav-w) + var(--app-motif-bleed)));
  right: var(--app-motif-right, auto);
  bottom: var(--app-motif-bleed);
  width: var(--app-motif-size);
  height: var(--app-motif-size);
  background-image: var(--app-page-motif, none);
  background-repeat: no-repeat;
  background-position: var(--app-motif-anchor, left bottom);
  background-size: contain;
  mix-blend-mode: multiply;
  opacity: 0.13;
  pointer-events: none;
}

@media (max-width: 900px) {
  /* Nothing to spare in the corner on a narrow window. */
  [data-app-motif] .main::after { display: none; }
}

/* The motif shows wherever the content above it is transparent, so the
   full-height list surfaces say so explicitly rather than relying on none of
   them ever growing a background. The sticky table header keeps its opaque
   --bg: rows have to disappear behind it as they scroll. */
[data-app-motif] .table-panel-wrap,
[data-app-motif] .table-container,
[data-app-motif] .data-table,
[data-app-motif] .data-table tbody tr,
[data-app-motif] .data-table tbody td {
  background-color: transparent;
}

/* Page orientation icon — fixed to top-left of main area, matches sidenav icon */
.page-nav-icon {
  position: fixed;
  top: 10px;
  left: calc(var(--sidenav-w) + 10px);
  z-index: 400;
  pointer-events: none;
  opacity: 0.55;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
}

/* Page + info panel two-column layout */
/* Published-destination icons (crm/shared/partials/published_links.html) — where
   a conversation is live. Here rather than in detail.css because its two hosts
   load different stylesheets: the holon/person detail pages take detail.css, the
   conversation table takes table.css, and only base.css is on every page. A
   not-yet-public destination is dimmed rather than hidden: the operator still
   wants the link, but the strip must not read as "this is out there" when it is
   not. Icon sizing comes from .contact-icon-mini (table.css / detail.css). */
.published-links {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
}
.published-links__link {
  display: inline-flex;
  color: var(--text-muted);
  text-decoration: none;
}
.published-links__link .contact-icon {
  width: 14px;
  height: 14px;
  vertical-align: middle;
}
.published-links__link:hover .contact-icon {
  color: var(--color-accent);
}
.published-links__link--private .contact-icon {
  opacity: 0.45;
}

/* A viewport-height page (kanban board, calendar, list+panel): it fills what is
   left of `main` and clips, so its own bottom edge — where the board's
   horizontal scrollbar lives — is the last visible row of the window.

   `flex: 1` + `min-height: 0`, not `height: 100%`. A percentage height is 100%
   of *main*, which is only the space actually available when this is main's
   sole child. It is not: the extension version banner renders above it, and a
   77px banner pushed the whole page 77px past the clipped bottom — taking the
   kanban scrollbar off-screen on every board (and it is `overflow-x: scroll`
   precisely so that bar is always there). Sized as a flex item it takes what is
   left over instead, whatever else main is carrying. */
.main:has(.page-with-panel) {
  padding: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.page-with-panel {
  display: flex;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.page-with-panel > *:first-child {
  flex: 1;
  min-width: 0;
}

/* Buttons. Tokenised on the tier-3 --btn-* tokens so a button re-accents
   with its app; destructive variants live in components/button.css. */
.btn {
  padding: var(--space-2) var(--space-4);
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-bg);
  border-radius: var(--btn-radius);
  font-size: var(--text-base);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);

  /* vertically align the text and icon */
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.export-btn {
  font-size: var(--text-sm);
  padding: 0.2rem 0.6rem;
  margin-left: auto;
  background: transparent;
  color: var(--text-muted);
  border-color: var(--border);
}
.btn:hover { background: var(--btn-bg-hover); border-color: var(--btn-bg-hover); color: var(--btn-fg); }
.btn-sm { padding: var(--space-xs) var(--space-sm); font-size: var(--text-base); }
.btn-save-wrapper {
  display: inline-block;
  cursor: not-allowed;
}
.btn-save-wrapper .btn:not(:disabled) {
  cursor: pointer;
}

/* Screen-reader-only text: extra context for icon controls and external links
   that would be noise on screen but is needed by assistive technology. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Background-job state chip — a rounded pill carrying a leading status dot.
   Colour tokens are the ones the IRIS pipeline rail already uses for these
   states (coherence/css/iris_console.css), so a list chip and the rail agree.
   The dot does the colour-shouting so the label can stay quiet and readable. */
.job-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 2px 9px 2px 7px;
  border-radius: var(--radius-full);
  border: 1px solid transparent;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.job-chip__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}
.job-chip--done {
  background: var(--success-bg);
  border-color: var(--success-border);
  color: var(--success-color);
}
.job-chip--error {
  background: var(--overdue-bg);
  border-color: var(--danger-border);
  color: var(--overdue-color);
}
/* Job finished, but its output waits on a person (pipeline_graph.WAITING_OPERATOR).
   Danger palette like --error: both mean the pipeline has stopped. */
.job-chip--waiting-operator {
  background: var(--overdue-bg);
  border-color: var(--danger-border);
  color: var(--overdue-color);
}
.job-chip--processing {
  background: var(--note-comment-bg);
  border-color: var(--note-comment-border);
  color: var(--note-comment-text);
}
.job-chip--processing .job-chip__dot {
  animation: job-chip-pulse 1.4s ease-in-out infinite;
}
.job-chip--queued {
  background: var(--surface-alt);
  border-color: var(--border);
  color: var(--text-muted);
}
@keyframes job-chip-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.35; transform: scale(0.8); }
}
@media (prefers-reduced-motion: reduce) {
  .job-chip--processing .job-chip__dot { animation: none; }
}

/* Entity chip — avatar + name pill for a person or holon in a dense list.
   See crm/shared/partials/entity_chips.html; the coherence conversation header
   has its own larger, removable variant (.pchip). */
.entity-chips {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  align-items: center;
  justify-content: flex-end;
  min-width: 0;
}
.entity-chips__empty { color: var(--text-light); font-size: var(--text-base); }

/* Follow-up date colors */
.follow-up-overdue {
  color: var(--overdue-color);
  font-weight: 500;
}
.follow-up-today {
  color: var(--today-color);
  font-weight: 500;
}

/* The chip hook for interest colours — `.chip--typed interest-…` reads the
   --chip-accent-* pair off the bare class. Issue #208; the .interest-tag
   compound that used to sit here (and its shape rule) was deleted once
   crm/color-guide.html, its last consumer, moved onto .chip (PR7). */
.interest-local-leader { --chip-accent-bg: var(--interest-leader-bg); --chip-accent-fg: var(--white); }
.interest-local-catalyst { --chip-accent-bg: var(--interest-catalyst-bg); --chip-accent-fg: var(--white); }
.interest-local-team { --chip-accent-bg: var(--accent); --chip-accent-fg: var(--text); }
.interest-ambassador { --chip-accent-bg: var(--interest-ambassador-bg); --chip-accent-fg: var(--white); }
.interest-gathering-global-team { --chip-accent-bg: var(--holon-domain-bg); --chip-accent-fg: var(--holon-domain-text); }

/* Interest tags under person name */
.person-interest-tags {
  margin-top: 2px;
}

/* List header */
.list-header {
  margin-bottom: var(--space-md);
}
.list-header--flex {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

/* Filters */
.filters { display: flex; gap: var(--space-sm); align-items: center; flex-wrap: wrap; }


/* Toggle group — pill style */
.toggle-group {
  display: inline-flex;
  background: var(--border-light);
  border-radius: var(--radius-lg);
  padding: 3px;
}
.toggle-btn {
  padding: 5px 16px;
  background: transparent;
  border: none;
  border-radius: var(--radius-lg);
  font-family: var(--font);
  font-size: var(--text-base);
  color: var(--text-muted);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.toggle-btn:hover {
  color: var(--text);
}
.toggle-btn.active {
  background: var(--surface);
  color: var(--text);
  font-weight: 500;
  box-shadow: var(--elev-1);
}
/* Icon-only variant: narrower horizontal padding */
.toggle-btn--icon {
  padding-left: 10px;
  padding-right: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0;
}
/* Mine filter button: avatar photo or initials */
.filter-mine-avatar {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}
.filter-mine-initials {
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  pointer-events: none;
}
/* Focus filter button: holon logo or initial badge */
.filter-focus-logo {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}
.filter-focus-initials {
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  pointer-events: none;
}
/* All/Mine sliding switch — single binary toggle (groups icon off, person icon on) */
.toggle-switch {
  position: relative;
  width: 54px;
  height: var(--toolbar-h);
  border-radius: calc(var(--toolbar-h) / 2);
  background: var(--border);
  border: none;
  padding: 0;
  flex-shrink: 0;
  cursor: pointer;
  transition: background var(--dur-base) var(--ease-out);
}
.toggle-switch--on {
  background: var(--accent);
}
.toggle-switch__knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: calc(var(--toolbar-h) - 6px);
  height: calc(var(--toolbar-h) - 6px);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-muted);
  box-shadow: var(--elev-1);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
  pointer-events: none;
}
.toggle-switch--on .toggle-switch__knob {
  transform: translateX(calc(54px - var(--toolbar-h)));
  color: var(--text);
}
.toggle-switch__icon {
  display: none;
  align-items: center;
  justify-content: center;
}
.toggle-switch__icon--off {
  display: flex;
}
.toggle-switch--on .toggle-switch__icon--off {
  display: none;
}
.toggle-switch--on .toggle-switch__icon--on {
  display: flex;
}
.toggle-switch__icon .filter-mine-avatar {
  width: 21px;
  height: 21px;
}
.toggle-switch__icon .filter-mine-initials {
  font-size: 10px;
}
/* List ⇄ Kanban view switch: a two-segment pill of icon links. Distinct from
   .toggle-switch (a binary on/off knob) because this is a segmented mode
   selector showing both options at once, with the active one highlighted. */
.view-toggle {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  overflow: hidden;
  background: var(--surface-alt);
  flex-shrink: 0;
}
.view-toggle__opt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--toolbar-h);
  height: var(--toolbar-h);
  color: var(--text-light);
  transition: background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.view-toggle__opt:hover { background: var(--border-light); color: var(--text-muted); }
.view-toggle__opt--active { background: var(--surface); color: var(--text); }
.view-toggle__opt svg { display: block; }
.search-input, .filter-select {
  padding: var(--space-sm) var(--space-md);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: var(--text-base);
  background: var(--surface);
  color: var(--text);
  outline: none;
}
.search-input:focus, .filter-select:focus {
  border-color: var(--accent);
}
.search-input {
  width: 260px;
  height: var(--toolbar-h);
  border-radius: calc(var(--toolbar-h) / 2);
  box-sizing: border-box;
  padding-left: 70px;
}

/* Empty states */
.empty-state {
  color: var(--text-light);
  text-align: center;
  padding: 0;
}
/* Hijack impersonation bar — merged into layout rule above */
.hijack-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
  padding: var(--space-sm) var(--space-md);
  background: var(--warning-bg);
  border-bottom: 2px solid var(--warning-btn);
  color: var(--warning-color);
  font-size: var(--text-md);
  flex-shrink: 0;
}
.hijack-release-btn {
  padding: var(--space-xs) var(--space-sm);
  background: var(--warning-btn);
  color: white;
  border: none;
  border-radius: var(--radius);
  font-size: var(--text-base);
  font-family: var(--font);
  cursor: pointer;
  font-weight: 500;
}
.hijack-release-btn:hover {
  background: var(--warning-btn-hover);
}

/* Holon type colours — applied to badges, pills, nav chips.
   Each rule declares the --chip-accent-* pair first, then sources its own
   background/color FROM that pair, so there is one token reference per type,
   not two hand-kept copies that could drift — CLAUDE.md's "never parallel
   hand-kept constants that must agree" (issue #208 item 0b review). The
   background/color declarations stay, sourced this way, because these
   classes are also used directly on non-chip elements (.tree-icon,
   .holon-type-icon, .filter-select); `.chip--typed` (which
   reads --chip-accent-* in @layer components) needs the custom property to
   win over @layer base regardless — a losing rule is in the wrong layer. */
.holon-type-organisation {
  --chip-accent-bg: var(--holon-org-bg); --chip-accent-fg: var(--holon-org-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}
.holon-type-domain {
  --chip-accent-bg: var(--holon-domain-bg); --chip-accent-fg: var(--holon-domain-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}
.holon-type-tenant {
  --chip-accent-bg: var(--holon-tenant-bg); --chip-accent-fg: var(--holon-tenant-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}
.holon-type-event {
  --chip-accent-bg: var(--holon-event-bg); --chip-accent-fg: var(--holon-event-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}
.holon-type-camp {
  --chip-accent-bg: var(--holon-camp-bg); --chip-accent-fg: var(--holon-camp-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}
/* Product type tokens kept here intentionally: these CSS classes are applied by
   platform templates (badges, status chips, kanban cards) for any installed app's
   holon types. They are global UI tokens, not product-owned presentation. */
.holon-type-local_gathering {
  --chip-accent-bg: var(--holon-local-gathering-bg); --chip-accent-fg: var(--holon-local-gathering-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}
.holon-type-conversation_event {
  --chip-accent-bg: var(--holon-coherence-conversation-bg); --chip-accent-fg: var(--holon-coherence-conversation-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}
.holon-type-experience {
  --chip-accent-bg: var(--holon-experience-bg); --chip-accent-fg: var(--holon-experience-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}
.holon-type-outreach-network {
  --chip-accent-bg: var(--holon-outreach-network-bg); --chip-accent-fg: var(--holon-outreach-network-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}
.holon-type-outreach-list {
  --chip-accent-bg: var(--holon-outreach-list-bg); --chip-accent-fg: var(--holon-outreach-list-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}
.holon-type-quest {
  --chip-accent-bg: var(--holon-quest-bg); --chip-accent-fg: var(--holon-quest-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}
.holon-type-mission {
  --chip-accent-bg: var(--holon-mission-bg); --chip-accent-fg: var(--holon-mission-text);
  background: var(--chip-accent-bg); color: var(--chip-accent-fg);
}

/* The chip hook for journey colours. There was never a bare .journey-type-*
   rule — only .journey-pill.* (detail.css) and .filter-chip.* (table.css) —
   so `.chip--typed journey-type-…`, documented in the ui-guide since #207,
   rendered the generic accent instead. Custom properties only: these three
   classes are never the sole colour source on a non-chip element, unlike
   .holon-type-* above. Issue #208 item 0b. */
.journey-type-person { --chip-accent-bg: var(--journey-person-bg); --chip-accent-fg: var(--color-accent); }
.journey-type-holon  { --chip-accent-bg: var(--journey-holon-bg);  --chip-accent-fg: var(--journey-holon-text); }
.journey-type-convo  { --chip-accent-bg: var(--journey-convo-bg);  --chip-accent-fg: var(--color-text-muted); }

/* Tree icon contrast — invert dark icons on dark type backgrounds.
   Tenant's stone-200 is light, like Organisation's, so neither is listed. */
.tree-icon.holon-type-domain img,
.tree-icon.holon-type-event img,
.holon-type-icon.holon-type-domain img,
.holon-type-icon.holon-type-event img {
  filter: brightness(0) invert(1);
}

/* Tree component (sidebar + explore page) */
.explore-tree {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  max-width: 700px;
}
.tree-section-label {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 12px 16px 6px;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  cursor: pointer;
  user-select: none;
}
.tree-section-label:hover { color: var(--text); }
.tree-section-label:not(:first-child) {
  border-top: 1px solid var(--border-light);
  margin-top: 4px;
}
.tree-section-label .tree-chevron { width: 14px; height: 14px; }
.tree-row {
  display: flex;
  align-items: center;
  padding: 4px 12px;
  gap: 6px;
  transition: background var(--dur-fast) var(--ease-out);
}
.tree-row:hover { background: var(--border-light); }
.depth-1 { padding-left: 36px; }
.depth-2 { padding-left: 60px; }
.depth-3 { padding-left: 84px; }
.depth-4 { padding-left: 108px; }
.depth-5 { padding-left: 132px; }
.tree-link {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1;
  min-width: 0;
  text-decoration: none;
  color: inherit;
}
.tree-chevron {
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius);
  cursor: pointer;
  color: var(--text-light);
  flex-shrink: 0;
  transition: transform var(--dur-base) var(--ease-out), color var(--dur-fast) var(--ease-out);
  user-select: none;
}
.tree-chevron:hover { color: var(--text-muted); }
.tree-chevron.open { transform: rotate(90deg); }
.tree-spacer { width: 18px; flex-shrink: 0; }
.tree-icon,
.holon-type-icon {
  width: 22px;
  height: 22px;
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.tree-icon img,
.holon-type-icon img { width: 14px; height: 14px; }
.tree-icon-neutral { background: var(--border-light); }
.tree-name {
  flex: 1;
  min-width: 0;
  font-size: var(--text-md);
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tree-link:hover .tree-name { color: var(--accent); }
.tree-right {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  flex-shrink: 0;
}
.tree-count { font-size: var(--text-sm); color: var(--text-light); }
.tree-count a { color: var(--text-muted); }
.tree-count a:hover { color: var(--accent); }
.tree-focus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: var(--radius);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out);
  flex-shrink: 0;
}
.tree-row:hover .tree-focus { opacity: 0.5; }
.tree-focus:hover { opacity: 1 !important; background: var(--border); }
.tree-focus img { width: 14px; height: 14px; }
.tree-children { display: none; }
.tree-children.open { display: block; }
.tree-empty { padding: 12px 16px; color: var(--text-light); font-size: var(--text-base); }

/* Sidebar tree link (Journeys label) */
.tree-section-label a { color: inherit; text-decoration: none; }
.tree-section-label a:hover { text-decoration: underline; }

/* Layout utilities */
.hidden { display: none; }
.d-inline { display: inline; }
.cursor-default { cursor: default; }
.cursor-pointer { cursor: pointer; }
.text-sm { font-size: 0.85em; }

/* Agent textarea */
.agent-textarea { min-height: 12rem; width: 100%; box-sizing: border-box; }

/* Agent schedule card */
.schedule-card { margin-bottom: 1.5rem; padding: 1rem; border: 1px solid var(--border); border-radius: var(--radius); }
.schedule-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem; }
.schedule-meta { display: flex; align-items: center; gap: var(--space-sm); }
.schedule-description { margin: 0.25rem 0 0.75rem; font-size: 0.85em; color: var(--text-muted); }

/* Task result cell */
.task-result-cell { word-break: break-word; white-space: pre-wrap; font-size: 0.85em; }

/* Error / no-access page */
.error-page { max-width: 480px; margin: 120px auto; text-align: center; }
.error-page h1 { font-size: var(--text-2xl); margin-bottom: 1rem; }
.error-page p { color: var(--text-muted); margin-bottom: 2rem; }
.error-page a { color: var(--accent); }

/* ── Focus-holon dropdown (global — used on chat, people, orgs pages) ─── */
.toggle-focus {
  position: relative;
  display: inline-flex;
}

.toggle-btn--focus {
  display: inline-flex;
  align-items: center;
  gap: 3px;
}

.toggle-focus__label {
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.toggle-focus__chevron {
  flex-shrink: 0;
  opacity: 0.4;
  transition: transform var(--dur-base) var(--ease-out), opacity var(--dur-base) var(--ease-out);
}

.toggle-focus.open .toggle-focus__chevron {
  transform: rotate(180deg);
  opacity: 0.7;
}

.toggle-focus__menu {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: 220px;
  max-width: 300px;
  max-height: 360px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--elev-3);
  z-index: 200;
  padding: 6px 0;
}

.toggle-focus.open .toggle-focus__menu {
  display: block;
  animation: focus-menu-in 0.15s ease-out;
}

@keyframes focus-menu-in {
  from { opacity: 0; transform: translateY(-6px) scale(0.97); }
  to   { opacity: 1; transform: translateY(0)    scale(1); }
}

.toggle-focus__menu::before {
  content: "";
  position: absolute;
  top: -5px;
  left: 14px;
  transform: rotate(45deg);
  width: 10px;
  height: 10px;
  background: var(--surface);
  border-top: 1px solid var(--border);
  border-left: 1px solid var(--border);
}

.toggle-focus__group-label {
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--text-light);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 8px 14px 4px;
  pointer-events: none;
}

.toggle-focus__group-label:not(:first-child) {
  border-top: 1px solid var(--border-light);
  margin-top: 4px;
  padding-top: 10px;
}

.toggle-focus__item {
  display: block;
  width: 100%;
  padding: 7px 14px;
  border: none;
  background: none;
  font-family: inherit;
  font-size: var(--text-base);
  color: var(--text);
  text-align: left;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border-radius: 0;
}

.toggle-focus__item:hover {
  background: var(--bg);
}

.toggle-focus__item--active {
  font-weight: 600;
  color: var(--accent);
  background: var(--bg);
}


/* The live "what this step grants / takes away" line under a step picker.
   Written by crm/js/journey_info_panel.js; see crm/shared/partials/journey_chip.html. */
/* The notice (crm/js/holon-target-picker.js: "the journey you chose isn't
   offered with that target", METIS-pub#447) is the same kind of news as the
   grant line — the form changed something under you — so one rule serves
   both. */
.journey-chip__grant-line,
.journey-chip__notice {
  margin: var(--space-1) 0 0;
  color: var(--color-warning);
  font-size: var(--text-xs);
}

/* The kanban grant confirm (crm/js/kanban_move.js). Built in JS because the
   move happens from two boards and neither owns the markup; the amber follows
   the grant chip in components/chip.css, because it is the same news in a
   bigger box. */
.grant-confirm {
  max-width: 32rem;
  padding: var(--space-4);
  border: 1px solid var(--color-warning-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
}

/* No overlay token exists and this issue does not invent a semantic tier;
   derived from the text colour, in oklab per the design-system rule. */
.grant-confirm::backdrop {
  background: color-mix(in oklab, var(--color-text) 45%, transparent);
}

.grant-confirm__title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-lg);
}

.grant-confirm__lead {
  margin: 0 0 var(--space-3);
  color: var(--color-warning);
}

.grant-confirm__list {
  margin: 0 0 var(--space-4);
  padding-left: var(--space-4);
  font-size: var(--text-sm);
}

.grant-confirm__list li { margin-bottom: var(--space-1); }

.grant-confirm__actions {
  display: flex;
  gap: var(--space-2);
  justify-content: flex-end;
}

/* ── @mention autocomplete dropdown ── */
.mention-dropdown {
  list-style: none;
  background: var(--bg, #fff);
  border: 1px solid var(--border, #ddd);
  border-radius: var(--radius-md);
  box-shadow: var(--elev-2);
  max-height: 240px;
  overflow-y: auto;
  padding: 0.25rem 0;
}

.mention-dropdown__item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.75rem;
  cursor: pointer;
  font-size: var(--text-md);
  color: var(--text);
}

.mention-dropdown__item:hover,
.mention-dropdown__item--active {
  background: var(--accent-ring, rgba(152,155,75,0.1));
}

.mention-dropdown__badge {
  margin-left: auto;
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.1rem 0.4rem;
  border-radius: var(--radius-full);
  background: var(--text-muted, #aaa);
  color: #fff;
  flex-shrink: 0;
}

.mention-dropdown__item--person .mention-dropdown__badge { background: #4a7c59; }
.mention-dropdown__item--holon  .mention-dropdown__badge { background: var(--holon-org-text, #192F2B); }

/* ── @mention rendered in note body ── */
.note-mention {
  display: inline-block;
  font-size: 0.8em;
  font-weight: 600;
  padding: 0.05em 0.4em;
  border-radius: var(--radius-full);
  white-space: nowrap;
}

.note-mention--person {
  background: #d4e5d0;
  color: #192F2B;
}

.note-mention--holon {
  background: var(--holon-org-bg, #d4e5d0);
  color: var(--holon-org-text, #192F2B);
}

/* ── Focus selector failure banner ──
   Shown by focus_selector.js when a focus change cannot be applied, so a
   failed change is never mistaken for a successful one. */
.focus-selector-error {
  position: fixed;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2000;
  max-width: 90vw;
  padding: 0.6em 1em;
  border-radius: var(--radius-md);
  background: var(--danger-bg);
  color: var(--danger-dark);
  border: 1px solid var(--danger-border);
  font-weight: 600;
  box-shadow: var(--elev-2);
}
.focus-selector-error[hidden] {
  display: none;
}

/* ---------------------------------------------------------------------------
   Extension-version banner
   Moved out of an inline <style> in web/app/templates/shell/base.html — every
   page inherits that template, so the rules were re-sent on every response and
   could not be cached. Paired with crm/js/extension_version_banner.js.
   --------------------------------------------------------------------------- */
.ext-version-banner {
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 16px;
  padding: 12px 14px;
  border: 1px solid var(--ext-banner-border);
  border-radius: var(--radius-md);
  background: var(--ext-banner-bg);
  color: var(--ext-banner-text);
  font-size: var(--text-md);
  line-height: 1.4;
}
.ext-version-banner.is-visible {
  display: flex;
}
.ext-version-banner__text strong {
  color: var(--ext-banner-text-strong);
}
.ext-version-banner__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 8px 12px;
  border-radius: var(--radius-md);
  border: 1px solid var(--ext-banner-action-border);
  background: var(--surface);
  color: var(--ext-banner-text);
  text-decoration: none;
  font-weight: 600;
  white-space: nowrap;
}
.ext-version-banner__action:hover {
  background: var(--ext-banner-action-hover);
}
@media (max-width: 720px) {
  .ext-version-banner {
    flex-direction: column;
    align-items: flex-start;
  }
}
}
