/* switchboard Admin UI.
   Hand-written, no framework: the whole page is a handful of panels, a few
   tables, and forms. The look is an operator's patch bay -- 2px ink frames,
   inverted header strips, square lamps for node state, and one amber for
   whatever is selected or primary. Colors come from a small token set so light
   and dark are the same stylesheet. */

/* IBM Plex, served from the binary rather than a font host: this page runs on
   a trusted network and should not reach out to anything to draw itself. The
   licence sits beside the files in fonts/OFL.txt. */
@font-face {
  font-family: "Plex Mono";
  src: url("fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Plex Mono";
  src: url("fonts/ibm-plex-mono-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: "Plex Condensed";
  src: url("fonts/ibm-plex-sans-condensed-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: "Plex Condensed";
  src: url("fonts/ibm-plex-sans-condensed-latin-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}

:root {
  /* Let the native controls -- checkboxes, carets, scrollbars -- follow the
     theme too, so a dark page has no white checkboxes punched through it. */
  color-scheme: light dark;
  accent-color: #101316;

  --bg: #d9dee2;
  --hover: #cdd3d8;
  --panel: #f6f7f8;
  --sunken: #eceff1;
  --ink: #101316;
  --muted: #545c64;
  /* The header strips are the ink inverted, so they flip with the theme. */
  --strip: #101316;
  --on-strip: #f6f7f8;
  /* Amber is the one accent: the open tab, the primary button, focus. */
  --lamp: #ff9f1a;
  --on-lamp: #101316;
  --ok: #12a150;
  --warn: #ff9f1a;
  --danger: #d42a1e;
  --on-danger: #ffffff;

  --mono: "Plex Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --label: "Plex Condensed", "Arial Narrow", "Roboto Condensed", sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root {
    accent-color: #e6eaed;

    --bg: #0e1113;
    --hover: #22272c;
    --panel: #181c20;
    --sunken: #111417;
    --ink: #e6eaed;
    --muted: #98a1a9;
    --strip: #e6eaed;
    --on-strip: #0e1113;
    --lamp: #ffae33;
    --on-lamp: #0e1113;
    --ok: #3ddc84;
    --warn: #ffae33;
    --danger: #ff6a5e;
    --on-danger: #0e1113;
  }
}

* { box-sizing: border-box; }

/* A flat board for the modules to sit on. It once had a faint 24px grid,
   which nothing on it lined up with. */
body {
  margin: 0;
  padding: 0 1.25rem 4rem;
  background: var(--bg);
  color: var(--ink);
  font: 14.5px/1.55 var(--mono);
}

header, main, footer { max-width: 1100px; margin: 0 auto; }

/* The hidden attribute is what the tab script toggles; nothing here may ever
   out-specify it. */
[hidden] { display: none !important; }

h1, h2, h3, th, label, button, .tag { font-family: var(--label); }

header { padding: 2rem 0 1.25rem; }
h1 {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0;
  font-size: 1.9rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  line-height: 1.1;
}
/* A lit jack: the page's mark, and the same thing the favicon draws. */
h1::before {
  content: "";
  flex: none;
  width: 1.1em;
  height: 1.1em;
  border: 2px solid var(--ink);
  border-radius: 50%;
  background: radial-gradient(circle, var(--on-lamp) 0 22%, transparent 24%), var(--lamp);
}
h2 { margin: 0; font-size: 1rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; }
h3 { margin: 0 0 0.5rem; font-size: 0.9rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; }
.lede { margin: 0.35rem 0 0; color: var(--muted); font-size: 0.82rem; }

code, pre, input, textarea { font-family: var(--mono); }
code { font-size: 0.86em; }

/* Tabs ----------------------------------------------------------------- */

/* A row of hardware selector keys: one frame, the pressed one lit. It sizes to
   its keys, so it has to find the page's left edge itself rather than taking
   the auto margins the other blocks center with. */
nav.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  width: fit-content;
  max-width: min(100%, 1100px);
  margin: 0 0 1.25rem max(0px, calc((100% - 1100px) / 2));
  border: 2px solid var(--ink);
  /* The gaps between keys show the ink behind them as their dividers, so a
     row that wraps is ruled off from the next the same way. */
  background: var(--ink);
}

nav.tabs button {
  flex: 1 0 auto;
  border: 0;
  border-radius: 0;
  padding: 0.55rem 1rem;
  background: var(--panel);
  color: var(--ink);
  font-size: 0.85rem;
}
nav.tabs button:hover { background: var(--sunken); color: var(--ink); }
nav.tabs button.active { background: var(--lamp); color: var(--on-lamp); }

/* The explainer at the top of a tab: what this thing is, before the controls
   for it. Prose, not chrome, so it reads before it decorates. */
.docs {
  max-width: 72ch;
  margin: 0 0 1rem;
  font-size: 0.8rem;
  color: var(--muted);
}
.docs p { margin: 0.4rem 0; }
.docs strong { color: var(--ink); font-weight: 600; }
.docs ul { margin: 0.4rem 0; padding-left: 1.1rem; }
.docs li { margin: 0.2rem 0; }
.docs a, .hint a {
  color: var(--ink);
  text-decoration-color: var(--lamp);
  text-decoration-thickness: 2px;
  text-underline-offset: 2px;
}

/* Panels ------------------------------------------------------------- */

/* A panel is one framed module. Its head strip and its forms row run to the
   frame, so they take back the panel's padding with negative margins. */
.panel {
  background: var(--panel);
  border: 2px solid var(--ink);
  padding: 0 1rem 1rem;
  margin-bottom: 1.5rem;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  margin: 0 -1rem 1rem;
  padding: 0.55rem 1rem;
  background: var(--strip);
  color: var(--on-strip);
}
.panel-head label.toggle { color: var(--on-strip); }
.panel-head input[type=checkbox] { accent-color: var(--lamp); }

/* Each region is its own jack field inside the cluster panel. */
#cluster { display: grid; gap: 1rem; }

.region { border: 2px solid var(--ink); min-width: 0; }

/* A region name is data; the two summary sections below them are labels. They
   sit at the same heading level, so the styling has to tell them apart. */
.region-name {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0;
  padding: 0.5rem 0.8rem;
  border-bottom: 2px solid var(--ink);
  font-size: 1.35rem;
  letter-spacing: 0.1em;
}
.region-name .count {
  font: 600 0.75rem/1.4 var(--mono);
  letter-spacing: 0;
  padding: 0 0.4rem;
  border: 1.5px solid var(--ink);
}
.region.meta { padding: 0.8rem; }
.region.meta > h3 { font-size: 0.82rem; }

.gateway {
  margin: 0;
  padding: 0.45rem 0.8rem;
  border-bottom: 1px solid var(--ink);
  background: var(--sunken);
  font-size: 0.78rem;
  color: var(--muted);
}
.gateway.none { color: var(--danger); }

/* Status line --------------------------------------------------------- */

/* The last mutation's result, led by a lamp in its color. */
.flash {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin-top: 1rem;
  font-size: 0.8rem;
}
.flash:empty { display: none; }
.flash::before {
  content: "";
  flex: none;
  width: 12px;
  height: 12px;
  border: 2px solid var(--ink);
}
.flash.ok::before { background: var(--ok); box-shadow: 0 0 8px var(--ok); }
.flash.error { color: var(--danger); }
.flash.error::before { background: var(--danger); box-shadow: 0 0 8px var(--danger); }

.error {
  margin: 0.5rem 0;
  padding: 0.45rem 0.7rem;
  border: 2px solid var(--danger);
  color: var(--danger);
  font-size: 0.8rem;
}

.empty { margin: 0.5rem 0; color: var(--muted); font-size: 0.82rem; }
.region > .empty { padding: 0 0.8rem 0.3rem; }
.hint { margin: 0.2rem 0; color: var(--muted); font-size: 0.76rem; }
.muted { color: var(--muted); }

/* Lamps --------------------------------------------------------------- */

/* A node's state at a glance: lit green while it polls, blinking amber once it
   goes stale, dark for a static node that never polls at all. */
.lamp {
  display: inline-block;
  flex: none;
  width: 12px;
  height: 12px;
  border: 2px solid var(--ink);
}
.lamp.live { background: var(--ok); box-shadow: 0 0 7px var(--ok); }
.lamp.stale { background: var(--warn); box-shadow: 0 0 7px var(--warn); animation: blink 1.2s steps(2, jump-none) infinite; }
.lamp.static { background: transparent; }
@keyframes blink { 50% { opacity: 0.25; } }

.node { display: flex; align-items: center; gap: 0.55rem; }

/* Tables -------------------------------------------------------------- */

/* A node table is wider than a phone; it scrolls inside its region instead of
   pushing the page sideways. */
.scroll { overflow-x: auto; }

table { width: 100%; border-collapse: collapse; font-size: 0.8rem; font-variant-numeric: tabular-nums; }
th {
  text-align: left;
  font-weight: 700;
  color: var(--muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 0.4rem 0.8rem;
  border-bottom: 1px solid var(--ink);
}
td { padding: 0.45rem 0.8rem; border-bottom: 1px dashed var(--muted); vertical-align: middle; }
tr:last-child td { border-bottom: 0; }
tr.is-stale td code { color: var(--muted); }
td.actions { text-align: right; white-space: nowrap; }
/* Node rows keep to one line each and let the region scroll instead. */
.region td { white-space: nowrap; }

ul.links, ul.edges { list-style: none; margin: 0; padding: 0; font-size: 0.8rem; }
ul.links li, ul.edges li {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.3rem 0;
  border-bottom: 1px dashed var(--muted);
}
ul.links li:last-child, ul.edges li:last-child { border-bottom: 0; }
ul.edges li { color: var(--muted); }

/* Tags ---------------------------------------------------------------- */

.tag {
  display: inline-block;
  padding: 0 0.4rem;
  border: 1.5px solid var(--ink);
  color: var(--ink);
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1.5;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.tag.ok { background: var(--ok); color: var(--on-lamp); }
.tag.warn { background: var(--warn); color: var(--on-lamp); }
.tag.link { background: var(--strip); color: var(--on-strip); }

/* Forms --------------------------------------------------------------- */

/* The forms row is a strip of modules along the bottom of the panel, divided
   by the same 2px rule as everything else. */
.forms {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  margin: 1rem -1rem -1rem;
  border-top: 2px solid var(--ink);
}
.forms > * { padding: 1rem; border-right: 2px solid var(--ink); }
.forms > :last-child { border-right: 0; }
@media (max-width: 680px) {
  .forms > * { border-right: 0; border-bottom: 2px solid var(--ink); }
  .forms > :last-child { border-bottom: 0; }
}
/* Straight under the head strip, the strip is already the rule above. */
.panel-head + .forms { margin-top: -1rem; border-top: 0; }
/* A stack nested in a forms cell is already inside its padding. */
.forms > * .stack { padding: 0; border: 0; }

.stack { display: flex; flex-direction: column; gap: 0.55rem; min-width: 0; }
.stack.narrow { max-width: 32rem; }

/* The Namespaces an API key may be limited to. Their names are identifiers,
   so they keep their case rather than taking the labels' small caps. */
fieldset.limit {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0;
  padding: 0.6rem;
  min-width: 0;
  border: 2px solid var(--ink);
}
fieldset.limit legend {
  padding: 0 0.3rem;
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
fieldset.limit label { text-transform: none; letter-spacing: 0; font-size: 0.85rem; }
fieldset.limit p { margin: 0; font-size: 0.8rem; }

label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
label > input:not([type=checkbox]) { flex: 0 1 68%; margin-left: auto; min-width: 0; }
label > textarea { flex: 1; min-width: 0; }
label.toggle { font-size: 0.8rem; }

input:not([type=checkbox]), textarea, select {
  padding: 0.4rem 0.5rem;
  border: 2px solid var(--ink);
  border-radius: 0;
  background: var(--sunken);
  color: var(--ink);
  font-size: 0.8rem;
}
td input:not([type=checkbox]) { padding: 0.2rem 0.35rem; }
input[type=checkbox] { width: 15px; height: 15px; }
textarea { resize: vertical; width: 100%; }

input:focus-visible, textarea:focus-visible, button:focus-visible {
  outline: 3px solid var(--lamp);
  outline-offset: 0;
}

.actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

button, a.button {
  padding: 0.35rem 0.8rem;
  border: 2px solid var(--ink);
  border-radius: 0;
  background: var(--panel);
  color: var(--ink);
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  cursor: pointer;
}
button:hover { background: var(--strip); color: var(--on-strip); }
button:active { background: var(--lamp); color: var(--on-lamp); }
button[type=submit] { background: var(--lamp); color: var(--on-lamp); }
button[type=submit]:hover { background: var(--strip); color: var(--on-strip); }
a.button { display: inline-block; text-decoration: none; background: var(--lamp); color: var(--on-lamp); }
a.button:hover { background: var(--strip); color: var(--on-strip); }
button.danger:hover { background: var(--danger); color: var(--on-danger); }

/* Keys and tokens ------------------------------------------------------ */

#keys, #appkeys { display: grid; gap: 0.75rem; }
.key { display: grid; gap: 0.5rem; padding: 0.75rem; border: 2px solid var(--ink); min-width: 0; }
.key-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.key-head .kid {
  color: var(--ink);
  cursor: pointer;
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: underline;
  text-decoration-color: var(--lamp);
  text-decoration-thickness: 3px;
  text-underline-offset: 3px;
}
.key-head .kid:hover { background: var(--lamp); color: var(--on-lamp); }
.key-head .muted { font-size: 0.78rem; }
.scope { margin: 0; font-size: 0.78rem; color: var(--muted); }

pre {
  margin: 0.4rem 0;
  padding: 0.6rem 0.7rem;
  background: var(--sunken);
  border: 2px solid var(--ink);
  font-size: 0.74rem;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-all;
}

.result:empty { display: none; }
.token-head { display: flex; align-items: center; gap: 0.5rem; font-size: 0.8rem; flex-wrap: wrap; }
.verified p { margin: 0; font-size: 0.8rem; }

/* Account dashboard ---------------------------------------------------- */

/* The signed-in identity strip: which namespace this page is showing, who is
   looking at it, and the way out. */
.whoami {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-top: 0.85rem;
}
.whoami .muted { font-size: 0.8rem; }
.whoami button { margin-left: auto; }

/* A namespace reads as identity rather than as status, so it is lit amber
   instead of taking one of the ok/warn colors. */
.tag.ns { background: var(--lamp); color: var(--on-lamp); }

/* A secret on its one and only appearance. Loud on purpose: scrolling past it
   means losing it. */
.fresh {
  margin: 0 0 0.9rem;
  padding: 0.6rem 0.75rem;
  border: 2px solid var(--ink);
  background: var(--lamp);
  color: var(--on-lamp);
}
.fresh pre.jwt { background: var(--panel); color: var(--ink); }
.fresh .hint, .fresh a { color: var(--on-lamp); }

footer { margin-top: 1.5rem; color: var(--muted); font-size: 0.76rem; }
footer p { margin: 0; }

/* htmx marks the element it is fetching for; a faint fade beats a spinner. */
.htmx-request, .htmx-request.htmx-swapping { opacity: 0.55; transition: opacity 120ms ease; }

@media (prefers-reduced-motion: reduce) {
  .lamp.stale { animation: none; }
  .htmx-request { transition: none; }
}

/* A list of things to go to: Organizations, or an Organization's Namespaces. */
ul.picker { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
ul.picker a.tag { text-decoration: none; }

/* Account dashboard shell -------------------------------------------- */

/* Signed in, the account dashboard is a sidebar beside the page: the
   Organization picker and that Organization's pages down the left, the page
   itself on the right. */
body.shell {
  display: grid;
  grid-template-columns: 15.5rem minmax(0, 1fr);
  min-height: 100vh;
  padding: 0;
}
.shell .content { min-width: 0; padding: 0 1.75rem 4rem; }
.shell header, .shell main, .shell footer { max-width: 1100px; margin-left: 0; }
.shell .flash { max-width: 1100px; margin: 0 0 1rem; }

.sidebar {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1rem 0.9rem 2rem;
  border-right: 2px solid var(--ink);
  background: var(--panel);
}

.sidebar-top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.sidebar-menu { display: flex; flex-direction: column; gap: 1rem; }
/* The menu button is the phone layout's alone. */
.menu-toggle, .menu-account { display: none; }

/* The page's mark, as h1 draws it on the signed-out page, at sidebar size. */
.brand {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--ink);
  font: 700 1.15rem/1.1 var(--label);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-decoration: none;
}
.brand::before {
  content: "";
  flex: none;
  width: 1.1em;
  height: 1.1em;
  border: 2px solid var(--ink);
  border-radius: 50%;
  background: radial-gradient(circle, var(--on-lamp) 0 22%, transparent 24%), var(--lamp);
}

/* The Organization picker: a framed selector that drops its list over the nav
   below it. A details element, so it opens with no script at all. */
.orgpicker { position: relative; }
.orgpicker summary {
  display: grid;
  gap: 0.1rem;
  padding: 0.45rem 2rem 0.45rem 0.6rem;
  border: 2px solid var(--ink);
  background: var(--sunken);
  cursor: pointer;
  list-style: none;
  position: relative;
}
.orgpicker summary::-webkit-details-marker { display: none; }
.orgpicker summary::after {
  content: "";
  position: absolute;
  right: 0.7rem;
  top: 50%;
  width: 0.45rem;
  height: 0.45rem;
  border-right: 2px solid var(--ink);
  border-bottom: 2px solid var(--ink);
  transform: translateY(-70%) rotate(45deg);
}
.orgpicker[open] summary::after { transform: translateY(-20%) rotate(225deg); }
.orgpicker summary:hover { background: var(--hover); }
.orgpicker summary:focus-visible { outline: 3px solid var(--lamp); outline-offset: 0; }
.orgpicker .label {
  font: 600 0.68rem/1.2 var(--label);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.orgpicker .current {
  font: 700 0.95rem/1.3 var(--label);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.orgpicker ul {
  position: absolute;
  z-index: 10;
  left: 0;
  right: 0;
  top: calc(100% - 2px);
  margin: 0;
  padding: 0;
  list-style: none;
  border: 2px solid var(--ink);
  background: var(--panel);
  max-height: 60vh;
  overflow-y: auto;
}
.orgpicker li + li { border-top: 1px dashed var(--muted); }
.orgpicker li.new { border-top: 2px solid var(--ink); }
.orgpicker a {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.45rem 0.6rem;
  color: var(--ink);
  font: 600 0.85rem/1.3 var(--label);
  text-decoration: none;
}
.orgpicker a .muted { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; }
.orgpicker a:hover { background: var(--strip); color: var(--on-strip); }
.orgpicker a:hover .muted { color: var(--on-strip); }
.orgpicker a[aria-current] { background: var(--lamp); color: var(--on-lamp); }
.orgpicker a[aria-current] .muted { color: var(--on-lamp); }

/* The Organization's pages. Section labels are labels; the links under them
   light amber for the page you are on, the way a pressed key does. */
.sidenav h3 {
  margin: 0.9rem 0 0.3rem;
  font-size: 0.7rem;
  color: var(--muted);
}
.sidenav h3:first-child { margin-top: 0; }
.sidenav ul { list-style: none; margin: 0; padding: 0; }
.sidenav ul ul { margin: 0.1rem 0 0.3rem 0.75rem; padding-left: 0.5rem; border-left: 2px solid var(--ink); }
.sidenav a {
  display: block;
  padding: 0.28rem 0.5rem;
  color: var(--ink);
  font: 600 0.88rem/1.35 var(--label);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* A Namespace's name is an identifier, so it is set like one. */
.sidenav a.ns { font: 0.82rem/1.4 var(--mono); }
.sidenav a.ns.open { font-weight: 600; }
.sidenav a:hover { background: var(--sunken); }
.sidenav a[aria-current="page"] { background: var(--lamp); color: var(--on-lamp); }
.sidenav a:focus-visible, .brand:focus-visible, .orgpicker a:focus-visible {
  outline: 3px solid var(--lamp);
  outline-offset: -3px;
}

/* Where the page is, and who is looking at it. */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  max-width: 1100px;
  padding: 1.1rem 0 1rem;
}
.crumbs {
  margin: 0;
  font: 700 1rem/1.3 var(--label);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.crumbs a { color: var(--ink); text-decoration-color: var(--lamp); text-decoration-thickness: 2px; text-underline-offset: 3px; }
.crumbs .sep { color: var(--muted); padding: 0 0.15rem; }
.topbar .whoami { margin: 0; }
.topbar .whoami button { margin-left: 0; }

/* On a phone the sidebar becomes a header strip above the page: the mark and
   a menu button, which opens the picker and the nav beneath it. It stays put
   at the top so the menu is always a thumb away. */
@media (max-width: 760px) {
  body.shell { display: block; }
  .sidebar {
    position: sticky;
    z-index: 20;
    height: auto;
    max-height: 100vh;
    gap: 0;
    padding: 0.6rem 1rem;
    border-right: 0;
    border-bottom: 2px solid var(--ink);
  }
  .menu-toggle { display: inline-block; min-width: 4.5rem; }
  .sidebar.open .menu-toggle { background: var(--lamp); color: var(--on-lamp); }
  .sidebar-menu { padding-top: 0.9rem; }
  .sidebar[data-collapsible]:not(.open) .sidebar-menu { display: none; }
  .sidebar.open { overflow-y: auto; }
  /* Thumb-sized targets. */
  .sidenav a { padding: 0.5rem 0.6rem; }
  .orgpicker a { padding: 0.6rem; }
  .orgpicker ul { position: static; border-top: 0; max-height: none; }

  .shell .content { padding: 0 1rem 3rem; }
  .topbar { padding: 0.9rem 0 0.75rem; flex-wrap: nowrap; align-items: flex-start; }
  .crumbs { font-size: 0.85rem; min-width: 0; overflow-wrap: anywhere; }
  /* Who is signed in moves into the menu; the way out stays to hand. */
  .topbar .whoami .muted { display: none; }
  .menu-account { display: block; margin: 0; font-size: 0.78rem; overflow-wrap: anywhere; }
  .topbar .whoami { flex: none; }

  /* A field's label sits above it, so the field gets the whole width. */
  .shell label:has(> input:not([type=checkbox]), > textarea, > select) {
    flex-direction: column;
    align-items: stretch;
    gap: 0.3rem;
  }
  .shell label > input:not([type=checkbox]) { flex: none; margin-left: 0; }

  /* A table's rows become cards, each cell led by its column's name, rather
     than a table scrolling sideways with its buttons out of sight. */
  .shell table.cards thead { display: none; }
  .shell table.cards, .shell table.cards tbody, .shell table.cards tr, .shell table.cards td { display: block; }
  .shell table.cards tr { padding: 0.6rem 0; border-bottom: 1px dashed var(--muted); }
  .shell table.cards tr:last-child { border-bottom: 0; }
  .shell table.cards td {
    display: flex;
    gap: 0.75rem;
    padding: 0.2rem 0;
    border: 0;
    overflow-wrap: anywhere;
  }
  .shell table.cards td[data-label]::before {
    content: attr(data-label);
    flex: none;
    width: 6.5rem;
    color: var(--muted);
    font: 700 0.7rem/1.9 var(--label);
    text-transform: uppercase;
    letter-spacing: 0.1em;
  }
  .shell table.cards td.actions { justify-content: flex-start; flex-wrap: wrap; gap: 0.5rem; padding-top: 0.5rem; white-space: normal; }
}
