/*
 * ═══════════════════════════════════════════════════════════════════════════
 * UNITY — the shared theme.  THE canonical copy.
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * One theme for every Innotel project, not just the OnTrak ones. `theme/README.md`
 * is the adoption guide for a new project; this file is the palette.
 *
 * Every product ships a byte-identical copy of this file (each app is built from its
 * own directory, so a file outside the build context cannot be imported).
 * `theme/tests/test_theme_copies.py` fails if any copy drifts, which is what stops
 * "one palette" from becoming five opinions over six months.
 *
 * ── Two names worth keeping apart ──────────────────────────────────────────
 *
 *   **Unity** (this)   the theme: three schemes, two modes, one vocabulary.
 *   **OnTrak Unity**  the portal that is one of the things wearing it. The theme
 *                     came first and the product took its name, which is the
 *                     direction that causes no trouble.
 *
 * ── What is here, and why it is shaped this way ────────────────────────────
 *
 * THREE SCHEMES, TWO MODES, ONE VOCABULARY.
 *
 *   scheme "desk"        the training range and the service desk — the violet
 *                        family that Tix and OnTrak IT Support Training already
 *                        use, so those two apps change least.
 *   scheme "operations"  the operations consoles — the graphite-and-blue family
 *                        that OnTrak Sync and the Unity portal already use.
 *   scheme "soc"         the security-operations console — the navy-and-cyan
 *                        family Sentinel wears, in the visual language of the
 *                        open-source SIEM consoles.
 *
 *   mode "light" / "dark" applies to all three, and `system` follows the machine.
 *
 * A product picks its default scheme; the person can override either axis, and the
 * choice is remembered per browser. That is the whole point of the exercise: the
 * same page should be readable in a bright office and at 3am, and an operator who
 * has learned one product's colours should not have to relearn them in the next.
 *
 * The vocabulary is deliberately semantic — `--surface`, `--ink-faint`,
 * `--attention` — and never visual. A class that says what a thing *is* (a
 * finding, an outage, an SLA breach) cannot quietly pick a new colour, and
 * `--unknown` exists as its own token because a check that never ran must never be
 * painted the same as a check that passed.
 *
 * Usage: set `data-scheme` and `data-mode` on <html> (see unity-theme.js), then use
 * the tokens. No component should name a raw colour.
 */

