/* ============================================================
   Swiftpoint Hub — shared site chrome.

   Three things live here, and nothing else on any page is allowed to
   restyle them:

     1. the header   — menu bar (row 1) + tool strip (row 2)
     2. the toolbar  — the vocabulary the tool strip is written in
     3. the footer

   Loaded LAST so these rules win over page-level styles. Page CSS may
   add its own controls to the strip (that is the point) but it builds
   them from `.tbar-*`, so a button looks the same in the Profile
   Builder, the OLED editor, the checker and the guides.

   Depends on: tokens.css, base.css, ui.css
   ============================================================ */

/* ------------------------------------------------------------
   Header

   Two rows, like a desktop app: a menu bar (row 1) and an
   optional tool strip (row 2, `.tbar`).

   The rule that keeps this from breaking: neither row may ever
   paint over the other. Row 1 gives the nav `min-width: 0` plus
   `overflow-x: auto`, so when space runs out the nav scrolls
   inside its own box instead of spilling across the action
   buttons. Everything in the action cluster is `flex-shrink: 0`
   so buttons never squash; the cluster itself may shrink and
   scroll.

   The blur lives on `.hdr-in`, not on `.hdr`, on purpose:
   `backdrop-filter` makes an element the containing block for its
   `position: fixed` descendants, and the command palette is a
   full-screen dialog that lives inside this element. Blurring the
   row instead of the header keeps the palette pinned to the
   viewport.
   ------------------------------------------------------------ */
.hdr {
  position: sticky;
  top: 0;
  z-index: var(--z-hdr);
  border-bottom: 1px solid var(--line);
}

/* Row 1 plus the tool strip. Set on <body>, not on .hdr, because what
   needs the number (the guides explorer and outline rail) is a sibling of
   the header, not a descendant. js/docs.js overrides it with the measured
   height once the strip has actually laid out. */
body:has(> .hdr > .tbar) {
  --hdr-total-h: calc(var(--hdr-h) + var(--hdr-sub-h));
}

/* App shells lock the body to the viewport, so the header is a flex row
   rather than a floating bar: no blur, no shadow, solid fill. Declared
   here instead of in each page's CSS — that is the whole point of
   putting the header in one place. */
body[data-app-shell] > .hdr {
  background: var(--panel-solid);
}

body[data-app-shell] > .hdr > .hdr-in {
  background: var(--panel-solid);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* ── Row 1: menu bar ── */
.hdr-in {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  /* min-height, not height: the row may grow rather than clip. */
  min-height: var(--hdr-h);
  padding-inline: var(--hdr-gutter);
  background: var(--hdr-bg);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
}

.hdr .brand {
  display: inline-flex;
  align-items: baseline;
  gap: 2px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
  flex-shrink: 0;
}

.hdr .brand-slash {
  color: var(--accent);
  font-weight: 500;
}

.hdr-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  min-width: 0;
  /* The overflow guard. Without this the nowrap links escape the
     box and land on top of the action buttons. */
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.hdr-nav::-webkit-scrollbar {
  display: none;
}

/* Nav items carry an icon as well as a label: the strip that runs across
   the top of the page is a set of tools, and five unlabelled words are
   slower to recognise than five pictograms plus a word. The label stays
   — the icon is decoration, the word is the name. */
.hdr .hdr-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-2);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--t-fast), background var(--t-fast);
}

.hdr .hdr-link:hover {
  color: var(--text);
  background: var(--surface-2);
  text-decoration: none;
}

.hdr .hdr-link .hdr-ico {
  flex-shrink: 0;
  opacity: 0.75;
  transition: opacity var(--t-fast), color var(--t-fast);
}

.hdr .hdr-link:hover .hdr-ico {
  opacity: 1;
}

/* The active tool: accent text, a filled chip behind it, and an
   underline that touches the row's bottom edge. The chip alone was
   ambiguous next to hover; the underline alone was too easy to miss
   at a glance. Both together are unambiguous. */
