/*
 * ui.css — faro's shared components, built from tokens.css only.
 *
 * No raw colors and no raw font stacks live here: every value resolves
 * through a semantic custom property, so a component renders correctly
 * under every shipped theme from its first commit. Mobile-first — the
 * base styles target the phone; the desktop grid and static nav rail are
 * added at the `width >= 900px` breakpoint.
 */

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
  padding: 0;
}

html,
body {
  height: 100%;
}

body {
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: var(--lh);
  letter-spacing: 0.1px;
  background: var(--app-glow), var(--surface-bg);
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
}

button {
  font-family: inherit;
}

:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}

.ic {
  display: inline-block;
  flex: none;
  fill: none;
  vertical-align: middle;
}

/* figures — monospaced tabular numerals so money columns align */
.num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.2px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ============================ SHELL ============================ */
.app {
  display: grid;
  grid-template-columns: 1fr;
  min-height: 100vh;
}

/* ============================ NAV RAIL / DRAWER ============================ */
.rail {
  position: fixed;
  inset: 0 auto 0 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  width: 264px;
  max-width: 82vw;
  height: 100vh;
  background: linear-gradient(180deg, var(--surface-1), var(--surface-bg));
  border-right: 1px solid var(--border-soft);
  box-shadow: var(--shadow-drawer);
  transform: translateX(-100%);

  /* hidden when closed so its links leave the tab order; the delayed
     visibility keeps the panel on screen through the slide-out */
  visibility: hidden;
  transition:
    transform var(--dur) var(--ease),
    visibility 0s var(--dur);
}

.nav-open .rail {
  transform: translateX(0);
  visibility: visible;
  transition:
    transform var(--dur) var(--ease),
    visibility 0s;
}

.brand {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: var(--space-5) var(--space-5) var(--space-4);
  border-bottom: 1px solid var(--border-soft);
}

.brand-mark {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: none;
  color: var(--text-2);
  background: radial-gradient(circle at 50% 32%, var(--beacon-soft), transparent 70%), var(--surface-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.brand-mark .beam {
  color: var(--beacon);
}

.brand-name {
  font-size: var(--fs-lg);
  font-weight: 650;
  letter-spacing: 1.5px;
  text-transform: lowercase;
}

.brand-sub {
  margin-top: 1px;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 2.4px;
  text-transform: uppercase;
  color: var(--text-3);
}

.nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-3);
  overflow-y: auto;
}

.nav-label {
  padding: var(--space-3) var(--space-3) var(--space-1);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--text-3);
}

.nav-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  font-size: var(--fs-base);
  font-weight: 500;
  color: var(--text-2);
  text-decoration: none;
  border-radius: var(--radius-sm);
}

.nav-item .ic {
  opacity: 0.85;
}

.nav-item:hover {
  color: var(--text);
  background: var(--surface-2);
}

.nav-item[aria-current="page"] {
  color: var(--text);
  background: var(--surface-3);
  box-shadow: inset 0 0 0 1px var(--border);
}

/* the beacon rail — amber beam marking the active destination */
.nav-item[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: calc(var(--space-3) * -1);
  top: 8px;
  bottom: 8px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--beacon);
  box-shadow: 0 0 12px 1px var(--beacon-line);
}

.nav-item[aria-current="page"] .ic {
  opacity: 1;
  color: var(--beacon);
}

.nav-badge {
  margin-left: auto;
  padding: 1px 7px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-2);
  background: var(--surface-hi);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
}

.rail-foot {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: auto;
  padding: var(--space-4);
  border-top: 1px solid var(--border-soft);
}

