/* Raidiam Status.
   =========================================================================
   Two surfaces share this sheet, deliberately.

   The public page is a document, read by a stranger during an outage on
   whatever connection and device they have. The console is a working tool,
   used by a handful of staff who are usually in a hurry for the same reason.
   They share the palette so that a state means the same thing in both, and
   they share nothing else: the document is narrow, calm and cacheable; the
   console is wide, dense and never cached.

   State colours are always namespaced to the element they colour. A bare
   `.state-x { color }` rule leaks onto anything carrying the class -- it once
   painted the banner's text the same colour as its own background, and there
   is a test that fails if it comes back. */

:root {
  --operational: #1f9d55;
  --degraded: #b7791f;
  --partial: #c05621;
  --major: #c53030;
  --maintenance: #2b6cb0;
  --unknown: #718096;

  /* The state colours above are the fills: bars and panel tints, which are
     graphical and need 3:1. The text tints below are the same states written
     as small type, which needs 4.5:1 against white -- #1f9d55 reaches 3.49 and
     #b7791f 3.64, so using the fill colour for a 13px label fails AA on the
     one page that has to be legible during an incident. Dark mode already
     clears 4.5:1 on every state, so it reuses its own values. */
  --operational-text: #15803d;
  --degraded-text: #7c5800;
  --partial-text: #9a3412;
  --major-text: #b91c1c;
  --maintenance-text: #2b6cb0;
  --unknown-text: #5f6c7d;

  --ink: #10151f;
  --quiet: #5f6c7d;
  --rule: #e3e8ef;
  --rule-strong: #cbd4e1;
  /* The canvas is tinted and the surfaces are white, so a card is a card
     because it is lighter than what is behind it rather than because it has
     a border drawn round it. On the console, where a screen can hold thirty
     of them, that is the difference between structure and a grid of boxes. */
  --canvas: #f4f6f9;
  --bg: #ffffff;
  --surface: #ffffff;
  --surface-sunk: #f7f9fb;
  --accent: #1a4fd6;
  --accent-ink: #ffffff;

  --shadow-sm: 0 1px 2px rgb(16 21 31 / 6%), 0 1px 1px rgb(16 21 31 / 4%);
  --shadow-md: 0 2px 4px rgb(16 21 31 / 5%), 0 4px 12px rgb(16 21 31 / 6%);

  --r-sm: .3125rem;
  --r-md: .5rem;
  --r-lg: .75rem;

  /* The focus ring is its own colour rather than a state colour: it has to
     stay visible against every panel on the page, including the tinted
     outage banner. */
  --focus: #1a4fd6;
}

/* Dark mode arrives two ways, and the values have to be identical either way.
   CSS cannot OR a media query with a selector, so the block below is written
   out twice: once for a reader who has expressed no preference and is
   following their system, and once for a reader who has chosen dark
   explicitly. A test compares the two and fails if they drift -- which is the
   failure this duplication would otherwise cause, silently, the first time
   someone adjusts a colour in one of them.

   The `:not([data-theme="light"])` is what lets an explicit light choice win
   against a dark system setting. Without it the media query would keep
   overriding the reader. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --operational: #48bb78;
    --degraded: #ecc94b;
    --partial: #ed8936;
    --major: #fc8181;
    --maintenance: #63b3ed;
    --unknown: #a0aec0;

    --operational-text: #48bb78;
    --degraded-text: #ecc94b;
    --partial-text: #ed8936;
    --major-text: #fc8181;
    --maintenance-text: #63b3ed;
    --unknown-text: #a0aec0;

    --ink: #eef2f7;
    --quiet: #9aa7b8;
    --rule: #262c3a;
    --rule-strong: #38414f;
    --canvas: #0f1219;
    --bg: #161a23;
    --surface: #1a1f2b;
    --surface-sunk: #141823;
    --accent: #7aa7ff;
    --accent-ink: #0f1219;

    --shadow-sm: 0 1px 2px rgb(0 0 0 / 40%);
    --shadow-md: 0 2px 4px rgb(0 0 0 / 35%), 0 8px 20px rgb(0 0 0 / 30%);

    --focus: #90cdf4;
  }
}
:root[data-theme="dark"] {
    --operational: #48bb78;
    --degraded: #ecc94b;
    --partial: #ed8936;
    --major: #fc8181;
    --maintenance: #63b3ed;
    --unknown: #a0aec0;

    --operational-text: #48bb78;
    --degraded-text: #ecc94b;
    --partial-text: #ed8936;
    --major-text: #fc8181;
    --maintenance-text: #63b3ed;
    --unknown-text: #a0aec0;

    --ink: #eef2f7;
    --quiet: #9aa7b8;
    --rule: #262c3a;
    --rule-strong: #38414f;
    --canvas: #0f1219;
    --bg: #161a23;
    --surface: #1a1f2b;
    --surface-sunk: #141823;
    --accent: #7aa7ff;
    --accent-ink: #0f1219;

    --shadow-sm: 0 1px 2px rgb(0 0 0 / 40%);
    --shadow-md: 0 2px 4px rgb(0 0 0 / 35%), 0 8px 20px rgb(0 0 0 / 30%);

    --focus: #90cdf4;
}

/* Native controls -- form fields, scrollbars, date pickers -- follow this
   rather than our custom properties. Left unset, a dark page renders a white
   scrollbar and a light select, which is the giveaway that a theme was
   painted on rather than declared. */