.hdr .hdr-link[aria-current='page'] {
  color: var(--accent);
  font-weight: 600;
  background: var(--accent-dim);
}

.hdr .hdr-link[aria-current='page'] .hdr-ico {
  opacity: 1;
}

.hdr .hdr-link[aria-current='page']::after {
  content: '';
  position: absolute;
  left: var(--sp-3);
  right: var(--sp-3);
  bottom: calc(var(--sp-2) * -1);
  height: 2px;
  border-radius: 2px 2px 0 0;
  background: var(--accent);
}

.hdr-grow {
  flex: 1 1 auto;
  min-width: var(--sp-2);
}

.hdr-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  /* May shrink (and scroll) — that is what protects the nav. */
  min-width: 0;
}

/* Controls keep their intrinsic size; the cluster scrolls instead. */
.hdr-actions > * {
  flex-shrink: 0;
}

.hdr-bmc {
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--text-2);
  text-decoration: none;
  white-space: nowrap;
  transition:
    color var(--t-fast),
    border-color var(--t-fast),
    background var(--t-fast);
}

.hdr-bmc:hover {
  color: var(--text);
  background: var(--surface-2);
  border-color: var(--line-strong);
  text-decoration: none;
}

/* Command trigger. Reads as a search field, because that is the
   affordance it stands in for; the kbd hint says how to summon it. */
.hdr-cmd {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 34px;
  padding: 0 var(--sp-2) 0 var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text-3);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  cursor: pointer;
  white-space: nowrap;
  transition:
    color var(--t-fast),
    background var(--t-fast),
    border-color var(--t-fast);
}

.hdr-cmd:not(:disabled):hover {
  color: var(--text);
  border-color: var(--line-strong);
}

.hdr-cmd:disabled {
  cursor: default;
  opacity: 0.55;
}

.hdr-cmd .hdr-ico {
  flex-shrink: 0;
}

.hdr-cmd-kbd {
  padding: 2px 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-xs);
  background: var(--bg-raise);
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.06em;
  line-height: 1.3;
}

/* Admin link. Present in the bar for admin sessions only, and the one
   row-1 control that is a destination rather than a setting. */
.hdr-admin {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 34px;
  padding: 0 var(--sp-3);
  border: 1px solid var(--accent-dim);
  border-radius: var(--r-sm);
  background: var(--accent-dim);
  color: var(--accent);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition:
    color var(--t-fast),
    background var(--t-fast),
    border-color var(--t-fast);
}

.hdr-admin:hover {
  color: var(--accent);
  background: var(--accent);
  border-color: var(--accent);
  text-decoration: none;
}

.hdr-admin:hover span {
  color: var(--on-accent);
}

.hdr-admin .hdr-ico {
  flex-shrink: 0;
}

/* Theme toggle */
.hdr-theme {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text-2);
  cursor: pointer;
  transition:
    color var(--t-fast),
    background var(--t-fast),
    border-color var(--t-fast);
}

.hdr-theme:hover {
  color: var(--text);
  background: var(--surface-2);
  border-color: var(--line-strong);
}

.hdr-theme svg {
  width: 16px;
  height: 16px;
}

.hdr-theme .ico-sun {
  display: none;
}

[data-theme='light'] .hdr-theme .ico-sun {
  display: block;
}

[data-theme='light'] .hdr-theme .ico-moon {
  display: none;
}

/* ------------------------------------------------------------
   The user menu

   One control instead of three: the chip opens a menu with the
   profile, the admin panel and log out. Signed out, the chip is
   replaced by a single "Log in" button.
   ------------------------------------------------------------ */
.hdr-user {
  position: relative;
}

.hdr-user-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 3px var(--sp-2) 3px 3px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color var(--t-fast), background var(--t-fast);
}

.hdr-user-btn:hover,
.hdr-user-btn[aria-expanded='true'] {
  background: var(--surface-2);
  border-color: var(--line-strong);
}