.avatar {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: none;
  font-size: var(--fs-sm);
  font-weight: 650;
  color: var(--text);
  background: linear-gradient(135deg, var(--surface-hi), var(--surface-2));
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.rail-foot .who {
  font-size: var(--fs-sm);
  font-weight: 600;
}

.rail-foot .role {
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.scrim {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 40;
  background: var(--scrim);
}

.nav-open .scrim {
  display: block;
}

.nav-open {
  overflow: hidden;
}

/* ============================ MAIN ============================ */
.main {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.topbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-soft);
  background: linear-gradient(180deg, var(--surface-1), transparent);
}

.topbar h1 {
  font-size: var(--fs-lg);
  font-weight: 620;
}

.topbar .crumb {
  margin-top: 2px;
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.topbar .spacer {
  display: none;
  flex: 1;
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  flex: none;
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.icon-btn:hover {
  color: var(--text);
  background: var(--surface-3);
}

.burger {
  order: -1;
}

.theme-toggle .ic {
  display: none;
}

:root .theme-toggle .icon-to-light {
  display: inline-block;
}

:root[data-theme="light"] .theme-toggle .icon-to-light {
  display: none;
}

:root[data-theme="light"] .theme-toggle .icon-to-dark {
  display: inline-block;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 11px;
  font-size: var(--fs-sm);
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
}

.status-pill .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--pos);
  box-shadow: 0 0 0 3px var(--pos-soft);
}

.field-search {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  order: 3;
  flex: 1 1 100%;
  padding: 7px 11px;
  color: var(--text-3);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.field-search input {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-sm);
  color: var(--text);
  background: transparent;
  border: none;
}

.field-search input:focus {
  outline: none;
}

.content {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  padding: var(--space-5) var(--space-4) var(--space-10);
}

.section-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
}

.section-head h2 {
  font-size: var(--fs-sm);
  font-weight: 650;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-2);
}

.section-head .hint {
  margin-left: auto;
  font-size: var(--fs-sm);
  color: var(--text-faint);
}

/* ============================ STAT TILES ============================ */
.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
  gap: var(--space-4);
}

.tile {
  position: relative;
  overflow: hidden;
  padding: var(--space-4) var(--space-4) var(--space-3);
  background: linear-gradient(180deg, var(--surface-2), var(--surface-1));
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.tile .lab {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-xs);
  font-weight: 650;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-3);
}

.tile .lab .ic {
  opacity: 0.7;
}

.tile .val {
  margin-top: var(--space-2);
  font-size: var(--fs-2xl);
  font-weight: 600;
  line-height: var(--lh-tight);
  color: var(--text);
}

.tile .val small {
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--text-3);
}

/* Money is a line per currency and never one blended figure (ADR-0017), so a
   money tile reads as a short list of figures, not one hero number. The step
   down keeps six admin tiles dense whether one currency shows or several. */
.tile .val--money {
  font-size: var(--fs-lg);
}

.tile .sub {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: var(--space-2);
  font-size: var(--fs-sm);
}

.tile .muted {
  color: var(--text-3);
}

/* the amber beam belongs only on the revenue tile */
.tile--beacon {
  border-color: var(--beacon-line);
}

.tile--beacon::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: var(--beacon-beam);
}

.delta {
  padding: 1px 6px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
  border-radius: 5px;
}

.delta--up {
  color: var(--pos);
  background: var(--pos-soft);
}

.delta--down {
  color: var(--neg);
  background: var(--neg-soft);
}

/* ============================ SPARKLINE ============================ */
.spark {
  display: block;
  width: 100%;
  height: 26px;
  margin-top: var(--space-2);
  color: var(--text-3);
  overflow: visible;
}

.spark--pos {
  color: var(--pos);
}

.spark--info {
  color: var(--info);
}

.spark--beacon {
  color: var(--beacon);
}