/* ══ scheme: desk — light ═══════════════════════════════════════════════════ */
:root {
  color-scheme: light;

  --canvas: #f7f6fb;
  --surface: #ffffff;
  --surface-muted: #f1effa;
  --surface-sunken: #ebe7f6;
  --line: #e4e0f0;
  --line-strong: #cec8e3;

  --ink: #191430;
  --ink-soft: #4b4468;
  --ink-faint: #6d6789;

  --brand: #5f3fe6;
  --brand-soft: #ece8ff;
  --brand-ink: #ffffff;
  --brand-ring: #b9a8f7;

  --ok: #146c2e;
  --ok-soft: #e4f6e8;
  --info: #1360a8;
  --info-soft: #e5f0fb;
  --bad: #b3261e;
  --bad-soft: #fdeceb;
  --attention: #8a5a00;
  --attention-soft: #fdf3dd;
  --unknown: #6b6b76;
  --unknown-soft: #efeff3;

  /* The products' identifying colours. A tone is a *label*, never the only
     signal: every tile also carries the product's name in text. */
  --tone-its: #4d6b00;
  --tone-tix: #0a5c9e;
  --tone-sentinel: #b0246a;
  --tone-sync: #05685e;
  --tone-genie: #7c3aed;
  --tone-engineer: #0f766e;
  --tone-lab: #b45309;
  --tone-godmode: #b91c1c;
  --tone-class: #4f46e5;
  --tone-unity: #0891b2;

  --shadow-card: 0 1px 2px rgb(25 20 48 / 5%), 0 10px 30px -14px rgb(25 20 48 / 18%);
  --shadow-pop: 0 8px 28px -8px rgb(25 20 48 / 26%);

  /*
   * ── Liquid glass ───────────────────────────────────────────────────────
   *
   * A surface made of light rather than of a solid colour: a translucent tint
   * over whatever is behind it, a hairline edge brighter than the tint (the
   * "light catch" on a pane's rim), a soft drop shadow to lift it off the
   * canvas, and a blur of the content underneath.
   *
   * The tokens are mixed from the *scheme's own* surface and ink, so they are
   * defined once here instead of six times — the value of `--surface` is resolved
   * where the glass is used, not where this block is written. A light scheme gets
   * white frosted panes, a dark one gets smoked glass, and a product does not have
   * to know which it is to use them.
   *
   * `--glass-tint` is the everyday pane (sidebar, rail, composer); the `-strong`
   * one is for something that must stay readable over busy content (a dialog, a
   * menu). Both keep enough opacity that text contrast does not depend on the blur
   * being supported.
   */
  --glass-tint: color-mix(in srgb, var(--surface) 66%, transparent);
  --glass-tint-strong: color-mix(in srgb, var(--surface) 86%, transparent);
  --glass-tint-soft: color-mix(in srgb, var(--surface) 42%, transparent);
  --glass-line: color-mix(in srgb, var(--ink) 12%, transparent);
  --glass-line-bright: color-mix(in srgb, #ffffff 55%, transparent);
  --glass-sheen: linear-gradient(
    180deg,
    color-mix(in srgb, #ffffff 22%, transparent),
    transparent 38%
  );
  --glass-shadow: 0 1px 2px color-mix(in srgb, var(--ink) 8%, transparent),
    0 24px 60px -32px color-mix(in srgb, var(--ink) 55%, transparent);
  --glass-shadow-pop: 0 1px 0 color-mix(in srgb, #ffffff 45%, transparent) inset,
    0 2px 6px color-mix(in srgb, var(--ink) 10%, transparent),
    0 30px 70px -28px color-mix(in srgb, var(--ink) 60%, transparent);
  --glass-blur: 20px;
  --glass-saturate: 140%;
  --glass-radius: 16px;

  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 18px;
  --radius-pill: 999px;

  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-display: var(--font-sans);
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 22px;
  --space-6: 32px;
}

/* ══ scheme: desk — dark ════════════════════════════════════════════════════ */
@media (prefers-color-scheme: dark) {
  :root:not([data-mode="light"]) {
    color-scheme: dark;

    --canvas: #100c22;
    --surface: #1a1433;
    --surface-muted: #221a40;
    --surface-sunken: #151029;
    --line: #332a55;
    --line-strong: #453a6e;

    --ink: #f5f3ff;
    --ink-soft: #c3bce0;
    --ink-faint: #9a92bd;

    --brand: #9b83ff;
    --brand-soft: #2a2154;
    --brand-ink: #14102a;
    --brand-ring: #5b46a8;

    --ok: #5ed37a;
    --ok-soft: #16301f;
    --info: #6cc0ff;
    --info-soft: #152a3f;
    --bad: #ff8a80;
    --bad-soft: #34191a;
    --attention: #ffc157;
    --attention-soft: #33260f;
    --unknown: #8f87b3;
    --unknown-soft: #241e42;

    --tone-its: #b4e85c;
    --tone-tix: #6cc0ff;
    --tone-sentinel: #ff7cb4;
    --tone-sync: #3fd3c1;
    --tone-genie: #c4b5fd;
    --tone-engineer: #5eead4;
    --tone-lab: #fbbf24;
    --tone-godmode: #fca5a5;
    --tone-class: #a5b4fc;
    --tone-unity: #67e8f9;

    --shadow-card: 0 1px 2px rgb(0 0 0 / 30%), 0 12px 32px -14px rgb(0 0 0 / 60%);
    --shadow-pop: 0 10px 34px -8px rgb(0 0 0 / 66%);
  }
}

/* The same thing, asked for explicitly. A person who picks "dark" gets dark on a
   machine that prefers light, which is the entire reason the toggle exists. */
:root[data-mode="dark"] {
  color-scheme: dark;

  --canvas: #100c22;
  --surface: #1a1433;
  --surface-muted: #221a40;
  --surface-sunken: #151029;
  --line: #332a55;
  --line-strong: #453a6e;

  --ink: #f5f3ff;
  --ink-soft: #c3bce0;
  --ink-faint: #9a92bd;

  --brand: #9b83ff;
  --brand-soft: #2a2154;
  --brand-ink: #14102a;
  --brand-ring: #5b46a8;

  --ok: #5ed37a;
  --ok-soft: #16301f;
  --info: #6cc0ff;
  --info-soft: #152a3f;
  --bad: #ff8a80;
  --bad-soft: #34191a;
  --attention: #ffc157;
  --attention-soft: #33260f;
  --unknown: #8f87b3;
  --unknown-soft: #241e42;

  --tone-its: #b4e85c;
  --tone-tix: #6cc0ff;
  --tone-sentinel: #ff7cb4;
  --tone-sync: #3fd3c1;
  --tone-genie: #c4b5fd;
  --tone-engineer: #5eead4;
  --tone-lab: #fbbf24;
  --tone-godmode: #fca5a5;
  --tone-class: #a5b4fc;
  --tone-unity: #67e8f9;

  --shadow-card: 0 1px 2px rgb(0 0 0 / 30%), 0 12px 32px -14px rgb(0 0 0 / 60%);
  --shadow-pop: 0 10px 34px -8px rgb(0 0 0 / 66%);
}

/* ══ scheme: operations — light (graphite neutrals, blue brand) ════════════ */
:root[data-scheme="operations"] {
  color-scheme: light;

  --canvas: #f4f6f8;
  --surface: #ffffff;
  --surface-muted: #eef2f5;
  --surface-sunken: #e6ebef;
  --line: #dde4ea;
  --line-strong: #c2ccd6;

  --ink: #10171d;
  --ink-soft: #46535f;
  --ink-faint: #6b7885;

  --brand: #1f6feb;
  --brand-soft: #e6f0ff;
  --brand-ink: #ffffff;
  --brand-ring: #9dc2ff;

  --tone-its: #3f6212;
  --tone-tix: #1f6feb;
  --tone-sentinel: #9d174d;
  --tone-sync: #0f766e;
  --tone-genie: #7c3aed;
  --tone-engineer: #0f766e;
  --tone-lab: #a16207;
  --tone-godmode: #b91c1c;
  --tone-class: #4f46e5;
  --tone-unity: #0891b2;

  --shadow-card: 0 1px 2px rgb(16 23 29 / 5%), 0 10px 30px -14px rgb(16 23 29 / 18%);
}

/* ══ scheme: operations — dark ═════════════════════════════════════════════ */
:root[data-scheme="operations"][data-mode="dark"] {
  color-scheme: dark;

  --canvas: #0b1015;
  --surface: #121a22;
  --surface-muted: #17212b;
  --surface-sunken: #0e151c;
  --line: #1e2a35;
  --line-strong: #2b3a48;

  --ink: #e6edf3;
  --ink-soft: #a9b8c6;
  --ink-faint: #78899a;

  --brand: #2f81f7;
  --brand-soft: #16243a;
  --brand-ink: #ffffff;
  --brand-ring: #1f4468;

  --ok: #3fb950;
  --ok-soft: #12261a;
  --info: #58a6ff;
  --info-soft: #14202e;
  --bad: #f85149;
  --bad-soft: #2d1615;
  --attention: #d29922;
  --attention-soft: #2a2110;
  --unknown: #8b949e;
  --unknown-soft: #1a222b;

  --tone-its: #7ee787;
  --tone-tix: #79c0ff;
  --tone-sentinel: #ff7b72;
  --tone-sync: #56d4dd;
  --tone-genie: #d0bcff;
  --tone-engineer: #5eead4;
  --tone-lab: #fbbf24;
  --tone-godmode: #fca5a5;
  --tone-class: #a5b4fc;
  --tone-unity: #67e8f9;

  --shadow-card: 0 1px 2px rgb(0 0 0 / 34%), 0 12px 32px -14px rgb(0 0 0 / 62%);
}

@media (prefers-color-scheme: dark) {
  :root[data-scheme="operations"]:not([data-mode="light"]) {
    color-scheme: dark;

    --canvas: #0b1015;
    --surface: #121a22;
    --surface-muted: #17212b;
    --surface-sunken: #0e151c;
    --line: #1e2a35;
    --line-strong: #2b3a48;

    --ink: #e6edf3;
    --ink-soft: #a9b8c6;
    --ink-faint: #78899a;

    --brand: #2f81f7;
    --brand-soft: #16243a;
    --brand-ink: #ffffff;
    --brand-ring: #1f4468;

    --ok: #3fb950;
    --ok-soft: #12261a;
    --info: #58a6ff;
    --info-soft: #14202e;
    --bad: #f85149;
    --bad-soft: #2d1615;
    --attention: #d29922;
    --attention-soft: #2a2110;
    --unknown: #8b949e;
    --unknown-soft: #1a222b;

    --tone-its: #7ee787;
    --tone-tix: #79c0ff;
    --tone-sentinel: #ff7b72;
    --tone-sync: #56d4dd;
    --tone-genie: #d0bcff;
    --tone-engineer: #5eead4;
    --tone-lab: #fbbf24;
    --tone-godmode: #fca5a5;
    --tone-class: #a5b4fc;
    --tone-unity: #67e8f9;

    --shadow-card: 0 1px 2px rgb(0 0 0 / 34%), 0 12px 32px -14px rgb(0 0 0 / 62%);
  }
}

/* ══ scheme: soc — light (cool neutrals, cyan brand) ══════════════════════
 * The security-operations console's own scheme: Sentinel. Deep navy in the dark,
 * a cool near-white in the light, and a cyan brand that means "this is the SOC"
 * the way violet means the desk and blue means operations. Modelled on the
 * open-source SIEM consoles (UTMStack and its neighbours), which is the visual
 * language somebody who works a security queue already reads without being told.
 */
:root[data-scheme="soc"] {
  color-scheme: light;

  --canvas: #f2f5f9;
  --surface: #ffffff;
  --surface-muted: #e9eff6;
  --surface-sunken: #dfe8f2;
  --line: #d3dfeb;
  --line-strong: #b3c4d6;

  --ink: #071a2b;
  --ink-soft: #37506a;
  --ink-faint: #5d7691;

  --brand: #0f6fd1;
  --brand-soft: #e0edfb;
  --brand-ink: #ffffff;
  --brand-ring: #93c0ea;

  --ok: #0d6b46;
  --ok-soft: #e2f5eb;
  --info: #0f6fd1;
  --info-soft: #e0edfb;
  --bad: #b3252b;
  --bad-soft: #fdeaea;
  --attention: #8a5a00;
  --attention-soft: #fdf2da;
  --unknown: #64748b;
  --unknown-soft: #edf1f6;

  --tone-its: #4d6b00;
  --tone-tix: #0f6fd1;
  --tone-sentinel: #0e7f9c;
  --tone-sync: #0f766e;
  --tone-genie: #7c3aed;
  --tone-engineer: #0f766e;
  --tone-lab: #b45309;
  --tone-godmode: #b91c1c;
  --tone-class: #4f46e5;
  --tone-unity: #0891b2;

  --shadow-card: 0 1px 2px rgb(7 26 43 / 5%), 0 10px 30px -14px rgb(7 26 43 / 18%);
}

/* ══ scheme: soc — dark (near-black navy, cyan) ═══════════════════════════ */
:root[data-scheme="soc"][data-mode="dark"] {
  color-scheme: dark;

  --canvas: #04080f;
  --surface: #0a1420;
  --surface-muted: #0f1c2b;
  --surface-sunken: #060d17;
  --line: #16273a;
  --line-strong: #23405c;

  --ink: #e6f2fb;
  --ink-soft: #a6c1d8;
  --ink-faint: #7590aa;

  --brand: #22c7e0;
  --brand-soft: #0a2c36;
  --brand-ink: #04161d;
  --brand-ring: #17788c;

  --ok: #3ad77f;
  --ok-soft: #0d2a1b;
  --info: #4cc6ff;
  --info-soft: #0c2437;
  --bad: #ff5f6d;
  --bad-soft: #33141a;
  --attention: #ffbb4d;
  --attention-soft: #33260f;
  --unknown: #7b93ad;
  --unknown-soft: #131f2c;

  --tone-its: #7ee787;
  --tone-tix: #6cb6ff;
  --tone-sentinel: #4fd0e8;
  --tone-sync: #56d4dd;
  --tone-genie: #d0bcff;
  --tone-engineer: #5eead4;
  --tone-lab: #fbbf24;
  --tone-godmode: #fda4af;
  --tone-class: #a5b4fc;
  --tone-unity: #67e8f9;

  --shadow-card: 0 1px 2px rgb(0 0 0 / 40%), 0 14px 34px -14px rgb(0 0 0 / 70%);
  --shadow-pop: 0 10px 34px -8px rgb(0 0 0 / 70%);
}

@media (prefers-color-scheme: dark) {
  :root[data-scheme="soc"]:not([data-mode="light"]) {
    color-scheme: dark;

    --canvas: #04080f;
    --surface: #0a1420;
    --surface-muted: #0f1c2b;
    --surface-sunken: #060d17;
    --line: #16273a;
    --line-strong: #23405c;

    --ink: #e6f2fb;
    --ink-soft: #a6c1d8;
    --ink-faint: #7590aa;

    --brand: #22c7e0;
    --brand-soft: #0a2c36;
    --brand-ink: #04161d;
    --brand-ring: #17788c;

    --ok: #3ad77f;
    --ok-soft: #0d2a1b;
    --info: #4cc6ff;
    --info-soft: #0c2437;
    --bad: #ff5f6d;
    --bad-soft: #33141a;
    --attention: #ffbb4d;
    --attention-soft: #33260f;
    --unknown: #7b93ad;
    --unknown-soft: #131f2c;

    --tone-its: #7ee787;
    --tone-tix: #6cb6ff;
    --tone-sentinel: #4fd0e8;
    --tone-sync: #56d4dd;
    --tone-genie: #d0bcff;
    --tone-engineer: #5eead4;
    --tone-lab: #fbbf24;
    --tone-godmode: #fda4af;
    --tone-class: #a5b4fc;
    --tone-unity: #67e8f9;

    --shadow-card: 0 1px 2px rgb(0 0 0 / 40%), 0 14px 34px -14px rgb(0 0 0 / 70%);
    --shadow-pop: 0 10px 34px -8px rgb(0 0 0 / 70%);
  }
}

/* ══ the shared primitives ═════════════════════════════════════════════════
 * Small, opinionated, and the same in every product: a surface, a button, a field,
 * a pill and a table. Everything else is a product's own layout, built out of
 * these, so two apps cannot drift in ways nobody notices until somebody has to
 * use both.
 */

.ot-surface {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.ot-panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.ot-panel > header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-muted);
}
.ot-panel > header h2 {
  margin: 0;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.ot-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--surface-muted);
  color: var(--ink);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 7px 12px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
}
.ot-btn:hover:not(:disabled) { border-color: var(--brand-ring); }
.ot-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.ot-btn--primary {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--brand-ink);
  font-weight: 600;
}
.ot-btn--quiet { background: transparent; }

