/* Arri Tech master admin — design system.
 *
 * An internal operations console. Five people, used daily, managing staff
 * access, brand credentials, audit history and download links across four
 * businesses. Nobody needs persuading; every pixel is information or a control.
 *
 * The chassis is neutral so that brand colour can carry meaning. Nearly every
 * screen shows one brand's data, and acting on the wrong brand's data is the
 * worst mistake available here — so brand colour is wayfinding, and it is the
 * only place any visual boldness goes.
 *
 * Order: tokens, reset, type, layout, components, utilities.
 * Rules: single class selectors, no nesting beyond two levels, no !important.
 */

/* ========================================================== 1. TOKENS ==== */

:root {
  /* Chassis. Neutral on purpose: if the interface itself is blue, a blue
     brand chip stops registering. */
  --ink:         #121921;  /* the wordmark's dark */
  --ink-soft:    #5B636D;
  --line:        #E3E5E8;  /* hairlines and table rules — decorative */
  --line-strong: #888D95;  /* control boundaries — must reach 3:1 */
  --surface:     #FFFFFF;
  --canvas:      #F5F6F7;

  /* Rail. */
  --rail-bg:     #121921;
  --rail-text:   #C7CBD1;
  --rail-active: #FFFFFF;
  --rail-line:   #2E3238;

  /* Semantic, for state only — never decoration. Dark and desaturated so the
     one suspended row does not pull the eye all day, and so each clears 4.5:1
     on white without needing a second variant. */
  --live:        #0A6B45;
  --attention:   #8A5300;
  --danger:      #A72118;

  /* The accent: Arri Tech orange, from the logo.
     Two tokens because one cannot cover both surfaces. #F06A2F is 5.74:1 on
     the dark rail and 3.08:1 on white -- fine for a mark, a failure for text.
     #B84C1A is the same hue darkened until it clears 4.5:1 (5.14:1).

     PERMITTED ON: the wordmark, the rail's active-item indicator, the login
     page. Nowhere else.

     NOT PERMITTED ON anything brand-scoped: no 3px brand edge, no brand chip,
     no status badge, no chart series. This is a hard constraint, not a
     preference. Colour on a panel or a row tells the reader which of the
     four businesses they are acting on -- acting on the wrong brand's
     credentials is unrecoverable -- and an Arri Tech orange competing in
     that same channel weakens the one signal the design exists to carry.
     Do not "tidy" a brand component onto these tokens. */
  --accent:     #F06A2F;   /* dark rail; non-text accents on white (3:1 applies) */
  --accent-ink: #B84C1A;   /* accent text on white -- 5.14:1 */

  --live-wash:      #ECF5F1;
  --attention-wash: #FBF3E7;
  --danger-wash:    #FBEEED;

  /* Brand colour is set per element from the database, never hard-coded.
     This is only the fallback when a brand has no colour stored. */
  --brand: var(--ink-soft);

  /* Type. Base 15px, ratio 1.25. */
  --font:      "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --micro: 12px;
  --small: 13px;
  --body:  15px;
  --h3:    19px;
  --h2:    24px;
  --h1:    30px;

  /* Space. A small set, used everywhere, so sections do not fight. */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;
  --s7: 48px;

  --radius: 6px;
  --rail-width: 232px;
  --page-max: 1400px;
  --form-max: 640px;
  --prose-max: 70ch;
}

/* ======================================================= 2. FONT FACES ==== */
/* Self-hosted. No Google Fonts CDN: it is a third-party dependency on the
   login page and a privacy question nobody needs to answer. */

@font-face {
  font-family: "IBM Plex Sans";
  src: url("/static/fonts/plex-sans-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/static/fonts/plex-sans-500.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/static/fonts/plex-sans-600.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/static/fonts/plex-mono-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/static/fonts/plex-mono-500.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}

/* =========================================================== 3. RESET ==== */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--body);
  line-height: 1.5;
  color: var(--ink);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, ul, ol, dl, dd, figure, pre { margin: 0; }
ul, ol { padding: 0; list-style: none; }

img, svg { display: block; max-width: 100%; }

button, input, select, textarea { font: inherit; color: inherit; }

/* Focus is never removed, only replaced. :focus-visible so a mouse click does
   not draw a ring, but every keyboard route does. */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: 2px;
}
.rail :focus-visible { outline-color: var(--rail-active); }