.spark polyline {
  fill: none;
  stroke: currentcolor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* ============================ CARDS / PANELS ============================ */
.card {
  overflow: hidden;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.card-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  border-bottom: 1px solid var(--border-soft);
}

.card-head h3 {
  font-size: var(--fs-md);
  font-weight: 620;
}

.card-head .tag {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.card-body {
  padding: var(--space-4);
}

/* ============================ DATA TABLE ============================ */
.table-wrap {
  overflow-x: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
}

thead th {
  padding: var(--space-3) var(--space-4);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  text-align: right;
  color: var(--text-3);
  border-bottom: 1px solid var(--border-soft);
}

thead th:first-child {
  text-align: left;
}

tbody td {
  padding: var(--space-3) var(--space-4);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-base);
  text-align: right;
  color: var(--text);
  border-bottom: 1px solid var(--border-soft);
}

tbody tr:last-child td {
  border-bottom: none;
}

tbody td:first-child {
  font-family: var(--font-sans);
  text-align: left;
}

tbody tr:hover td {
  background: var(--surface-2);
}

.cell-lead {
  display: flex;
  align-items: center;
  gap: 11px;
}

.cell-glyph {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  flex: none;
  font-size: var(--fs-base);
  font-weight: 700;
  color: var(--info);
  background: var(--surface-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.cell-name {
  font-weight: 600;
}

.cell-sub {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-3);
}

/* ============================ BUTTONS ============================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 38px;
  padding: 8px 14px;
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--text);
  background: var(--surface-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-decoration: none;
}

.btn:hover {
  background: var(--surface-hi);
}

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

.btn--ghost {
  background: transparent;
}

/* The amber action. Sanctioned positions only: the withdrawals beam, and the
   single primary CTA of a sign-in step (the beam that lets you in). Never a
   second beacon on one surface, never a mundane save. */
.btn--beacon {
  color: var(--beacon-ink);
  background: var(--beacon);
  border-color: var(--beacon);
}

.btn--beacon:hover {
  background: var(--beacon-bright);
  border-color: var(--beacon-bright);
}

.btn--sm {
  min-height: 30px;
  padding: 5px 11px;
  font-size: var(--fs-sm);
}

/* ============================ FORMS ============================ */
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* .field-label names a group of controls, which no single <label> can own. */
.field > label,
.field > .field-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-2);
}

/* A closed set the admin picks from — the settlement currencies a Host app
   declares. Chips rather than a multi-select: the set is a handful of codes and
   a native multi-select cannot be multi-picked by touch at all. */
.checks {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.check {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 7px 13px;
  font-size: var(--fs-md);
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  cursor: pointer;
}

.check:hover {
  background: var(--surface-3);
}

.check:focus-within {
  box-shadow: var(--focus-ring);
}

.check input {
  margin: 0;
  accent-color: var(--beacon);
}

.input {
  width: 100%;
  padding: 9px 11px;
  font-family: inherit;
  font-size: var(--fs-md);
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.input::placeholder {
  /* --text-faint is under 4.5:1 on --surface-2 in both themes. */
  color: var(--text-3);
}

.input:focus {
  outline: none;
  border-color: var(--beacon-line);
  box-shadow: var(--focus-ring);
}

.input[aria-invalid="true"] {
  border-color: var(--neg);
}

.field .hint {
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.field .error {
  font-size: var(--fs-sm);
  color: var(--neg);
}

/* ============================ FILTER BAR ============================ */

/* The one filter that drives every dashboard module: an app select and a date
   range. Fields grow and wrap on a phone; the submit hugs the row's baseline. */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.filter-bar .field {
  flex: 1 1 160px;
}

.filter-bar .btn {
  flex: none;
}

/* ============================ BADGES ============================ */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-2);
  background: var(--surface-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
}

.badge--pos {
  color: var(--pos);
  background: var(--pos-soft);
  border-color: transparent;
}

.badge--neg {
  color: var(--neg);
  background: var(--neg-soft);
  border-color: transparent;
}

.badge--beacon {
  color: var(--beacon-text);
  background: var(--beacon-soft);
  border-color: var(--beacon-line);
}

.badge .num {
  font-size: var(--fs-sm);
}

/* masked identifier — PII stays masked in feeds and lists */
.mask {
  padding: 0 5px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  letter-spacing: 1px;
  color: var(--text-2);
  background: var(--surface-3);
  border-radius: 4px;
}

/* ============================ SECRET, SHOWN ONCE ============================ */

/* A credential faro can never redisplay. `user-select: all` makes one click take
   the whole key, since a half-copied one cannot be looked at again — but it is
   the fallback behind the copy button, not the affordance: it asks for a mouse.
   The -webkit- prefix is written by hand because there is no build step and so
   no autoprefixer, and iOS Safari below 17 reads only the prefixed property. */
.secret {
  display: block;
  padding: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  overflow-wrap: anywhere;
  -webkit-user-select: all;
  user-select: all;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

/* ============================ ACTIVITY FEED ============================ */
.feed {
  display: flex;
  flex-direction: column;
}

.feed-row {
  position: relative;
  display: grid;
  grid-template-columns: 28px 1fr auto;
  gap: var(--space-3);
  align-items: start;
  padding: var(--space-3) var(--space-4);
}

.feed-row + .feed-row::before {
  content: "";
  position: absolute;
  left: 29px;
  top: calc(var(--space-3) * -1);
  height: var(--space-4);
  width: 1px;
  background: var(--border-soft);
}

.feed-ic {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex: none;
  z-index: 1;
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.feed-ic--signup {
  color: var(--info);
}

.feed-ic--paid {
  color: var(--pos);
}

.feed-ic--withdraw {
  color: var(--beacon-bright);
}

.feed-ic--revenue {
  color: var(--beacon);
}

.feed-ic--refund {
  color: var(--neg);
}

.feed-body .t {
  font-size: var(--fs-base);
  line-height: 1.4;
}

.feed-body .t b {
  font-weight: 600;
}

.feed-body .t .att {
  font-weight: 600;
  color: var(--text);
}

.feed-body .m {
  margin-top: 3px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.feed-time {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  white-space: nowrap;
  color: var(--text-3);
}

/* ============================ LEADERBOARD ROW ============================ */
.lb-row {
  display: grid;
  grid-template-columns: 26px 1fr auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-soft);
}

.lb-row:last-child {
  border-bottom: none;
}

.lb-row .rank {
  font-family: var(--font-mono);
  font-size: var(--fs-base);
  font-weight: 600;
  text-align: center;
  color: var(--text-3);
}

.lb-row--top .rank {
  color: var(--beacon);
}

.lb-name {
  font-size: var(--fs-base);
  font-weight: 600;
}

.lb-flow {
  margin-top: 1px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.lb-bar {
  height: 4px;
  margin-top: 6px;
  overflow: hidden;
  background: var(--surface-3);
  border-radius: 3px;
}

.lb-bar > span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--text-faint), var(--text-3));
  border-radius: 3px;
}

.lb-amt {
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  font-weight: 600;
  text-align: right;
}

.lb-cur {
  font-size: var(--fs-xs);
  letter-spacing: 0.5px;
  color: var(--text-3);
  text-align: right;
}

/* ============================ WITHDRAWALS ACTION PANEL ============================ */
.action {
  position: relative;
  border-color: var(--beacon-line);
}

.action::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--beacon), transparent);
}

