/* SDS Manager sidebar theme.
 * ---------------------------------------------------------------------------
 * Deliberately NOT in contentagent.css. That file is scoped under
 * .contentagent-ui so it can never touch a screen the VN team owns. This one
 * is the opposite: it restyles Wagtail's own sidebar on every admin screen,
 * which is exactly why it is a separate file behind a settings flag
 * (CONTENTAGENT_SIDEBAR_THEME) that turns it off in one line.
 *
 * TWO RULES THIS FILE IS BUILT ON
 *
 * 1. Change variables, not Wagtail's class names. A rule written against
 *    .sidebar__inner .menu-item breaks silently the first time Wagtail renames
 *    an internal class — it breaks by looking wrong, not by raising, so nobody
 *    finds out until someone opens a screenshot. Overriding a custom property
 *    survives a rename because Wagtail's own rules keep reading the property.
 *    Every rule below that does depend on a Wagtail class name is marked
 *    INTERNAL and listed in PR_NOTES.md under "rules that depend on Wagtail
 *    internals", so the next upgrade has a checklist.
 *
 * 2. Scope to the sidebar, never :root. --w-color-secondary colours buttons,
 *    focus rings and links across the whole CMS; redefining it on :root would
 *    restyle every screen including the page editor. Redefined on .sidebar,
 *    everything derived inside recalculates and nothing outside changes.
 *
 *    Verified rather than assumed: every submenu panel Wagtail renders
 *    (.sidebar-sub-menu-panel and friends) is a DOM descendant of .sidebar —
 *    measured in a real browser, sb.contains(panel) === true for all of them —
 *    so nothing is portalled out to document.body and no override leaks.
 *
 * ONE SET OF VALUES FOR BOTH THEMES
 *
 * The sidebar stays dark in light mode. That is a decision, not an oversight,
 * and it works because custom properties inherit: Wagtail defines its tokens on
 * <html> (:root for light, .w-theme-dark, and .w-theme-system inside a
 * prefers-color-scheme:dark media query), and a redefinition on .sidebar
 * shadows all three for that subtree. So one block covers every theme.
 *
 * The surface and the text colours are set TOGETHER for that reason. Setting
 * only the surface leaves the light theme handing its own dark text to this
 * dark background — black on black — and it would be invisible to anyone whose
 * setting follows an OS that is dark.
 *
 * HSL, NOT HEX
 *
 * Wagtail derives shades, hovers and borders from hue/saturation/lightness with
 * calc(): --w-color-primary-200 resolves to
 *   hsl(calc(254.3 - 0.5) calc(50.4% - 0.4%) calc(24.5% - 4.1%))
 * A hex value breaks every one of those derivations. Hex is in the comments for
 * checking by eye only.
 */

.sidebar,
.sidebar-loading {
  /* --- surfaces ------------------------------------------------------- */
  --w-color-surface-menus: hsl(20 13% 9%); /* #1A1614 */
  --w-color-surface-field: hsl(20 14% 12%); /* #241E1B — search inset */
  --w-color-surface-menu-item-active: hsl(22 14% 15%); /* #2C2521 */
  --w-color-border-furniture: hsl(18 12% 16%); /* #2E2724 */

  /* --- text and icons -------------------------------------------------- */
  /* Set with the surface above, never without it. 7.3:1 against #1A1614. */
  --w-color-text-label-menus-default: hsl(28 9% 65%); /* #ADA49C */
  --w-color-text-label-menus-active: hsl(0 0% 100%); /* #FFFFFF, 15.1:1 */
  --w-color-icon-primary: hsl(26 10% 59%); /* #A1958C, 5.6:1 */

  /* --- accent ---------------------------------------------------------- */
  /* Periwinkle from the SDS Manager logo files. Scoped here so it colours the
     rail and the active icon without touching a single button elsewhere. */
  --w-color-secondary: hsl(236 93% 68%); /* #626DF9 */
  /* White on #626DF9 measures 4.14:1 and fails AA for text, which is why a
     filled button uses this darker step at 5.4:1 instead of the brand tone.
     Any change to either value needs re-measuring, not eyeballing. */
  --w-color-secondary-600: hsl(235 70% 59%); /* #4F5AE0 */

  /* --- our own tokens, not Wagtail's ----------------------------------- */
  --ca-sb-hover: hsl(22 12% 13%); /* #241F1C */
  --ca-sb-amber: hsl(43 100% 62%); /* #FFC93C, 11.7:1 */
  --ca-sb-amber-bg: hsl(39 54% 15%); /* #3D2E12 */
  --ca-sb-alive: hsl(153 60% 53%); /* #3ECF8E */
  --ca-sb-alive-bg: hsl(141 22% 13%); /* #19271E */
  --ca-sb-alive-br: hsl(151 34% 25%); /* #2A5540 */
  --ca-sb-radius: 7px;
  --ca-sb-gutter: 8px;
}