:root { color-scheme: light dark; }
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

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

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font: 16px/1.55 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 { letter-spacing: -.012em; line-height: 1.25; }
h1 { font-size: 1.625rem; margin: 0 0 1.25rem; font-weight: 650; }
h2 { font-size: 1.1875rem; font-weight: 640; }
h3 { font-size: 1rem; font-weight: 640; }
a { color: inherit; }
a:hover { text-decoration-thickness: 2px; }

/* The public document sits on a white sheet floating over the tinted canvas;
   the console spans the canvas itself, because it is a workspace rather than
   a page. */
.wrap {
  max-width: 50rem;
  margin: 2rem auto;
  padding: 2.25rem 2rem 2.75rem;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-md);
}
@media (max-width: 40rem) {
  .wrap { margin: 0; border: 0; border-radius: 0; box-shadow: none; padding: 1.5rem 1.125rem 2rem; }
}

/* ------------------------------------------------------------- banner -- */

.banner {
  display: flex;
  align-items: center;
  gap: .75rem;
  border: 1px solid;
  border-radius: var(--r-md);
  padding: 1rem 1.125rem;
  margin-bottom: 2rem;
}
.banner h2 { margin: 0; font-size: 1.0625rem; font-weight: 640; }
.banner .dot {
  flex: none;
  width: .625rem;
  height: .625rem;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 0 .25rem color-mix(in srgb, currentColor 18%, transparent);
}
/* Tinted panel rather than a solid slab: the text stays high-contrast
   against the page background in both colour schemes, so there is no way for
   it to end up the same colour as its own fill. */
.banner.state-operational       { color: var(--operational-text); border-color: color-mix(in srgb, var(--operational) 45%, transparent); background: color-mix(in srgb, var(--operational) 10%, transparent); }
.banner.state-degraded          { color: var(--degraded-text);    border-color: color-mix(in srgb, var(--degraded) 45%, transparent);    background: color-mix(in srgb, var(--degraded) 10%, transparent); }
.banner.state-partial_outage    { color: var(--partial-text);     border-color: color-mix(in srgb, var(--partial) 45%, transparent);     background: color-mix(in srgb, var(--partial) 10%, transparent); }
.banner.state-major_outage      { color: var(--major-text);       border-color: color-mix(in srgb, var(--major) 45%, transparent);       background: color-mix(in srgb, var(--major) 10%, transparent); }
.banner.state-under_maintenance { color: var(--maintenance-text); border-color: color-mix(in srgb, var(--maintenance) 45%, transparent); background: color-mix(in srgb, var(--maintenance) 10%, transparent); }
.banner.state-unknown           { color: var(--unknown-text);     border-color: color-mix(in srgb, var(--unknown) 45%, transparent);     background: color-mix(in srgb, var(--unknown) 10%, transparent); }

/* --------------------------------------------------------- components -- */

.component { border-top: 1px solid var(--rule); padding: 1rem 0; }
.component:first-child { border-top: 0; padding-top: .25rem; }
/* The rail is what makes a child a child. Indentation alone leaves a reader
   inferring the hierarchy from whitespace, and at three levels that stops
   working. */