.action-head {
  background: var(--beacon-soft);
}

.action-head .warn {
  color: var(--beacon-bright);
}

.action-head .count {
  margin-left: auto;
  padding: 3px 9px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--beacon-text);
  background: var(--surface-2);
  border: 1px solid var(--beacon-line);
  border-radius: var(--radius-pill);
}

.wd-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-soft);
}

.wd-row:last-child {
  border-bottom: none;
}

.wd-info {
  flex: 1 1 120px;
  min-width: 0;
}

.wd-info .h {
  font-size: var(--fs-base);
  font-weight: 600;
}

.wd-info .m {
  margin-top: 1px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.wd-amt {
  font-family: var(--font-mono);
  font-size: var(--fs-base);
  font-weight: 600;
  white-space: nowrap;
  text-align: right;
}

/* Pay and reject sit together at the end of a queued row. */
.wd-actions {
  display: flex;
  gap: var(--space-2);
}

/* ============================ EMPTY STATE ============================ */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-8) var(--space-4);
  text-align: center;
}

.empty .ic {
  color: var(--text-faint);
}

.empty h4 {
  font-size: var(--fs-md);
  font-weight: 620;
  color: var(--text);
}

.empty p {
  max-width: 40ch;
  font-size: var(--fs-sm);
  color: var(--text-3);
}

/* Centered reads as a caption for one line and as a ransom note for three, so
   the measure is capped: long notes wrap like prose, short ones still center. */
.foot-note {
  max-width: 56ch;
  margin-inline: auto;
  padding-top: var(--space-1);
  font-size: var(--fs-sm);
  text-align: center;
  color: var(--text-3);
}

/* ============================ FLASH ============================ */
.flashes {
  position: fixed;
  inset-block-start: var(--space-4);
  inset-inline: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding-inline: var(--space-4);
  pointer-events: none;
}

.flash {
  pointer-events: auto;
  width: 100%;
  max-width: 460px;
  padding: var(--space-3) var(--space-4);
  font-size: var(--fs-base);
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--info);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
}

.flash--notice {
  border-inline-start-color: var(--pos);
}

.flash--alert,
.flash--error {
  border-inline-start-color: var(--neg);
}