.hdr-user-btn .hdr-caret {
  color: var(--text-3);
  flex-shrink: 0;
  transition: transform var(--t-fast);
}

.hdr-user-btn[aria-expanded='true'] .hdr-caret {
  transform: rotate(180deg);
}

/* The avatar is 26px and always round. `user-avatar` is the <img>;
   when a user has no avatar we show their initials instead, so the
   identity is never a blank hole in the header. */
.hdr-avatar {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border-radius: 50%;
  overflow: hidden;
  background: var(--accent-dim);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.hdr-avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.hdr-avatar-initials {
  line-height: 1;
  user-select: none;
}

.hdr .user-name {
  max-width: 12ch;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* "Admin" badge inside the user chip */
.hdr .admin-tag {
  padding: 2px 7px 1px;
  border-radius: var(--r-pill);
  background: var(--accent-dim);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.hdr-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: var(--z-pop);
  min-width: 210px;
  padding: var(--sp-1);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  animation: cmdPop var(--t-fast);
}

.hdr-menu-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-2);
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}

.hdr-menu-item:hover,
.hdr-menu-item:focus-visible {
  background: var(--surface-2);
  color: var(--text);
  text-decoration: none;
}

.hdr-menu-ico,
.hdr-menu-item .hdr-ico {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  color: var(--text-3);
}

.hdr-menu-item:hover .hdr-menu-ico,
.hdr-menu-item:hover .hdr-ico {
  color: var(--text);
}

.hdr-menu-sep {
  display: block;
  height: 1px;
  margin: var(--sp-1) var(--sp-2);
  background: var(--line);
}

/* Brand tagline dot */
.hdr .brand .dot {
  width: 6px;
  height: 6px;
  margin-left: 5px;
  border-radius: 50%;
  background: var(--accent);
  align-self: center;
}

/* ------------------------------------------------------------
   Row 2: the tool strip

   Optional, and the same on every page. A tool page puts its
   controls here instead of crowding the menu bar, and writes them
   from the vocabulary below so nothing has to be re-invented:

     .tbar            the strip                    (zones inside)
     .tbar-start      left zone                    (flex: 1 1 0)
     .tbar-center     middle zone, content centred
     .tbar-end        right zone
     .tbar-group      a run of related controls, wraps as one
     .tbar-btn        a control                    (--primary, --danger,
                                                    --ghost, --icon)
     .tbar-btn.is-active / [aria-pressed]   selected tool
     .tbar-sep        vertical rule between groups
     .tbar-label      small caption naming a group
     .tbar-status     read-only text, (.is-dirty for unsaved)
     .tbar-input      inline field (.tbar-num for a short one)
     .tbar-opt        a checkbox/select pair
     .tbar-search     icon + input + kbd hint
     .tbar-btn-row    a stack of buttons that does not stretch

   `.tbar--rows` is the answer for a strip that is too wide to show: it
   lays the zones out as exactly two rows, each of which can scroll on its
   own, so the reader sees the whole toolset's *shape* instead of one
   long ribbon (the OLED editor). `.tbar--balanced` gives the two side
   zones the same basis so a centred control is optically centred (the
   guides' search).
   ------------------------------------------------------------ */
.tbar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--hdr-gutter);
  border-top: 1px solid var(--line);
  background: var(--bg-raise);
  font-size: var(--fs-xs);
  /* Predictable height so --hdr-total-h stays honest; the strip may wrap
     on narrow viewports, which is why docs.js measures it for real. */
  min-height: var(--hdr-sub-h);
}

.tbar[hidden] {
  display: none;
}

/* The three zones share the row. `min-width: 0` is load-bearing: a zone
   may shrink below its content and wrap it onto a second line, which is
   how a narrow strip grows instead of one zone spilling over the next.
   Nothing here may set a fixed width, or that guarantee is gone. */
.tbar-start,
.tbar-center,
.tbar-end {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex: 1 1 auto;
  min-width: 0;
  flex-wrap: wrap;
}