.component .children {
  margin-left: .5rem;
  padding-left: 1.125rem;
  border-left: 2px solid var(--rule);
}
.component .children .component { border-top: 0; padding: .625rem 0; }
.row { display: flex; align-items: baseline; gap: .75rem; }
.name { font-weight: 620; }
.state-label { margin-left: auto; font-size: .8125rem; font-weight: 550; white-space: nowrap; }
.state-label.state-operational       { color: var(--operational-text); }
.state-label.state-degraded          { color: var(--degraded-text); }
.state-label.state-partial_outage    { color: var(--partial-text); }
.state-label.state-major_outage      { color: var(--major-text); }
.state-label.state-under_maintenance { color: var(--maintenance-text); }
.state-label.state-unknown           { color: var(--unknown-text); }

.delayed {
  font-size: .6875rem;
  color: var(--quiet);
  background: var(--surface-sunk);
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: .0625rem .5rem;
  white-space: nowrap;
}

/* ------------------------------------------------------------ history -- */

.history svg { width: 100%; height: 34px; display: block; margin-top: .625rem; }
rect.bar { fill: var(--operational); }
rect.bar.state-degraded          { fill: var(--degraded); }
rect.bar.state-partial_outage    { fill: var(--partial); }
rect.bar.state-major_outage      { fill: var(--major); }
rect.bar.state-under_maintenance { fill: var(--maintenance); }
rect.bar.state-unknown, rect.bar.no-data { fill: var(--rule-strong); }

.history .scale {
  display: flex;
  justify-content: space-between;
  color: var(--quiet);
  font-size: .75rem;
  margin: .375rem 0 0;
}
/* The marker under a bar that is not a clean, observed period: the chart's
   meaning must not depend on hue alone. */
rect.mark { fill: var(--ink); }
.bars-note { margin: .375rem 0 0; }

/* ---------------------------------------------------------- incidents -- */

.quiet { color: var(--quiet); font-size: .8125rem; }
.meta  { color: var(--quiet); font-size: .8125rem; }
.incident { border-top: 1px solid var(--rule); padding: 1.125rem 0; }
.incident h3 { margin: 0 0 .375rem; font-size: 1rem; }
.badge {
  display: inline-block;
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  padding: .0625rem .5rem;
  margin-right: .375rem;
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .03em;
  color: var(--quiet);
  white-space: nowrap;
  vertical-align: .0625rem;
}
/* The impact class was already on every incident article and had never been
   drawn. A list of incidents where a CRITICAL and a MINOR look identical
   makes the reader open both to find out which mattered. */
.incident.impact-critical, .incident.impact-major,
.incident.impact-minor, .incident.impact-none {
  border-left: 3px solid var(--rule-strong);
  padding-left: .875rem;
}
.incident.impact-critical { border-left-color: var(--major); }
.incident.impact-major    { border-left-color: var(--partial); }
.incident.impact-minor    { border-left-color: var(--degraded); }
.incident.impact-none     { border-left-color: var(--rule-strong); }

.update {
  border-left: 2px solid var(--rule);
  padding-left: .875rem;
  margin-top: .875rem;
}
.update p { margin: .25rem 0 0; }
footer { margin-top: 2.5rem; border-top: 1px solid var(--rule); padding-top: 1rem; }

/* The section navigation. Plain links in a list, so the pages are reachable
   from each other without JavaScript and a screen reader can list them. */
ul.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem;
  list-style: none;
  padding: .25rem;
  margin: 0 0 1.75rem;
  font-size: .875rem;
  background: var(--surface-sunk);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
}
ul.site-nav a {
  display: block;
  padding: .3125rem .75rem;
  border-radius: var(--r-sm);
  text-decoration: none;
  color: var(--quiet);
  font-weight: 550;
}
ul.site-nav a:hover { background: var(--bg); color: var(--ink); }
ul.site-nav a[aria-current] { background: var(--bg); color: var(--ink); box-shadow: var(--shadow-sm); }
header h1 { margin-bottom: .875rem; }
header h1 a { text-decoration: none; }
header h1 a:hover { text-decoration: underline; }
/* A subtitle sitting directly under the page title, not a section heading:
   the markup has to stay an h2 so the heading ladder is unbroken, but it
   should not read with a section's weight. */
header h1 + h2 { margin: -.5rem 0 1rem; font-size: 1rem; font-weight: 550; color: var(--quiet); }

/* The uptime window switch. Plain links, because switching window must work
   with JavaScript disabled -- the same reason the page itself is rendered
   server-side. */
.window-switch {
  display: flex;
  gap: .75rem;
  margin: 0 0 1rem;
  font-size: .8125rem;
  color: var(--quiet);
}
.window-switch [aria-current] { font-weight: 640; color: var(--ink); }