.ot-field > span {
  display: block;
  font-size: 12px;
  color: var(--ink-soft);
  margin-bottom: 4px;
}
.ot-field input,
.ot-field select,
.ot-input {
  width: 100%;
  background: var(--surface-sunken);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--ink);
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
}
.ot-input:focus, .ot-field input:focus, .ot-field select:focus {
  outline: 2px solid var(--brand-ring);
  outline-offset: 1px;
  border-color: var(--brand);
}

.ot-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: var(--surface-muted);
  color: var(--ink-soft);
  padding: 2px 10px;
  font-size: 11.5px;
  white-space: nowrap;
}
.ot-pill--ok { border-color: var(--ok); color: var(--ok); background: var(--ok-soft); }
.ot-pill--bad { border-color: var(--bad); color: var(--bad); background: var(--bad-soft); }
.ot-pill--attention { border-color: var(--attention); color: var(--attention); background: var(--attention-soft); }
.ot-pill--unknown { border-color: var(--unknown); color: var(--unknown); background: var(--unknown-soft); }
.ot-pill--brand { border-color: var(--brand); color: var(--brand); background: var(--brand-soft); }

.ot-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--unknown); flex: none; }
.ot-dot--ok { background: var(--ok); }
.ot-dot--bad { background: var(--bad); }
.ot-dot--attention { background: var(--attention); }