/* ============================================================ 4. TYPE ==== */

h1 { font-size: var(--h2); font-weight: 600; line-height: 1.3; letter-spacing: -0.01em; }
h2 { font-size: var(--h3); font-weight: 600; line-height: 1.3; }
h3 { font-size: var(--body); font-weight: 600; line-height: 1.3; }

a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }

.prose { max-width: var(--prose-max); }
.muted { color: var(--ink-soft); }
.small { font-size: var(--small); }
.micro { font-size: var(--micro); line-height: 1.45; }

/* Mono is for one thing: values that get copied, compared character by
   character, or typed. UUIDs, client ids, secret hints, slugs, IP prefixes.
   Not labels, not timestamps, not counts — that would be decoration. */
.mono, code, pre {
  font-family: var(--font-mono);
  font-size: 0.92em;
  font-feature-settings: "zero" 1;
}
code { background: none; padding: 0; }

/* Any number that sits in a column, so digits line up down the page. */
.num, td.num, th.num { font-variant-numeric: tabular-nums; text-align: right; }

/* ========================================================== 5. LAYOUT ==== */

.shell { display: flex; min-height: 100vh; }

.rail {
  flex: 0 0 var(--rail-width);
  width: var(--rail-width);
  background: var(--rail-bg);
  color: var(--rail-text);
  display: flex;
  flex-direction: column;
  padding: var(--s5) 0;
  position: sticky;
  top: 0;
  height: 100vh;
}

.rail-brand {
  display: block;
  padding: 0 var(--s5) var(--s6);
  color: var(--rail-active);
  font-size: var(--body);
  font-weight: 600;
  text-decoration: none;
  letter-spacing: -0.01em;
}
.rail-brand span { display: block; font-weight: 400; font-size: var(--micro); color: var(--rail-text); margin-top: var(--s2); }

.rail-nav { display: flex; flex-direction: column; gap: 2px; padding: 0 var(--s3); }

.rail-link {
  display: block;
  padding: var(--s2) var(--s3);
  border-radius: var(--radius);
  color: var(--rail-text);
  text-decoration: none;
  font-size: var(--body);
}
.rail-link:hover { background: var(--rail-line); color: var(--rail-active); }
/* The current section carries the accent as a 3px edge. This is one of the
   accent's three permitted places; the same technique on a brand row uses
   --brand, and the two must never be confused. */
.rail-link[aria-current="page"] {
  background: var(--rail-line); color: var(--rail-active); font-weight: 500;
  box-shadow: inset 3px 0 0 var(--accent);
}

.rail-foot { margin-top: auto; padding: var(--s4) var(--s5) 0; border-top: 1px solid var(--rail-line); }
.rail-who { color: var(--rail-active); font-size: var(--small); }
.rail-role { color: var(--rail-text); font-size: var(--micro); }

.main {
  flex: 1 1 auto;
  min-width: 0;
  padding: var(--s6) var(--s6) var(--s7);
}
.wrap { max-width: var(--page-max); }
.wrap-form { max-width: var(--form-max); }

/* Page header: title left, one primary action right, hairline under. */
.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s4);
  padding-bottom: var(--s4);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--s5);
}
.page-head-text { min-width: 0; }
.page-head p { color: var(--ink-soft); font-size: var(--small); margin-top: var(--s1); max-width: var(--prose-max); }
.page-head-actions { display: flex; gap: var(--s2); flex-shrink: 0; }

/* Auth pages: one left-aligned column at optical centre. No card, no shadow,
   no split-screen photograph. */
.auth { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: var(--s5); }
.auth-col { width: 380px; max-width: 100%; margin-bottom: 6vh; }
.auth-mark { margin-bottom: var(--s5); }
.auth-mark span { display: block; font-size: var(--small); color: var(--ink-soft); margin-top: var(--s2); }

/* --- Logo -------------------------------------------------------------- */
/* One inline SVG partial serves both surfaces. The wordmark's dark paths are
   fill="currentColor", so the wrapper's colour decides whether they render as
   drawn (ink, on the login page) or white (on the rail). The orange paths take
   the accent token. An <img> could not do this without two files kept in sync. */