/* "Load older incidents" is a link that htmx happens to intercept, so it is
   styled as the control it looks like rather than inheriting link colour. */
a.load-more {
  display: inline-block;
  font-size: .875rem;
  font-weight: 550;
  color: var(--accent);
  text-decoration: underline;
  margin-top: 1rem;
}

/* ------------------------------------------------------------- forms -- */

form.stack { display: flex; flex-direction: column; gap: .875rem; max-width: 36rem; margin-top: .875rem; }
form.stack label { display: flex; flex-direction: column; gap: .3125rem; font-size: .8125rem; font-weight: 620; }
form.stack label.check { flex-direction: row; align-items: flex-start; gap: .5rem; font-weight: 400; font-size: .875rem; }
form.stack label.check input { margin-top: .1875rem; }
form.stack small { font-weight: 400; line-height: 1.45; }
form.stack input[type=text], form.stack input:not([type]),
form.stack input[type=url], form.stack input[type=number],
form.stack input[type=date], form.stack input[type=datetime-local],
form.stack input[type=email], form.stack select, form.stack textarea {
  font: inherit;
  font-size: .9375rem;
  padding: .4375rem .625rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-sm);
  background: var(--bg);
  color: var(--ink);
  width: 100%;
}
form.stack textarea { resize: vertical; line-height: 1.5; }
form.stack input:focus, form.stack select:focus, form.stack textarea:focus { border-color: var(--accent); }
form.stack fieldset {
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  padding: .875rem 1rem;
  background: var(--surface-sunk);
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
form.stack legend { font-size: .8125rem; font-weight: 640; padding: 0 .375rem; }

/* One button treatment across both surfaces. A form's submit is the primary
   action; anything destructive says so in its own colour rather than looking
   identical to Save until it is pressed. */
button, form.stack button[type=submit] {
  font: inherit;
  font-size: .875rem;
  font-weight: 600;
  padding: .4375rem 1rem;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: var(--accent-ink);
  cursor: pointer;
}
button:hover { filter: brightness(1.08); }
form.stack button[type=submit] { align-self: flex-start; }
button.danger, form.stack button.danger[type=submit] {
  background: var(--major);
  color: #fff;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) button.danger,
  :root:not([data-theme="light"]) form.stack button.danger[type=submit] { color: #1a0505; }
}
:root[data-theme="dark"] button.danger,
:root[data-theme="dark"] form.stack button.danger[type=submit] { color: #1a0505; }

/* A control that is a link in everything but markup: it posts a form, so it
   has to be a button, but it belongs in a row of links. */
button.link {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: inherit;
  font-weight: 550;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}
button.link:hover { filter: none; text-decoration-thickness: 2px; }
button.link.danger { background: none; color: var(--major-text); }

.form-error {
  border: 1px solid color-mix(in srgb, var(--major) 55%, transparent);
  border-left-width: 3px;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--major) 10%, transparent);
  color: var(--major-text);
  padding: .75rem 1rem;
  margin: 0 0 1.5rem;
}
.warn { color: var(--partial-text); font-size: .8125rem; }

/* The outcome of a form submission, carried through the redirect. */
.notice {
  border: 1px solid var(--rule);
  border-left: 3px solid var(--operational);
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--operational) 7%, transparent);
  padding: .75rem 1rem;
  margin: 0 0 1.5rem;
}
.form-notice {
  border: 1px solid color-mix(in srgb, var(--maintenance) 50%, transparent);
  border-left-width: 3px;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--maintenance) 10%, transparent);
  padding: .75rem 1rem;
  margin: 0 0 1rem;
}
label.inline { display: inline; font-weight: 400; }

/* Nested component checkboxes on the subscribe form: a tree, not bullets. */
ul.plain { list-style: none; padding-left: 1rem; margin: .25rem 0; }
ul.plain > li { margin: .125rem 0; }

details { margin-top: .75rem; }
summary { cursor: pointer; font-size: .875rem; font-weight: 550; color: var(--accent); }
summary::marker { color: var(--quiet); }

/* ======================================================= administration ==
   The console shares the palette so a state means the same thing in both
   places, but it is a working surface rather than a document: wider, denser,
   and never cached. */

body.admin { background: var(--canvas); }

/* The brand bar is fixed furniture. It exists so that every console page says
   where you are before you have read anything on it, and so "back to the
   index" is always in the same place rather than being the first of a row of
   links that differs page to page. */
.brandbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .625rem 1.5rem;
  background: var(--surface);
  border-bottom: 1px solid var(--rule);
  box-shadow: var(--shadow-sm);
}
.brandbar .brand {
  font-weight: 700;
  letter-spacing: -.02em;
  text-decoration: none;
  font-size: .9375rem;
}
.brandbar .brand span { color: var(--accent); }
.brandbar .env {
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--quiet);
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  padding: .0625rem .5rem;
}

.wrap.wide {
  max-width: 74rem;
  margin: 1.5rem auto 4rem;
  padding: 0 1.5rem;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* Breadcrumbs, not a row of assorted links. The console's whole difficulty is
   that a monitor lives in a component, in a page, in a tenant, and the old
   header gave no way to tell which of those you were looking at. */
nav.crumbs { margin: 0 0 .625rem; font-size: .8125rem; }
nav.crumbs ol { list-style: none; display: flex; flex-wrap: wrap; align-items: center; gap: .375rem; margin: 0; padding: 0; }
nav.crumbs li { display: flex; align-items: center; gap: .375rem; color: var(--quiet); }
nav.crumbs li + li::before { content: "/"; color: var(--rule-strong); }
nav.crumbs a { color: var(--quiet); text-decoration: none; font-weight: 550; }
nav.crumbs a:hover { color: var(--ink); text-decoration: underline; }
nav.crumbs [aria-current] { color: var(--ink); font-weight: 620; }

.page-head { margin-bottom: 1.5rem; }
.page-head-row { display: flex; align-items: flex-start; gap: 1rem; flex-wrap: wrap; }
.page-head-row h1 { margin: 0; flex: 1 1 18rem; }
.page-head .sub { margin: .375rem 0 0; }

.admin .ident { display: flex; align-items: center; gap: .625rem; flex-wrap: wrap; }
.admin .ident form { display: inline; margin: 0; }

.admin section { margin-bottom: 2.25rem; }
.admin h3 { margin: 0 0 .25rem; }

/* A panel is the console's unit of content: a titled surface. Sections used
   to be separated by nothing but vertical space, so a long page read as one
   undifferentiated column of forms. */
.panel {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  padding: 1.25rem 1.375rem;
}
.panel > h2 { margin: 0 0 .25rem; }
.panel > h2 + .quiet { margin-top: 0; }

/* The console's own section navigation. Without JavaScript these are anchor
   links to sections that are all present; the script turns them into tabs
   that show one at a time. Either way every section is reachable. */
.console-nav {
  display: flex;
  gap: .25rem;
  flex-wrap: wrap;
  list-style: none;
  margin: 0 0 1.5rem;
  padding: .25rem;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  font-size: .875rem;
}
.console-nav a {
  display: block;
  padding: .375rem .875rem;
  border-radius: var(--r-sm);
  text-decoration: none;
  color: var(--quiet);
  font-weight: 600;
}
.console-nav a:hover { background: var(--surface-sunk); color: var(--ink); }
.console-nav a[aria-current] { background: var(--accent); color: var(--accent-ink); }

/* The shape of the page, counted. A component with no monitor is the item
   worth leading with: it renders green for ever whatever happens to the thing
   it claims to represent, and it is invisible in a list. */
.stats { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0 0 1.25rem; padding: 0; list-style: none; }
.stat {
  display: flex;
  align-items: baseline;
  gap: .4375rem;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: .25rem .875rem;
  font-size: .8125rem;
  color: var(--quiet);
  box-shadow: var(--shadow-sm);
}
.stat b { font-size: .9375rem; font-weight: 680; color: var(--ink); }
.stat.attention { border-color: color-mix(in srgb, var(--partial) 55%, transparent); background: color-mix(in srgb, var(--partial) 9%, transparent); color: var(--partial-text); }
.stat.attention b { color: var(--partial-text); }

/* ------------------------------------------------------- component tree -- */

/* The tree is the whole point of this surface. A page owns components, a
   component owns components and monitors, and a monitor is the only thing
   that can actually change a state. The old console rendered that as a flat
   list of articles with a depth-N left margin, which is a picture of
   indentation rather than a picture of ownership. */
ul.tree, ul.tree ul { list-style: none; margin: 0; padding: 0; }
ul.tree ul.tree {
  margin: .5rem 0 0 1.25rem;
  padding-left: 1.5rem;
  border-left: 2px solid var(--accent);
  border-image: linear-gradient(var(--accent), color-mix(in srgb, var(--accent) 25%, transparent)) 1;
}
ul.tree > li { margin: 0 0 .75rem; position: relative; }
ul.tree ul.tree > li::before {
  /* The elbow joining a child to its parent's rail. */
  content: "";
  position: absolute;
  left: -1.5rem;
  top: 1.4375rem;
  width: 1.25rem;
  height: 2px;
  background: color-mix(in srgb, var(--accent) 55%, transparent);
}

.node-card {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
/* A component holding an override is lying to the public on purpose. It says
   so on its own edge, not only in a badge that scrolls away. */
.node-card.is-overridden { border-left: 3px solid var(--degraded); }
.node-card.is-unmonitored { border-left: 3px solid var(--rule-strong); }

.node-head {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .75rem 1rem;
  flex-wrap: wrap;
}
.node-head .node-title { font-weight: 640; font-size: .9375rem; }
.node-head .spacer { flex: 1 1 auto; }

/* The disclosure toggle. It is a real <button> only when the script is
   present; without it the markup is a plain span and everything is open. */
.node-toggle {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-sm);
  background: var(--surface-sunk);
  color: var(--ink);
  font-size: .8125rem;
  line-height: 1;
  padding: 0;
  cursor: pointer;
}
.node-toggle:hover { background: var(--rule); filter: none; }
.node-toggle::before { content: "\25BE"; }
[data-collapsed="true"] > .node-head .node-toggle::before { content: "\25B8"; }
[data-collapsed="true"] > .node-body,
[data-collapsed="true"] + ul.tree { display: none; }

.node-body { border-top: 1px solid var(--rule); padding: .75rem 1rem 1rem; background: var(--surface-sunk); }

/* A row of actions, not a paragraph of links squeezed together. */
.toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: .625rem; font-size: .8125rem; }
.toolbar form { display: inline; margin: 0; }
.toolbar a { color: var(--accent); text-decoration: none; font-weight: 550; }
.toolbar a:hover { text-decoration: underline; }
.toolbar .sep { color: var(--rule-strong); }
.move-group { display: inline-flex; gap: .1875rem; }
.move-group button {
  background: var(--surface-sunk);
  border: 1px solid var(--rule-strong);
  color: var(--quiet);
  padding: .0625rem .4375rem;
  font-size: .75rem;
  text-decoration: none;
}
.move-group button:hover { color: var(--ink); filter: none; }

