/* =====================================================================
   DEMANUS ID // account portal
   ---------------------------------------------------------------------
   The landing page at demanus.com is an eye that watches the visitor.
   This is the one room on the network where the instrument points the
   other way: it is where you decide what it, and every site behind it,
   is allowed to see.

   The palette is not invented here. Every value is lifted from the
   landing page's :root so the portal reads as a room inside the same
   building. --accent is the exception: it is re-tinted at runtime to the
   colour of whichever profile is currently forward, which makes the
   abstract idea (a profile is the face sites see) physically visible.
   ===================================================================== */

:root {
  /* inherited verbatim from the landing page */
  --cyan:       92, 232, 255;
  --cyan-deep:  23, 145, 255;
  --ice:        228, 249, 255;
  --steel:      132, 157, 171;
  --amber:      255, 187, 79;
  --red:        255, 58, 101;

  --void:  #00040a;
  --deep:  #020a12;
  --panel: #04101b;

  /* re-tinted from the active profile; the cyan is only the default */
  --accent: 92, 232, 255;

  --line:       rgba(var(--cyan), .13);
  --line-soft:  rgba(var(--steel), .16);
  --text:       rgb(var(--ice));
  --text-dim:   rgb(var(--steel));

  --display: 'Archivo', 'Archivo Expanded', 'Helvetica Neue', Arial, sans-serif;
  --body:    'IBM Plex Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono:    'IBM Plex Mono', ui-monospace, 'Cascadia Mono', 'Consolas', monospace;

  --gutter: clamp(1.25rem, 4vw, 3rem);
  --radius: 2px;   /* the landing page has no soft corners; neither does this */
}

* { box-sizing: border-box; }

/* The browser's own [hidden] rule is `display: none`, which loses to any author rule
   that sets display — and `.gate` and `.shell` both set `display: grid`. Without this,
   toggling `hidden` in JS does nothing to them and the signed-out page renders the whole
   signed-in panel underneath it, just below the fold where it is easy to miss. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  /* Nothing on this page is meant to scroll sideways. Wide content that cannot wrap
     gets its own scroller; the page itself never does. `clip` rather than `hidden`
     because `hidden` makes this a scroll container, which would break the sticky rail. */
  overflow-x: clip;
  background: var(--void);
  color: var(--text);
  font-family: var(--body);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  cursor: crosshair;      /* the landing page's cursor, carried through */
}

/* Anything you actually operate gets a normal pointer back. The crosshair is
   atmosphere, not an obstacle. */
a, button, input, select, summary, label, .row { cursor: default; }
a, button, summary, .swatch { cursor: pointer; }
input, textarea { cursor: text; }

/* ---------------------------------------------------------------- field */

/* Containment keeps the atmosphere out of the page's layout and paint work; without it
   the full-viewport overlays are repainted against live content. Deliberately not
   `strict`, which adds size containment — this element takes its size from `inset: 0`
   and telling the engine to size it as if empty invites trouble for no benefit. */
.field {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  contain: layout paint style;
}