/* The warm near-black has to sit behind the whole rail, including the strip
   the collapse toggle lives on, or the join reads as a seam. */
.sidebar__inner,
.sidebar-loading__inner {
  background: var(--w-color-surface-menus);
}

/* INTERNAL (1/6): .sidebar-menu-item__link — the anchor Wagtail renders for a
   menu row. There is no token for item padding or radius. */
.sidebar .sidebar-menu-item__link {
  margin: 0 var(--ca-sb-gutter);
  border-radius: var(--ca-sb-radius);
  font-size: 13.5px;
  /* Height is Wagtail's own and has to keep working with the density setting,
     so it is not set here — only the box around it. */
}

/* INTERNAL (2/6): hover state. No token exists for it; Wagtail hard-codes a
   background on this class. */
.sidebar .sidebar-menu-item__link:hover {
  background: var(--ca-sb-hover);
  color: var(--w-color-text-label-menus-active);
}

/* INTERNAL (3/6): the active row. The rail is an inset box-shadow rather than
   a border because a 3px border shifts the label 3px and nothing else on the
   row moves with it. */
.sidebar .sidebar-menu-item--active > .sidebar-menu-item__link {
  background: var(--w-color-surface-menu-item-active);
  box-shadow: inset 3px 0 0 var(--w-color-secondary);
  color: var(--w-color-text-label-menus-active);
  font-weight: 600;
}

.sidebar .sidebar-menu-item--active > .sidebar-menu-item__link .icon {
  color: var(--w-color-secondary);
}

/* INTERNAL (4/6): icon sizing. Wagtail sets these per-icon with no token. */
.sidebar .sidebar-menu-item__link .icon {
  width: 15px;
  height: 15px;
  stroke-width: 1.5;
}

/* --- the count badge ------------------------------------------------------
 * Driven by an attribute WE put on the menu item from Python
 * (ContentAgentMenuItem passes attrs through Wagtail's own MenuItem API), not
 * by a Wagtail class name. If Wagtail renames every class in the sidebar this
 * still works, because data-ca-count travels on the element Wagtail renders.
 *
 * It is the only number in the sidebar, and it is the reason to glance at it.
 */
.sidebar [data-ca-count]::after {
  content: attr(data-ca-count);
  margin-inline-start: auto;
  min-width: 1.25rem;
  padding: 0 0.35rem;
  border-radius: 999px;
  background: var(--ca-sb-amber-bg);
  color: var(--ca-sb-amber);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.45;
  text-align: center;
}

/* Nothing waiting is not a zero worth printing. */
.sidebar [data-ca-count="0"]::after {
  content: none;
}

/* The collapsed rail is icon-only; a badge there would sit on top of the icon. */
.sidebar--slim [data-ca-count]::after,
.sidebar--collapsed [data-ca-count]::after {
  content: none;
}