/* ============================ ERROR PAGE ============================ */
.error-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: 100dvh;
  padding: var(--space-8) var(--space-4);
  text-align: center;
  background: var(--surface-bg);
}

.error-page .error-code {
  font-size: var(--fs-2xl);
  color: var(--text-2);
}

.error-page h1 {
  font-size: var(--fs-xl);
  color: var(--text);
}

.error-page .error-body {
  max-width: 44ch;
  font-size: var(--fs-md);
  color: var(--text-3);
}

/* ============================ TWO-COLUMN LAYOUT ============================ */
.grid-2,
.grid-2 .col {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  min-width: 0;
}

/* ============================ AUTH ============================ */
.auth {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100dvh;
  padding: var(--space-8) var(--space-4);
  background: var(--surface-bg);
}

.auth-card {
  width: 100%;
  max-width: 400px;
  padding: var(--space-6);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.auth-brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-block-end: var(--space-5);
}

.auth-brand .brand-name {
  font-size: var(--fs-lg);
}

.auth-card h1 {
  font-size: var(--fs-lg);
  color: var(--text);
}

.auth-lede {
  margin-block: var(--space-2) var(--space-5);
  font-size: var(--fs-md);
  color: var(--text-3);
}

/* .stack is the bare primitive; .form-stack is it plus the full-width submit a
   form wants. Prose and a button are a stack, not a form. */
.stack,
.form-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.form-stack .btn {
  justify-content: center;
}

.auth-card .foot-note {
  margin-block-start: var(--space-5);
  text-align: start;
}

.code-input {
  font-family: var(--font-mono);
  font-size: var(--fs-lg);
  letter-spacing: 0.4em;
}

/* ============================ SIGNED-IN PANEL ============================ */
.panel {
  min-height: 100dvh;
  background: var(--surface-bg);
}

.panel-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-block-end: 1px solid var(--border);
  background: var(--surface-1);
}

.panel-head .brand-name {
  font-size: var(--fs-md);
}

.panel-actions {
  display: flex;
  gap: var(--space-2);
  margin-inline-start: auto;
}

.panel-body {
  max-width: 720px;
  margin-inline: auto;
  padding: var(--space-6) var(--space-4) var(--space-10);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* Ops surfaces (the Monitor) opt out of the reading-width cap to use the full
   width for their tile grid. */
.panel-body--wide {
  max-width: none;
  padding-inline: var(--space-6);
}

.panel-body h1 {
  font-size: var(--fs-xl);
  color: var(--text);
}

.panel-lede {
  font-size: var(--fs-md);
  color: var(--text-3);
}

/* ============================ INFLUENCER DASHBOARD ============================ */

/* The calmer influencer surface: the same cards and tiles as the admin console,
   composed roomier. A small caps label heads a group inside a card; the kv list
   is the payout profile; chips are Referral Codes; a note is muted supporting
   copy. All token-only, so both themes resolve from this commit. */
.card-label {
  font-size: var(--fs-xs);
  font-weight: 650;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-3);
}