.field::before {
  content: '';
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(circle at 22% 8%, rgba(var(--cyan-deep), .1), transparent 45vmin),
    radial-gradient(circle at 84% 96%, rgba(var(--accent), .07), transparent 50vmin),
    linear-gradient(180deg, #020b13 0%, #00050a 58%, #000207 100%);
}

.field-grid {
  position: absolute;
  inset: 0;
  opacity: .5;
  background-image:
    linear-gradient(rgba(var(--cyan), .05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(var(--cyan), .04) 1px, transparent 1px);
  background-size: 72px 72px, 72px 72px;
  mask-image: radial-gradient(circle at 50% 30%, black, transparent 85%);
}

.field-wash {
  position: absolute;
  inset: 0;
  mix-blend-mode: screen;
  opacity: .3;
  background: linear-gradient(112deg, transparent 0 40%, rgba(var(--ice), .045) 43%, transparent 48%);
}

/* A 3px repeating gradient across the whole viewport is expensive to rasterise on a
   large display. Four pixels, a lighter line, and its own layer costs a fraction and
   looks the same at arm's length. */
.field-scan {
  position: absolute;
  inset: 0;
  opacity: .22;
  will-change: transform;
  background: repeating-linear-gradient(
    180deg, rgba(0, 0, 0, 0) 0 3px, rgba(0, 0, 0, .3) 3px 4px);
}

/* ---------------------------------------------------------------- type */

h1, h2, h3 {
  font-family: var(--display);
  font-variation-settings: 'wdth' 118;
  font-weight: 700;
  letter-spacing: -.005em;
  margin: 0;
}

/* Parked with clip-path rather than a -9999px offset: an element sitting 9999px away
   is still part of the layout, and one more of those is one more thing that can widen
   the page. This takes up no space at all until it is focused. */
.skip {
  position: absolute;
  left: .5rem; top: .5rem;
  background: rgb(var(--cyan)); color: #001018;
  padding: .6rem 1rem; z-index: 100; font-weight: 600;
  clip-path: inset(50%);
}
.skip:focus { clip-path: none; }

/* Every focusable thing gets the same unmistakable ring. */
:focus-visible {
  outline: 2px solid rgb(var(--accent));
  outline-offset: 2px;
}

/* ================================================================ gate */

.gate {
  position: relative;
  z-index: 1;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: clamp(2rem, 6vw, 5rem) var(--gutter);
}

.gate-inner { width: 100%; max-width: 46rem; text-align: center; }

/* The aperture is the hero; the wordmark supports it. A heavier glow here made a
   visible rectangular haze behind the text and pulled focus off the instrument. */
.gate-title {
  font-size: clamp(2rem, 5.5vw, 3.1rem);
  font-variation-settings: 'wdth' 125;
  text-transform: uppercase;
  letter-spacing: .05em;
  margin: 1.6rem 0 0;
  color: rgb(var(--ice));
  text-shadow: 0 0 18px rgba(var(--accent), .2);
}

.gate-lede {
  margin: .85rem auto 0;
  max-width: 34rem;
  color: var(--text-dim);
  font-size: 1.02rem;
}

.gate-note {
  min-height: 1.4rem;
  margin: 1rem 0 0;
  font-family: var(--mono);
  font-size: .8rem;
  color: rgb(var(--amber));
}
.gate-note:empty { margin: 0; }

/* ---------------------------------------------------------- providers */

/* Fixed column counts rather than auto-fit: six doors want two tidy rows of three,
   not four-then-two. */
.providers {
  display: grid;
  grid-template-columns: 1fr;
  gap: .6rem;
  margin: 2.25rem auto 0;
  max-width: 40rem;
}
@media (min-width: 26rem) { .providers { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 46rem) { .providers { grid-template-columns: repeat(3, 1fr); } }

.loading { grid-column: 1 / -1; color: var(--text-dim); font-family: var(--mono); font-size: .82rem; }

.provider {
  position: relative;
  display: flex;
  align-items: center;
  gap: .7rem;
  min-height: 3.4rem;
  padding: .7rem 1rem;
  background: linear-gradient(180deg, rgba(var(--cyan), .05), rgba(0, 0, 0, .3));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: rgb(var(--ice));
  font: 600 .82rem/1 var(--display);
  font-variation-settings: 'wdth' 112;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-align: left;
  text-decoration: none;
  transition: border-color .18s, background .18s, transform .18s;
}
.provider:hover {
  border-color: rgba(var(--accent), .5);
  background: linear-gradient(180deg, rgba(var(--accent), .12), rgba(0, 0, 0, .3));
  transform: translateY(-1px);
}
.provider .mark { width: 18px; height: 18px; flex: none; fill: currentColor; opacity: .85; }

/* A provider with no credentials is not hidden and not merely greyed: it is
   shuttered. The visitor can see the door exists and that it is not open yet.
   The status sits under the name rather than beside it, because at three columns
   there is no room beside it and the two used to overlap. */
.provider--shut {
  color: rgba(var(--steel), .72);
  border-style: dashed;
  border-color: var(--line-soft);
  background: rgba(0, 0, 0, .25);
  pointer-events: none;
}
.provider--shut > span {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  min-width: 0;
}
.provider--shut > span::after {
  content: 'not connected yet';
  font-family: var(--mono);
  font-size: .58rem;
  font-weight: 400;
  letter-spacing: .06em;
  text-transform: none;
  color: rgba(var(--steel), .55);
}

/* ---------------------------------------------------------- promise */

.promise {
  margin: 3rem 0 0;
  padding: 1.5rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  background: rgba(0, 0, 0, .28);
  text-align: left;
}
.promise-heading {
  font-size: .68rem;
  font-variation-settings: 'wdth' 100;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(var(--steel), .9);
  margin-bottom: 1rem;
}
.promise-grid { display: grid; gap: 1rem; margin: 0; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }
.promise-grid dt {
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgb(var(--accent));
  margin-bottom: .3rem;
}
.promise-grid div:last-child dt { color: rgb(var(--amber)); }
.promise-grid dd { margin: 0; color: var(--text-dim); font-size: .88rem; }
.promise-foot {
  margin: 1.1rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--line-soft);
  color: rgba(var(--steel), .85);
  font-size: .82rem;
}

/* ---------------------------------------------------------- sysadmin door */

.sysdoor { margin: 2rem auto 0; max-width: 22rem; text-align: left; }
.sysdoor summary {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(var(--steel), .75);
  list-style: none;
  padding: .5rem 0;
  text-align: center;
}
.sysdoor summary::-webkit-details-marker { display: none; }
.sysdoor summary:hover { color: rgb(var(--amber)); }
.sysdoor[open] summary { color: rgb(var(--amber)); }

.sysform {
  display: grid;
  gap: .4rem;
  padding: 1.1rem;
  border: 1px solid rgba(var(--amber), .28);
  border-radius: var(--radius);
  background: rgba(20, 12, 0, .35);
}
.sysform-note { margin: 0 0 .5rem; font-size: .78rem; color: var(--text-dim); }

/* ================================================================ shell */

.shell {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 17.5rem minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  max-width: 74rem;
  margin: 0 auto;
  padding: clamp(1.5rem, 4vw, 3rem) var(--gutter) 5rem;
  align-items: start;
}

.rail { position: sticky; top: clamp(1.5rem, 4vw, 3rem); display: grid; gap: 1.25rem; }

.rail-id { text-align: center; }
.rail-handle {
  margin: 0;
  font-family: var(--mono);
  font-size: 1rem;
  letter-spacing: .06em;
  color: rgb(var(--ice));
}
.rail-sub {
  margin: .25rem 0 0;
  font-size: .74rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.rail-nav { display: grid; gap: 1px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.rail-nav a {
  padding: .6rem .2rem;
  color: var(--text-dim);
  text-decoration: none;
  font-family: var(--display);
  font-variation-settings: 'wdth' 108;
  font-size: .78rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  border-left: 2px solid transparent;
  padding-left: .7rem;
  transition: color .16s, border-color .16s;
}
.rail-nav a:hover { color: rgb(var(--ice)); border-left-color: rgb(var(--accent)); }

.rail-foot { display: grid; gap: .4rem; }

/* ================================================================ modules */

/* minmax(0, 1fr), not the default `auto`: with `auto` the widest module sets the column
   width and stretches every other one to match, so one long unbreakable status line made
   the entire page 21px wider than the phone it was on. */
.modules { display: grid; grid-template-columns: minmax(0, 1fr); gap: 2.5rem; min-width: 0; }

.module { scroll-margin-top: 2rem; min-width: 0; }

.module-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .25rem 1rem;
  padding-bottom: .6rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: .9rem;
}
.module-head h2 {
  font-size: 1.35rem;
  font-variation-settings: 'wdth' 120;
  text-transform: uppercase;
  letter-spacing: .05em;
}

/* The state line is information, not ornament: it always reports a live count
   or condition, never a label that could have been written in advance. */
.module-state {
  margin: 0;
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(var(--steel), .85);
  text-align: right;
  /* Deliberately allowed to wrap. These lines are live status, so their length is not
     known in advance, and one long one used to widen the whole page. */
}

.module-lede { margin: 0 0 1.1rem; color: var(--text-dim); font-size: .9rem; max-width: 46rem; }

.module--danger .module-head { border-bottom-color: rgba(var(--red), .3); }
.module--danger .module-head h2 { color: rgb(var(--red)); }
.module--admin .module-head { border-bottom-color: rgba(var(--amber), .3); }
.module--admin .module-head h2 { color: rgb(var(--amber)); }
.module--admin .module-state { color: rgb(var(--amber)); }

/* ---------------------------------------------------------- rows */

.rows { display: grid; gap: .5rem; }
.rows--tight { gap: 1px; }

.row {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .85rem 1rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  background: rgba(var(--panel), 1);
  background: linear-gradient(180deg, rgba(4, 16, 27, .9), rgba(1, 6, 12, .9));
}
.row--lit { border-color: rgba(var(--accent), .34); }
.row--muted { opacity: .62; }

.row-main { flex: 1 1 12rem; min-width: 0; }
.row-title {
  margin: 0;
  font-family: var(--display);
  font-variation-settings: 'wdth' 112;
  font-weight: 600;
  font-size: .92rem;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: rgb(var(--ice));
}
.row-meta { margin: .15rem 0 0; font-size: .78rem; color: var(--text-dim); }
/* A client id like dmn_nullcromancer_zlvkW6wymc1S is one unbreakable word. Left to
   itself it sets the row's minimum width and pushes the whole page sideways on a phone,
   which is exactly what it was doing: 21px of horizontal scroll at 390px wide. */
.row-meta code {
  font-family: var(--mono);
  font-size: .74rem;
  color: rgba(var(--accent), .9);
  overflow-wrap: anywhere;
}
.row-actions { display: flex; gap: .4rem; flex-wrap: wrap; align-items: center; }

.tag {
  display: inline-block;
  padding: .12rem .45rem;
  border: 1px solid rgba(var(--accent), .35);
  border-radius: var(--radius);
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgb(var(--accent));
}
.tag--amber { border-color: rgba(var(--amber), .4); color: rgb(var(--amber)); }
.tag--quiet { border-color: var(--line-soft); color: var(--text-dim); }

.swatch {
  width: 1.1rem; height: 1.1rem; flex: none;
  border: 1px solid var(--line-soft);
  border-radius: 50%;
  padding: 0;
  background: currentColor;
}

/* ---------------------------------------------------------- controls */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  padding: .55rem .95rem;
  border: 1px solid rgba(var(--accent), .4);
  border-radius: var(--radius);
  background: rgba(var(--accent), .1);
  color: rgb(var(--ice));
  font: 600 .74rem/1 var(--display);
  font-variation-settings: 'wdth' 110;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background .16s, border-color .16s, color .16s;
}
.btn:hover { background: rgba(var(--accent), .2); border-color: rgba(var(--accent), .7); }
.btn:disabled { opacity: .4; pointer-events: none; }

.btn--ghost { background: transparent; }
.btn--quiet {
  background: transparent;
  border-color: var(--line-soft);
  color: var(--text-dim);
}
.btn--quiet:hover { color: rgb(var(--ice)); border-color: rgba(var(--steel), .5); }
.btn--amber { border-color: rgba(var(--amber), .5); background: rgba(var(--amber), .12); }
.btn--amber:hover { background: rgba(var(--amber), .22); border-color: rgb(var(--amber)); }
.btn--danger { border-color: rgba(var(--red), .5); background: rgba(var(--red), .1); color: rgb(var(--red)); }
.btn--danger:hover { background: rgba(var(--red), .2); border-color: rgb(var(--red)); color: rgb(var(--ice)); }

.field-label {
  display: block;
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: .25rem;
}

.input, select.input {
  width: 100%;
  padding: .55rem .7rem;
  background: rgba(0, 0, 0, .45);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  color: rgb(var(--ice));
  font-family: var(--mono);
  font-size: .84rem;
}
.input:focus { border-color: rgba(var(--accent), .6); outline: none; box-shadow: 0 0 0 2px rgba(var(--accent), .15); }
.input::placeholder { color: rgba(var(--steel), .45); }

select.input { cursor: pointer; }
select.input option { background: var(--deep); color: rgb(var(--ice)); }

.hint { margin: .25rem 0 0; font-size: .72rem; color: rgba(var(--steel), .75); }

/* align-items: start, not end. With `end`, a field carrying a hint underneath is taller
   than its neighbours and its input floats above theirs, so the row of inputs stops
   lining up. Starting them together keeps the labels and inputs on shared baselines; the
   button is nudged down by one label's height to sit level with the inputs. */
.inline-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: .75rem;
  align-items: start;
  margin-top: 1rem;
  padding: 1.1rem;
  border: 1px dashed var(--line-soft);
  border-radius: var(--radius);
}
.inline-form > .btn { margin-top: 1.2rem; }
@media (max-width: 30rem) { .inline-form > .btn { margin-top: 0; } }
.inline-field--wide { grid-column: 1 / -1; }

.form-error { margin: .5rem 0 0; min-height: 1.2rem; font-size: .8rem; color: rgb(var(--red)); }

/* ---------------------------------------------------------- banner, toast */

.banner {
  margin: 0;
  padding: .8rem 1rem;
  border: 1px solid rgba(var(--accent), .35);
  border-left-width: 3px;
  border-radius: var(--radius);
  background: rgba(var(--accent), .07);
  font-size: .88rem;
}
.banner--warn { border-color: rgba(var(--amber), .45); background: rgba(var(--amber), .07); }

.toast {
  position: fixed;
  left: 50%;
  bottom: 1.5rem;
  transform: translateX(-50%);
  z-index: 60;
  padding: .7rem 1.2rem;
  border: 1px solid rgba(var(--accent), .5);
  border-radius: var(--radius);
  background: #010a12;
  color: rgb(var(--ice));
  font-size: .85rem;
  box-shadow: 0 0 40px rgba(0, 0, 0, .8);
  max-width: calc(100vw - 2rem);
}
.toast--bad { border-color: rgba(var(--red), .6); color: rgb(var(--red)); }

/* ---------------------------------------------------------- secret slip */

.secret-slip {
  margin-top: 1rem;
  padding: 1.1rem;
  border: 1px solid rgba(var(--amber), .5);
  border-radius: var(--radius);
  background: rgba(24, 15, 0, .5);
}
.secret-slip-head {
  margin: 0 0 .75rem;
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgb(var(--amber));
}
.secret-slip-body { margin: 0; display: grid; gap: .6rem; }
.secret-slip-body dt {
  font-family: var(--mono); font-size: .64rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-dim);
}
.secret-slip-body dd {
  margin: .15rem 0 0; font-family: var(--mono); font-size: .82rem;
  color: rgb(var(--ice)); word-break: break-all; user-select: all;
}

