/* Control Center — the front door's design system.
 *
 * This is Inertia Studios' own surface, so it wears Inertia's brand: the neon-noir canvas from
 * inertiaroleplay.gg with the motion language TorqueStack established (the
 * cubic-bezier(.22,1,.36,1) reveal, the staggered scroll-in, the drifting particle field).
 *
 * WHY IT IS HAND-WRITTEN CSS AND NOT TAILWIND/NEXT, which is what both of those sites use:
 *
 * This deployable's whole job is routing, and Vercel resolves the FILESYSTEM before rewrites. The
 * routing rules are generated and gated (scripts/check.mjs re-runs the generator and diffs it), and
 * a build step would put a bundler between that gate and what actually ships. There is also no
 * framework worth its bytes here: two pages, one fetch each. So the design language is ported as
 * tokens and classes rather than imported as a dependency - the token names match
 * inertiaroleplay.gg's globals.css deliberately, so moving this onto Next later is a paste.
 *
 * NO THIRD-PARTY ASSETS. No webfont, no CDN script. This stylesheet is loaded by the page a staff
 * member reaches when their server is already broken, and the one thing it must do is arrive. The
 * display face is therefore the system stack with the tracking tightened, not Geist.
 *
 * THE TOKENS BELOW ARE DUPLICATED, ON PURPOSE, in lib/render.js - the outage pages inline their CSS
 * so they never depend on a second request succeeding. That duplication used to be a comment asking
 * people to remember; scripts/check.mjs now extracts both lists and fails when they disagree.
 */

/* ── Tokens ────────────────────────────────────────────────────────────────
   Ported from inertiaroleplay.gg. Keep the names; they are the contract with
   render.js and with any future move onto Tailwind's @theme.                */