.card-note {
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.kv-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.kv {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: baseline;
  font-size: var(--fs-base);
}

.kv dt {
  flex: none;
  min-width: 8ch;
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.kv dd {
  min-width: 0;
  color: var(--text);
  overflow-wrap: anywhere;
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* ============================ SUPPORT INBOX ============================ */

/* The triage queue reuses the data table; the thread view is its own reading
   surface. Admin and customer entries are told apart by an edge accent, not a
   chat-bubble gimmick: the customer (the person we help) carries the info tint,
   admin stays neutral so the amber beacon is kept for the action queue. */
.ticket-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.meta-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.meta-age {
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.ticket-issue {
  font-size: var(--fs-sm);
  color: var(--text-3);
  overflow-wrap: anywhere;
}

.ticket-issue a {
  color: var(--info);
}

.thread {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.thread-entry {
  padding: var(--space-3) var(--space-4);
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-inline-start: 3px solid var(--border);
  border-radius: var(--radius);
}

.thread-entry--customer {
  border-inline-start-color: var(--info);
}

.thread-entry-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.thread-entry-who {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-2);
}

.thread-entry--customer .thread-entry-who {
  color: var(--info);
}

.thread-entry-time {
  margin-inline-start: auto;
  font-size: var(--fs-sm);
  color: var(--text-3);
}

.thread-entry-body {
  font-size: var(--fs-base);
  line-height: var(--lh);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.thread-entry-body--empty {
  color: var(--text-3);
  font-style: italic;
}

.thread-entry-images {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.thread-entry-images img {
  display: block;
  max-width: 220px;
  max-height: 180px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.locked-note {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  font-size: var(--fs-base);
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.locked-note .ic {
  flex: none;
  color: var(--text-3);
}

.disposition-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

textarea.input {
  resize: vertical;
  line-height: var(--lh);
}

/* ============================ DESKTOP ============================ */
@media (width >= 900px) {
  .app {
    grid-template-columns: 236px 1fr;
  }

  /* A stretched button is a full-bleed tap target on a phone and a slab of one on
     a desktop. Only bare buttons stretch — a button_to wraps its own form, which
     is the flex item, so the button inside already hugs its label. */
  .panel-body > .btn,
  .stack > .btn {
    align-self: start;
  }

  .rail {
    position: sticky;
    top: 0;
    width: auto;
    max-width: none;
    box-shadow: none;
    transform: none;
    visibility: visible;
    transition: none;
  }

  .scrim {
    display: none;
  }

  .burger {
    display: none;
  }

  .topbar {
    flex-wrap: nowrap;
    padding: var(--space-4) var(--space-6);
  }

  .topbar .spacer {
    display: block;
  }

  .field-search {
    order: 0;
    flex: none;
    width: 220px;
  }

  .content {
    padding: var(--space-5) var(--space-6) var(--space-10);
  }

  .grid-2 {
    display: grid;
    grid-template-columns: 1.55fr 1fr;
    gap: var(--space-6);
    align-items: start;
  }

  .grid-2 .col {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
    min-width: 0;
  }
}

/* ============================ MONITOR (ADR-0016) ============================ */
.mono {
  font-family: var(--font-mono);
  letter-spacing: -0.2px;
}

.health {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  font-size: var(--fs-xs);
  font-weight: 650;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
}

.health .health-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentcolor;
}

.health--ok {
  color: var(--health-ok);
  background: var(--health-ok-soft);
  border-color: transparent;
}

.health--watch {
  color: var(--health-watch);
  background: var(--health-watch-soft);
  border-color: transparent;
}

.health--critical {
  color: var(--health-critical);
  background: var(--health-critical-soft);
  border-color: transparent;
}

.monitor-title {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

/* The Monitor's two destinations. Navigation, not ARIA tabs, so it reuses the
   sidebar's nav item and its beacon rail rather than inventing a tab component;
   in a row the rail sits flush against the active destination instead of hanging
   out into the sidebar's gutter. */
.monitor-tabs {
  display: flex;
  gap: var(--space-2);
  padding-bottom: var(--space-3);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--border-soft);
}

.monitor-tabs .nav-item[aria-current="page"]::before {
  left: 0;
}

.monitor-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.monitor-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-sm);
  color: var(--text-2);
}

.monitor-observed {
  color: var(--text-3);
}

/* At 375px the head carries the state line, the attention pill and Triage, so the
   button keeps its own row rather than being pushed off the end of a shared one. */
.monitor-head .btn {
  margin-left: auto;
}

@media (width < 480px) {
  .monitor-head .btn {
    margin-left: 0;
  }
}

/* A resource tile's stacked sub-facts: what the headline figure does not say on
   its own — swap under memory, load and cores under CPU, uptime under Containers. */
.monitor-facts {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  margin-top: var(--space-3);
  font-size: var(--fs-sm);
  list-style: none;
}

.monitor-facts .muted {
  color: var(--text-3);
}

.monitor-note {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  color: var(--health-watch);
}

.monitor-note .ic {
  flex: none;
  margin-top: 2px;
}

/* The Monitor's tile grid: two per row on phones (kept), then bigger cards that
   fill all available width on wider screens. */
.monitor-tiles {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (width >= 900px) {
  .monitor-tiles {
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  }
}

.monitor-tile {
  display: block;
  color: inherit;
  text-decoration: none;
  transition: border-color var(--dur) var(--ease);
}

.monitor-tile:hover {
  border-color: var(--border);
}

.monitor-tile-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.monitor-tile-head .mono,
.monitor-drill-head .mono {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* The card's figures two-up on a card ~124px wide inside. The tracks take
   minmax(0) and the labels may break, because the Spanish of any of them
   ("SOLICITUDES") is half again the English and would otherwise push the card
   past its own grid track. Requests renders only where there is traffic, so the
   usual card is four cells and the busy one is five with the odd cell last. */
.monitor-metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2) var(--space-3);
}

.monitor-metrics .lab {
  display: block;
  overflow-wrap: anywhere;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-3);
}

.monitor-metrics .num {
  font-size: var(--fs-md);
  color: var(--text);
}

.monitor-reason {
  margin-top: var(--space-3);
  font-size: var(--fs-sm);
  color: var(--text-2);
}

.monitor-flag {
  margin-top: var(--space-3);
}

.monitor-flag .ic {
  margin-right: 4px;
  color: var(--health-watch);
}

/* The Droplet view's stack below the resource tiles. */
.monitor-panels {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-top: var(--space-4);
}

/* ATTRIBUTION PANELS (ADR-0019 memory, ADR-0020 disk)
   One component, two panels, so the two breakdowns cannot drift apart.

   Three segments, never one per Container: at 375px nineteen of them render
   sub-pixel — invisible, and untappable where each links to a drill-in — and
   nineteen distinguishable fills is decorative colour at scale. Three works at
   every width with no breakpoint. Widths are shares of the three parts rather
   than of the measured total, so an overlap — a Container's working set against
   MemAvailable, image layers against a Volume — can never push the bar past its
   own end.

   The fills carry meaning, not identity: what was attributed is the informational
   tone, what could not be is faint, and free is the empty track. Volumes and
   Containers share one tone because they answer the same question about a
   different resource. */
.attr-bar {
  display: flex;
  overflow: hidden;
  height: 10px;
  background: var(--surface-3);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-pill);
}

.attr-bar-part--containers,
.attr-bar-part--volumes {
  background: var(--info);
}

.attr-bar-part--outside,
.attr-bar-part--other {
  background: var(--text-faint);
}

.attr-bar-part--free {
  background: var(--surface-hi);
}

/* The two attributed fills sit close in luminance in the light theme, and the
   boundary between them is the one thing the bar exists to show. A hairline in
   the card's own colour separates them whatever the fills resolve to, which a
   colour pairing alone cannot promise across two themes (WCAG 1.4.11). */
.attr-bar-part + .attr-bar-part {
  border-left: 1px solid var(--surface-1);
}

.attr-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-3);
  font-size: var(--fs-sm);
  color: var(--text-2);
  list-style: none;
}

.attr-legend li {
  display: flex;
  align-items: center;
  gap: 6px;
}

.attr-swatch {
  width: 9px;
  height: 9px;
  border-radius: 2px;
}

.attr-swatch--containers,
.attr-swatch--volumes {
  background: var(--info);
}

.attr-swatch--outside,
.attr-swatch--other {
  background: var(--text-faint);
}

.attr-swatch--free {
  background: var(--surface-hi);
  border: 1px solid var(--border);
}

/* Capped like every other prose block in the system: this panel sits in
   .panel-body--wide, which removes the page's own measure. */
.attr-caveat {
  max-width: 72ch;
  margin-top: var(--space-3);
  font-size: var(--fs-sm);
  color: var(--text-3);
}

/* Who is holding it, top five. A row is label · bytes · share, the figures
   right-aligned so they read down the column as one number. */
.attr-rank {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: 72ch;
  padding-top: var(--space-4);
  margin-top: var(--space-4);
  border-top: 1px solid var(--border-soft);
  list-style: none;
}

/* No bar above it — df unread while the Volumes are measured — leaves the rule
   sitting under the card head's own. */
.card-body > .attr-rank:first-child {
  padding-top: 0;
  margin-top: 0;
  border-top: 0;
}

.attr-rank li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: var(--space-3);
  align-items: baseline;
  font-size: var(--fs-sm);
}