.tbar-start {
  justify-content: flex-start;
}

.tbar-center {
  justify-content: center;
}

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

/* Optically centred. A centred control is only truly centred when the
   two side zones are the same width, and flexbox has no way to say
   that — so the modifier gives them the same basis, and since they also
   share the same grow, they stay equal however the middle behaves. */
.tbar--balanced {
  --tbar-side: 180px;
}

.tbar--balanced .tbar-start,
.tbar--balanced .tbar-end {
  flex: 1 1 var(--tbar-side);
}

/* ------------------------------------------------------------
   `.tbar--rows` — a strip that is two rows tall, not one long one.

   The OLED editor had forty controls in a single strip, which meant
   the toolbar was wider than any screen and the tools past the fold
   were invisible: a reader could not tell whether a shape existed
   without scrolling to find out, which is the worst property a
   toolbar can have.

   Two rows is the fix, and it is a fixed two — the strip never grows a
   third, so the canvas below it does not move when a control changes
   the row count. Each row scrolls on its own as a fallback below
   ~1040px, where two rows of everything genuinely do not fit, because
   the alternative is dropping controls, and a tool that is not there
   is worse than one that is a swipe away.
   ------------------------------------------------------------ */
.tbar--rows {
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-1);
  padding-top: var(--sp-1);
  padding-bottom: var(--sp-1);
}

.tbar--rows > .tbar-start,
.tbar--rows > .tbar-center,
.tbar--rows > .tbar-end {
  flex: 1 1 100%;
  min-width: 0;
  flex-wrap: nowrap;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
  padding-bottom: 1px;
}

/* The middle and end zones share the second row, which is why the
   centre keeps its own scroll rather than being squeezed. */
.tbar--rows > .tbar-center {
  flex: 0 0 auto;
  max-width: 100%;
}

.tbar--rows::-webkit-scrollbar,
.tbar--rows > .tbar-start::-webkit-scrollbar,
.tbar--rows > .tbar-center::-webkit-scrollbar,
.tbar--rows > .tbar-end::-webkit-scrollbar {
  height: 4px;
}
.tbar--rows::-webkit-scrollbar-thumb,
.tbar--rows > .tbar-start::-webkit-scrollbar-thumb,
.tbar--rows > .tbar-center::-webkit-scrollbar-thumb,
.tbar--rows > .tbar-end::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: 2px;
}

/* A zone that centres itself in the second row has nothing to centre
   against once the row is the strip, so the group's own margin is what
   keeps it readable. */
.tbar--rows .tbar-group { flex: 0 0 auto; }

/* Below the width where two rows fit, the rows keep their two heights
   and scroll. Above it they never need to. */
@media (min-width: 1040px) {
  .tbar--rows > .tbar-start,
  .tbar--rows > .tbar-center,
  .tbar--rows > .tbar-end {
    overflow-x: visible;
  }
}

/* A group never breaks apart, and never stretches its buttons. */
.tbar-group {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  flex-shrink: 0;
}

.tbar-group--wrap {
  flex-wrap: wrap;
}

/* Vertical rule between groups. */
.tbar-sep {
  width: 1px;
  align-self: stretch;
  margin: 0 var(--sp-1);
  background: var(--line-med);
  flex-shrink: 0;
}

/* Small caption naming a group. */
.tbar-label {
  flex-shrink: 0;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Read-only status text in the strip. */
.tbar-status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.tbar-status b {
  color: var(--accent);
  font-weight: 600;
}

.tbar-status.is-dirty {
  color: var(--orange);
}

/* Unsaved-work marker. A dot that appears rather than a label that
   changes size, so toggling it cannot reflow the strip. */
.tbar-status.is-dirty::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--orange);
  box-shadow: 0 0 0 3px var(--orange-dim);
}

/* ---- Controls ---- */
.tbar-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  height: 28px;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text-2);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition:
    color var(--t-fast),
    background var(--t-fast),
    border-color var(--t-fast);
}