:root {
  --background: #0a0c13;
  --surface: #0e1119;
  --card: #12151f;
  --raised: #1a1e2b;
  --line: rgba(255, 255, 255, 0.08);
  --line-strong: rgba(255, 255, 255, 0.14);
  --foreground: #e9ebf5;
  --mute: #9aa0b8;
  --faint: #78819e;

  /* Neon brand triad */
  --neon-cyan: #ff7a45;
  --neon-violet: #ffb347;
  --neon-magenta: #ff5c6a;
  --neon-blue: #6fb4ff;

  /* States */
  --ok: #46d684;
  --warn: #ffc24d;
  --danger: #ff5c6a;
  --blurple: #5865f2;

  --body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* The signature easing. Every reveal and lift uses it so the whole estate
     accelerates the same way. */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ── Reset and base ─────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  color-scheme: dark;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: var(--background);
  color: var(--foreground);
  font: 400 15px/1.65 var(--body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4 { letter-spacing: -0.022em; margin: 0; }
p { margin: 0; }
ul { margin: 0; padding: 0; }
img { max-width: 100%; display: block; }
a { color: var(--neon-cyan); text-decoration: none; }
a:hover { text-decoration: underline; }
[hidden] { display: none !important; }

::selection {
  background-color: rgba(255, 122, 69, 0.45);
  color: #fff;
}

:focus-visible {
  outline: 2px solid var(--neon-cyan);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Skip link — the front door is one column, but the directory is a list and
   tabbing past the chrome every time is a real annoyance with a keyboard. */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 12px 18px;
  background: var(--card);
  border: 1px solid var(--neon-cyan);
  border-radius: 0 0 10px 0;
  color: var(--foreground);
  font-weight: 650;
}
.skip:focus { left: 0; text-decoration: none; }

/* ── Layout ────────────────────────────────────────────────────────────── */
.shell {
  margin-inline: auto;
  width: 100%;
  max-width: 68rem;
  padding-inline: 1.25rem;
}
@media (min-width: 768px) {
  .shell { padding-inline: 2rem; }
}
.shell-narrow { max-width: 44rem; }

main { flex: 1 0 auto; }

.section { position: relative; padding-block: 3.5rem; }
@media (min-width: 768px) {
  .section { padding-block: 5rem; }
}
.section-tight { padding-block: 2.5rem; }

.stack { display: grid; gap: 1rem; }
.stack-lg { display: grid; gap: 1.75rem; }

/* Grid and flex items default to min-width:auto, which refuses to shrink below
   their min-content width. A single nowrap element then widens its whole column
   and the page scrolls sideways - and on this product that element is a Discord
   display name, which the visitor chooses and can make arbitrarily long. Without
   this the `text-overflow: ellipsis` rules further down have nothing to clip
   against and silently do nothing. */
.stack, .stack-lg, .servers, .who, .row-between { min-width: 0; }
.stack > *, .stack-lg > *, .servers > li, .row-between > * { min-width: 0; }

/* ── Top bar ───────────────────────────────────────────────────────────── */
.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 1px solid transparent;
  transition: background-color 0.3s var(--ease), border-color 0.3s var(--ease),
              backdrop-filter 0.3s var(--ease);
}
/* .is-stuck is set by panel.js on scroll — the same treatment as the site's navbar. */
.topbar.is-stuck {
  background: rgba(5, 6, 12, 0.82);
  border-bottom-color: var(--line);
  backdrop-filter: blur(14px);
  box-shadow: 0 8px 30px -16px rgba(0, 0, 0, 0.7);
}
.topbar .shell {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 4rem;
}

/* ── Brand mark ────────────────────────────────────────────────────────────
   Real text beside a gradient tile, same construction as the site's <Logo>:
   it stays crisp at every size and recolours with the tokens.               */
.brandmark {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--foreground);
}
.brandmark:hover { text-decoration: none; }
.brandmark .tile {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  flex: none;
  border-radius: 0.6rem;
  background: linear-gradient(135deg, var(--neon-cyan), var(--neon-violet) 55%, var(--neon-magenta));
  color: #04060a;
  box-shadow: 0 8px 22px -8px rgba(255, 179, 71, 0.55);
}
.brandmark .tile svg {
  width: 60%;
  height: 60%;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* nowrap matters: at 375px the wordmark otherwise breaks after "Inertia" and the
   bar grows to two lines, taking whatever sits beside it with it. */
.brandmark .words { font-size: 1.02rem; white-space: nowrap; }
.brandmark .words span { color: var(--neon-cyan); }

@media (max-width: 480px) {
  .brandmark .words { font-size: 0.88rem; }
  .brandmark .tile { width: 1.75rem; height: 1.75rem; }
}

/* ── Eyebrow ───────────────────────────────────────────────────────────── */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--neon-cyan);
}
.eyebrow::before {
  content: "";
  width: 1.5rem;
  height: 1px;
  background: linear-gradient(90deg, var(--neon-cyan), transparent);
}

/* ── Type treatments ───────────────────────────────────────────────────── */
.display {
  letter-spacing: -0.035em;
  line-height: 1.02;
  text-wrap: balance;
  font-weight: 800;
  font-size: clamp(2rem, 6vw, 3.25rem);
}
.display-sm { font-size: clamp(1.5rem, 4vw, 2rem); }