/* These replaced per-Container bar segments precisely because those were too
   small to tap (ADR-0019); the replacement has to clear the bar it set. */
.attr-rank .mono {
  padding-block: 4px;
  overflow-wrap: anywhere;
  color: var(--text);
  text-decoration: none;
}

.attr-rank .mono:hover {
  text-decoration: underline;
}

.attr-rank .num {
  text-align: right;
}

.attr-rank .muted {
  min-width: 3.5em;
  color: var(--text-3);
}

.attr-more {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding-block: 4px;
  margin-top: var(--space-3);
  font-size: var(--fs-sm);
  color: var(--text-2);
  text-decoration: none;
}

.attr-more:hover {
  color: var(--text);
  text-decoration: underline;
}

.attr-note {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding-top: var(--space-3);
  margin-top: var(--space-3);
  font-size: var(--fs-sm);
  color: var(--text-3);
  border-top: 1px solid var(--border-soft);
}

.attr-note .mono {
  overflow-wrap: anywhere;
  color: var(--text-2);
}

/* A date the trend names, drawn only off a trend. It stays plain: what pages
   ops is the Droplet's own signal, not this sentence. */
.monitor-projection {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: var(--space-4);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--text-2);
}

.monitor-projection .ic {
  flex: none;
  color: var(--text-3);
}