/* ----------------------------------------------------------- monitors -- */

/* Monitors are rendered as the leaves they are: inside the component that
   owns them, marked so they cannot be mistaken for a nested component. */
ul.monitors { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .375rem; }
li.monitor {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
  font-size: .8125rem;
}
li.monitor.is-paused { background: var(--surface-sunk); }
.monitor-row {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  padding: .5rem .75rem;
}
.monitor-row .mon-name { font-weight: 620; font-size: .875rem; }
li.monitor.is-paused .mon-name { color: var(--quiet); }
.monitor-row .mon-target {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .75rem;
  color: var(--quiet);
  overflow-wrap: anywhere;
  /* Its own line below the name and chips. Sharing the row meant a long mTLS
     URL wrapped into three lines and shoved the controls out of alignment
     with every other monitor on the page. */
  flex: 1 0 100%;
  order: 2;
  min-width: 0;
}
.monitor-row .mon-actions { display: flex; gap: .625rem; align-items: center; margin-left: auto; white-space: nowrap; order: 1; }
.monitor-row .mon-actions form { display: inline; margin: 0; }
/* The monitor's own settings, folded under the row it belongs to rather than
   collected into a list of drawers all called "Edit". */
details.mon-edit { margin: 0; border-top: 1px solid var(--rule); }
details.mon-edit > summary { padding: .375rem .75rem; font-size: .75rem; }
details.mon-edit[open] > summary { border-bottom: 1px solid var(--rule); }
details.mon-edit .drawer-body { padding: .25rem .875rem 1rem; }

/* The chip carries a monitor's configuration at a glance -- kind, cadence,
   hubs -- because those three are what someone is checking when they open
   this page at all. */
.chip {
  display: inline-block;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-sm);
  padding: 0 .375rem;
  font-size: .6875rem;
  font-weight: 600;
  color: var(--quiet);
  white-space: nowrap;
}
.chip.kind-https_mtls { border-color: color-mix(in srgb, var(--maintenance) 55%, transparent); color: var(--maintenance-text); background: color-mix(in srgb, var(--maintenance) 9%, transparent); }
.chip.kind-cert_expiry { border-color: color-mix(in srgb, var(--degraded) 55%, transparent); color: var(--degraded-text); background: color-mix(in srgb, var(--degraded) 9%, transparent); }