.ot-table { width: 100%; border-collapse: collapse; }
.ot-table th, .ot-table td {
  text-align: left;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
  font-size: 13px;
}
.ot-table th {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  font-weight: 600;
  background: var(--surface-muted);
}
.ot-table tbody tr:last-child td { border-bottom: none; }
.ot-table tbody tr:hover { background: var(--surface-muted); }

.ot-note {
  border-left: 3px solid var(--line-strong);
  background: var(--surface-muted);
  color: var(--ink-soft);
  padding: 9px 12px;
  font-size: 12.5px;
  border-radius: 0 6px 6px 0;
}
.ot-note--warn { border-left-color: var(--attention); background: var(--attention-soft); color: var(--ink); }
.ot-note--bad { border-left-color: var(--bad); background: var(--bad-soft); color: var(--ink); }
.ot-note--ok { border-left-color: var(--ok); background: var(--ok-soft); color: var(--ink); }

.ot-muted { color: var(--ink-faint); }
.ot-dim { color: var(--ink-soft); }
.ot-mono { font-family: var(--mono); font-size: 12.5px; }
.ot-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/* ── the theme switch ──────────────────────────────────────────────────────
 * The control that flips light → dark → system. It lives here rather than in each
 * product's stylesheet because a switch that looks different in each of five apps
 * is precisely the drift this file exists to prevent, and because the markup is
 * the same everywhere: a group of buttons that call `window.OntrakTheme`.
 *
 * A product drops its <ThemeToggle> into its masthead and gets these styles; it
 * does not restyle them.
 */