/* triage modal — native <dialog> */
.modal {
  width: min(560px, 92vw);
  margin: auto; /* native showModal() centers via margin:auto; the reset zeroes it */
  padding: 0;
  color: var(--text);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-drawer);
}

.modal::backdrop {
  background: var(--scrim);
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border-soft);
}

.modal-head h3 {
  font-size: var(--fs-lg);
}

.modal-body {
  padding: var(--space-4) var(--space-5) var(--space-5);
}

.triage-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  list-style: none;
}

.triage-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--border-soft);
}

.triage-row:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.triage-main {
  min-width: 0;
}

.triage-main .monitor-reason {
  margin-top: var(--space-1);
}

/* drill-in */
.monitor-drill-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-2);
}

.monitor-drill-head h1 {
  font-size: var(--fs-xl);
}

/* The 15-minute figures above the 24-hour panel: what the verdict was computed
   from, stated once instead of repeated on every chart. */
.monitor-now {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-5);
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--border-soft);
}

.monitor-now div {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

.monitor-now .lab {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-3);
}

.monitor-now .num {
  font-size: var(--fs-md);
  color: var(--text);
}

/* ============================ ANCHORED CHART ============================ */

/* Hand-rolled inline SVG (ADR-0001, ADR-0019): zero-anchored, scaled to the
   series' own maximum, with the verdict's own thresholds drawn as rules. The
   viewBox scales uniformly, so the picture keeps its proportions at every width
   and a point marker stays round. */
.chart-block + .chart-block {
  margin-top: var(--space-5);
}

.chart-block-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-3);
}

.chart-block-head .lab {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-3);
}

.chart-detail {
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--text-2);
}

/* The verdict lines that sit above the axis: stated once, never by topping the
   axis at them. */
.chart-off {
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  color: var(--text-3);
}

.chart-frame {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-2) var(--space-3);
  align-items: stretch;
}

.chart-axis-y,
.chart-axis-x {
  grid-column: 2;
  font-size: var(--fs-xs);
  color: var(--text-3);
}

.chart-axis-y {
  display: flex;
  flex-direction: column;
  grid-column: 1;
  justify-content: space-between;
  text-align: right;
  white-space: nowrap;
}

.chart-axis-x {
  display: flex;
  justify-content: space-between;
}

.chart {
  display: block;
  grid-column: 2;
  width: 100%;
  height: auto;
  aspect-ratio: 10 / 3;
  color: var(--info);
}

.chart polyline {
  fill: none;
  stroke: currentcolor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.chart .chart-area {
  fill: currentcolor;
  stroke: none;
  opacity: 0.12;
}

.chart-rule {
  stroke: var(--text-3);
  stroke-width: 1;
  stroke-dasharray: 5 5;
  opacity: 0.6;
  vector-effect: non-scaling-stroke;
}

.chart-rule--watch {
  stroke: var(--health-watch);
  opacity: 0.85;
}

.chart-rule--critical {
  stroke: var(--health-critical);
  opacity: 0.85;
}

.chart-rule--ceiling {
  stroke: var(--health-critical);
  stroke-dasharray: 2 4;
  opacity: 1;
}

.chart-point {
  fill: currentcolor;
  opacity: 0.6;
}

/* The two floors the leak finding divided. */
.chart-point--anchor {
  fill: var(--text);
  stroke: var(--surface-1);
  stroke-width: 1.5;
  opacity: 1;
}