/* The empty state that matters. A component with no monitor is a green light
   wired to nothing, so it is not an absence to be noted in grey -- it is the
   one thing on the page to act on. */
.no-monitors {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  border: 1px dashed var(--rule-strong);
  border-radius: var(--r-sm);
  padding: .625rem .875rem;
  font-size: .8125rem;
  color: var(--quiet);
  background: var(--surface);
}

/* Drawers. Every write the console can do is one of these: closed by default
   so the page is readable, open on click, working without script. */
.drawers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: .25rem;
  margin-top: .875rem;
  align-items: start;
}
/* An open drawer holds a form, so it takes the full width and leaves the
   closed ones packed alongside each other. */
.drawers details[open] { grid-column: 1 / -1; }
.drawers details { margin: 0; border: 1px solid var(--rule); border-radius: var(--r-sm); background: var(--surface); }
.drawers details[open] { box-shadow: var(--shadow-sm); }
.drawers summary { padding: .4375rem .625rem; font-size: .8125rem; list-style-position: inside; }
.drawers details[open] > summary { border-bottom: 1px solid var(--rule); }
.drawers .drawer-body { padding: .25rem .875rem 1rem; }
.drawers summary.danger { color: var(--major-text); }

.badge.excluded { color: var(--degraded-text); border-color: var(--degraded); background: color-mix(in srgb, var(--degraded) 10%, transparent); }

/* ------------------------------------------------------ lists & tables -- */

.tenant {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  padding: 1rem 1.125rem;
  margin-bottom: .875rem;
}
.tenant h3 { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }

ul.pages { list-style: none; padding: 0; margin: .75rem 0 0; display: flex; flex-direction: column; gap: .25rem; }
ul.pages li {
  padding: .5rem .75rem;
  display: flex;
  gap: .625rem;
  align-items: center;
  flex-wrap: wrap;
  background: var(--surface-sunk);
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
  font-size: .875rem;
}
ul.pages li a { font-weight: 620; }
ul.pages li form { display: inline; margin: 0; margin-left: auto; }

table.monitors, table.checks { width: 100%; border-collapse: collapse; margin-top: .75rem; font-size: .8125rem; }
table.monitors th, table.checks th {
  text-align: left;
  font-size: .6875rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--quiet);
  font-weight: 650;
}
table.monitors td, table.monitors th,
table.checks td, table.checks th { border-bottom: 1px solid var(--rule); padding: .4375rem .625rem .4375rem 0; vertical-align: top; }
table.checks tbody tr:hover { background: var(--surface-sunk); }
td.target, td.detail { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .75rem; overflow-wrap: anywhere; }
td.actions { white-space: nowrap; }
td.actions form { display: inline; margin-left: .75rem; }
.on  { color: var(--operational-text); font-weight: 600; }
.off { color: var(--quiet); }

tr.verdict-bad      td { color: var(--major-text); }
tr.verdict-degraded td { color: var(--degraded-text); }
tr.verdict-unknown  td { color: var(--quiet); }

.incident-admin {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  padding: 1rem 1.125rem;
  margin-bottom: .75rem;
}
.incident-admin.open { border-left: 3px solid var(--major); }
.incident-admin h3 { display: flex; align-items: center; gap: .375rem; flex-wrap: wrap; }

.controls { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; margin: .5rem 0; }
.controls form { display: inline; margin: 0; }

/* ------------------------------------------------------- filter (JS) -- */

/* Added by the script and removed with it: a console with forty components
   is unusable without a way to find one, and a console with four does not
   need a search box cluttering it. */
.tree-tools { display: none; gap: .625rem; align-items: center; flex-wrap: wrap; margin: 0 0 1rem; }
.tree-tools.ready { display: flex; }
.tree-tools input[type=search] {
  font: inherit;
  font-size: .875rem;
  padding: .375rem .625rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  min-width: 15rem;
}
.tree-tools button {
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  color: var(--quiet);
  font-size: .8125rem;
}
.tree-tools button:hover { color: var(--ink); filter: none; }
.tree-tools .count { font-size: .8125rem; color: var(--quiet); }
[hidden] { display: none !important; }

/* ------------------------------------------------------- api key issue -- */