.audit { margin-top: 1.5rem; }
.audit summary {
  font-family: var(--mono); font-size: .7rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-dim); padding: .5rem 0;
}
.audit-row {
  display: grid;
  grid-template-columns: 11rem 12rem 1fr;
  gap: .75rem;
  padding: .35rem 0;
  border-bottom: 1px solid rgba(var(--steel), .08);
  font-family: var(--mono);
  font-size: .72rem;
  color: var(--text-dim);
}
.audit-row b { color: rgba(var(--accent), .9); font-weight: 500; }

/* ================================================================ aperture */
/*
   The signature. It is the landing page's eye, made small and made yours.
   Nothing about it is arbitrary:
     - the pupil dilates from shut to open as the session opens
     - each of the six outer nodes is one federated provider; a node lights
       when that provider is linked to this account
     - the iris takes the accent colour of the profile currently forward
*/

.aperture {
  --open: 0;
  width: 100%;
  max-width: 10rem;
  margin: 0 auto;
  aspect-ratio: 1;
}
.aperture--large { max-width: 16rem; }
.aperture svg { width: 100%; height: 100%; display: block; overflow: visible; }

.ap-ring { fill: none; stroke: rgba(var(--steel), .34); stroke-width: 5; }
.ap-ring--calib {
  stroke: rgba(var(--cyan), .4);
  stroke-dasharray: 3 21;
  stroke-width: 8;
  transform-origin: 500px 500px;
  transform-box: fill-box;
  transform-origin: center;
  will-change: transform;
  animation: ap-rotate 60s linear infinite;
}
.ap-ring--inner { stroke: rgba(var(--accent), .38); stroke-width: 2; }