.accent-text {
  background-image: linear-gradient(100deg, #ff7a45 0%, #ffb347 52%, #ff5c6a 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.lead { color: var(--foreground); font-size: 1.02rem; }
.body { color: var(--mute); }
.note { color: var(--faint); font-size: 0.88rem; }
.mono { font-family: var(--mono); font-size: 0.92em; }
strong { color: var(--foreground); font-weight: 650; }

h2.heading {
  font-size: 1.3rem;
  font-weight: 700;
}
h3.subheading {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ── Cards ─────────────────────────────────────────────────────────────── */
.card {
  border-radius: 1rem;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.035), rgba(255, 255, 255, 0.008));
  padding: 1.6rem;
  transition: transform 0.3s var(--ease), border-color 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
@media (min-width: 640px) {
  .card { padding: 2rem; }
}
.card-hover:hover {
  transform: translateY(-3px);
  border-color: rgba(255, 122, 69, 0.45);
  box-shadow: 0 28px 60px -32px rgba(255, 122, 69, 0.35);
}
.card-flush { padding: 0; overflow: hidden; }

/* Rotating conic neon ring. Reserved for the one element on a page that is the
   point of the page — the sign-in card. Used more widely it stops meaning
   anything and starts being a light show. */
@property --nb-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}
.neon-border { position: relative; isolation: isolate; }
.neon-border::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  padding: 1.5px;
  background: conic-gradient(from var(--nb-angle), #ff7a45, #ffb347, #ff5c6a, #ff7a45);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  animation: nb-spin 7s linear infinite;
  opacity: 0.8;
}
@keyframes nb-spin { to { --nb-angle: 360deg; } }
/* Without mask-composite the ring cannot be cut out, and a filled spinning
   block over the card is far worse than no ring. Degrade to a plain card. */
@supports not ((-webkit-mask-composite: xor) or (mask-composite: exclude)) {
  .neon-border::before { display: none; }
}

/* ── Buttons ───────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  border: 1px solid transparent;
  border-radius: 9999px;
  padding: 0.8rem 1.5rem;
  font: 650 0.9rem/1 var(--body);
  cursor: pointer;
  transition: transform 0.2s var(--ease), background-color 0.2s var(--ease),
              background-position 0.35s var(--ease), border-color 0.2s var(--ease),
              box-shadow 0.2s var(--ease), color 0.2s var(--ease);
}
.btn:hover { text-decoration: none; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.55; cursor: default; }
.btn svg { flex: none; }

.btn-primary {
  color: #04060a;
  font-weight: 750;
  background-image: linear-gradient(100deg, var(--neon-cyan), var(--neon-violet) 60%, var(--neon-magenta));
  background-size: 180% 100%;
  background-position: 0% 50%;
  box-shadow: 0 0 0 0 rgba(255, 179, 71, 0), 0 14px 38px -16px rgba(255, 122, 69, 0.55);
}
.btn-primary:hover:not(:disabled) {
  background-position: 100% 50%;
  box-shadow: 0 0 28px -4px rgba(255, 179, 71, 0.55), 0 18px 46px -14px rgba(255, 179, 71, 0.6);
  transform: translateY(-2px);
}
.btn-primary:active:not(:disabled) { transform: translateY(0) scale(0.985); }

/* The glow treatment: a pill with a soft halo in the brand colours that brightens on hover, a
   lift, and a press. The Discord button carries it on the sign-in page; it is the one thing to press. */
.btn-glow { position: relative; isolation: isolate; }
.btn-glow::after {
  content: ""; position: absolute; inset: -2px; border-radius: inherit; z-index: -1;
  background: linear-gradient(100deg, var(--neon-cyan), var(--neon-violet), var(--neon-magenta));
  filter: blur(14px); opacity: 0.45; transition: opacity 0.25s var(--ease), filter 0.25s var(--ease);
}
.btn-glow:hover::after { opacity: 0.85; filter: blur(18px); }
.btn-glow:active { transform: translateY(0) scale(0.985); }

.btn-secondary {
  color: var(--foreground);
  border-color: var(--line-strong);
  background: rgba(255, 255, 255, 0.025);
}
.btn-secondary:hover {
  border-color: rgba(255, 122, 69, 0.6);
  color: #fff;
  box-shadow: 0 0 26px -6px rgba(255, 122, 69, 0.5);
  transform: translateY(-1px);
}
.btn-secondary:active { transform: translateY(0) scale(0.985); }

.btn-discord {
  color: #1a0d05;
  background-image: linear-gradient(100deg, #ff7a45, #ffb347);
  background-size: 180% 100%;
  background-position: 0% 50%;
  box-shadow: 0 14px 38px -16px rgba(255, 122, 69, 0.7);
}
.btn-discord:hover {
  background-position: 100% 50%;
  box-shadow: 0 0 30px -4px rgba(255, 179, 71, 0.5), 0 18px 46px -14px rgba(255, 122, 69, 0.8);
  transform: translateY(-2px);
}

.btn-quiet {
  color: var(--mute);
  background: transparent;
  border-color: var(--line);
  padding: 0.5rem 0.95rem;
  font-size: 0.84rem;
  white-space: nowrap;
}
.btn-quiet:hover { color: var(--foreground); border-color: rgba(255, 179, 71, 0.6); box-shadow: 0 0 22px -8px rgba(255, 179, 71, 0.5); }

/* For chrome that is a convenience rather than a control. "Already have your
   address?" is a shortcut to a section further down the same page, so dropping
   it on a narrow screen costs a scroll; "Sign out" is not optional and never
   carries this class. */
@media (max-width: 560px) {
  .hide-sm { display: none !important; }
}

.btn-wide { width: 100%; }
.btn-lg { padding: 0.95rem 1.9rem; font-size: 0.98rem; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
}

/* ── Decorative backgrounds ────────────────────────────────────────────── */
.glow-bg {
  background:
    radial-gradient(ellipse 60% 50% at 50% -5%, rgba(255, 122, 69, 0.14), transparent 60%),
    radial-gradient(ellipse 55% 45% at 85% 18%, rgba(255, 92, 106, 0.10), transparent 62%),
    radial-gradient(ellipse 50% 45% at 12% 75%, rgba(255, 179, 71, 0.12), transparent 60%);
}
.grid-bg {
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px);
  background-size: 56px 56px;
  -webkit-mask-image: radial-gradient(ellipse 70% 70% at 50% 35%, #000 20%, transparent 75%);
  mask-image: radial-gradient(ellipse 70% 70% at 50% 35%, #000 20%, transparent 75%);
  animation: grid-drift 60s linear infinite;
}
@keyframes grid-drift { to { background-position: 56px 56px; } }

/* The aurora: three big soft bands of the brand triad, blurred and slowly drifting over each other.
   Pure CSS, GPU-composited transforms only, so it costs almost nothing and runs under the particles.
   overflow:hidden on the backdrop keeps the blur from spilling past the section. */
.aurora {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
  opacity: 0.85;
}
.aurora span {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  mix-blend-mode: screen;
  will-change: transform;
  opacity: 0.55;
}
.aurora .a1 { width: 70vw; height: 46vw; left: -12vw; top: -18vw;
  background: radial-gradient(closest-side, rgba(255, 179, 71, 0.55), rgba(255, 179, 71, 0) 70%);
  animation: aurora-1 34s ease-in-out infinite alternate; }
.aurora .a2 { width: 60vw; height: 40vw; right: -16vw; top: -6vw;
  background: radial-gradient(closest-side, rgba(255, 92, 106, 0.42), rgba(255, 92, 106, 0) 70%);
  animation: aurora-2 41s ease-in-out infinite alternate; }
.aurora .a3 { width: 55vw; height: 36vw; left: 18vw; bottom: -20vw;
  background: radial-gradient(closest-side, rgba(255, 122, 69, 0.34), rgba(255, 122, 69, 0) 70%);
  animation: aurora-3 47s ease-in-out infinite alternate; }
.aurora .a4 { width: 34vw; height: 34vw; left: 38vw; top: 8vw;
  background: radial-gradient(closest-side, rgba(111, 180, 255, 0.30), rgba(111, 180, 255, 0) 70%);
  animation: aurora-4 29s ease-in-out infinite alternate; }
@keyframes aurora-1 { from { transform: translate3d(0, 0, 0) scale(1); } to { transform: translate3d(14vw, 9vw, 0) scale(1.15); } }
@keyframes aurora-2 { from { transform: translate3d(0, 0, 0) scale(1.1); } to { transform: translate3d(-12vw, 12vw, 0) scale(0.95); } }
@keyframes aurora-3 { from { transform: translate3d(0, 0, 0) scale(1); } to { transform: translate3d(-10vw, -10vw, 0) scale(1.2); } }
@keyframes aurora-4 { from { transform: translate3d(0, 0, 0) scale(0.9); } to { transform: translate3d(8vw, -6vw, 0) scale(1.25); } }

/* The effects stage is the hero section: pointer position lands on it as --mx/--my (pixels) and
   --px/--py (-0.5..0.5), set by initFx. Everything below reads those. */
.fx-stage { --mx: -999px; --my: -999px; --px: 0; --py: 0; }
.fx { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; }
/* Aurora leans away from the pointer: cheap parallax, one transform on the whole layer. */
.fx-stage .aurora {
  transform: translate3d(calc(var(--px) * -14px), calc(var(--py) * -10px), 0);
  transition: transform 0.9s var(--ease);
}
/* A spotlight under the pointer, and the grid shows through more strongly there. */
.spot {
  position: absolute; inset: 0; pointer-events: none; z-index: 0; mix-blend-mode: screen;
  background: radial-gradient(220px circle at var(--mx) var(--my), rgba(255, 122, 69, 0.14),
              rgba(255, 179, 71, 0.05) 45%, transparent 70%);
}
.fx-stage .grid-bg {
  -webkit-mask-image: radial-gradient(ellipse 70% 70% at 50% 35%, #000 20%, transparent 75%),
                      radial-gradient(260px circle at var(--mx) var(--my), #000 0%, transparent 100%);
  mask-image: radial-gradient(ellipse 70% 70% at 50% 35%, #000 20%, transparent 75%),
              radial-gradient(260px circle at var(--mx) var(--my), #000 0%, transparent 100%);
  -webkit-mask-composite: source-over; mask-composite: add;
}
/* Click: a ring that grows out and fades. */
.ring {
  position: absolute; width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%;
  border: 1.5px solid rgba(255, 122, 69, 0.75); pointer-events: none; z-index: 0;
  animation: ring 1.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes ring { to { transform: scale(26); opacity: 0; } }
/* The gradient word in the heading slowly shimmers. */
.display .shimmer { background-size: 200% 100% !important; animation: shimmer 6s ease-in-out infinite; }
@keyframes shimmer { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }

/* A single sweeping light beam, very faint, so the dark areas are never flat. */
.beam {
  position: absolute;
  inset: -20% -10%;
  pointer-events: none;
  z-index: 0;
  background: linear-gradient(115deg, transparent 38%, rgba(255, 255, 255, 0.035) 48%, rgba(255, 122, 69, 0.05) 50%,
              rgba(255, 255, 255, 0.035) 52%, transparent 62%);
  animation: beam 26s ease-in-out infinite alternate;
  mix-blend-mode: screen;
}
@keyframes beam { from { transform: translateX(-18%) } to { transform: translateX(18%) } }
.backdrop {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}
.backdrop-fade-bottom {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 45%;
  pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--background));
  z-index: 0;
}
.layer { position: relative; z-index: 1; }

.divider {
  height: 1px;
  width: 100%;
  background: linear-gradient(90deg, transparent, var(--line), transparent);
}
.neon-divider {
  height: 1px;
  width: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 122, 69, 0.55),
              rgba(255, 179, 71, 0.55), rgba(255, 92, 106, 0.55), transparent);
  background-size: 200% 100%;
  animation: sheen 8s linear infinite;
}
@keyframes sheen { to { background-position: 200% 0; } }

/* The particle field. A 2D canvas, not the sites' three.js shader: a WebGL
   dependency on the page that has to load during an outage is the wrong trade,
   and the cyan-violet-magenta drift reads the same at this scale. */
.field {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  transition: opacity 1.2s var(--ease);
}
.field.is-ready { opacity: 1; }

/* Film grain. Fixed, soft-light, barely there — it takes the flatness off the
   large dark areas. Skipped on touch, where it costs more than it gives. */
.grain {
  position: fixed;
  inset: -150px;
  z-index: 60;
  pointer-events: none;
  opacity: 0.05;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px 200px;
  animation: grain 0.6s steps(3) infinite;
}
@keyframes grain {
  0% { transform: translate(0, 0); }
  33% { transform: translate(-6px, 4px); }
  66% { transform: translate(4px, -6px); }
  100% { transform: translate(0, 0); }
}
@media (hover: none), (pointer: coarse) {
  .grain { display: none; }
}

/* Cursor glow, positioned by panel.js through --cx/--cy. */
.cursor-glow {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 40;
  width: 460px;
  height: 460px;
  margin: -230px 0 0 -230px;
  pointer-events: none;
  border-radius: 9999px;
  background: radial-gradient(closest-side, rgba(255, 122, 69, 0.1),
              rgba(255, 179, 71, 0.055), transparent 70%);
  mix-blend-mode: screen;
  transform: translate(var(--cx, -9999px), var(--cy, -9999px));
}

/* ── Reveal ────────────────────────────────────────────────────────────────
   Hidden-then-revealed is opt-IN, keyed on html.reveal-ready, which the head
   snippet sets only when it has both IntersectionObserver and the user's
   consent to motion. Arming in the head rather than from panel.js means
   elements are never painted visible and then snatched back, which is the
   flash this ordering exists to avoid.

   The rule below is the only thing on the site that hides content, so read it
   with that in mind. Default-visible holds when JavaScript is off wholesale,
   because then the head snippet does not run either - but that is NOT the same
   as panel.js failing, where the snippet has already armed and the un-hiding
   code never arrives. That gap was real and is closed in the head snippet, on
   the script tag, and in boot(); see the comment at the top of panel.js. If
   you move this rule, move those three nets with it.                       */
.reveal { transition: opacity 0.75s var(--ease), transform 0.75s var(--ease); }

html.reveal-ready .reveal {
  opacity: 0;
  transform: translateY(20px) scale(0.985);
  will-change: opacity, transform;
}
html.reveal-ready .reveal.is-visible {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* ── Fact grid ─────────────────────────────────────────────────────────── */
.topbar-actions { display: flex; gap: 0.5rem; align-items: center; }
.btn-sm { padding: 0.45rem 0.85rem; font-size: 0.8rem; }
.wrong-place { display: grid; gap: 0.6rem; justify-items: center; text-align: center; margin-top: 0.4rem; padding-top: 0.9rem; border-top: 1px solid var(--line); }
.wrong-place p { margin: 0; }
.wrong-place-links { display: flex; gap: 0.6rem; flex-wrap: wrap; justify-content: center; }
.two-col { display: grid; gap: 2rem; align-items: start; }
@media (min-width: 900px) { .two-col { grid-template-columns: 1.1fr 0.9fr; gap: 3rem; } }
.steps { list-style: none; counter-reset: step; display: grid; gap: 1rem; padding: 0; margin: 0 0 1rem; }
.steps li { position: relative; padding-left: 2.6rem; color: var(--mute); line-height: 1.6; }
.steps li b { color: var(--foreground); }
.steps li::before {
  counter-increment: step; content: counter(step);
  position: absolute; left: 0; top: 0.05rem; width: 1.8rem; height: 1.8rem; border-radius: 50%;
  display: grid; place-items: center; font: 750 0.85rem/1 var(--body); color: #04060a;
  background: linear-gradient(135deg, var(--neon-cyan), var(--neon-violet));
}
.facts {
  padding: 1.1rem 1.25rem;
  background: rgba(5, 6, 12, 0.5);
  border: 1px solid var(--line);
  border-radius: 0.85rem;
  font-size: 0.9rem;
}
.facts dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.45rem 1rem;
  margin: 0;
}
.facts dt { color: var(--faint); }
.facts dd { margin: 0; color: var(--foreground); }

/* Trust points on the front door — an icon, a claim, a qualification. */
/* The sign-in page: copy on the left, the sign-in panel on the right; one column on phones. */
.hero-split { display: grid; gap: 2rem; align-items: center; }
@media (min-width: 900px) {
  .hero-split { grid-template-columns: 1.1fr 0.9fr; gap: 3.5rem; }
}
.hero-copy .display { font-size: clamp(2.4rem, 5vw, 3.6rem); }
.hero-aside { color: var(--faint); font-size: 0.9rem; margin: 0; }
.hero-aside a { color: var(--mute); }
.hero-aside a:hover { color: var(--foreground); }
.signin-panel { display: grid; gap: 1.4rem; padding: 1.6rem; }
.signin-panel .note { margin: 0; }
.points-stack { gap: 0.55rem; }
.points-stack .point { grid-template-columns: auto 1fr; align-items: start; gap: 0.85rem; padding: 0.9rem 1rem; }
.points-stack .point h3 { font-size: 0.92rem; margin-bottom: 0.15rem; }
.points-stack .point p { font-size: 0.85rem; margin: 0; }
.points-stack .point div { display: grid; gap: 0.2rem; }

/* The sign-in card: everything the page is for, in one card. */
.compact-card { display: grid; gap: 1.3rem; padding: 2rem; }
@media (min-width: 640px) { .compact-card { padding: 2.4rem; } }
.compact-top { text-align: center; justify-items: center; }
.compact-top .eyebrow { justify-content: center; }
.compact-top .body, .compact-top .note { margin: 0; }
.compact-facts { list-style: none; display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.6rem; padding: 0; margin: 0; }
.compact-facts li {
  display: grid; justify-items: center; text-align: center; gap: 0.3rem; padding: 0.9rem 0.6rem;
  border: 1px solid var(--line); border-radius: 0.85rem; background: rgba(255, 255, 255, 0.02);
  font-size: 0.82rem; color: var(--mute);
}
.compact-facts b { color: var(--foreground); font-size: 0.9rem; }
.compact-facts .ico { display: grid; place-items: center; width: 2rem; height: 2rem; border-radius: 0.6rem; background: rgba(255, 122, 69, 0.1); color: var(--neon-cyan); }
.compact-facts .ico svg { width: 1rem; height: 1rem; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.compact-aside { text-align: center; }
@media (max-width: 600px) { .compact-facts { grid-template-columns: 1fr; } }

.points { display: grid; gap: 1rem; list-style: none; }
@media (min-width: 720px) {
  .points-3 { grid-template-columns: repeat(3, 1fr); }
}
.point {
  display: grid;
  gap: 0.55rem;
  padding: 1.25rem;
  border: 1px solid var(--line);
  border-radius: 0.85rem;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.028), rgba(255, 255, 255, 0.006));
}
.point .ico {
  display: grid;
  place-items: center;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 0.6rem;
  background: rgba(255, 122, 69, 0.1);
  border: 1px solid rgba(255, 122, 69, 0.22);
  color: var(--neon-cyan);
}
.point .ico svg {
  width: 1.1rem;
  height: 1.1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.point h3 { font-size: 0.97rem; font-weight: 700; color: var(--foreground); }
.point p { color: var(--mute); font-size: 0.9rem; }

/* ── The signed-in user chip ───────────────────────────────────────────── */
.who {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0.75rem 0.9rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 0.8rem;
}
.who .avatar {
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  flex: none;
  background: var(--raised);
  object-fit: cover;
  border: 1px solid var(--line-strong);
}
.who .id { min-width: 0; flex: 1; }
.who .id strong {
  display: block;
  font-size: 0.95rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The Discord ID is 18 unbreakable digits, so it needs the same clipping the
   display name above it gets. */
.who .id span {
  display: block;
  color: var(--faint);
  font-size: 0.78rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── The server list ───────────────────────────────────────────────────── */
.servers { list-style: none; display: grid; gap: 0.75rem; }
.servers li {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem 1rem;
  padding: 1.1rem 1.25rem;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.035), rgba(255, 255, 255, 0.008));
  border: 1px solid var(--line);
  border-radius: 0.85rem;
  transition: transform 0.3s var(--ease), border-color 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.servers li:hover {
  transform: translateY(-2px);
  border-color: rgba(255, 122, 69, 0.4);
  box-shadow: 0 24px 50px -32px rgba(255, 122, 69, 0.35);
}
.servers .name { flex: 1 1 14rem; min-width: 0; }
.servers .name strong { display: block; font-size: 1rem; }
.servers .name span {
  display: block;
  color: var(--faint);
  font-size: 0.82rem;
  font-family: var(--mono);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tag {
  flex: none;
  padding: 0.2rem 0.55rem;
  border-radius: 9999px;
  background: rgba(255, 122, 69, 0.1);
  border: 1px solid rgba(255, 122, 69, 0.28);
  color: var(--neon-cyan);
  font-size: 0.68rem;
  font-weight: 750;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.empty {
  padding: 2rem 1.5rem;
  text-align: center;
  border: 1px dashed var(--line-strong);
  border-radius: 0.85rem;
  background: rgba(255, 255, 255, 0.012);
  display: grid;
  gap: 0.6rem;
  justify-items: center;
}

/* A loading row that looks like the thing it is waiting for, so the page does
   not jump when the list arrives. */
.skeleton { display: grid; gap: 0.75rem; }
.skeleton div {
  height: 4.4rem;
  border-radius: 0.85rem;
  border: 1px solid var(--line);
  background: linear-gradient(100deg, rgba(255, 255, 255, 0.022) 30%,
              rgba(255, 255, 255, 0.055) 50%, rgba(255, 255, 255, 0.022) 70%);
  background-size: 220% 100%;
  animation: shimmer 1.5s linear infinite;
}
@keyframes shimmer { to { background-position: -220% 0; } }

/* ── Status dot ────────────────────────────────────────────────────────── */
.state {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--faint);
  font-size: 0.85rem;
}
.dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--faint);
  flex: none;
  animation: pulse 1.8s ease-in-out infinite;
}
.dot.ok { background: var(--ok); animation: none; }
@keyframes pulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }

/* ── Footer ────────────────────────────────────────────────────────────── */
.foot {
  border-top: 1px solid var(--line);
  background: #04050a;
  margin-top: 2rem;
}
.foot .shell {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.6rem;
}
.foot p { color: var(--faint); font-size: 0.82rem; }
.foot p > a { color: var(--mute); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: rgba(255, 255, 255, 0.2); }
.foot p > a:hover { color: var(--foreground); text-decoration-color: var(--neon-cyan); }
.legal-line { color: var(--faint); font-size: 0.8rem; margin: 0; }
.legal-line a { color: var(--mute); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: rgba(255, 255, 255, 0.2); }
.legal-line a:hover { color: var(--foreground); text-decoration-color: var(--neon-cyan); }
.foot .legal-line { margin-top: 0.4rem; }

.row-between {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

/* ── Reduced motion ────────────────────────────────────────────────────────
   One block, matching the sites. Everything decorative stops; nothing that
   conveys state (the pulsing probe dot aside, which is why it is listed) is
   left mid-transition.                                                      */
@media (prefers-reduced-motion: reduce) {
  .aurora span, .grid-bg, .beam, .display .shimmer { animation: none; }
  .fx, .spot, .ring { display: none; }
  .fx-stage .aurora { transition: none; transform: none; }
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .reveal { opacity: 1 !important; transform: none !important; }
  .grain, .cursor-glow, .field { display: none; }
}
