/* Base elements, utilities, roles and the stale (lost connection) state. */
* { box-sizing: border-box; }
html { background: var(--ink); color-scheme: dark; }
body { margin: 0; background: var(--ink); color: var(--text); font: .9375rem/1.4 var(--body); min-height: 100vh; -webkit-font-smoothing: antialiased; }
.hidden { display: none !important; }
.grow { flex: 1; }
.mono, code { font-family: var(--mono); }
.num, .mono { font-variant-numeric: tabular-nums; }
.accent { color: var(--accent); }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
::selection { background: rgba(54, 214, 255, .35); }

/* ---------- permissions (docs/access.md) ---------- */
/* A control says what it needs: data-perm="delay", or several ids any one of which is enough
   (data-perm="settings keys users"). Without it the control is removed, not greyed. main.js puts
   one class per permission on body: can-view, can-delay … can-recordings-delete (dots become
   dashes). One rule: hidden unless one of its ids is held, so the element's own display (and
   .hidden) apply untouched when it shows. */
[data-perm]:not(
  body.can-view [data-perm~="view"],
  body.can-delay [data-perm~="delay"],
  body.can-outputs [data-perm~="outputs"],
  body.can-feeds [data-perm~="feeds"],
  body.can-recording [data-perm~="recording"],
  body.can-recordings-delete [data-perm~="recordings.delete"],
  body.can-standby-test [data-perm~="standby.test"],
  body.can-settings [data-perm~="settings"],
  body.can-keys [data-perm~="keys"],
  body.can-token [data-perm~="token"],
  body.can-users [data-perm~="users"]
) { display: none !important; }

/* ---------- lost connection ---------- */
/* Values freeze and nothing that changes state can be pressed until the push comes back. */
body.stale { --sticky-top: calc(var(--bar-h) + 2.75rem); }
body.stale .stale-dim { opacity: .45; filter: grayscale(1); transition: opacity 300ms, filter 300ms; }
body.stale [data-perm]:not(.tab, section), body.stale [data-act="nudge"] { pointer-events: none; opacity: .4; }

/* ---------- narrow windows (not a target, just not broken) ---------- */
@media (max-width: 760px) {
  :root { --gutter: 1rem; }
  .topbar { flex-wrap: wrap; height: auto; padding: var(--s2) var(--s4); gap: var(--s2); position: static; }
  .readouts { order: 5; width: 100%; }
}