.logo { display: block; color: var(--ink); }
.logo svg { width: 100%; height: auto; }
.logo-accent { fill: var(--accent); }
.auth-logo { width: 176px; }
.rail-logo { width: 120px; color: var(--rail-active); }

/* ====================================================== 6. COMPONENTS ==== */

/* --- Panel ------------------------------------------------------------- */

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s5);
}
.panel-flush { padding: 0; overflow: hidden; }
.panel-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s4);
  padding: var(--s4) var(--s5);
  border-bottom: 1px solid var(--line);
}
.panel-body { padding: var(--s5); }
.panel-foot { padding: var(--s4) var(--s5); border-top: 1px solid var(--line); }

/* Brand wayfinding, place one of two: a 3px left border on anything scoped to
   a brand. Always the same place, so it becomes peripheral rather than
   something you have to read. */
.brand-edge { border-left: 3px solid var(--brand); }

/* --- Brand chip -------------------------------------------------------- */
/* Place two of two: in the page header. Colour is never the only signal —
   the brand's name is right there in the chip. */

.brand-chip {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-size: var(--small); font-weight: 500;
  color: var(--brand);
  white-space: nowrap;
}
.brand-chip::before {
  content: ""; width: 10px; height: 10px; border-radius: 3px;
  background: var(--brand); flex: 0 0 auto;
}

/* --- Table ------------------------------------------------------------- */
/* The primary component: most screens are one. Hairlines between rows, no
   zebra striping, no vertical rules, no outer border. */

.table-scroll { overflow-x: auto; }

table.data { width: 100%; border-collapse: collapse; font-size: var(--body); }

table.data th {
  position: sticky; top: 0; z-index: 1;
  background: var(--surface);
  text-align: left;
  font-size: var(--small); font-weight: 500; color: var(--ink-soft);
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
table.data td {
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
  height: 44px;
}
table.data tbody tr:hover { background: var(--canvas); }
table.data tbody tr:last-child td { border-bottom: 0; }
table.data .cell-meta { display: block; font-size: var(--micro); color: var(--ink-soft); }
table.data td.nowrap, table.data th.nowrap { white-space: nowrap; }
/* Actions wrap rather than forcing the whole table into a horizontal scroll.
   A row with three controls is a row that needs two lines, not a scrollbar. */
table.data td.actions { text-align: right; }
table.data td.actions > * + * { margin-left: var(--s3); }
.action-list { display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3); justify-content: flex-end; }
/* The same row of controls outside a table cell, on a detail page. */
.action-list-start { justify-content: flex-start; align-items: center; gap: var(--s3); }
.action-list-start .confirm-toggle[open] { flex-basis: 100%; }

/* A brand-scoped row carries the same 3px edge as a brand-scoped panel. */
table.data tr.brand-row td:first-child { box-shadow: inset 3px 0 0 var(--brand); }

/* --- Empty state ------------------------------------------------------- */
/* Never "No results." Say what would be here and how to put it there. */

.empty { padding: var(--s6) var(--s5); }
.empty h3 { margin-bottom: var(--s2); }
.empty p { color: var(--ink-soft); max-width: var(--prose-max); font-size: var(--small); }
.empty .btn { margin-top: var(--s4); }

/* --- Status badge ------------------------------------------------------ */
/* Fixed vocabulary, and colour never carries the state on its own — the word
   is always there. Two of five staff being colour-blind is not unlikely. */

.badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--small); font-weight: 500; white-space: nowrap;
}
.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: 0 0 auto; }
.badge-live      { color: var(--live); }
.badge-attention { color: var(--attention); }
.badge-danger    { color: var(--danger); }
.badge-neutral   { color: var(--ink-soft); }