/* Fibers stay legible shut and brighten as the aperture opens; invisible-when-closed
   made the whole instrument read as a spinner rather than a shutter. */
.ap-fiber {
  fill: none;
  stroke: rgba(var(--accent), .5);
  stroke-width: 4;
  stroke-linecap: round;
  opacity: calc(.42 + var(--open) * .58);
  transition: opacity .9s ease;
}
.ap-fiber--hot { stroke: rgba(var(--ice), .7); }

.ap-pupil {
  fill: #000206;
  stroke: rgba(var(--accent), .85);
  stroke-width: 5;
  /* shut = 46, open = 128. The whole state change is this one number. */
  r: calc(46px + var(--open) * 82px);
  transition: r 1.2s cubic-bezier(.2, .8, .2, 1);
  filter: drop-shadow(0 0 18px rgba(var(--accent), .6));
}

.ap-glow {
  fill: rgba(var(--accent), .1);
  r: calc(70px + var(--open) * 110px);
  transition: r 1.2s cubic-bezier(.2, .8, .2, 1);
}

/* The reticle: four ticks aimed at a shut pupil, which retract as it opens. It is the
   page cursor's crosshair, borrowed, and it is the clearest signal that the closed
   state is closed on purpose. */
.ap-tick {
  stroke: rgba(var(--ice), .5);
  stroke-width: 5;
  stroke-linecap: round;
  opacity: calc(1 - var(--open));
  transition: opacity .7s ease;
}