.ot-theme {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  background: var(--surface-muted);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 2px;
}
.ot-theme button {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--ink-faint);
  border-radius: var(--radius-pill);
  padding: 4px 9px;
  font: inherit;
  font-size: 11.5px;
  cursor: pointer;
}
.ot-theme button:hover { color: var(--ink); }
.ot-theme button[aria-pressed="true"] {
  background: var(--surface);
  border-color: var(--line-strong);
  color: var(--ink);
  font-weight: 600;
}
.ot-theme svg { width: 13px; height: 13px; }

/* ── the front door ────────────────────────────────────────────────────────
 * The sign-in gate, the masthead above it and the footer below it — the page a
 * person is handed when they follow a link to a product they are not yet signed
 * in to. It lives here rather than in each product's stylesheet for the reason
 * `.ot-theme` does: nobody chooses which product they arrive at first, and six
 * front doors drawn six ways is drift that nothing fails on.
 *
 * A product brings two things of its own and nothing else. Its name, in the
 * wordmark, and its tone — `--tone-<product>` is where the mark's gradient lands,
 * which is why that token must exist in every scheme and every mode. The mark
 * itself is one silhouette everywhere, the shield, with the product's own stroke
 * inside it: the family is recognisable at a glance and the product is still
 * legible. `.masthead__mark` is the same shape at the masthead's size.
 */