.tbar-btn:hover:not(:disabled) {
  color: var(--text);
  background: var(--surface-2);
  border-color: var(--line-med);
}

.tbar-btn:active:not(:disabled) {
  transform: translateY(1px);
}

.tbar-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.tbar-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.tbar-btn svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
}

.tbar-btn--icon {
  width: 28px;
  padding: 0;
}

.tbar-btn--primary {
  background: var(--accent);
  border-color: transparent;
  color: var(--on-accent);
}

.tbar-btn--primary:hover:not(:disabled) {
  background: var(--accent-hi);
  color: var(--on-accent);
  border-color: transparent;
}

.tbar-btn--danger {
  color: var(--red);
}

.tbar-btn--danger:hover:not(:disabled) {
  color: var(--red);
  background: var(--red-dim);
  border-color: var(--red-dim);
}

.tbar-btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--text-3);
}

.tbar-btn--ghost:hover:not(:disabled) {
  background: var(--surface-2);
  color: var(--text);
  border-color: var(--line);
}

/* The selected tool in a group of tool buttons. One definition, used by
   every page that has a "current tool" concept. */
.tbar-btn.is-active,
.tbar-btn[aria-pressed='true'] {
  background: var(--accent-dim);
  border-color: var(--accent);
  color: var(--accent);
}

.tbar-btn--primary.is-active,
.tbar-btn--primary[aria-pressed='true'] {
  background: var(--accent);
  color: var(--on-accent);
}

/* A button that carries a symbol rather than a word. */
.tbar-btn--sym {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  padding: 0 8px;
}

/* Inline fields size themselves; they do not stretch the group. */
.tbar-input,
.tbar-select {
  height: 28px;
  padding: 0 var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  min-width: 0;
}

.tbar-input::placeholder {
  color: var(--text-4);
}

.tbar-input:focus,
.tbar-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}

.tbar-num {
  width: 76px;
  text-align: center;
}

.tbar-select {
  cursor: pointer;
  padding-right: var(--sp-1);
}

/* Checkbox / select pair with a caption. */
.tbar-opt {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
}

.tbar-opt input[type='checkbox'],
.tbar-opt input[type='range'] {
  accent-color: var(--accent);
}

/* A search field with an icon and a kbd hint, for the one strip that
   has one (the guides). */
.tbar-search {
  position: relative;
  display: flex;
  align-items: center;
  width: min(420px, 100%);
}

.tbar-search-ico {
  position: absolute;
  left: var(--sp-3);
  display: grid;
  place-items: center;
  color: var(--text-3);
  pointer-events: none;
}

.tbar-search-ico svg {
  width: 15px;
  height: 15px;
}

.tbar-search .tbar-input {
  width: 100%;
  height: 30px;
  padding-left: 34px;
  padding-right: 34px;
  font-family: var(--font-body);
}

.tbar-search-kbd {
  position: absolute;
  right: var(--sp-2);
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-xs);
  background: var(--bg-raise);
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: 10px;
  pointer-events: none;
}

/* The one control per strip that earns the accent: the thing you came
   here to do. */
.tbar-cta {
  box-shadow: 0 0 0 1px var(--lime-glow);
}

/* ---- Scroll variant ----
   For strips that cannot fit any viewport. The zones stop sharing the
   row (that would squash them to nothing) and the whole strip scrolls;
   the end zone still pins right whenever there is room left over.

   The scrollbar stays visible here, thin. A toolbar that silently
   clips its overflow gives no hint that there is more to reach. */
.tbar--scroll {
  flex-wrap: nowrap;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}

.tbar--scroll::-webkit-scrollbar {
  height: 4px;
}

.tbar--scroll::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: 2px;
}

.tbar--scroll .tbar-start,
.tbar--scroll .tbar-center {
  flex: 0 0 auto;
  flex-wrap: nowrap;
}

.tbar--scroll .tbar-end {
  flex: 1 0 auto;
}