/* --- Buttons ----------------------------------------------------------- */
/* Three kinds only. Labels say what happens: "Suspend Bo Chen", not "Confirm". */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  padding: 9px 16px;
  font-size: var(--body); font-weight: 500; line-height: 1.2;
  border-radius: var(--radius);
  border: 1px solid transparent;
  background: none;
  cursor: pointer;
  text-decoration: none;
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-primary { background: var(--ink); color: var(--surface); border-color: var(--ink); }
.btn-primary:hover:not(:disabled) { background: #2C3037; border-color: #2C3037; }

.btn-secondary { background: var(--surface); color: var(--ink); border-color: var(--line-strong); }
.btn-secondary:hover:not(:disabled) { background: var(--canvas); }

/* Destructive should feel deliberate to click, not inviting: outline until
   hover, then solid. */
.btn-danger { background: var(--surface); color: var(--danger); border-color: var(--danger); }
.btn-danger:hover:not(:disabled) { background: var(--danger); color: var(--surface); }

.btn-small { padding: 5px 10px; font-size: var(--small); }

/* A link that behaves as an inline control. Still a real <button>. */
.btn-link {
  background: none; border: 0; padding: 0;
  color: var(--ink); font-size: var(--small);
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
}
.btn-link-danger { color: var(--danger); }

.btn-row { display: flex; gap: var(--s3); align-items: center; flex-wrap: wrap; }

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

.field { margin-bottom: var(--s5); max-width: var(--form-max); }
.field label { display: block; font-size: var(--small); color: var(--ink-soft); margin-bottom: var(--s1); }

.input, input[type="text"], input[type="email"], input[type="password"],
input[type="url"], input[type="date"], select, textarea {
  width: 100%;
  padding: 10px 12px;
  font-size: var(--body);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
}
textarea { min-height: 96px; font-family: var(--font-mono); font-size: var(--small); }
select {
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--ink-soft) 50%),
    linear-gradient(135deg, var(--ink-soft) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 36px;
}

.help { display: block; font-size: var(--micro); color: var(--ink-soft); margin-top: var(--s1); max-width: var(--prose-max); }

/* Errors replace help text and name what to fix. */
.field-error { display: block; font-size: var(--micro); color: var(--danger); margin-top: var(--s1); }
.field-invalid input, .field-invalid select, .field-invalid textarea { border-color: var(--danger); }

.check { display: flex; align-items: flex-start; gap: var(--s2); }
.check input { width: auto; margin-top: 3px; }
.check span { font-size: var(--body); }

/* The colour input sits beside a swatch, so what you typed is visible. */
.colour-field { display: flex; align-items: center; gap: var(--s3); }

/* --- Metric row --------------------------------------------------------- */
/* Headline figures with the previous period behind them. A number with no
   comparison is not information: 1,237 clicks is only meaningful next to what
   it was. */

.metric-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--s5); }
.metric { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.metric-label { font-size: var(--small); color: var(--ink-soft); }
.metric-value { font-size: var(--h1); font-weight: 600; line-height: 1.1; letter-spacing: -0.02em; text-align: left; }
.metric-change { font-size: var(--micro); color: var(--ink-soft); }

/* Direction is never colour alone: the figure carries a sign or a word, and
   these only reinforce it. Two of five staff being colour-blind is not
   unlikely, and a red number that means nothing else is a number they cannot
   read. */
.up   { color: var(--live); }
.down { color: var(--danger); }
td.up, td.down { font-variant-numeric: tabular-nums; }

/* --- SEO layout --------------------------------------------------------- */

.seo-two-col { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s5); align-items: start; }

@media (max-width: 1100px) {
  .seo-two-col { grid-template-columns: 1fr; }
}

/* --- Prefixed input ----------------------------------------------------- */
/* For a value that is only ever the last segment of something longer. The
   fixed part is shown, greyed and unselectable-looking, welded to the left of
   the field, so the shape of what belongs in the box is obvious before it is
   typed rather than after a validation message. */

.affix-field { display: flex; align-items: stretch; max-width: var(--form-max); }
.affix-field .affix {
  display: flex; align-items: center;
  padding: 0 10px;
  background: var(--canvas);
  border: 1px solid var(--line-strong);
  border-right: 0;
  border-radius: var(--radius) 0 0 var(--radius);
  color: var(--ink-soft);
  font-family: var(--font-mono); font-size: var(--small);
  white-space: nowrap;
  user-select: none;
}
.affix-field input { border-radius: 0 var(--radius) var(--radius) 0; min-width: 0; }
/* The focus ring belongs round the pair, not half of it. */
.affix-field:focus-within .affix { border-color: var(--ink); }
.affix-field input:focus-visible { outline-offset: -1px; }
.colour-swatch { width: 38px; height: 38px; border-radius: var(--radius); border: 1px solid var(--line-strong); flex: 0 0 auto; background: var(--brand); }