.ap-node { fill: rgba(var(--steel), .25); transition: fill .5s ease, r .5s ease; r: 10; }
.ap-node--lit { fill: rgb(var(--accent)); r: 15; filter: drop-shadow(0 0 10px rgba(var(--accent), .9)); }
.ap-spoke { stroke: rgba(var(--steel), .18); stroke-width: 3; }
.ap-spoke--lit { stroke: rgba(var(--accent), .5); }

@keyframes ap-rotate { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------- entrance */

.stagger > * {
  animation: rise .55s cubic-bezier(.2, .8, .2, 1) backwards;
}
@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------- responsive */

@media (max-width: 60rem) {
  .shell { grid-template-columns: 1fr; }
  .rail {
    position: static;
    grid-template-columns: 6rem 1fr;
    align-items: center;
    gap: 1rem 1.25rem;
    padding-bottom: 1.25rem;
    border-bottom: 1px solid var(--line);
  }
  .aperture { max-width: 6rem; margin: 0; }
  .rail-id { text-align: left; }
  /* min-width: 0 is doing real work here. A grid item defaults to min-width: auto, so
     this row of links refuses to shrink below its content, `overflow-x: auto` never
     engages, and the nav pushes the whole page sideways — it was 610px wide inside a
     390px viewport, which is where the horizontal scrollbar came from. */
  .rail-nav {
    grid-column: 1 / -1;
    grid-auto-flow: column;
    grid-auto-columns: max-content;
    min-width: 0;
    overflow-x: auto;
    gap: 1.25rem;
    scrollbar-width: none;
  }
  .rail-nav::-webkit-scrollbar { display: none; }
  .rail-foot { grid-column: 1 / -1; grid-auto-flow: column; justify-content: start; min-width: 0; }
  .rail-nav a { border-left: 0; border-bottom: 2px solid transparent; padding: .5rem 0; }
  .rail-nav a:hover { border-left-color: transparent; border-bottom-color: rgb(var(--accent)); }
  .audit-row { grid-template-columns: 1fr; gap: .1rem; }
}

@media (max-width: 30rem) {
  .row { flex-direction: column; align-items: stretch; }
  .row-actions { justify-content: flex-start; }
}

/* Motion is atmosphere here, never information: with it off, the aperture simply
   arrives at the state it would have animated to. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}