/* Single-line field that grows to use the room (the admin search). */
.tbar-start .tbar-input--grow,
.tbar-center .tbar-input--grow {
  flex: 1 1 240px;
  max-width: 460px;
}

/* ------------------------------------------------------------
   Command palette

   Full-screen dialog, `position: fixed` — which is why `.hdr` itself
   carries no backdrop-filter. Populated by js/chrome.js from the
   nav that is already on the page, so the two cannot disagree.
   ------------------------------------------------------------ */
.cmdbar {
  position: fixed;
  inset: 0;
  z-index: var(--z-toast);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: clamp(var(--sp-5), 12vh, 120px) var(--sp-4) var(--sp-4);
}

.cmdbar[hidden] {
  display: none;
}

.cmdbar-backdrop {
  position: absolute;
  inset: 0;
  background: var(--scrim);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

.cmdbar-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(560px, 100%);
  max-height: min(560px, 78vh);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  animation: cmdPop var(--t-fast);
}

@keyframes cmdPop {
  from {
    opacity: 0;
    transform: translateY(-8px) scale(0.99);
  }
}

.cmdbar-field {
  position: relative;
  display: flex;
  align-items: center;
  border-bottom: 1px solid var(--line);
  color: var(--text-3);
}

.cmdbar-field > svg {
  position: absolute;
  left: var(--sp-4);
  width: 17px;
  height: 17px;
  pointer-events: none;
}

.cmdbar-input {
  width: 100%;
  height: 52px;
  padding: 0 var(--sp-4) 0 46px;
  border: 0;
  background: transparent;
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-body);
}

.cmdbar-input:focus {
  outline: none;
}

.cmdbar-input::placeholder {
  color: var(--text-3);
}

.cmdbar-list {
  flex: 1 1 auto;
  margin: 0;
  padding: var(--sp-2);
  list-style: none;
  overflow-y: auto;
}

.cmdbar-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  color: var(--text-2);
  font-size: var(--fs-sm);
  text-decoration: none;
  cursor: pointer;
}

.cmdbar-item .hdr-ico {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  color: var(--text-3);
}

/* A palette row can carry a second line — a profile's game under its
   title. It sits inside the same text span, so the ellipsis on a long
   title still works and the group pill still hangs off the right. */
.cmdbar-item-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cmdbar-item-sub {
  margin-left: 8px;
  color: var(--text-3);
  font-size: var(--fs-2xs);
}
.cmdbar-item-sub::before { content: '· '; }

.cmdbar-item-group {
  margin-left: auto;
  padding: 2px 7px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.cmdbar-item[aria-selected='true'],
.cmdbar-item:hover {
  background: var(--surface-2);
  color: var(--text);
  text-decoration: none;
}

.cmdbar-item[aria-selected='true'] .hdr-ico,
.cmdbar-item[aria-selected='true'] .cmdbar-item-group {
  color: var(--accent);
}

.cmdbar-empty {
  padding: var(--sp-5) var(--sp-3);
  color: var(--text-3);
  font-size: var(--fs-sm);
  text-align: center;
}

.cmdbar-foot {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-2) var(--sp-4);
  border-top: 1px solid var(--line);
  background: var(--bg-raise);
  color: var(--text-3);
  font-size: var(--fs-2xs);
}

.cmdbar-foot span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.cmdbar-foot kbd {
  padding: 1px 5px;
  border: 1px solid var(--line);
  border-radius: var(--r-xs);
  background: var(--surface);
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.4;
}

/* ------------------------------------------------------------
   Responsive

   Narrow screens: the nav drops to its own full-width strip and
   the action cluster keeps whatever room is left and scrolls.
   Deliberately CSS-only — a burger would hide the nav when JS is
   unavailable, and a scroll strip is one less thing to break.
   ------------------------------------------------------------ */
@media (max-width: 1080px) {
  /* Five icons plus five words stops fitting; the words go, the
     icons and their tooltips stay. */
  .hdr .hdr-link span {
    display: none;
  }

  .hdr .hdr-link {
    padding: var(--sp-2);
  }
}