.page {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 var(--space-5);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
.page__main { flex: 1; padding: var(--space-5) 0 var(--space-6); }

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 16px 0 14px;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
}
/* `text-decoration: none` is on the base rule rather than only on `:hover` because
   this is a link the browser would otherwise underline by default — and the two
   products that never reset anchors globally (Genie and Sentinel) were the ones
   showing it. The name is a wordmark here, not a link somebody is meant to click. */
.masthead__brand { display: flex; align-items: center; gap: 9px; color: var(--ink); text-decoration: none; }
.masthead__brand:hover { text-decoration: none; }
.masthead__brand strong {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.masthead__brand span {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-faint);
}
.masthead__mark { width: 30px; height: 30px; flex: none; }
.masthead__tools { display: flex; align-items: center; gap: 10px; }

.footer {
  padding: 16px 0 26px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  color: var(--ink-faint);
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* The gate: one centred card holding the mark, the name and the single control.
   A column with its own rhythm rather than a margin on each child, because the
   card also has to hold an error, or the sentence that says no provider is
   configured here, and the gap is what keeps it from looking collapsed in any of
   those cases. `width: 100%` because the product that wraps it in a centred flex
   row would otherwise shrink the card to its content. */
.gate {
  width: 100%;
  max-width: 420px;
  margin: 9vh auto 0;
  display: flex;
  flex-direction: column;
  gap: 22px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: 32px 28px 28px;
  text-align: center;
}
/* The mark and the name are one lockup, so they are one column: the shield above
   the words at every product, rather than beside them at one of them. */
.gate__mark-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}
.gate__mark {
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--ink);
}
.gate__mark span { color: var(--brand); }
.gate__mark-svg {
  width: 44px;
  height: 44px;
  flex: none;
  filter: drop-shadow(0 1px 1px rgb(0 0 0 / 12%));
}

/* An anchor, not a button: the handshake is a browser navigation, and fetching it
   is what breaks it. */
.sso-button {
  display: block;
  text-align: center;
  /* The same reset as the masthead's: an anchor is underlined by default, and this
     one is a button. Left to the products, two of the six drew it underlined. */
  text-decoration: none;
  background: var(--brand);
  border: 1px solid var(--brand);
  border-radius: var(--radius-sm);
  padding: 11px 13px;
  color: var(--brand-ink);
  font-weight: 650;
  font-size: 13.5px;
}
.sso-button:hover { text-decoration: none; filter: brightness(1.06); }