/* --- Messages ---------------------------------------------------------- */

.note { padding: var(--s3) var(--s4); border-radius: var(--radius); font-size: var(--small); border: 1px solid; }
.note-live      { background: var(--live-wash);      border-color: #C6E0D5; color: var(--live); }
.note-attention { background: var(--attention-wash); border-color: #EBD8B4; color: var(--attention); }
.note-danger    { background: var(--danger-wash);    border-color: #EFC9C6; color: var(--danger); }
.note ul { margin-top: var(--s2); padding-left: 18px; list-style: disc; }
.note li { margin-bottom: var(--s1); }

/* --- Confirmation, tier one: reversible -------------------------------- */
/* An inline panel naming the exact target and its consequence. */

.confirm {
  border: 1px solid var(--line-strong);
  border-left: 3px solid var(--danger);
  border-radius: var(--radius);
  padding: var(--s4);
  background: var(--surface);
}
.confirm p { font-size: var(--small); max-width: var(--prose-max); }
.confirm .btn-row { margin-top: var(--s4); }

/* --- Confirmation, tier two: irreversible ------------------------------ */

dialog.modal {
  border: 0; border-radius: var(--radius); padding: 0;
  max-width: 520px; width: calc(100% - 32px);
  background: var(--surface); color: var(--ink);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
}
dialog.modal::backdrop { background: rgba(26, 29, 33, 0.45); }
.modal-body { padding: var(--s5); }
.modal-body h2 { margin-bottom: var(--s3); }
.modal-body p { font-size: var(--small); max-width: var(--prose-max); }
.modal-foot { display: flex; gap: var(--s3); justify-content: flex-end; padding: var(--s4) var(--s5); border-top: 1px solid var(--line); }

/* --- The one-time secret ----------------------------------------------- */
/* The only genuinely dramatic moment in the interface, and it earns it: the
   value is unrecoverable once the page closes. */

.secret {
  background: var(--ink);
  color: var(--surface);
  border-radius: var(--radius);
  padding: var(--s5);
  animation: secret-in 200ms ease-out;
}
.secret h2 { color: var(--surface); margin-bottom: var(--s2); }
.secret p { color: #C7CBD1; font-size: var(--small); max-width: var(--prose-max); }
.secret-value {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--h3);
  letter-spacing: 0.06em;
  word-break: break-all;
  padding: var(--s4) 0;
  color: var(--surface);
  user-select: all;
}
.secret .btn-secondary { background: transparent; color: var(--surface); border-color: #4A5058; }
.secret .btn-secondary:hover { background: #2C3037; }

@keyframes secret-in { from { opacity: 0; } to { opacity: 1; } }

/* --- Definition lists -------------------------------------------------- */

.facts { display: grid; grid-template-columns: 200px 1fr; gap: var(--s3) var(--s4); font-size: var(--body); }
.facts dt { color: var(--ink-soft); font-size: var(--small); }
.facts dd { min-width: 0; word-break: break-word; }
/* Tabular numerals without the right-alignment: a value in a definition list
   sits next to its label, not against the far edge of the panel. */
.facts dd.num { text-align: left; }

/* --- Chart ------------------------------------------------------------- */
/* One chart type. No fills, no gradients, no second Y-axis. */

.chart { display: flex; align-items: flex-end; gap: 2px; height: 120px; }
.chart-col { flex: 1 1 0; display: flex; flex-direction: column; justify-content: flex-end; height: 100%; min-width: 3px; }
.chart-bar { background: var(--ink); border-radius: 1px 1px 0 0; min-height: 1px; }
.chart-axis { display: flex; justify-content: space-between; font-size: var(--micro); color: var(--ink-soft); padding-top: var(--s2); border-top: 1px solid var(--line); }


/* --- Bar heights ------------------------------------------------------- */
/* A static scale rather than inline styles. The CSP has no 'unsafe-inline'
   for styles, and a nonce covers <style> elements but not style attributes --
   so a bar's height is a class. 101 rules is about 2KB and needs no
   JavaScript, no library and no build step. */

.h-0 { height: 0%; }
.h-1 { height: 1%; }
.h-2 { height: 2%; }
.h-3 { height: 3%; }
.h-4 { height: 4%; }
.h-5 { height: 5%; }
.h-6 { height: 6%; }
.h-7 { height: 7%; }
.h-8 { height: 8%; }
.h-9 { height: 9%; }
.h-10 { height: 10%; }
.h-11 { height: 11%; }
.h-12 { height: 12%; }
.h-13 { height: 13%; }
.h-14 { height: 14%; }
.h-15 { height: 15%; }
.h-16 { height: 16%; }
.h-17 { height: 17%; }
.h-18 { height: 18%; }
.h-19 { height: 19%; }
.h-20 { height: 20%; }
.h-21 { height: 21%; }
.h-22 { height: 22%; }
.h-23 { height: 23%; }
.h-24 { height: 24%; }
.h-25 { height: 25%; }
.h-26 { height: 26%; }
.h-27 { height: 27%; }
.h-28 { height: 28%; }
.h-29 { height: 29%; }
.h-30 { height: 30%; }
.h-31 { height: 31%; }
.h-32 { height: 32%; }
.h-33 { height: 33%; }
.h-34 { height: 34%; }
.h-35 { height: 35%; }
.h-36 { height: 36%; }
.h-37 { height: 37%; }
.h-38 { height: 38%; }
.h-39 { height: 39%; }
.h-40 { height: 40%; }
.h-41 { height: 41%; }
.h-42 { height: 42%; }
.h-43 { height: 43%; }
.h-44 { height: 44%; }
.h-45 { height: 45%; }
.h-46 { height: 46%; }
.h-47 { height: 47%; }
.h-48 { height: 48%; }
.h-49 { height: 49%; }
.h-50 { height: 50%; }
.h-51 { height: 51%; }
.h-52 { height: 52%; }
.h-53 { height: 53%; }
.h-54 { height: 54%; }
.h-55 { height: 55%; }
.h-56 { height: 56%; }
.h-57 { height: 57%; }
.h-58 { height: 58%; }
.h-59 { height: 59%; }
.h-60 { height: 60%; }
.h-61 { height: 61%; }
.h-62 { height: 62%; }
.h-63 { height: 63%; }
.h-64 { height: 64%; }
.h-65 { height: 65%; }
.h-66 { height: 66%; }
.h-67 { height: 67%; }
.h-68 { height: 68%; }
.h-69 { height: 69%; }
.h-70 { height: 70%; }
.h-71 { height: 71%; }
.h-72 { height: 72%; }
.h-73 { height: 73%; }
.h-74 { height: 74%; }
.h-75 { height: 75%; }
.h-76 { height: 76%; }
.h-77 { height: 77%; }
.h-78 { height: 78%; }
.h-79 { height: 79%; }
.h-80 { height: 80%; }
.h-81 { height: 81%; }
.h-82 { height: 82%; }
.h-83 { height: 83%; }
.h-84 { height: 84%; }
.h-85 { height: 85%; }
.h-86 { height: 86%; }
.h-87 { height: 87%; }
.h-88 { height: 88%; }
.h-89 { height: 89%; }
.h-90 { height: 90%; }
.h-91 { height: 91%; }
.h-92 { height: 92%; }
.h-93 { height: 93%; }
.h-94 { height: 94%; }
.h-95 { height: 95%; }
.h-96 { height: 96%; }
.h-97 { height: 97%; }
.h-98 { height: 98%; }
.h-99 { height: 99%; }
.h-100 { height: 100%; }

/* Row sparkline: cheap, no library. */
.spark { display: inline-flex; align-items: flex-end; gap: 1px; height: 18px; width: 72px; }
.spark span { flex: 1 1 0; background: var(--line-strong); border-radius: 1px; min-height: 1px; }

/* --- Metadata disclosure ----------------------------------------------- */

details.meta summary { font-size: var(--small); color: var(--ink-soft); cursor: pointer; }
details.meta summary:hover { color: var(--ink); }
details.meta pre {
  margin-top: var(--s2); padding: var(--s3);
  background: var(--canvas); border: 1px solid var(--line); border-radius: var(--radius);
  font-size: var(--micro); overflow-x: auto; white-space: pre-wrap; word-break: break-word;
}

/* --- Filter bar -------------------------------------------------------- */

.filters { display: flex; flex-wrap: wrap; gap: var(--s3); align-items: flex-end; margin-bottom: var(--s4); }
.filters .field { margin-bottom: 0; max-width: 190px; }
.filters .field-wide { max-width: 260px; }

/* --- Brand launcher ---------------------------------------------------- */

.launch-row {
  display: flex; align-items: center; gap: var(--s4);
  padding: var(--s4) var(--s5);
  border-bottom: 1px solid var(--line);
  border-left: 3px solid var(--brand);
}
.launch-row:last-child { border-bottom: 0; }
.launch-name { font-weight: 500; min-width: 150px; }
.launch-meta { display: flex; gap: var(--s4); align-items: center; flex: 1 1 auto; flex-wrap: wrap; font-size: var(--small); color: var(--ink-soft); }
.launch-row .btn { margin-left: auto; }

/* --- Activity strip ---------------------------------------------------- */
/* Two lists side by side, no cards: a hairline above, a heading, rows. It
   sits below the brand launcher and is read at a glance; the audit log and
   the analytics pages are where the detail lives. */

.strip {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s6);
  padding-top: var(--s5); border-top: 1px solid var(--line);
}
.strip-col { min-width: 0; }
.strip-head { font-size: var(--small); font-weight: 500; color: var(--ink-soft); margin-bottom: var(--s3); }
.strip-total { font-size: var(--h2); font-weight: 600; line-height: 1.2; margin-bottom: var(--s3); }
.strip-total .num { text-align: left; }
.strip-list > li { border-top: 1px solid var(--line); }
.strip-row {
  display: flex; align-items: baseline; gap: var(--s4);
  padding: var(--s2) 0; font-size: var(--small);
}
.strip-row.brand-sample, .strip-row[class*="brand-"] { padding-left: var(--s3); box-shadow: inset 3px 0 0 var(--brand); }
.strip-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.strip-when { color: var(--ink-soft); white-space: nowrap; }
.strip-ip { min-width: 120px; text-align: right; font-size: var(--micro); }
.strip-count { min-width: 48px; }
.strip-empty { font-size: var(--small); color: var(--ink-soft); padding: var(--s2) 0; }

/* --- htmx -------------------------------------------------------------- */
/* Indicator on the triggering control, never a page overlay. */

.htmx-indicator { display: none; font-size: var(--small); color: var(--ink-soft); }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { display: inline; }

/* ======================================================= 7. UTILITIES ==== */
/* Spacing lives here rather than on components, so sections do not fight over
   which margin wins. */

.stack > * + * { margin-top: var(--s4); }
.stack-tight > * + * { margin-top: var(--s2); }
.stack-loose > * + * { margin-top: var(--s6); }

.row { display: flex; gap: var(--s3); align-items: center; flex-wrap: wrap; }
.row-between { display: flex; gap: var(--s3); align-items: center; justify-content: space-between; flex-wrap: wrap; }
.push { margin-left: auto; }

.dim { opacity: 0.6; }
.nowrap { white-space: nowrap; }
.break { word-break: break-all; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Skip link: visible the moment it takes focus. */
.skip {
  position: absolute; left: var(--s3); top: -60px; z-index: 10;
  background: var(--surface); color: var(--ink);
  padding: var(--s2) var(--s3); border: 1px solid var(--ink); border-radius: var(--radius);
  transition: top 120ms ease;
}
.skip:focus { top: var(--s3); }

/* ====================================================== 8. RESPONSIVE ==== */
/* Down to tablet the rail becomes a top bar. Below that it degrades rather
   than being redesigned — nobody administers four businesses from a phone. */

@media (max-width: 900px) {
  .shell { display: block; }
  .rail {
    width: auto; flex: none; height: auto; position: static;
    flex-direction: row; align-items: center; flex-wrap: wrap;
    gap: var(--s3); padding: var(--s3) var(--s4);
  }
  .rail-brand { padding: 0; margin-right: var(--s4); }
  .rail-brand span { display: none; }
  .rail-nav { flex-direction: row; padding: 0; flex-wrap: wrap; }
  .rail-foot { margin: 0 0 0 auto; padding: 0; border-top: 0; }
  .rail-role { display: none; }
  .main { padding: var(--s5) var(--s4) var(--s6); }
  .page-head { flex-direction: column; align-items: stretch; }
  .facts { grid-template-columns: 1fr; gap: var(--s1) 0; }
  .facts dd { margin-bottom: var(--s3); }
  .launch-row { flex-wrap: wrap; }
  .launch-row .btn { margin-left: 0; }
  .strip { grid-template-columns: 1fr; }
}

/* ================================================= 9. REDUCED MOTION ==== */
/* Everything off, including the secret reveal. */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms;
    animation-iteration-count: 1;
    transition-duration: 0.001ms;
    scroll-behavior: auto;
  }
  .secret { animation: none; }
}

/* =========================================================== 10. PRINT === */

@media print {
  .rail, .page-head-actions, .btn { display: none; }
  body { background: #fff; }
  .panel { border: 1px solid #999; }
}

/* Rail footer links sit flush with the rest of the rail rather than carrying
   the nav link's inset. */
.rail-foot-links { display: flex; gap: var(--s4); align-items: center; margin-top: var(--s2); }
.rail-foot-links .rail-link { padding-left: 0; padding-right: 0; font-size: var(--small); }
.rail-foot-links button.rail-link { border: 0; background: none; cursor: pointer; }

/* --- Inline confirmation toggle ---------------------------------------- */
/* Tier one, reversible: a <details> so the confirmation is inline, keyboard
   reachable and needs no JavaScript. */

.confirm-toggle { display: inline-block; }
.confirm-toggle summary { display: inline; list-style: none; cursor: pointer; }
.confirm-toggle summary::-webkit-details-marker { display: none; }
.confirm-toggle[open] { display: block; margin-top: var(--s2); }
.confirm-toggle .confirm { margin-top: var(--s2); text-align: left; white-space: normal; min-width: 320px; }

form.inline { display: inline; }

/* --- QR code ----------------------------------------------------------- */

img.qr {
  image-rendering: pixelated;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  padding: var(--s2);
  width: 256px; height: 256px;
}

/* --- Styleguide -------------------------------------------------------- */

.sg-section { scroll-margin-top: var(--s5); }
.sg-swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: var(--s3); }
.sg-swatch { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.sg-chip { height: 56px; }
.sg-chip-ink { background: var(--ink); }
.sg-chip-inksoft { background: var(--ink-soft); }
.sg-chip-line { background: var(--line); }
.sg-chip-linestrong { background: var(--line-strong); }
.sg-chip-surface { background: var(--surface); }
.sg-chip-canvas { background: var(--canvas); }
.sg-chip-live { background: var(--live); }
.sg-chip-attention { background: var(--attention); }
.sg-chip-danger { background: var(--danger); }
.sg-chip-brand { background: var(--brand); }
.sg-chip-accent { background: var(--accent); }
.sg-chip-accentink { background: var(--accent-ink); }
/* The logo on its two surfaces, side by side. */
.sg-logos { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }
.sg-logo-light, .sg-logo-dark { padding: var(--s6); border-radius: var(--radius); display: flex; align-items: center; justify-content: center; }
.sg-logo-light { background: var(--canvas); border: 1px solid var(--line); }
.sg-logo-dark { background: var(--rail-bg); }
.sg-logo-light .logo, .sg-logo-dark .logo { width: 200px; }
.sg-logo-dark .logo { color: var(--rail-active); }
.sg-swatch-meta { padding: var(--s2) var(--s3); font-size: var(--micro); }
.sg-swatch-meta code { display: block; color: var(--ink-soft); }
.sg-toc { display: flex; flex-wrap: wrap; gap: var(--s3); font-size: var(--small); }