/* --- the heartbeat --------------------------------------------------------
 * Same mechanism as the badge: our attributes on a menu item, so no Wagtail
 * class name is load-bearing. Two lines, one claim each, and the claim is
 * deliberately weak — see contentagent/heartbeat.py for why this reports last
 * activity rather than pinging the worker.
 *
 * The status line is the menu item's own label, not a pseudo-element. The
 * first version put the title in `content: attr(data-ca-title)` as well as
 * leaving the label to render, so every sidebar said "Nothing in flight"
 * twice. ::before is now the dot alone and ::after the detail line.
 */
.sidebar [data-ca-beat] {
  display: block;
  box-sizing: border-box;
  width: calc(100% - (var(--ca-sb-gutter) * 2));
  margin: 0.5rem var(--ca-sb-gutter);
  padding: 0.55rem 0.65rem;
  border: 1px solid var(--w-color-border-furniture);
  border-radius: var(--ca-sb-radius);
  color: var(--w-color-text-label-menus-default);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.35;
  text-decoration: none;
  white-space: normal;
}

.sidebar [data-ca-beat]:hover {
  background: var(--ca-sb-hover);
}

/* The dot, sized independently of the label so it reads as a status light. */
.sidebar [data-ca-beat]::before {
  content: "\25CF";
  margin-inline-end: 0.35rem;
  font-size: 9px;
  vertical-align: 0.15em;
}

.sidebar [data-ca-beat]::after {
  content: attr(data-ca-detail);
  display: block;
  margin-top: 0.15rem;
  color: var(--w-color-icon-primary);
  font-size: 11px;
  font-weight: 400;
  line-height: 1.4;
}

.sidebar [data-ca-beat="working"] {
  border-color: var(--ca-sb-alive-br);
  background: var(--ca-sb-alive-bg);
  color: var(--ca-sb-alive);
}

.sidebar [data-ca-beat="stalled"] {
  border-color: var(--ca-sb-amber-bg);
  color: var(--ca-sb-amber);
}

/* Collapsed, there is no room for a sentence — the dot and the border carry
   it, and the label stays as the accessible name. */
.sidebar--slim [data-ca-beat],
.sidebar--collapsed [data-ca-beat] {
  font-size: 0;
  text-align: center;
}

.sidebar--slim [data-ca-beat]::before,
.sidebar--collapsed [data-ca-beat]::before {
  margin-inline-end: 0;
  font-size: 10px;
}

.sidebar--slim [data-ca-beat]::after,
.sidebar--collapsed [data-ca-beat]::after {
  content: none;
}

/* INTERNAL (5/6): the row Wagtail wraps around a menu item. It is built for a
   link with its own padding and a fixed height; the heartbeat is a block, so
   the wrapper has to stop imposing either. */
.sidebar .sidebar-menu-item:has([data-ca-beat]) {
  margin: 0;
}

/* --- the logo ------------------------------------------------------------- */
/* INTERNAL (6/6): .sidebar-custom-branding is the class Wagtail puts on the
   container it renders our branding_logo block into. */
.sidebar .sidebar-custom-branding {
  padding: 0.9rem var(--ca-sb-gutter) 0.6rem;
}

.ca-brand {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.ca-brand__symbol {
  width: 28px;
  height: 28px;
  flex: 0 0 28px;
}

/* A stand-in until the horizontal negative lockup file exists: the wordmark is
   set in type rather than drawn. When the real file arrives it replaces the
   symbol and this span together, as one image. */
.ca-brand__word {
  color: var(--w-color-text-label-menus-active);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
}

.sidebar--slim .ca-brand__word,
.sidebar--collapsed .ca-brand__word {
  display: none;
}

/* The contrast setting is Wagtail's and stays working: w-contrast-more raises
   the border token on <html>, and because this file never sets
   --w-color-border-furniture-more-contrast, that path is untouched. The one
   thing to restore is the resting label, which at more-contrast should be the
   active colour rather than the muted one. */
.w-contrast-more .sidebar {
  --w-color-text-label-menus-default: hsl(0 0% 100%);
  --w-color-icon-primary: hsl(28 9% 78%);
}