@media (max-width: 860px) {
  /* The bar stays one row.
     It used to wrap here: the nav dropped to a full-width second line
     with its words back, and the row grew until the action cluster was
     squeezed against the edge. The words go again — the icons carry the
     nav, and `title`/`aria-label` keep them nameable — and the row keeps
     its natural height instead of growing into the page. */
  .hdr .hdr-link span {
    display: none;
  }

  .hdr .hdr-link {
    padding: var(--sp-2);
  }

  .hdr-in {
    flex-wrap: nowrap;
    min-height: 0;
    padding-block: var(--sp-2);
    gap: var(--sp-2);
  }

  .hdr-nav {
    order: 0;
    width: auto;
  }

  .hdr-grow {
    display: none;
  }

  /* The action cluster keeps its intrinsic size: theme and the account
     control are the two things a phone visitor has to be able to hit. */
  .hdr-actions {
    flex: 0 0 auto;
    overflow: visible;
    margin-left: auto;
  }

  /* The command palette trigger is a search *field* by design: it is the
     affordance it stands in for, and at this width a field-sized box is
     what pushes everything else off the row. Ctrl/Cmd+K still opens the
     palette — that binding is on the document, not on this button. */
  .hdr-cmd {
    display: none;
  }

  /* Support link is a nicety; the row needs the room more. */
  .hdr .hdr-bmc {
    display: none;
  }

  .tbar {
    padding-inline: var(--sp-4);
  }
}

@media (max-width: 640px) {
  .hdr .brand {
    font-size: 13px;
  }

  /* Tighter nav items: five of them plus the brand and the account
     control is the whole row, and every pixel here is one the nav does
     not have to scroll for. */
  .hdr .hdr-link {
    padding: var(--sp-2) 6px;
  }

  .hdr-in {
    gap: 6px;
    padding-inline: var(--sp-3);
  }

  .hdr-cmd-label,
  .hdr-cmd-kbd,
  .tbar-search-kbd {
    display: none;
  }

  .hdr-cmd {
    width: 34px;
    padding: 0;
    justify-content: center;
  }

  .tbar {
    padding-inline: var(--sp-3);
  }

  .tbar-label {
    display: none;
  }

  /* Icon-only buttons once there is no room for the words. Only the ones
     that have an icon to fall back on — a word-only button would go blank. */
  .tbar-btn:has(svg) > span {
    display: none;
  }

  .tbar-btn:has(svg) {
    padding: 0 9px;
  }
}

@media (max-width: 520px) {
  /* Scroll the strip rather than letting the header grow to three
     rows on a phone — and keep the scrollbar visible so it is clear
     there is more. */
  .tbar {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--line-strong) transparent;
  }

  .tbar::-webkit-scrollbar {
    height: 4px;
  }

  .tbar::-webkit-scrollbar-thumb {
    background: var(--line-strong);
    border-radius: 2px;
  }

  .tbar-start,
  .tbar-center,
  .tbar-end {
    flex: 0 0 auto;
    flex-wrap: nowrap;
  }

  .tbar-end {
    flex: 1 0 auto;
  }
}

/* ------------------------------------------------------------
   Footer
   ------------------------------------------------------------ */
.ftr {
  margin-top: var(--sp-8);
  border-top: 1px solid var(--line);
  background: var(--bg-raise);
}

.ftr-in {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
  max-width: var(--content-width);
  margin-inline: auto;
  padding: var(--sp-5);
  font-size: var(--fs-xs);
  color: var(--text-3);
}

.ftr-nav {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
}

.ftr-nav a {
  color: var(--text-2);
  text-decoration: none;
  transition: color var(--t-fast);
}

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

.ftr-note {
  margin: 0;
  margin-left: auto;
}

@media (max-width: 860px) {
  .ftr-in {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-3);
  }

  .ftr-note {
    margin-left: 0;
  }
}