/* The issued key is shown once, so it has to be selectable and unmistakable
   rather than styled like the rest of the table. */
code.token {
  display: inline-block;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .9375rem;
  overflow-wrap: anywhere;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-sm);
  padding: .625rem .75rem;
  background: var(--surface);
}

/* ------------------------------------------------ accessibility basics -- */

/* Content that exists for a screen reader and nothing else. Never
   display:none, which removes it from the accessibility tree as well. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The skip link is the first thing in the tab order on every page. A status
   page puts the component tree ahead of the incident someone came to read,
   and a keyboard user should not have to tab through ninety bars to reach
   it. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--bg);
  color: var(--ink);
  border: 2px solid var(--accent);
  border-radius: 0 0 var(--r-sm) 0;
  padding: .5rem .75rem;
  z-index: 100;
}
.skip-link:focus { left: 0; }

/* A visible focus ring everywhere, including on the elements whose default
   ring the resets above would have removed. Two pixels and an offset so it
   survives against both the light and the dark background. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: .125rem;
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ------------------------------------------------------- theme switch -- */

/* Three states, not two. A two-state toggle has to assume a starting point,
   and whichever it assumes is wrong for every reader whose system already
   says otherwise -- so "System" is a real option and it is the default.
   Rendered hidden and revealed by the script, because a theme control that
   cannot store a choice is a button that does nothing. */
.theme-switch {
  display: inline-flex;
  align-items: center;
  gap: .125rem;
  padding: .1875rem;
  background: var(--surface-sunk);
  border: 1px solid var(--rule);
  border-radius: 999px;
}
.theme-switch button {
  background: none;
  border: 0;
  border-radius: 999px;
  padding: .1875rem .5625rem;
  font-size: .75rem;
  font-weight: 600;
  color: var(--quiet);
  cursor: pointer;
}
.theme-switch button:hover { color: var(--ink); background: var(--bg); filter: none; }
.theme-switch button[aria-pressed="true"] {
  background: var(--bg);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}

/* On the public page the switch sits at the end of the section navigation,
   pushed to the trailing edge; on the console it sits in the brand bar. */
ul.site-nav .theme-switch { margin-left: auto; }
ul.site-nav li.nav-theme { margin-left: auto; display: flex; align-items: center; }
.brandbar .theme-switch { margin-left: auto; }

/* ---------------------------------------------------------- utilities -- */

/* A short list, kept short on purpose. These exist because a Content-Security
   Policy worth having cannot allow style-src 'unsafe-inline', and a style
   attribute is indistinguishable to the browser from one an injection wrote.
   Eight shortcuts in the console templates were the whole reason the policy
   would have needed that hole. */
.flush-top { margin-top: 0; }
.spaced-above { margin-top: 1.25rem; }
.spaced-above-sm { margin-top: .875rem; }
.tight-below { margin-bottom: .75rem; }
.full-width { max-width: none; }
form.inline { display: inline; margin: 0; }

/* ------------------------------------------------- client identities -- */

.certificate {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  padding: 1rem 1.125rem;
  margin-bottom: .875rem;
}
/* An identity with no certificate yet is not a problem, but it is unfinished
   work, and it cannot be given to a monitor. It reads as outstanding rather
   than as broken. */
.certificate.is-pending { border-left: 3px solid var(--degraded); }
.certificate h3 { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }

/* The three steps of issuance. Numbered because the order is the whole point:
   the request has to exist before a PKI can issue against it. */
ol.steps { margin: .75rem 0 0; padding-left: 1.25rem; font-size: .875rem; }
ol.steps li { margin: .375rem 0; }

/* A signing request, shown so it can be selected and copied. It is public
   material -- there is deliberately nothing here that needs hiding. */
pre.pem {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .75rem;
  line-height: 1.45;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  background: var(--surface-sunk);
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
  padding: .75rem .875rem;
  margin: .5rem 0 0;
}

/* Where a control used to be.
   The console kept every operational surface and lost the configuration ones,
   so a person who has used this before will look for a form that is no longer
   there. Saying what owns it now, in the place the form stood, is the whole
   point -- an absence explains nothing. */
.managed-note {
  margin: 0;
  padding: .75rem .875rem;
  border: 1px dashed var(--rule-strong);
  border-radius: var(--r-md);
  background: var(--surface-sunk);
  color: var(--quiet);
  font-size: .8125rem;
  line-height: 1.5;
}
.managed-note code {
  color: var(--ink);
}