/* ══ liquid glass — the shared surface treatment ═════════════════════════════ */

/*
 * `.glass` is a pane; `.glass-strong` is a pane something is read *through*
 * (menus, dialogs, the composer while it is focused). They are utilities because
 * the treatment is the same everywhere: tint, hairline, sheen, lift, blur. A
 * product that wants a different radius overrides `--glass-radius` on the element
 * rather than redeclaring the four properties.
 *
 * `@supports` is not politeness: without `backdrop-filter` the tint would show the
 * canvas through it and text would sit on a moving background. The fallback is the
 * opaque surface, which is what a glass pane is pretending to be.
 */
.glass,
.glass-strong {
  position: relative;
  background: var(--glass-tint);
  border: 1px solid var(--glass-line);
  border-radius: var(--glass-radius);
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
}

/*
 * The sheen is a separate layer rather than a second background, because a pane's
 * children paint above its background but *below* a pseudo-element only when it is
 * positioned — this one is, and `pointer-events: none` keeps it out of the way of
 * the controls sitting on the pane.
 */
.glass::before,
.glass-strong::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--glass-sheen);
  pointer-events: none;
}

.glass-strong {
  background: var(--glass-tint-strong);
  box-shadow: var(--glass-shadow-pop);
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass,
  .glass-strong { background: var(--surface); }
}

/*
 * LIQUID — the canvas a glass pane needs
 *
 * Adopted from Genie, where the console chrome was rebuilt as glass. The material
 * itself is already here (the .glass primitives and the --glass-* tokens); what was
 * missing is the half that makes it read as glass rather than as a translucent
 * slab: a canvas with something on it. A pane blurred over one flat colour looks
 * flat.
 *
 * Two soft colour fields, fixed behind everything, one the product's own tone and
 * one the family brand. Both come from tokens, so a product opts in by putting
 * class="liquid" on its body and gets its own colours in all six rendered states
 * — no product writes a wash of its own.
 *
 * A system preference for less transparency wins over the effect: somebody who
 * asked for it gets the opaque surface, not a blurrier one.
 */
.liquid { background: var(--canvas); }
.liquid::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(
      760px 520px at 8% -12%,
      color-mix(in oklab, var(--brand) 22%, transparent),
      transparent 68%
    ),
    radial-gradient(
      720px 560px at 104% 112%,
      color-mix(in oklab, var(--tone, var(--brand)) 18%, transparent),
      transparent 70%
    ),
    var(--canvas);
}

@media (prefers-reduced-transparency: reduce) {
  .liquid::before { background: var(--canvas); }
  .glass,
  .glass-strong {
    background: var(--surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}
/* ══ the glass default ══════════════════════════════════════════════════════ */

/*
 * Unity ships the material, not only the tokens.
 *
 * The `.glass` utilities above are opt-in, which put the decision in each
 * product's markup: two of them painted their own opaque slabs and the family
 * stopped looking like one family. This block makes the shared primitives wear
 * the material by default, so a product picks up the look by using the primitive
 * it already uses for a panel or a dialog — no markup change, nothing to adopt.
 *
 * Nothing here reaches a product's own classes. A page that has not been
 * converted is unchanged; a page that uses `.ot-panel` or a dialog is glass from
 * the moment it loads. That is the whole of the rollout, and the reason it can be
 * one block instead of six pull requests.
 *
 * The two fallbacks are the same rules the utilities carry, kept in step with
 * them on purpose: no `backdrop-filter` means the opaque surface, and a person
 * who asked the system for less transparency means the same.
 */
.ot-panel,
dialog,
[role="dialog"] {
  background: var(--glass-tint);
  border-color: var(--glass-line);
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
}

/* A dialog is read *through*, so it gets the stronger tint the utility reserves
   for menus and focused composers. */
dialog,
[role="dialog"] {
  background: var(--glass-tint-strong);
  box-shadow: var(--glass-shadow-pop);
}

/* The page under it: one canvas, whatever the product's own body rule says. The
   colour is a token, so this is the light canvas in light mode and each scheme's
   own in dark — it is not a repaint. */
body {
  background-color: var(--canvas);
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .ot-panel,
  dialog,
  [role="dialog"] {
    background: var(--surface);
  }
}

@media (prefers-reduced-transparency: reduce) {
  .ot-panel,
  dialog,
  [role="dialog"] {
    background: var(--surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}
