/* ============================================================
   GoyHub — CS2 companion site
   Visual language: HEAVY LIQUID GLASS. Every surface is a thick
   refractive pane floating over a live field of coloured light —
   backdrop refraction, a specular edge that runs the whole rim, a
   sheen that tracks the pointer, and gel physics on press. The
   React Bits-derived motion components (see public/js/fx.js) still
   drive the hero; they now light glass instead of paper.

   Read the material spec below before changing a surface: the fill,
   the edge and the shadow all come from tokens, so re-skinning is a
   token edit, not a component-by-component rewrite.
   ============================================================ */

/* ---------- Self-hosted fonts (SIL OFL 1.1; served from /fonts) ---------- */
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("/fonts/space-grotesk-var.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("/fonts/jetbrains-mono-var.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ============================================================
   LIQUID GLASS — the material
   ------------------------------------------------------------
   Every surface on this site is one material: a thick, refractive
   pane floating over a slow-moving field of coloured light. Three
   things have to be true at once or it reads as "blurry box":

   1. THERE MUST BE SOMETHING BEHIND IT. Blur over flat paint is
      invisible, so the page ships its own ambient light field
      (see .lg-field below) that every pane bends.
   2. THE EDGE CARRIES THE LIGHT. Real glass is brightest where it
      curves — a hot top rim, a full inner ring, a bounce along the
      bottom lip. That whole stack lives in --ring-shadow, which the
      components already spend, so redefining it re-skins the site.
   3. IT REACTS. The pane picks up a specular smear under the
      pointer (fx.js feeds --spot-x/--spot-y), swells on hover and
      compresses under a press.

   Shape system — Apple's, near enough. iOS radii are tighter than a
   glass-first instinct suggests, and they nest concentrically (an inner
   radius is the outer one minus the gap between them):
   - fields, cells, tabs, small controls ... 10px  (grouped table cell)
   - buttons ............................... 12px  (large bordered button)
   - cards, panels, rows ................... 14px  (alert)
   - floating panels, sheets, dialogs ...... 20px
   - badges and pips ....................... capsule / circle

   Value is only half of it: an iOS corner is a CONTINUOUS curve, not a
   circular arc, which is why the same number reads softer there than in
   a browser. `corner-shape: squircle` gets that curve — see the block at
   the end of this file.
   ============================================================ */

:root {
  /* Grounds. Deliberately NOT white: a pane of near-white glass only
     reads as glass when the ground it floats over is darker and
     coloured. The ambient field adds the colour; these set the floor. */
  --bg: #e7ecf9;

  /* Panes. Translucent by definition — every component that reaches for
     --panel gets the material, and the backdrop blur is added by the
     .lg-surface group below. */
  --panel: rgba(255, 255, 255, 0.62);
  --panel-2: rgba(255, 255, 255, 0.38);

  /* Structural ink. --border is a divider (panel heads, table rules,
     timelines) so it has to stay visible ON a bright pane — it is a
     dark hairline, never a white one. The bright specular edge is a
     separate job, done by --ring-shadow. */
  --border: rgba(14, 26, 58, 0.11);
  --border-strong: #6b7a99; /* 4.0:1 on the pane — clears SC 1.4.11 for control boundaries */
  --text: #0a1226;
  --text-soft: #263149;
  --muted: #55627e;

  /* Brand — one accent family, used identically site-wide */
  --accent: #0137b7;
  --accent-hover: #0246d8;
  --accent-deep: #012a8c;
  --accent-soft: rgba(1, 55, 183, 0.09);
  --accent-tint: rgba(1, 55, 183, 0.18);
  --accent-glow: rgba(1, 55, 183, 0.3);

  /* Semantic — all AA on the pane */
  --success: #0c6f3f;
  --danger: #c01829;
  --warn: #8a5a00;

  /* Component inks and tints. These live in variables (not [data-theme]
     component overrides) so the no-JS prefers-color-scheme dark fallback
     gets the same AA-critical treatment as the toggled dark theme. */
  --on-accent: #ffffff;
  --on-success: #ffffff;
  --accent-ink: #0137b7;
  --ghost-hover: rgba(10, 18, 38, 0.06);
  --tint-success: rgba(12, 111, 63, 0.12);
  --tint-danger: rgba(192, 24, 41, 0.12);
  --tint-danger-strong: rgba(192, 24, 41, 0.18);
  --tint-danger-soft: rgba(192, 24, 41, 0.07);
  --tint-warn: rgba(138, 90, 0, 0.14);
  --tier-dev-ink: #6a3fb5;
  --tier-dev-tint: rgba(106, 63, 181, 0.14);
  --announcement-bg: linear-gradient(90deg, var(--accent-deep), var(--accent));

  --radius-ctl: 10px;
  --radius-btn: 12px;
  --radius-card: 14px;
  --radius-xl: 20px;
  --radius-tag: 999px;

  /* ---- The material ---- */
  /* Blur strengths. Only three surfaces spend a backdrop pass (see "Where
     the refraction actually goes" below), so both can be generous. */
  --glass-blur-nav: 30px;
  --glass-blur-modal: 44px;
  --glass-sat: 180%;

  /* Edge light. Read top-down: hot rim, inner ring, bottom bounce,
     outer hairline. Components spend this as the first layer of their
     box-shadow, so it lands on every pane at once. */
  --glass-hi: rgba(255, 255, 255, 0.95);
  --glass-ring: rgba(255, 255, 255, 0.42);
  --glass-lo: rgba(255, 255, 255, 0.7);
  --glass-edge: rgba(12, 22, 50, 0.1);
  --ring-shadow:
    inset 0 1px 0 var(--glass-hi),
    inset 0 0 0 1px var(--glass-ring),
    inset 0 -20px 34px -28px var(--glass-lo),
    0 0 0 1px var(--glass-edge);

  /* The film: the gradient painted across the face of a pane. Steep,
     so the top-left corner catches light and the body stays clear. */
  --glass-film: linear-gradient(
    158deg,
    rgba(255, 255, 255, 0.5) 0%,
    rgba(255, 255, 255, 0.08) 32%,
    rgba(255, 255, 255, 0) 58%,
    rgba(255, 255, 255, 0.22) 100%
  );
  /* Specular smear that tracks the pointer across a pane */
  --glass-sheen: rgba(255, 255, 255, 0.55);

  --shadow-sm: 0 2px 8px -2px rgba(10, 20, 48, 0.1), 0 10px 26px -16px rgba(10, 20, 48, 0.18);
  --shadow: 0 8px 20px -8px rgba(10, 20, 48, 0.14), 0 30px 66px -22px rgba(10, 20, 48, 0.3);
  --shadow-lift: 0 12px 26px -10px rgba(10, 20, 48, 0.18), 0 44px 90px -26px rgba(10, 20, 48, 0.36);
  --shadow-accent: 0 10px 30px -6px rgba(1, 55, 183, 0.4), 0 2px 10px -2px rgba(1, 55, 183, 0.3);

  /* The ambient light field the glass refracts. */
  --field-1: rgba(1, 55, 183, 0.34);
  --field-2: rgba(0, 172, 236, 0.3);
  --field-3: rgba(124, 62, 232, 0.28);
  --field-4: rgba(0, 204, 184, 0.24);
  --field-wash: rgba(255, 255, 255, 0.58);
  --field-opacity: 1;
  --grain-opacity: 0.14;

  /* Full-bleed bands (stats strip, download rail, footer). Translucent so
     the ambient field keeps running underneath them instead of being
     interrupted by an opaque slab. */
  --band: rgba(255, 255, 255, 0.44);

  --nav-h: 82px;

  --font: system-ui, -apple-system, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --font-display: "Space Grotesk", "Segoe UI", system-ui, -apple-system, sans-serif;
  --mono: "JetBrains Mono", "Cascadia Code", Consolas, "SF Mono", monospace;

  /* Canvas effect palette (RGB triplets / colors consumed by fx.js) */
  --fx-link: 104, 122, 158;
  --fx-dot: 104, 122, 158;
  --fx-ember: 1, 55, 183;
  --fx-spark: #0137b7;
  --fx-aurora-a: #a8c0f2;
  --fx-aurora-b: #7fa4f0;
  --aurora-opacity: 0.55;
  --spot-color: rgba(1, 55, 183, 0.09);
  --glass: rgba(255, 255, 255, 0.55);

  color-scheme: light;
}

/* ============================================================
   Dark theme — set on <html data-theme="dark"> by public/js/boot.js
   before first paint (from a saved choice or prefers-color-scheme),
   and flipped live by the nav toggle. The media-query block below is
   a no-JS fallback so a dark-OS visitor without scripting still gets
   correct variables.

   Dark glass is not "the same pane, darker". It is a thin white film
   over near-black: the tint drops to single-digit percentages, the
   edge light halves, and the drop shadow does the separating that the
   ring can no longer do.
   ============================================================ */
:root[data-theme="dark"] {
  --bg: #04060d;
  --panel: rgba(10, 16, 34, 0.58);
  --panel-2: rgba(4, 7, 18, 0.46);
  --border: rgba(255, 255, 255, 0.12);
  --border-strong: rgba(255, 255, 255, 0.42);
  --text: #eef2fb;
  --text-soft: #c3cce3;
  --muted: #98a3c4;
  --accent: #85aaff;
  --accent-hover: #b0caff;
  --accent-deep: #4a76e8;
  --accent-soft: rgba(133, 170, 255, 0.15);
  --accent-tint: rgba(133, 170, 255, 0.3);
  --accent-glow: rgba(133, 170, 255, 0.45);
  --success: #3ecb82;
  --danger: #ff6b7a;
  --warn: #e0a83c;
  --on-accent: #05070f;
  --on-success: #05070f;
  --accent-ink: #a8c4ff;
  --ghost-hover: rgba(255, 255, 255, 0.09);
  --tint-success: rgba(62, 203, 130, 0.16);
  --tint-danger: rgba(255, 107, 122, 0.16);
  --tint-danger-strong: rgba(255, 107, 122, 0.2);
  --tint-danger-soft: rgba(255, 107, 122, 0.1);
  --tint-warn: rgba(224, 168, 60, 0.18);
  --tier-dev-ink: #b79cf0;
  --tier-dev-tint: rgba(167, 124, 235, 0.18);
  --announcement-bg: var(--accent-deep);

  --glass-hi: rgba(255, 255, 255, 0.3);
  --glass-ring: rgba(255, 255, 255, 0.09);
  --glass-lo: rgba(255, 255, 255, 0.22);
  --glass-edge: rgba(0, 0, 0, 0.6);
  --glass-film: linear-gradient(
    158deg,
    rgba(255, 255, 255, 0.16) 0%,
    rgba(255, 255, 255, 0.03) 34%,
    rgba(255, 255, 255, 0) 60%,
    rgba(255, 255, 255, 0.07) 100%
  );
  --glass-sheen: rgba(160, 195, 255, 0.22);

  --shadow-sm: 0 2px 8px -2px rgba(0, 0, 0, 0.5), 0 10px 26px -16px rgba(0, 0, 0, 0.6);
  --shadow: 0 10px 24px -10px rgba(0, 0, 0, 0.6), 0 34px 72px -24px rgba(0, 0, 0, 0.8);
  --shadow-lift: 0 14px 30px -12px rgba(0, 0, 0, 0.66), 0 48px 96px -28px rgba(0, 0, 0, 0.86);
  --shadow-accent: 0 10px 32px -6px rgba(133, 170, 255, 0.45), 0 2px 12px -2px rgba(133, 170, 255, 0.3);

  --field-1: rgba(29, 63, 168, 0.55);
  --field-2: rgba(0, 122, 190, 0.4);
  --field-3: rgba(88, 44, 200, 0.42);
  --field-4: rgba(0, 140, 140, 0.3);
  --field-wash: rgba(20, 34, 74, 0.55);
  --field-opacity: 1;
  --grain-opacity: 0.2;

  --fx-link: 116, 142, 205;
  --fx-dot: 116, 142, 205;
  --fx-ember: 120, 160, 255;
  --fx-spark: #85aaff;
  --fx-aurora-a: #1d3fa8;
  --fx-aurora-b: #5c8cff;
  --aurora-opacity: 0.85;
  --spot-color: rgba(140, 175, 255, 0.12);
  --glass: rgba(8, 13, 30, 0.66);
  --band: rgba(4, 7, 16, 0.42);
  color-scheme: dark;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) {
    --bg: #04060d;
    --panel: rgba(10, 16, 34, 0.58);
    --panel-2: rgba(4, 7, 18, 0.46);
    --border: rgba(255, 255, 255, 0.12);
    --border-strong: rgba(255, 255, 255, 0.42);
    --text: #eef2fb;
    --text-soft: #c3cce3;
    --muted: #98a3c4;
    --accent: #85aaff;
    --accent-hover: #b0caff;
    --accent-deep: #4a76e8;
    --accent-soft: rgba(133, 170, 255, 0.15);
    --accent-tint: rgba(133, 170, 255, 0.3);
    --accent-glow: rgba(133, 170, 255, 0.45);
    --success: #3ecb82;
    --danger: #ff6b7a;
    --warn: #e0a83c;
    --on-accent: #05070f;
    --on-success: #05070f;
    --accent-ink: #a8c4ff;
    --ghost-hover: rgba(255, 255, 255, 0.09);
    --tint-success: rgba(62, 203, 130, 0.16);
    --tint-danger: rgba(255, 107, 122, 0.16);
    --tint-danger-strong: rgba(255, 107, 122, 0.2);
    --tint-danger-soft: rgba(255, 107, 122, 0.1);
    --tint-warn: rgba(224, 168, 60, 0.18);
    --tier-dev-ink: #b79cf0;
    --tier-dev-tint: rgba(167, 124, 235, 0.18);
    --announcement-bg: var(--accent-deep);
    --glass-hi: rgba(255, 255, 255, 0.3);
    --glass-ring: rgba(255, 255, 255, 0.09);
    --glass-lo: rgba(255, 255, 255, 0.22);
    --glass-edge: rgba(0, 0, 0, 0.6);
    --glass-film: linear-gradient(
      158deg,
      rgba(255, 255, 255, 0.16) 0%,
      rgba(255, 255, 255, 0.03) 34%,
      rgba(255, 255, 255, 0) 60%,
      rgba(255, 255, 255, 0.07) 100%
    );
    --glass-sheen: rgba(160, 195, 255, 0.22);
    --shadow-sm: 0 2px 8px -2px rgba(0, 0, 0, 0.5), 0 10px 26px -16px rgba(0, 0, 0, 0.6);
    --shadow: 0 10px 24px -10px rgba(0, 0, 0, 0.6), 0 34px 72px -24px rgba(0, 0, 0, 0.8);
    --shadow-lift: 0 14px 30px -12px rgba(0, 0, 0, 0.66), 0 48px 96px -28px rgba(0, 0, 0, 0.86);
    --shadow-accent: 0 10px 32px -6px rgba(133, 170, 255, 0.45), 0 2px 12px -2px rgba(133, 170, 255, 0.3);
    --field-1: rgba(29, 63, 168, 0.55);
    --field-2: rgba(0, 122, 190, 0.4);
    --field-3: rgba(88, 44, 200, 0.42);
    --field-4: rgba(0, 140, 140, 0.3);
    --field-wash: rgba(20, 34, 74, 0.55);
    --grain-opacity: 0.2;
    --fx-link: 116, 142, 205;
    --fx-dot: 116, 142, 205;
    --fx-ember: 120, 160, 255;
    --fx-spark: #85aaff;
    --fx-aurora-a: #1d3fa8;
    --fx-aurora-b: #5c8cff;
    --aurora-opacity: 0.85;
    --spot-color: rgba(140, 175, 255, 0.12);
    --glass: rgba(8, 13, 30, 0.66);
    --band: rgba(4, 7, 16, 0.42);
    color-scheme: dark;
  }
  /* No-JS dark fallback: the [data-theme="dark"] ink overrides below only fire
     once boot.js stamps the attribute. Repeat them here (guarded so an explicit
     light choice still wins) so a dark-OS visitor without scripting also gets
     navy ink on the light-blue accent instead of low-contrast white. */
  :root:not([data-theme="light"]):not([data-theme="dark"]) .btn-primary,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .btn-primary:hover,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .announcement,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .announcement-dismiss,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .skip-link,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .page.current { color: #0a1226; }
}

/* ============================================================
   THE AMBIENT FIELD
   ------------------------------------------------------------
   Glass is a lens, and a lens over flat paint shows nothing. So the
   document ships its own light to bend: four wide colour lobes and a
   central wash, fixed to the viewport, drifting slowly enough that you
   read it as depth rather than as animation.

   It is painted by ::before on <body> at z-index -1. <html> owns the
   base colour so the pseudo-element lands ABOVE the canvas background
   and BELOW every pane. <body> deliberately keeps no background and no
   stacking context of its own, which is what lets -1 resolve there.
   ============================================================ */
html { background: var(--bg); }

body::before,
body::after {
  content: "";
  position: fixed;
  inset: -30%;
  z-index: -1;
  pointer-events: none;
}

body::before {
  background:
    radial-gradient(46rem 34rem at 18% 12%, var(--field-1), transparent 62%),
    radial-gradient(40rem 30rem at 84% 6%, var(--field-2), transparent 64%),
    radial-gradient(44rem 36rem at 76% 84%, var(--field-3), transparent 62%),
    radial-gradient(36rem 30rem at 10% 82%, var(--field-4), transparent 64%),
    radial-gradient(60rem 46rem at 50% 46%, var(--field-wash), transparent 72%);
  opacity: var(--field-opacity);
  animation: lg-drift 46s ease-in-out infinite alternate;
  will-change: transform;
}

/* Grain. A perfectly smooth gradient reads as a screen; a grained one
   reads as a material. feTurbulence rather than a bitmap, so it costs a
   few hundred bytes and stays sharp at any density.

   Three details make it actual grain rather than a flat wash:
   color-interpolation-filters='sRGB' (the default, linearRGB, lands the
   noise around 187 instead of 128, so `overlay` would only ever
   lighten); the saturate matrix, which greys it; and the alpha ramp,
   which pins alpha at 1 — raw fractalNoise varies alpha too, and a
   half-transparent noise field just tints the page. */
body::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: var(--grain-opacity);
  mix-blend-mode: overlay;
}

@keyframes lg-drift {
  0% { transform: translate3d(0, 0, 0) scale(1); }
  50% { transform: translate3d(2.5%, -2%, 0) scale(1.06); }
  100% { transform: translate3d(-2%, 2.5%, 0) scale(1.02); }
}

/* ============================================================
   THE PANE
   ------------------------------------------------------------
   One shared recipe, spent by every surface class on the site. It
   supplies only what a colour token cannot: the backdrop refraction,
   the film across the face, and the specular smear that tracks the
   pointer. Fill, edge and shadow keep coming from --panel, --border
   and --ring-shadow, so a component that already said
   `background: var(--panel)` needs no edit to become glass.

   This block sits BEFORE the component rules on purpose: everything
   below can still override it (a sticky sidebar keeps its sticky).
   ============================================================ */
.lg-pane,
.nav-inner,
.panel,
.feature-card,
.recent-thread,
.category-card,
.thread-row,
.post,
.reply-box,
.auth-card,
.forum-sidebar,
.hud-card,
.download-box,
.faq-item,
.plan-card,
.stat-card,
.support-step,
.csat,
.status-hero,
.status-components,
.incident,
.status-note,
.legal-toc,
.legal-contact,
.legal-summary,
.try-first,
.terms-gate-card,
.code-block,
.empty-state,
.switch-note,
.upgrade-note,
.admin-tabs,
.component-picker,
.pay-details,
.help-card,
.stats-strip,
.site-footer {
  position: relative;
  isolation: isolate;
  border-radius: var(--radius-card);
}

/* ---------- Where the refraction actually goes ----------
   A backdrop pass costs one full snapshot per element, and it only shows
   when there is DETAIL behind it to bend. Measured against rendered
   pixels: a pane over the ambient field is within 1-5/255 of the same
   pane with no pass at all (the field is smooth radial gradient — blur
   a gradient and you get the gradient back), while the hero HUD, which
   floats over the live particle canvas and aurora, differs by a mean of
   14 and a peak of 232.

   So the pass is spent on the three surfaces with real content behind
   them, and every other pane gets its glass from the tint, the edge
   light and the film — same pixels, bounded cost. */
.nav-inner,
.hud-card {
  -webkit-backdrop-filter: blur(var(--glass-blur-nav)) saturate(var(--glass-sat));
  backdrop-filter: blur(var(--glass-blur-nav)) saturate(var(--glass-sat));
}
/* The dialog is the fourth: the entire page is behind it. Its scrim carries a
   pass of its own so the depth-of-field starts at the scrim, not at the card
   (see .terms-gate). */
.terms-gate-card {
  -webkit-backdrop-filter: blur(var(--glass-blur-modal)) saturate(var(--glass-sat));
  backdrop-filter: blur(var(--glass-blur-modal)) saturate(var(--glass-sat));
}

/* The face of the pane: a steep film, plus a radial smear parked under
   the pointer. fx.js feeds --spot-x/--spot-y in pixels; with no pointer
   (touch, keyboard, no JS) the smear rests off the top edge, which is
   exactly where a fixed overhead light would put it. */
.lg-pane::before,
.nav-inner::before,
.panel::before,
.feature-card::before,
.recent-thread::before,
.category-card::before,
.thread-row::before,
.post::before,
.reply-box::before,
.auth-card::before,
.forum-sidebar::before,
.hud-card::before,
.download-box::before,
.faq-item::before,
.plan-card::before,
.stat-card::before,
.support-step::before,
.csat::before,
.status-hero::before,
.status-components::before,
.incident::before,
.status-note::before,
.legal-toc::before,
.legal-contact::before,
.legal-summary::before,
.try-first::before,
.terms-gate-card::before,
.code-block::before,
.empty-state::before,
.switch-note::before,
.upgrade-note::before,
.admin-tabs::before,
.component-picker::before,
.pay-details::before,
.help-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  background:
    radial-gradient(16rem 12rem at var(--spot-x, 50%) var(--spot-y, -25%), var(--glass-sheen), transparent 72%),
    var(--glass-film);
}

/* Liquid response. A pane under the pointer swells and its edge light
   comes up; a pressed pane compresses like a gel button. Components
   that already own a :hover transform (the bento cards, the category
   rows) keep theirs — this only raises the light. */
.lg-pane,
.feature-card,
.recent-thread,
.category-card,
.thread-row,
.plan-card,
.stat-card,
.support-step,
.faq-item,
.help-card,
.incident {
  transition:
    transform 0.32s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.32s cubic-bezier(0.22, 1, 0.36, 1),
    border-color 0.24s ease;
}

.lg-pane:hover,
.feature-card:hover,
.recent-thread:hover,
.category-card:hover,
.thread-row:hover,
.plan-card:hover,
.support-step:hover,
.help-card:hover {
  --glass-sheen: rgba(255, 255, 255, 0.72);
}
[data-theme="dark"] .lg-pane:hover,
[data-theme="dark"] .feature-card:hover,
[data-theme="dark"] .recent-thread:hover,
[data-theme="dark"] .category-card:hover,
[data-theme="dark"] .thread-row:hover,
[data-theme="dark"] .plan-card:hover,
[data-theme="dark"] .support-step:hover,
[data-theme="dark"] .help-card:hover { --glass-sheen: rgba(170, 205, 255, 0.32); }

/* ---------- Chips: glass without the blur ----------
   Small things nested inside a pane get the tint and the edge but no
   backdrop pass of their own. Nesting refraction inside refraction
   costs a compositor layer each and looks flatter, not deeper. */
.tag,
.uid-badge,
.attach-item,
.shout-row,
.chat-msg,
.pagination .page,
.ai-draft-body,
.pay-address,
.pay-value,
.post-author,
.beacon-dot {
  box-shadow:
    inset 0 1px 0 var(--glass-ring),
    inset 0 -1px 0 var(--glass-edge);
}

/* ---------- Base ---------- */
* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

/* Transparent on purpose. <html> holds the ground colour so that the
   ambient field on body::before (z-index -1) paints above it; a colour
   here would paint over the field and take the light away from every
   pane on the page. */
body {
  font-family: var(--font);
  background: transparent;
  color: var(--text);
  line-height: 1.6;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}

main { flex: 1; }

/* Display type is medium-weight and tight (crafted look: hierarchy from
   size and space, not boldness) */
h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.02em; }

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }

/* Focus on glass: the hard outline stays (it is the accessible part) and a
   soft accent halo is added underneath so the ring reads against a pane
   that is itself already bright at the edge. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}

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

.container { width: min(1160px, 92%); margin: 0 auto; }
.container.narrow { max-width: 760px; }
.center { text-align: center; }
.muted { color: var(--muted); }
.mono { font-family: var(--mono); font-size: 0.85em; }
.nowrap { white-space: nowrap; }
.fineprint { color: var(--muted); font-size: 0.8rem; margin-top: 1.2rem; }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--accent-deep); color: #fff; padding: 0.6rem 1.2rem;
  border-radius: 0 0 var(--radius-ctl) 0;
  box-shadow: var(--shadow-accent);
}
.skip-link:focus { left: 0; }

/* Screen-reader-only text (used by fx.js for split/scrambled headlines) */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Full-viewport canvas for the ClickSpark effect (created by fx.js).
   Explicit size matters: a canvas is a replaced element, so inset alone
   would leave it at its intrinsic (dpr-scaled) pixel size. */
.click-spark-canvas {
  position: fixed; inset: 0; width: 100%; height: 100%; z-index: 90;
  pointer-events: none;
}

/* ---------- Buttons: glass pills ----------
   Curvature is what makes a small pane read as glass, so every button
   is fully round. Each one carries the same three layers as a card —
   a film (::before), an edge-light stack (box-shadow) and a drop
   shadow — scaled down. Only the translucent variants pay for a
   backdrop pass; the primary button is near-opaque, so refraction
   behind it would be work nobody can see. */
.btn {
  position: relative;
  isolation: isolate;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  font-family: var(--font-display); font-size: 1rem; font-weight: 500; cursor: pointer;
  padding: 0.62rem 1.4rem; border-radius: var(--radius-btn);
  border: 1px solid transparent;
  transition: color 0.2s ease, background 0.2s ease, border-color 0.2s ease,
    box-shadow 0.3s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
  white-space: nowrap;
}
.btn::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  border-radius: inherit; pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.45) 0%,
    rgba(255, 255, 255, 0.06) 46%,
    rgba(255, 255, 255, 0) 62%,
    rgba(255, 255, 255, 0.16) 100%
  );
}
/* Gel physics: the pill swells toward the pointer and compresses under
   a press, the way a soft solid would. */
.btn:hover { transform: translateY(-1px) scale(1.025); }
.btn:active { transform: translateY(0) scale(0.965); transition-duration: 0.09s; }
.btn svg { width: 1.15em; height: 1.15em; }

/* Dark themes flip the primary-button ink to dark-on-bright via
   --on-accent (white on the bright dark accent fails AA at 3.6:1). */
.btn-primary {
  background: linear-gradient(180deg, var(--accent-hover), var(--accent));
  color: var(--on-accent);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.4),
    inset 0 0 0 1px rgba(255, 255, 255, 0.16),
    inset 0 -10px 18px -14px rgba(255, 255, 255, 0.5),
    var(--shadow-accent);
}
.btn-primary:hover {
  background: linear-gradient(180deg, var(--accent), var(--accent-hover));
  color: var(--on-accent);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 0 0 1px rgba(255, 255, 255, 0.22),
    inset 0 -10px 18px -14px rgba(255, 255, 255, 0.6),
    0 14px 40px -8px var(--accent-glow), var(--shadow-accent);
}

.btn-outline {
  background: var(--panel-2); color: var(--accent-ink); border-color: var(--border-strong);
  box-shadow: inset 0 1px 0 var(--glass-ring), var(--shadow-sm);
}
.btn-outline:hover {
  border-color: var(--accent); color: var(--accent-hover); background: var(--accent-soft);
  box-shadow: inset 0 1px 0 var(--glass-hi), 0 10px 28px -10px var(--accent-glow);
}
.btn-ghost { background: transparent; color: var(--muted); border-color: transparent; }
.btn-ghost::before { opacity: 0; transition: opacity 0.2s ease; }
.btn-ghost:hover::before { opacity: 1; }
.btn-ghost:hover {
  color: var(--text); background: var(--ghost-hover);
  box-shadow: inset 0 1px 0 var(--glass-ring), var(--shadow-sm);
}
/* Soft destructive: tinted fills, never solid red slabs */
.btn-danger {
  background: var(--tint-danger-soft); color: var(--danger); border-color: transparent;
  box-shadow: inset 0 1px 0 var(--glass-ring);
}
.btn-danger:hover { background: var(--tint-danger); color: var(--danger); box-shadow: inset 0 1px 0 var(--glass-hi), var(--shadow-sm); }
.btn-warn {
  background: var(--tint-warn); color: var(--warn); border-color: transparent;
  box-shadow: inset 0 1px 0 var(--glass-ring);
}
.btn-warn:hover { background: var(--tint-danger-soft); color: var(--warn); box-shadow: inset 0 1px 0 var(--glass-hi), var(--shadow-sm); }
/* Smaller buttons take a smaller radius rather than a scaled one: a 12px
   corner on a 26px-tall control reads as a lozenge. */
.btn-sm { padding: 0.38rem 1rem; font-size: 0.9rem; border-radius: 10px; }
.btn-xs { padding: 0.2rem 0.7rem; font-size: 0.78rem; border-radius: 8px; }
.btn-lg { padding: 0.9rem 1.9rem; font-size: 1.05rem; border-radius: 14px; }
.btn-block { width: 100%; }
.btn:disabled { opacity: 0.55; cursor: not-allowed; transform: none; box-shadow: none; }
.btn:disabled::before { opacity: 0.4; }
.btn-primary:disabled:hover { background: linear-gradient(180deg, var(--accent-hover), var(--accent)); transform: none; box-shadow: none; }

/* Magnet (React Bits) — fx.js feeds --magnet-x/y on [data-magnet] */
[data-magnet] {
  transform: translate3d(var(--magnet-x, 0px), var(--magnet-y, 0px), 0);
  transition: transform 0.3s ease-out; will-change: transform;
}
[data-magnet]:hover { transform: translate3d(var(--magnet-x, 0px), var(--magnet-y, 0px), 0); }

/* ShinyText (React Bits) — sweeping highlight over a button label */
.btn-download { position: relative; overflow: hidden; }
.btn-download::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(110deg, transparent 30%, rgba(255, 255, 255, 0.4) 50%, transparent 70%);
  transform: translateX(-120%);
  animation: shine 3.2s ease-in-out infinite;
}
@keyframes shine { 0%, 60% { transform: translateX(-120%); } 100% { transform: translateX(120%); } }

/* ---------- Download button click choreography ----------
   Layers on the ShinyText button above. Idle: the arrow nudges on hover.
   Clicked: the shine parks, the arrow falls over an indeterminate progress
   strip while the browser starts the download, then the button settles green
   with a drawn checkmark. Driven by fx.js; a no-JS button keeps its idle look
   and still downloads. Indeterminate on purpose — a native download reports no
   bytes back to the page, so nothing here fakes a percentage. */
.btn-download.is-busy::after, .btn-download.is-done::after { animation: none; opacity: 0; }

.dl-icon { position: relative; flex: none; width: 1.15em; height: 1.15em; }
.dl-icon svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.dl-arrow, .dl-check { transition: opacity 0.2s ease, transform 0.2s ease; }
.dl-check { opacity: 0; transform: scale(0.5); }
.btn-download:hover .dl-arrow { animation: dl-nudge 1.1s ease-in-out infinite; }
@keyframes dl-nudge { 0%, 100% { transform: translateY(0); } 45% { transform: translateY(2.5px); } }

.btn-download.is-busy .dl-arrow { animation: dl-drop 0.85s ease-in-out infinite; }
@keyframes dl-drop {
  0% { transform: translateY(-65%); opacity: 0; }
  30% { opacity: 1; }
  70% { transform: translateY(30%); opacity: 1; }
  100% { transform: translateY(55%); opacity: 0; }
}
.btn-download.is-done { background: var(--success); border-color: var(--success); }
.btn-download.is-done .dl-arrow { opacity: 0; transform: scale(0.5); animation: none; }
.btn-download.is-done .dl-check { opacity: 1; transform: none; }
.dl-check path { stroke-dasharray: 24; stroke-dashoffset: 24; }
.btn-download.is-done .dl-check path { animation: dl-draw 0.36s 0.04s ease forwards; }
@keyframes dl-draw { to { stroke-dashoffset: 0; } }

/* Label text is swapped mid-fade so "Download now" -> "Starting…" doesn't jump. */
.dl-label { transition: opacity 0.16s ease; }
.btn-download.is-swapping .dl-label { opacity: 0; }

.dl-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; opacity: 0; overflow: hidden; }
.dl-progress::before {
  content: ""; position: absolute; top: 0; bottom: 0; width: 38%; border-radius: 3px;
  background: rgba(255, 255, 255, 0.92); transform: translateX(-110%);
}
.btn-download.is-busy .dl-progress { opacity: 1; }
.btn-download.is-busy .dl-progress::before { animation: dl-sweep 1s ease-in-out infinite; }
@keyframes dl-sweep { to { transform: translateX(275%); } }

/* Held shut for a moment after a click: a second click would spend one of the
   downloads an IP gets per window (see routes-main.js rate limit). */
.btn-download.is-busy, .btn-download.is-done { pointer-events: none; }

/* ---------- Download confirmation toast ---------- */
.dl-toast {
  position: fixed; right: 1.1rem; bottom: 1.1rem; z-index: 60;
  display: flex; align-items: flex-start; gap: 0.7rem;
  width: min(340px, calc(100vw - 2.2rem));
  background: var(--panel); color: var(--text);
  border: 1px solid var(--border-strong); border-left: 3px solid var(--success);
  border-radius: 12px; padding: 0.85rem 1rem; box-shadow: var(--shadow);
  animation: dl-toast-in 0.42s cubic-bezier(0.2, 0.9, 0.3, 1);
}
.dl-toast.out { animation: dl-toast-out 0.28s ease forwards; }
.dl-toast svg { flex: none; width: 20px; height: 20px; color: var(--success); margin-top: 0.1rem; }
.dl-toast-title { font-weight: 700; font-size: 0.95rem; }
.dl-toast-body { color: var(--muted); font-size: 0.85rem; margin-top: 0.15rem; word-break: break-word; }
.dl-toast-close {
  margin-left: auto; flex: none; background: none; border: 0; cursor: pointer;
  color: var(--muted); font-size: 1rem; line-height: 1; padding: 0.1rem 0.2rem;
}
.dl-toast-close:hover { color: var(--text); }
@keyframes dl-toast-in { from { opacity: 0; transform: translateY(14px) scale(0.97); } }
@keyframes dl-toast-out { to { opacity: 0; transform: translateY(10px); } }

/* StarBorder (React Bits) — two glowing comets chasing along the top and
   bottom edges of the border. Wrap a .btn in <span class="star-border">;
   the 2px padding is the "thickness" the moving glow shines through. */
.star-border {
  position: relative; display: inline-block;
  border-radius: calc(var(--radius-btn) + 2px);
  padding: 2px; overflow: hidden; vertical-align: middle;
  background: var(--accent-soft);
}
.star-border::before,
.star-border::after {
  content: ""; position: absolute; width: 300%; height: 50%;
  background: radial-gradient(circle, var(--accent), transparent 10%);
  opacity: 0.7; border-radius: 50%;
  animation: star-move-bottom 6s linear infinite alternate;
}
.star-border::after { bottom: -12px; right: -250%; }
.star-border::before { top: -12px; left: -250%; animation-name: star-move-top; }
.star-border .btn { position: relative; z-index: 1; }
/* The wrapper clips the button's own focus outline (overflow: hidden),
   so the ring moves to the wrapper. */
.star-border:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.star-border .btn:focus-visible { outline: none; }
@keyframes star-move-bottom {
  0% { transform: translateX(0); opacity: 1; }
  100% { transform: translateX(-100%); opacity: 0; }
}
@keyframes star-move-top {
  0% { transform: translateX(0); opacity: 1; }
  100% { transform: translateX(100%); opacity: 0; }
}

/* ---------- Nav: the floating capsule ----------
   The header itself is nothing — an invisible sticky rail. The pane is
   .nav-inner, a rounded capsule that hovers clear of the viewport edge
   so the page visibly runs underneath and through it. This is the one
   surface that is always over moving content, so it takes the heaviest
   blur on the site. */
.site-nav {
  position: sticky; top: 0; z-index: 50;
  background: transparent;
  padding: 0.7rem 0 0.3rem;
}
.nav-inner {
  display: flex; align-items: center; gap: 1.4rem;
  padding: 0.5rem 0.6rem 0.5rem 1.15rem;
  border-radius: var(--radius-xl);
  background: var(--glass);
  box-shadow: var(--ring-shadow), var(--shadow);
}
.brand {
  display: inline-flex; align-items: center; gap: 0.55rem;
  font-family: var(--font-display); font-size: 1.25rem; font-weight: 700;
  letter-spacing: 0.01em; color: var(--text);
}
.brand:hover { color: var(--text); }
.brand em { color: var(--accent-ink); font-style: normal; }
.brand-mark { width: 26px; height: 26px; color: var(--accent-ink); animation: spin-slow 24s linear infinite; }
@keyframes spin-slow { to { transform: rotate(360deg); } }
.nav-links { display: flex; gap: 0.25rem; margin-left: 0.4rem; flex: 1; flex-wrap: wrap; }
.nav-links a {
  position: relative;
  color: var(--muted); font-family: var(--font-display); font-weight: 500; font-size: 0.95rem;
  padding: 0.32rem 0.8rem; border-radius: var(--radius-ctl);
  border: 1px solid transparent;
  transition: color 0.18s ease, background 0.18s ease, box-shadow 0.24s ease;
}
.nav-links a:hover { color: var(--text); background: var(--ghost-hover); }
/* The current page is a lit pill: a tinted pane with its own edge light,
   which survives on glass where a 2px underline would disappear. */
.nav-links a.active {
  color: var(--accent-ink); background: var(--accent-soft);
  border-color: var(--accent-tint);
  box-shadow: inset 0 1px 0 var(--glass-hi), 0 6px 18px -10px var(--accent-glow);
}
.nav-auth { display: flex; align-items: center; gap: 0.6rem; }
.nav-user { display: inline-flex; align-items: center; gap: 0.5rem; color: var(--text); font-weight: 600; font-size: 0.95rem; }
a.nav-user:hover { color: var(--accent-ink); }
.inline-form { display: inline; }

/* The toggle only works with JS, so it only appears with JS. */
.theme-toggle { display: none; }
.js .theme-toggle {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 36px; height: 36px; border-radius: 50%;
  border: 1px solid var(--border-strong); background: var(--panel-2); color: var(--text-soft);
  cursor: pointer;
  box-shadow: inset 0 1px 0 var(--glass-ring);
  transition: border-color 0.18s ease, color 0.18s ease, background 0.18s ease,
    box-shadow 0.28s ease, transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
.theme-toggle:hover {
  border-color: var(--accent); color: var(--accent-ink); transform: scale(1.08);
  box-shadow: inset 0 1px 0 var(--glass-hi), 0 8px 22px -10px var(--accent-glow);
}
.theme-toggle:active { transform: scale(0.94); }
.theme-toggle svg { width: 18px; height: 18px; }
.theme-toggle .icon-moon { display: none; }
[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
[data-theme="dark"] .theme-toggle .icon-moon { display: block; }

/* The toggle only works with JS, so it only appears with JS. */
.ip-hide-toggle { display: none; }
.js .ip-hide-toggle { display: inline-flex; }
.ip-hide-toggle[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-hover); border-color: var(--accent); }

/* Blurs every tagged IP address on the page; a viewer can still reveal one
   at a time by hovering or focusing it, e.g. to copy it for a ban. */
[data-hide-ips="1"] .ip-addr { filter: blur(4px); user-select: none; transition: filter 0.12s ease; }
[data-hide-ips="1"] .ip-addr:hover, [data-hide-ips="1"] .ip-addr:focus-within { filter: none; }

.avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent-hover), var(--accent-deep));
  color: var(--on-accent); font-weight: 800; font-size: 0.9rem;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    inset 0 0 0 1px rgba(255, 255, 255, 0.14),
    0 6px 18px -8px var(--accent-glow);
}
.avatar-lg { width: 52px; height: 52px; font-size: 1.4rem; }

/* ---------- Announcement banner ---------- */
.announcement {
  background: var(--announcement-bg); color: #fff; font-weight: 600; font-size: 0.92rem;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), inset 0 -1px 0 rgba(0, 0, 0, 0.18);
}
.announcement-inner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.55rem 0; }
.announcement-dismiss {
  background: transparent; border: 0; color: #fff; font: inherit; cursor: pointer;
  opacity: 0.8; padding: 0.1rem 0.4rem; border-radius: 5px; flex: none;
}
.announcement-dismiss:hover { opacity: 1; background: rgba(255, 255, 255, 0.15); }

/* ---------- Flash ---------- */
.flash {
  padding: 0.7rem 0; font-weight: 600;
  animation: flash-in 0.3s ease; transition: opacity 0.35s ease;
}
.flash-success { background: var(--tint-success); color: var(--success); box-shadow: inset 0 1px 0 var(--glass-hi), inset 0 -1px 0 currentColor; }
.flash-error { background: var(--tint-danger); color: var(--danger); box-shadow: inset 0 1px 0 var(--glass-hi), inset 0 -1px 0 currentColor; }
.flash-out { opacity: 0; }
@keyframes flash-in { from { opacity: 0; transform: translateY(-6px); } }

/* ---------- Hero ---------- */
.hero {
  position: relative; overflow: hidden;
  min-height: calc(100vh - var(--nav-h));
  min-height: calc(100dvh - var(--nav-h));
  display: flex; align-items: center;
  background: transparent;
}

/* Aurora (React Bits) — three drifting blurred color fields behind the hero */
.hero-aurora { position: absolute; inset: -20% -10%; opacity: var(--aurora-opacity); pointer-events: none; }
.hero-aurora::before,
.hero-aurora::after,
.hero-aurora .aurora-blob {
  content: ""; position: absolute; border-radius: 50%;
  filter: blur(70px); will-change: transform;
}
.hero-aurora::before {
  width: 55vw; height: 46vh; left: 46%; top: 4%;
  background: radial-gradient(closest-side, var(--accent-tint), transparent 70%);
  animation: aurora-a 16s ease-in-out infinite alternate;
}
.hero-aurora::after {
  width: 42vw; height: 40vh; left: -6%; bottom: -4%;
  background: radial-gradient(closest-side, rgba(47, 111, 240, 0.16), transparent 70%);
  animation: aurora-b 21s ease-in-out infinite alternate;
}
.hero-aurora .aurora-blob {
  width: 30vw; height: 32vh; right: 4%; bottom: 8%;
  background: radial-gradient(closest-side, var(--accent-soft), transparent 70%);
  animation: aurora-c 13s ease-in-out infinite alternate;
}
@keyframes aurora-a { to { transform: translate3d(-8%, 10%, 0) scale(1.15); } }
@keyframes aurora-b { to { transform: translate3d(10%, -8%, 0) scale(1.1); } }
@keyframes aurora-c { to { transform: translate3d(-6%, -12%, 0) scale(1.2); } }

/* Live aurora curtain drawn by fx.js (sits over the blob wash) */
#aurora-canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: var(--aurora-opacity);
}

#hero-canvas { position: absolute; inset: 0; width: 100%; height: 100%; }

/* DotGrid (React Bits) — masked dot field over the aurora */
.hero-grid-overlay {
  position: absolute; inset: 0; pointer-events: none;
  background-image: radial-gradient(var(--accent-tint) 1px, transparent 1.4px);
  background-size: 30px 30px;
  mask-image: radial-gradient(ellipse 85% 75% at 42% 42%, #000 25%, transparent 72%);
  -webkit-mask-image: radial-gradient(ellipse 85% 75% at 42% 42%, #000 25%, transparent 72%);
}

.hero-inner {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 3rem; align-items: center;
  padding: 4.5rem 0 5.5rem;
}

.hero-kicker {
  font-family: var(--mono); color: var(--accent-ink); letter-spacing: 0.22em;
  font-size: 0.85rem; margin-bottom: 1.1rem; min-height: 1.4em;
}
.hero-title {
  font-size: clamp(2.6rem, 6vw, 4.4rem);
  line-height: 1.04; font-weight: 600; letter-spacing: -0.03em;
  margin-bottom: 1.3rem; text-wrap: balance;
}
/* GradientText (React Bits) — animated gradient fill, 300% track panned
   back and forth (linear, alternate) */
.gradient-text {
  background: linear-gradient(90deg, var(--accent), var(--accent-hover), var(--accent));
  background-size: 300% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: gradient-pan 8s linear infinite alternate;
}
@keyframes gradient-pan { from { background-position: 0% 0; } to { background-position: 100% 0; } }

/* SplitText (React Bits) — fx.js wraps [data-split] text in these spans.
   power3.out easing, per-char delay staggered from JS. */
.split-word { display: inline-block; white-space: nowrap; }
.split-char { display: inline-block; opacity: 0; transform: translateY(0.55em); }
.split-go .split-char {
  animation: char-rise 0.9s cubic-bezier(0.215, 0.61, 0.355, 1) forwards;
  animation-delay: var(--char-delay, 0ms);
}
@keyframes char-rise {
  from { opacity: 0; transform: translateY(0.55em); }
  to { opacity: 1; transform: translateY(0); }
}

/* BlurText (React Bits) — whole-line blur entrance for the gradient line,
   scoped to .js so the no-script page stays fully visible */
.js .hero-line2 { display: inline-block; animation: blur-in 0.9s cubic-bezier(0.16, 1, 0.3, 1) 0.55s both; }
@keyframes blur-in {
  from { opacity: 0; filter: blur(10px); transform: translateY(0.25em); }
  to { opacity: 1; filter: blur(0); transform: translateY(0); }
}

.hero-sub { color: var(--text-soft); font-size: 1.15rem; max-width: 34rem; margin-bottom: 2rem; }
.hero-cta { display: flex; gap: 0.9rem; flex-wrap: wrap; align-items: center; }

/* HUD cards — glassy stat tiles floating beside the copy */
.hero-cards { position: relative; z-index: 2; display: flex; flex-direction: column; gap: 1.1rem; padding: 1rem 0; }
.hud-card {
  display: flex; flex-direction: column; gap: 0.15rem;
  background: var(--glass);
  border-radius: var(--radius-xl);
  padding: 1.1rem 1.4rem;
  box-shadow: var(--ring-shadow), var(--shadow);
  position: relative; overflow: hidden;
  animation: float 7s ease-in-out infinite;
}
.hud-card::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 36%, rgba(255, 255, 255, 0.38) 50%, transparent 64%);
  transform: translateX(-130%);
  animation: glare-sweep 6s ease-in-out infinite;
}
.hud-card-1 { align-self: flex-end; width: min(240px, 100%); rotate: 2deg; animation-delay: 0s; }
.hud-card-2 { align-self: flex-start; width: min(230px, 100%); rotate: -2deg; animation-delay: -2.4s; }
.hud-card-2::after { animation-delay: -2s; }
.hud-card-3 { align-self: center; width: min(250px, 100%); rotate: 1deg; animation-delay: -4.8s; }
.hud-card-3::after { animation-delay: -4s; }
@keyframes float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-14px); }
}
@keyframes glare-sweep { 0%, 55% { transform: translateX(-130%); } 100% { transform: translateX(130%); } }
.hud-label { font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.18em; color: var(--muted); }
.hud-value { font-family: var(--font-display); font-size: 1.9rem; font-weight: 700; line-height: 1.1; color: var(--text); font-variant-numeric: tabular-nums; }
.hud-trend { font-size: 0.75rem; color: var(--muted); }
.hud-trend.up { color: var(--success); }

.hero-fade {
  position: absolute; left: 0; right: 0; bottom: 0; height: 140px; z-index: 1;
  background: linear-gradient(transparent, var(--field-wash));
  pointer-events: none;
}

/* ---------- Sections ---------- */
.section { padding: 4.5rem 0; }
.section-title {
  font-size: clamp(1.7rem, 3.6vw, 2.6rem); font-weight: 600;
  letter-spacing: -0.025em; line-height: 1.12; margin-bottom: 1rem; text-wrap: balance;
}

/* Reveal on scroll — the hidden state only applies when JS actually runs
   (html.js is set by boot.js), so content stays visible for no-JS visitors.
   fx.js assigns --reveal-delay for staggered groups and removes the classes
   once the rise finishes, so components get their own hover transitions
   back (a transition here would override e.g. .feature-card's). */
.js .reveal { opacity: 0; }
.js .reveal.visible {
  animation: reveal-rise 0.65s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: var(--reveal-delay, 0ms);
}
/* Failsafe: boot.js adds .reveal-failsafe when fx.js never reported in (an
   extension or filter blocked it, a stale cache 404s, the network dropped).
   fx.js owns the reveals, so without this a dead fx.js leaves every revealed
   element at opacity 0 and the page renders as an empty background. */
.reveal-failsafe .reveal { opacity: 1; transform: none; animation: none; }
@keyframes reveal-rise {
  from { opacity: 0; transform: translateY(22px); }
  to { opacity: 1; transform: none; }
}

/* ---------- Stats strip (CountUp) ---------- */
.stats-strip {
  background:
    radial-gradient(var(--accent-soft) 1px, transparent 1.4px) 0 0 / 26px 26px,
    var(--band);
  border-block: 1px solid var(--border); padding: 2.8rem 0;
  border-radius: 0;
  box-shadow: inset 0 1px 0 var(--glass-hi), inset 0 -1px 0 var(--glass-ring);
}
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.5rem; }
.stat { text-align: center; }
.stat-value {
  display: block; font-family: var(--font-display); font-size: 2.5rem; font-weight: 700;
  color: var(--accent); font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.stat-label { color: var(--muted); font-size: 0.9rem; }

/* ---------- Features — bento of SpotlightCards ---------- */
.features-grid {
  display: grid; grid-template-columns: repeat(4, 1fr);
  grid-template-areas: "a a b c" "d e f f";
  gap: 1.1rem; margin-top: 2.2rem;
}
.features-grid .feature-card:nth-child(1) { grid-area: a; }
.features-grid .feature-card:nth-child(2) { grid-area: b; }
.features-grid .feature-card:nth-child(3) { grid-area: c; }
.features-grid .feature-card:nth-child(4) { grid-area: d; }
.features-grid .feature-card:nth-child(5) { grid-area: e; }
.features-grid .feature-card:nth-child(6) { grid-area: f; }

.feature-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-card);
  padding: 1.7rem; box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.feature-card:hover {
  transform: translateY(-6px) scale(1.012);
  border-color: var(--accent-tint);
  box-shadow: var(--ring-shadow), var(--shadow-lift);
}
/* The two wide bento cells carry their own visual field */
.feature-featured {
  background:
    radial-gradient(var(--accent-soft) 1px, transparent 1.4px) 0 0 / 22px 22px,
    linear-gradient(135deg, var(--accent-soft), transparent 55%),
    var(--panel);
}
.feature-icon {
  width: 46px; height: 46px; border-radius: var(--radius-ctl); margin-bottom: 1rem;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent-ink);
  border: 1px solid var(--accent-tint);
  box-shadow: inset 0 1px 0 var(--glass-hi), 0 8px 20px -12px var(--accent-glow);
}
.feature-icon svg { width: 24px; height: 24px; }
.feature-card h3 { font-size: 1.1rem; margin-bottom: 0.4rem; }
.feature-card p { color: var(--muted); font-size: 0.95rem; }

/* SpotlightCard (React Bits) — pointer-tracked radial highlight.
   fx.js feeds --spot-x/--spot-y; color comes from the theme. */
.spotlight-card { position: relative; overflow: hidden; }
.spotlight-card::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(circle at var(--spot-x, 50%) var(--spot-y, 50%), var(--spot-color), transparent 80%);
  opacity: 0; transition: opacity 0.5s ease;
}
.spotlight-card.spotlight-on::after,
.spotlight-card:focus-within::after { opacity: 0.75; }

/* ---------- Community / recent ---------- */
.recent-threads { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; margin: 2rem 0; }
.recent-thread {
  display: flex; flex-direction: column; gap: 0.25rem;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-card);
  padding: 1.15rem 1.35rem; color: var(--text); box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.recent-thread:hover {
  border-color: var(--accent-tint); transform: translateY(-4px) scale(1.01); color: var(--text);
  box-shadow: var(--ring-shadow), var(--shadow-lift);
}
.recent-cat { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.15em; color: var(--accent-ink); text-transform: uppercase; }
.recent-title { font-weight: 700; font-family: var(--font-display); }
.recent-meta { color: var(--muted); font-size: 0.85rem; }

.download-cta {
  background:
    radial-gradient(var(--accent-soft) 1px, transparent 1.4px) 0 0 / 26px 26px,
    radial-gradient(720px 340px at 50% 0%, var(--accent-tint), transparent 70%),
    var(--band);
  border-top: 1px solid var(--border);
  box-shadow: inset 0 1px 0 var(--glass-hi);
}

/* ---------- Forms ---------- */
.stack { display: flex; flex-direction: column; gap: 1.1rem; }
.stack label { display: flex; flex-direction: column; gap: 0.35rem; font-weight: 600; font-size: 0.95rem; }
/* Fields are the one glass shape that reads as pressed INTO the pane
   rather than sitting on it: the light gathers along the top inner
   edge instead of the top outer edge, which is what inverts the
   depth cue. Focus floods the well and lights an accent halo. */
input[type="text"], input[type="email"], input[type="password"], input[type="search"], textarea, select {
  font: inherit; color: var(--text);
  background: var(--panel-2); border: 1px solid var(--border-strong); border-radius: var(--radius-ctl);
  padding: 0.68rem 0.95rem; width: 100%;
  box-shadow:
    inset 0 2px 5px -2px rgba(10, 20, 48, 0.14),
    inset 0 -1px 0 var(--glass-ring);
  transition: border-color 0.18s ease, box-shadow 0.24s ease, background 0.18s ease;
}
input::placeholder, textarea::placeholder { color: var(--muted); }
input:focus, textarea:focus, select:focus {
  outline: none; border-color: var(--accent); background: var(--panel);
  box-shadow:
    inset 0 2px 5px -2px rgba(10, 20, 48, 0.1),
    0 0 0 3px var(--accent-tint),
    0 10px 30px -12px var(--accent-glow);
}
textarea { resize: vertical; min-height: 90px; }
.form-errors {
  background: var(--tint-danger-soft);
  border: 1px solid var(--tint-danger-strong);
  border-radius: var(--radius-card); padding: 0.95rem 1.15rem 0.95rem 2.2rem; margin-bottom: 1.2rem;
  color: var(--danger); font-size: 0.95rem;
  box-shadow: inset 0 1px 0 var(--glass-hi), var(--shadow-sm);
}

/* ---------- CAPTCHA ---------- */
/* Honeypot: off-screen rather than display:none, which trivial bots skip. */
.honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.captcha-box {
  border: 1px solid var(--border-strong); border-radius: var(--radius-card);
  padding: 0.95rem 1.05rem; background: var(--panel-2);
  box-shadow: inset 0 2px 6px -3px rgba(10, 20, 48, 0.16), inset 0 -1px 0 var(--glass-ring);
}
.captcha-status { display: flex; flex-direction: column; gap: 0.5rem; }
.captcha-trigger {
  display: inline-flex; align-items: center; gap: 0.6rem; align-self: flex-start;
  font: inherit; font-weight: 600; cursor: pointer;
  background: var(--panel); border: 1px solid var(--border-strong); border-radius: var(--radius-ctl);
  padding: 0.5rem 0.9rem; color: var(--text); transition: border-color 0.15s ease;
}
.captcha-trigger:hover:not(:disabled) { border-color: var(--accent); }
.captcha-trigger:disabled { cursor: default; opacity: 0.9; }
.captcha-mark {
  width: 20px; height: 20px; border-radius: 5px; flex: none;
  border: 2px solid var(--border-strong); background: var(--panel);
  display: inline-block; position: relative;
}
.captcha-text { font-size: 0.85rem; }
.captcha-box[data-state="working"] .captcha-mark {
  border-color: var(--accent); border-right-color: transparent; border-radius: 50%;
  animation: captcha-spin 0.7s linear infinite;
}
@keyframes captcha-spin { to { transform: rotate(360deg); } }
.captcha-box[data-state="done"] { border-color: var(--success); background: rgba(15, 122, 69, 0.06); }
.captcha-box[data-state="done"] .captcha-mark { border-color: var(--success); background: var(--success); }
.captcha-box[data-state="done"] .captcha-mark::after {
  content: ""; position: absolute; left: 5px; top: 1px; width: 4px; height: 9px;
  border: solid var(--on-success); border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.captcha-box[data-state="done"] .captcha-text { color: var(--success); }
.captcha-box[data-state="error"] { border-color: var(--danger); }
.captcha-box[data-state="error"] .captcha-text { color: var(--danger); }

/* ---------- Terms acceptance gate ---------- */
/* The scrim is the site's depth-of-field: everything behind the dialog
   goes properly out of focus rather than merely dark, which is what
   makes the pane on top read as near. */
.terms-gate {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center; padding: 1.5rem;
  background: rgba(5, 7, 15, 0.32);
  backdrop-filter: blur(20px) saturate(130%); -webkit-backdrop-filter: blur(20px) saturate(130%);
}
.terms-gate-card {
  background: var(--panel); border-radius: var(--radius-xl);
  padding: 2.2rem; max-width: 540px; width: 100%;
  box-shadow: var(--ring-shadow), var(--shadow-lift);
  max-height: 90vh; overflow-y: auto;
  animation: dialog-in 0.16s ease-out;
}
@keyframes dialog-in { from { opacity: 0; transform: scale(0.96); } }
.terms-gate-card h2 { font-size: 1.35rem; margin-bottom: 0.6rem; }
.terms-gate-card p { color: var(--text-soft); font-size: 0.95rem; margin-bottom: 0.9rem; }
.terms-gate-points { padding-left: 1.2rem; color: var(--text-soft); font-size: 0.92rem; margin-bottom: 1.2rem; }
.terms-gate-points li { margin: 0.35rem 0; }
.terms-gate-actions { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center; }
.terms-gate-note { font-size: 0.8rem; color: var(--muted); margin-top: 1rem; margin-bottom: 0; }

/* ---------- Profile & upgrade pages ---------- */
.profile-card { padding: 1.6rem 1.8rem; margin-bottom: 1.4rem; overflow: visible; }
.profile-card h2 { font-size: 1.15rem; margin-bottom: 0.8rem; }
.profile-identity { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.2rem; }
.profile-name { font-family: var(--font-display); font-size: 1.3rem; font-weight: 700; display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.profile-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.9rem; margin-bottom: 0.6rem; }
.profile-facts dt { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
.profile-facts dd { margin: 0; font-weight: 600; }
.license-block { word-break: break-all; white-space: pre-wrap; }
.upgrade-benefits { padding-left: 1.3rem; }
.upgrade-benefits li { margin: 0.45rem 0; color: var(--text-soft); }
.upgrade-price { font-size: 1.3rem; margin-top: 1rem; font-family: var(--font-display); }
.upgrade-note {
  border-radius: var(--radius-card); padding: 0.9rem 1.15rem; margin-bottom: 1.4rem;
  border: 1px solid rgba(15, 122, 69, 0.3); background: var(--tint-success);
  box-shadow: inset 0 1px 0 var(--glass-ring);
}
/* Plan cards on /buy — one per membership length. */
.plan-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.9rem; margin: 0.4rem 0 1.2rem; }
.plan-card {
  display: flex; flex-direction: column; gap: 0.3rem;
  background: var(--panel-2); border: 1px solid var(--border);
  border-radius: var(--radius-card); padding: 1.2rem 1.1rem;
  box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.plan-card:hover { transform: translateY(-4px); box-shadow: var(--ring-shadow), var(--shadow); }
.plan-blurb { font-size: 0.85rem; color: var(--muted); margin: 0.1rem 0 0.3rem; }
.plan-card form { margin-top: auto; padding-top: 0.7rem; }
.plan-card .btn { margin-top: 0; }
.plan-name { font-family: var(--font-display); font-size: 1rem; font-weight: 700; margin: 0; }
.plan-price { display: flex; align-items: baseline; gap: 0.3rem; margin: 0; }
.plan-amount { font-family: var(--font-display); font-size: 1.7rem; font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
.plan-currency { font-size: 0.75rem; color: var(--muted); letter-spacing: 0.06em; }
.plan-term { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--accent-ink); margin-bottom: 0.4rem; }

.pay-addresses { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 1rem; }
.pay-address {
  display: flex; gap: 0.8rem; align-items: baseline; background: var(--panel-2);
  border: 1px solid var(--border); border-radius: var(--radius-ctl);
  padding: 0.75rem 1.05rem; overflow-wrap: anywhere;
}
.pay-coin { font-weight: 800; min-width: 3.5rem; color: var(--accent-ink); }
.error-actions { display: flex; gap: 0.7rem; justify-content: center; flex-wrap: wrap; }
/* Compound selector: .panel is defined later and would otherwise win the
   box-shadow cascade over a bare .danger-zone. */
.panel.danger-zone { box-shadow: var(--ring-shadow), 0 0 0 1px var(--tint-danger-strong), var(--shadow-sm); }
.danger-zone h2 { color: var(--danger); }
.panel-form-inline { margin-top: 1rem; display: block; }

/* ---------- FAQ & changelog ---------- */
.faq-list { display: flex; flex-direction: column; gap: 0.6rem; margin: 1.6rem 0 2rem; }
.faq-item {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-card);
  padding: 0; box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.faq-item:hover { border-color: var(--border-strong); }
.faq-item summary {
  cursor: pointer; font-weight: 600; font-family: var(--font-display); padding: 1.05rem 1.35rem;
  list-style-position: inside; border-radius: inherit;
}
.faq-item summary:hover { color: var(--accent-ink); }
.faq-item[open] { border-color: var(--accent-tint); box-shadow: var(--ring-shadow), var(--shadow); }
.faq-item[open] summary { border-bottom: 1px solid var(--border); }
.faq-item p { padding: 0.9rem 1.3rem 1.1rem; color: var(--text-soft); }
.release { margin: 2rem 0; }
.release h2 { font-size: 1.2rem; margin-bottom: 0.2rem; }
.release-date { font-size: 0.85rem; margin-bottom: 0.6rem; }
.release ul { padding-left: 1.3rem; color: var(--text-soft); }
.release li { margin: 0.3rem 0; }

/* Account-switch notice on the login page */
.switch-note {
  background: var(--accent-soft); border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: var(--radius-card); padding: 0.95rem 1.15rem; margin-bottom: 1.2rem;
  font-size: 0.92rem; color: var(--text-soft);
  box-shadow: inset 0 1px 0 var(--glass-ring), var(--shadow-sm);
}
.switch-note .inline-form { display: block; margin-top: 0.5rem; }

/* ---------- Auth ---------- */
.auth-page {
  display: flex; align-items: center;
  background: radial-gradient(var(--accent-soft) 1px, transparent 1.4px) 0 0 / 26px 26px;
}
.auth-card {
  max-width: 430px; background: var(--panel);
  border-radius: var(--radius-xl); padding: 2.5rem;
  box-shadow: var(--ring-shadow), var(--shadow-lift);
  position: relative;
}
/* The accent filament across the top lip. It rides ABOVE the film
   (::before is the film here), so it gets its own layer. */
.auth-card::after {
  content: ""; position: absolute; top: 0; left: 14%; right: 14%; height: 2px;
  border-radius: 2px; pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  filter: drop-shadow(0 0 6px var(--accent-glow));
}
.auth-card h1 { margin-bottom: 0.3rem; font-size: 1.6rem; }
.auth-card > .muted { margin-bottom: 1.5rem; }
.auth-card form { margin-bottom: 1.2rem; }

/* ---------- Forum ---------- */
.page-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.8rem; }
.breadcrumbs { color: var(--muted); font-size: 0.9rem; margin-bottom: 1rem; display: flex; gap: 0.5rem; flex-wrap: wrap; }
.forum-layout { display: grid; grid-template-columns: 1fr 300px; gap: 1.6rem; align-items: start; }
.category-list { display: flex; flex-direction: column; gap: 0.9rem; }
.category-card {
  display: grid; grid-template-columns: 1fr auto 220px; gap: 1.2rem; align-items: center;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-card);
  padding: 1.25rem 1.45rem; color: var(--text); box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.category-card:hover {
  border-color: var(--accent-tint); transform: translateX(6px); color: var(--text);
  box-shadow: var(--ring-shadow), var(--shadow-lift);
}
.category-card h2 { font-size: 1.15rem; margin-bottom: 0.15rem; }
.category-card p { font-size: 0.9rem; }
.category-stats { display: flex; flex-direction: column; gap: 0.1rem; color: var(--muted); font-size: 0.85rem; text-align: right; }
.category-stats strong { color: var(--text); }
.category-latest { display: flex; flex-direction: column; font-size: 0.85rem; border-left: 1px solid var(--border); padding-left: 1.2rem; }
.latest-title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.forum-sidebar {
  background: var(--panel); border-radius: var(--radius-card);
  padding: 1.35rem; position: sticky; top: calc(var(--nav-h) + 8px);
  box-shadow: var(--ring-shadow), var(--shadow);
}
.forum-sidebar h2 { font-size: 0.85rem; font-family: var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); margin-bottom: 0.9rem; }
.sidebar-thread { display: flex; flex-direction: column; padding: 0.55rem 0; border-top: 1px solid var(--border); color: var(--text); font-size: 0.92rem; }
.sidebar-thread:first-of-type { border-top: 0; }
.sidebar-thread:hover .sidebar-title { color: var(--accent-ink); }
.sidebar-title { font-weight: 600; }
.sidebar-thread .muted { font-size: 0.8rem; }

.shoutbox { margin-top: 1.4rem; padding-top: 1.2rem; border-top: 1px solid var(--border); }
.shoutbox-head { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.9rem; }
.shoutbox-head h2 { margin-bottom: 0; }
.shoutbox h2 { font-size: 0.85rem; font-family: var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.shout-list { display: flex; flex-direction: column; gap: 0.5rem; height: 260px; overflow-y: auto; margin-bottom: 0.9rem; }
.shout-row { position: relative; display: flex; flex-direction: column; flex-shrink: 0; font-size: 0.85rem; padding: 0.5rem 1.6rem 0.5rem 0.7rem; border-radius: var(--radius-ctl); background: var(--panel-2); }
.shout-del-form { position: absolute; top: 0.3rem; right: 0.4rem; }
.shout-del {
  background: transparent; border: 0; cursor: pointer; color: var(--muted);
  font-size: 0.75rem; padding: 0.1rem 0.25rem; border-radius: 4px;
}
.shout-del:hover { color: var(--danger); background: var(--tint-danger); }
.shout-user { font-weight: 700; color: var(--text); }
.shout-body { color: var(--text-soft); overflow-wrap: break-word; }
.shout-time { font-size: 0.72rem; }
.shout-empty { padding: 0.3rem 0; }
.shout-form { display: flex; gap: 0.4rem; }
.shout-form input { flex: 1; padding: 0.5rem 0.7rem; font-size: 0.88rem; }
.shout-login-note { font-size: 0.85rem; }

.thread-list { display: flex; flex-direction: column; gap: 0.6rem; }
.thread-row {
  display: grid; grid-template-columns: auto 1fr 220px; gap: 1rem; align-items: center;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-card);
  padding: 1rem 1.35rem; color: var(--text); box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.thread-row:hover {
  border-color: var(--accent-tint); color: var(--text); transform: translateY(-2px);
  box-shadow: var(--ring-shadow), var(--shadow);
}
.thread-flags:empty { display: none; }
/* Search results reuse the row chrome but carry only the main column. */
.thread-row--flush { grid-template-columns: 1fr; }
.thread-title { font-weight: 700; display: block; font-family: var(--font-display); }
.thread-nums { display: flex; flex-direction: column; font-size: 0.83rem; color: var(--muted); text-align: right; }
.thread-nums strong { color: var(--text); }
.empty-state {
  padding: 2.6rem 1.5rem; text-align: center; text-wrap: balance;
  border: 1px dashed var(--border-strong); border-radius: var(--radius-card);
  background: var(--panel-2);
  box-shadow: inset 0 1px 0 var(--glass-ring);
}

.tag {
  display: inline-block; font-family: var(--mono); font-size: 0.62rem; font-weight: 700;
  letter-spacing: 0.12em; padding: 0.2rem 0.65rem; border-radius: var(--radius-tag); vertical-align: middle;
}
.tag-pin { background: var(--accent-soft); color: var(--accent-ink); }
.tag-lock { background: var(--panel-2); color: var(--muted); }
.tag-admin { background: var(--accent-soft); color: var(--accent-ink); }
.tag-banned { background: var(--tint-danger); color: var(--danger); }

/* Tier badges */
.tag-tier-user { background: var(--panel-2); color: var(--muted); }
.tag-tier-paid { background: var(--tint-success); color: var(--success); }
.tag-tier-developer { background: var(--tier-dev-tint); color: var(--tier-dev-ink); }
.tag-tier-trial_admin { background: var(--tint-warn); color: var(--warn); }
.tag-tier-admin { background: var(--accent-soft); color: var(--accent-ink); }
/* Device-fingerprint badge (device trust feature) */
.tag-device { background: var(--panel-2); color: var(--muted); }

.panel-spaced { margin-top: 1.8rem; }

/* thread view */
.thread-heading { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.thread-actions { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.forum-head-actions { display: flex; gap: 0.7rem; align-items: center; flex-wrap: wrap; }
.forum-search { display: flex; gap: 0.4rem; }
.forum-search input { width: 220px; padding: 0.45rem 0.8rem; font-size: 0.9rem; }
.search-group { font-size: 1.1rem; margin: 1.6rem 0 0.8rem; }
.member-link { color: inherit; font-weight: inherit; }
.member-link:hover { color: var(--accent-ink); }
.post-actions { display: inline-flex; gap: 0.35rem; align-items: center; }
.post-edited { font-size: 0.8rem; }
.report-box { margin-top: 0.8rem; font-size: 0.85rem; }
.report-box summary { cursor: pointer; color: var(--muted); width: fit-content; }
.report-box summary:hover { color: var(--warn); }
.report-form { display: flex; gap: 0.4rem; margin-top: 0.5rem; flex-wrap: wrap; }
.report-form input { flex: 1; min-width: 220px; padding: 0.45rem 0.7rem; font-size: 0.87rem; }
.form-row { display: flex; gap: 0.7rem; align-items: center; flex-wrap: wrap; }
.uid-badge {
  display: inline-block; font-family: var(--mono); font-size: 0.68rem; font-weight: 700;
  letter-spacing: 0.06em; padding: 0.14rem 0.6rem; border-radius: var(--radius-tag); vertical-align: middle;
  background: var(--panel-2); color: var(--muted); border: 1px solid var(--border);
}
.uid-badge.uid-reserved { background: var(--accent-soft); color: var(--accent-ink); border-color: var(--accent); }
.title-edit summary { list-style: none; cursor: pointer; }
.title-edit summary::-webkit-details-marker { display: none; }
.title-edit-form { display: flex; gap: 0.4rem; margin-top: 0.5rem; flex-wrap: wrap; }
.title-edit-form input { min-width: 260px; flex: 1; padding: 0.45rem 0.7rem; font-size: 0.9rem; }
.admin-user-tools { display: inline-block; font-size: 0.85rem; margin-top: 0.3rem; }
.admin-user-tools summary { cursor: pointer; color: var(--muted); }
.admin-user-tools summary:hover { color: var(--accent-ink); }
.admin-user-tools[open] { display: block; }
.admin-user-tools .inline-form { display: flex; gap: 0.3rem; margin-top: 0.4rem; align-items: center; }
.admin-user-tools input { width: 160px; padding: 0.35rem 0.6rem; font-size: 0.82rem; }
.paid-days-input { width: 70px; padding: 0.35rem 0.5rem; font-size: 0.82rem; }
/* Users tab: narrower page, compact 4-column table, inline subscription tools */
.admin-narrow { max-width: 1020px; }
.users-table table { font-size: 0.85rem; }
.users-table th, .users-table td { padding: 0.55rem 0.8rem; }
.sub-cell { min-width: 150px; }
.sub-adjust { display: flex; gap: 0.3rem; margin-top: 0.35rem; align-items: center; }
.sub-adjust input { width: 70px; padding: 0.3rem 0.45rem; font-size: 0.8rem; }
.sub-mass-panel { margin-bottom: 1.3rem; }
.sub-mass-panel .filter-bar { margin-bottom: 0; }
.cat-edit-form { gap: 0.4rem; margin-top: 0.5rem; max-width: 320px; }
.cat-edit-form input { padding: 0.4rem 0.6rem; font-size: 0.85rem; }
.cf-turnstile { margin: 0.4rem 0; }
.post-list { display: flex; flex-direction: column; gap: 1rem; margin-bottom: 2rem; }
.post {
  display: grid; grid-template-columns: 170px 1fr;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-card);
  overflow: hidden; box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.post { scroll-margin-top: calc(var(--nav-h) + 10px); }
.post:target { border-color: var(--accent); box-shadow: var(--ring-shadow), 0 0 0 3px var(--accent-tint), 0 16px 44px -16px var(--accent-glow); }
.post-author {
  display: flex; flex-direction: column; align-items: flex-start; gap: 0.3rem;
  background: var(--panel-2); padding: 1.2rem; font-size: 0.85rem;
  border-right: 1px solid var(--border);
}
.post-username { font-weight: 700; font-size: 0.98rem; }
.post-body { padding: 1.2rem 1.4rem; min-width: 0; }
.post-meta { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.7rem; font-size: 0.85rem; }
.post-text { white-space: pre-wrap; overflow-wrap: break-word; color: var(--text-soft); }
.locked-note { padding: 1rem 0; }
.reply-box { background: var(--panel); border-radius: var(--radius-card); padding: 1.6rem; box-shadow: var(--ring-shadow), var(--shadow); }
.reply-box h2 { font-size: 1.1rem; margin-bottom: 1rem; }

.pagination { display: flex; gap: 0.4rem; margin-top: 1.6rem; flex-wrap: wrap; }
.pagination .page {
  display: inline-flex; min-width: 2.3rem; height: 2.3rem; align-items: center; justify-content: center;
  padding: 0 0.6rem; border-radius: var(--radius-ctl); border: 1px solid var(--border);
  color: var(--muted); font-weight: 600; background: var(--panel);
  transition: color 0.18s ease, border-color 0.18s ease, box-shadow 0.24s ease, transform 0.24s ease;
}
.pagination .page:hover { border-color: var(--accent); color: var(--accent-ink); transform: translateY(-1px); }
.pagination .page.current {
  background: var(--accent); border-color: transparent; color: var(--on-accent);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), var(--shadow-accent);
}
.pagination .page.gap { border-color: transparent; background: transparent; box-shadow: none; }

/* ---------- Download page ---------- */
.download-box {
  display: flex; justify-content: space-between; align-items: center; gap: 1.5rem; flex-wrap: wrap;
  background: var(--panel); border-radius: var(--radius-xl);
  padding: 1.8rem 2rem; margin: 1.8rem 0 2.5rem;
  box-shadow: var(--ring-shadow), var(--shadow-lift);
}
.download-gate { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.download-page h2 { margin: 2rem 0 0.6rem; font-size: 1.25rem; }
.code-block {
  background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--radius-ctl);
  padding: 0.95rem 1.15rem; overflow-x: auto; font-size: 0.82rem; color: var(--text-soft);
  box-shadow: inset 0 2px 6px -3px rgba(10, 20, 48, 0.18), inset 0 -1px 0 var(--glass-ring);
}
.steps { padding-left: 1.3rem; }
.steps li { margin: 0.4rem 0; }
.download-page ul { padding-left: 1.3rem; }

/* ---------- Legal pages ---------- */
.legal-layout { display: grid; grid-template-columns: 250px 1fr; gap: 3rem; align-items: start; }
.legal-toc {
  position: sticky; top: calc(var(--nav-h) + 8px); max-height: calc(100vh - var(--nav-h) - 28px); overflow-y: auto;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-card);
  padding: 1.25rem 1.35rem;
  box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.legal-toc h2 { font-size: 0.75rem; font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.14em; color: var(--muted); margin-bottom: 0.7rem; }
.legal-toc ol { list-style: none; counter-reset: toc; display: flex; flex-direction: column; gap: 0.15rem; }
.legal-toc a {
  display: block; font-size: 0.87rem; color: var(--text-soft); padding: 0.2rem 0;
  border-left: 2px solid transparent; padding-left: 0.6rem; margin-left: -0.6rem;
}
.legal-toc a:hover { color: var(--accent-ink); border-left-color: var(--accent); }

.legal-body { max-width: 68ch; }
.legal-updated { font-family: var(--mono); font-size: 0.8rem; color: var(--muted); margin-bottom: 1.6rem; }
.legal-summary {
  background: var(--accent-soft); border: 1px solid var(--border);
  border-left: 3px solid var(--accent); border-radius: var(--radius-card);
  padding: 1.25rem 1.45rem; margin-bottom: 2.2rem;
  box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.legal-summary h2 { font-size: 0.95rem; margin: 0 0 0.5rem; padding: 0; border-bottom: 0; color: var(--accent-ink); }
.legal-summary p, .legal-summary li { font-size: 0.92rem; color: var(--text-soft); }
.legal-summary ul { padding-left: 1.2rem; margin-top: 0.4rem; }

.legal-body h2 {
  font-size: 1.2rem; margin: 2.4rem 0 0.7rem; scroll-margin-top: calc(var(--nav-h) + 10px);
  padding-bottom: 0.4rem; border-bottom: 1px solid var(--border);
}
.legal-body h2:first-of-type { margin-top: 0; }
.legal-body h3 { font-size: 1rem; margin: 1.4rem 0 0.4rem; color: var(--text); }
.legal-body p { color: var(--text-soft); margin-bottom: 0.9rem; }
.legal-body ul, .legal-body ol { padding-left: 1.4rem; margin-bottom: 0.9rem; color: var(--text-soft); }
.legal-body li { margin: 0.3rem 0; }
.legal-body strong { color: var(--text); }

.legal-contact {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-card);
  padding: 1.35rem 1.55rem; margin-top: 2.4rem; scroll-margin-top: calc(var(--nav-h) + 10px);
  box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.legal-contact h2 { border: 0; margin: 0 0 0.5rem; padding: 0; font-size: 1.05rem; }
.legal-contact address { font-style: normal; color: var(--text-soft); font-size: 0.93rem; line-height: 1.7; }

.legal-placeholder-note {
  background: var(--tint-warn); border: 1px solid rgba(138, 90, 0, 0.34);
  border-radius: var(--radius-ctl); padding: 0.95rem 1.25rem; margin-bottom: 2rem;
  color: var(--warn); font-size: 0.87rem;
  box-shadow: inset 0 1px 0 var(--glass-ring);
}

/* ---------- Admin ---------- */
/* Segmented control: a recessed muted well with the active tab as a raised
   pill (the shadcn-craft tabs pattern) */
.admin-tabs {
  display: inline-flex; gap: 3px; margin-bottom: 1.8rem; flex-wrap: wrap;
  background: var(--panel-2); border-radius: var(--radius-ctl); padding: 3px;
  box-shadow: inset 0 2px 6px -2px rgba(10, 20, 48, 0.16), inset 0 -1px 0 var(--glass-ring);
}
.admin-tabs a {
  padding: 0.45rem 1.1rem; color: var(--muted); font-family: var(--font-display); font-weight: 500;
  /* Concentric with the 3px well around it, the way UISegmentedControl
     nests 7pt inside 9pt. */
  border-radius: 7px; border: 1px solid transparent;
  transition: color 0.18s ease, background 0.18s ease, box-shadow 0.24s ease;
}
.admin-tabs a:hover { color: var(--text); }
/* The active tab is the only raised pane in a recessed well. */
.admin-tabs a.active {
  color: var(--text); background: var(--panel);
  box-shadow: inset 0 1px 0 var(--glass-hi), var(--shadow-sm);
  border-color: var(--glass-ring);
}

.stat-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.8rem; }
.stat-card {
  background: var(--panel); border-radius: var(--radius-card);
  padding: 1.2rem 1.4rem; display: flex; flex-direction: column;
  box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.stat-card-warn { box-shadow: var(--ring-shadow), 0 0 0 1px rgba(138, 90, 0, 0.5), var(--shadow-sm); }
.stat-card-value { font-family: var(--font-display); font-size: 1.9rem; font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.stat-card-label { color: var(--muted); font-size: 0.85rem; }
.stat-card-warn .stat-card-value { color: var(--warn); }

.admin-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 1.4rem; align-items: start; }
.panel { background: var(--panel); border-radius: var(--radius-card); overflow: hidden; box-shadow: var(--ring-shadow), var(--shadow); }
/* A pane divided by a rule reads as one thick sheet with a scored line,
   not as two stacked sheets: the head shares the pane's fill and only
   the hairline separates it. */
.panel-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 1.05rem 1.35rem; border-bottom: 1px solid var(--border);
}
.panel-head h2 { font-size: 1.05rem; }
.panel-form { padding: 1.2rem 1.3rem; border-top: 1px solid var(--border); }
.panel-form h3 { font-size: 0.95rem; }

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
th, td { text-align: left; padding: 0.65rem 1rem; border-bottom: 1px solid var(--border); vertical-align: top; }
th {
  color: var(--muted); font-family: var(--mono); font-size: 0.72rem; text-transform: uppercase;
  letter-spacing: 0.08em; white-space: nowrap;
  background: var(--panel-2);
  box-shadow: inset 0 1px 0 var(--glass-ring);
}
tbody tr { transition: background 0.16s ease; }
tbody tr:hover { background: var(--accent-soft); }
tbody tr:last-child td { border-bottom: 0; }
.row-banned td { background: var(--tint-danger-soft); }
tbody tr.row-banned:hover td { background: var(--tint-danger); }
.actions-cell { white-space: nowrap; }
.actions-cell .inline-form { margin-right: 0.25rem; }
.detail-cell, .ua-cell { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Audit-log event badges. .tag-event is also the fallback skin, so an event
   type added later renders as a neutral badge instead of bare text. */
.tag-event { text-transform: uppercase; background: var(--panel-2); color: var(--muted); }
.tag-signup { background: var(--tint-success); color: var(--success); }
.tag-login { background: var(--accent-soft); color: var(--accent-ink); }
.tag-login_failed { background: var(--tint-danger); color: var(--danger); }
.tag-login_blocked { background: var(--tint-danger-strong); color: var(--danger); }
.tag-logout { background: var(--panel-2); color: var(--muted); }
.tag-download { background: var(--accent-soft); color: var(--accent-ink); }
.tag-admin_action { background: var(--tint-warn); color: var(--warn); }
.tag-captcha_failed { background: var(--tint-warn); color: var(--warn); }
.tag-terms_accepted { background: var(--tint-success); color: var(--success); }
.tag-password_changed { background: var(--accent-soft); color: var(--accent-ink); }
.tag-loader_auth { background: var(--accent-soft); color: var(--accent-ink); }
.tag-loader_auth_failed { background: var(--tint-danger); color: var(--danger); }
.tag-ip_autoban { background: var(--tint-danger-strong); color: var(--danger); }
.tag-signup_surge_blocked { background: var(--tint-warn); color: var(--warn); }
.tag-post_reported { background: var(--tint-warn); color: var(--warn); }
.tag-email_changed { background: var(--accent-soft); color: var(--accent-ink); }
.tag-account_deleted { background: var(--panel-2); color: var(--muted); }
.tag-shout_deleted { background: var(--panel-2); color: var(--muted); }
.tag-password_reset_requested { background: var(--tint-warn); color: var(--warn); }
.tag-password_reset { background: var(--accent-soft); color: var(--accent-ink); }
.tag-email_verified { background: var(--tint-success); color: var(--success); }
/* Payment status badges (admin queue) */
.tag-pay-new, .tag-pay-processing { background: var(--tint-warn); color: var(--warn); }
.tag-pay-settled { background: var(--tint-success); color: var(--success); }
.tag-pay-expired { background: var(--panel-2); color: var(--muted); }
.tag-pay-invalid { background: var(--tint-danger); color: var(--danger); }
.tag-report-open { background: var(--tint-danger-strong); color: var(--danger); }
.tag-report-resolved { background: var(--tint-success); color: var(--success); }
/* Resolved reports: tinted surface, full-contrast text (an opacity dim
   would fail AA for the muted cells) */
.row-resolved td { background: var(--panel-2); }

.filter-bar { display: flex; gap: 0.6rem; align-items: center; margin-bottom: 1.3rem; flex-wrap: wrap; }
.filter-bar input[type="search"] { max-width: 320px; }
.filter-bar select { width: auto; }
.filter-bar .muted { margin-left: auto; font-size: 0.88rem; }
.filter-check { display: flex; align-items: center; gap: 0.35rem; font-size: 0.88rem; color: var(--muted); cursor: pointer; white-space: nowrap; }
.filter-check input { width: auto; }
.filter-check { display: flex; align-items: center; gap: 0.35rem; font-size: 0.88rem; color: var(--muted); cursor: pointer; white-space: nowrap; }
.filter-check input { width: auto; }

/* ---------- Error page ---------- */
.error-page { padding: 6rem 0; }
.error-code {
  font-family: var(--font-display); font-size: clamp(5rem, 14vw, 9rem); font-weight: 600; line-height: 1;
  background: linear-gradient(180deg, var(--accent-hover), var(--accent-deep));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.error-page h1 { margin: 0.5rem 0; }
.error-page .btn { margin-top: 1.2rem; }

/* ---------- Footer ---------- */
.site-footer {
  background: var(--band); border-top: 1px solid var(--border); margin-top: auto;
  border-radius: 0;
  box-shadow: inset 0 1px 0 var(--glass-hi);
}
.footer-grid { display: grid; grid-template-columns: 2fr repeat(5, 1fr); gap: 2rem; padding: 3rem 0 2rem; }
.brand-footer { font-size: 1.1rem; }
.footer-blurb { color: var(--muted); font-size: 0.9rem; margin-top: 0.8rem; max-width: 300px; }
.site-footer h3 { font-size: 0.75rem; font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.12em; color: var(--muted); margin-bottom: 0.7rem; }
.site-footer nav a { display: block; color: var(--text-soft); padding: 0.2rem 0; font-size: 0.92rem; }
.site-footer nav a:hover { color: var(--accent-ink); }
.footer-bottom {
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  padding: 1.2rem 0 1.6rem; border-top: 1px solid var(--border);
  color: var(--muted); font-size: 0.8rem;
}
.footer-legal-line { max-width: 640px; }

/* ---------- Responsive ---------- */
@media (max-width: 1000px) {
  :root { --nav-h: 76px; }
  .hero-inner { grid-template-columns: 1fr; gap: 2rem; }
  .hero-cards { flex-direction: row; flex-wrap: wrap; padding: 0; }
  .hud-card { animation: none; }
  .hud-card-1, .hud-card-2, .hud-card-3 { align-self: auto; rotate: none; width: auto; flex: 1 1 160px; }
  .features-grid { grid-template-columns: repeat(2, 1fr); grid-template-areas: "a a" "b c" "d e" "f f"; }
  .forum-layout { grid-template-columns: 1fr; }
  .forum-sidebar { position: static; }
  .admin-columns { grid-template-columns: 1fr; }
  .stat-cards { grid-template-columns: repeat(2, 1fr); }
  .footer-grid { grid-template-columns: 1fr 1fr 1fr; }
  .legal-layout { grid-template-columns: 1fr; gap: 1.6rem; }
  .legal-toc { position: static; }
}
@media (max-width: 700px) {
  /* The capsule becomes a rounded slab once the links wrap onto their
     own row — a pill that tall reads as a lozenge, not as chrome. */
  :root { --nav-h: 118px; }
  .site-nav { padding: 0.5rem 0 0.2rem; }
  .nav-inner { flex-wrap: wrap; gap: 0.6rem; padding: 0.6rem 0.7rem; border-radius: var(--radius-card); }
  /* flex-basis, not width: .nav-links carries flex:1 from the base rule, so a
     width alone leaves it squeezed onto the brand's row instead of taking a
     line of its own. */
  .nav-links { order: 3; flex: 1 0 100%; justify-content: center; margin: 0; gap: 0.2rem; }
  .nav-auth { margin-left: auto; }
  .hero-inner { padding: 3.5rem 0 4.5rem; }
  .hero-cards { display: none; }
  .stats-grid { grid-template-columns: repeat(2, 1fr); }
  .features-grid { grid-template-columns: 1fr; grid-template-areas: "a" "b" "c" "d" "e" "f"; }
  .recent-threads { grid-template-columns: 1fr; }
  .category-card { grid-template-columns: 1fr; gap: 0.6rem; }
  .category-latest { border-left: 0; padding-left: 0; }
  .category-stats { flex-direction: row; gap: 1rem; text-align: left; }
  .thread-row { grid-template-columns: 1fr; gap: 0.4rem; }
  .thread-nums { flex-direction: row; gap: 1rem; text-align: left; }
  .post { grid-template-columns: 1fr; }
  .post-author { flex-direction: row; align-items: center; gap: 0.7rem; border-right: 0; border-bottom: 1px solid var(--border); padding: 0.8rem 1.2rem; }
  .auth-card { padding: 1.6rem; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
  /* The ambient field keeps its colour — it is the thing the glass
     refracts — but stops drifting, and panes stop swelling. */
  body::before { animation: none; }
  .btn:hover, .btn:active, .theme-toggle:hover, .theme-toggle:active,
  .feature-card:hover, .recent-thread:hover, .thread-row:hover,
  .plan-card:hover, .support-step:hover, .pagination .page:hover,
  .uptime-bar:hover { transform: none; }
  .js .reveal { opacity: 1; transform: none; animation: none; }
  .split-char { opacity: 1; transform: none; }
  .js .hero-line2 { animation: none; }
  .hud-card::after { display: none; }
  /* Download button: no sweeps; the busy strip stays a static bar so a click
     still visibly does something. */
  .btn-download.is-busy .dl-progress { opacity: 1; }
  .btn-download.is-busy .dl-progress::before { width: 100%; transform: none; }
}

/* ---------- Direct-to-wallet crypto payment page ---------- */

.pay-subtitle { margin-top: -.4rem; }

.pay-panel + .pay-panel { margin-top: 1.1rem; }

.pay-status {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin: 0 0 .8rem;
}

.pay-status-waiting {
  padding: .9rem 1.05rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--accent-soft);
  color: inherit;
  box-shadow: inset 0 1px 0 var(--glass-ring), var(--shadow-sm);
}

/* A quiet, continuous "we are watching" cue. Reduced-motion users get a static
   dot rather than nothing, so the state still reads as live. */
.pay-spinner {
  width: .8rem;
  height: .8rem;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 2px solid var(--accent);
  border-top-color: transparent;
  animation: pay-spin 900ms linear infinite;
}

@keyframes pay-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .pay-spinner { animation: none; border-top-color: var(--accent); opacity: .6; }
}

.pay-network {
  padding: .85rem 1.05rem;
  border-radius: var(--radius-card);
  border: 1px solid rgba(138, 90, 0, .34);
  background: var(--tint-warn);
  margin: 0 0 1rem;
  box-shadow: inset 0 1px 0 var(--glass-ring);
}

.pay-grid {
  display: flex;
  gap: 1.4rem;
  align-items: flex-start;
  flex-wrap: wrap;
}

.pay-fields { flex: 1 1 20rem; min-width: 0; }

.pay-field + .pay-field { margin-top: .9rem; }

.pay-field-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: .6rem;
  margin-bottom: .3rem;
}

.pay-field-label { font-weight: 600; }
.pay-field-hint { font-size: .85em; opacity: .7; }

.pay-field-body {
  display: flex;
  gap: .5rem;
  align-items: stretch;
}

/* The two values a buyer must reproduce exactly. Wrapping rather than
   truncating: a half-shown address invites a half-copied address. */
.pay-value {
  flex: 1 1 auto;
  min-width: 0;
  padding: .65rem .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-ctl);
  background: var(--panel-2);
  font-size: 1.02rem;
  line-height: 1.4;
  overflow-wrap: anywhere;
  word-break: break-all;
  user-select: all;
}

.pay-copy { flex: 0 0 auto; align-self: center; }
.pay-copy.pay-copied { opacity: .75; }

.pay-qr {
  flex: 0 0 auto;
  margin: 0;
  text-align: center;
}

/* The QR stays on a hard white plate whatever the theme — a scanner
   needs the quiet zone opaque, so this is the one surface on the site
   that is deliberately not glass. */
.pay-qr svg {
  display: block;
  border-radius: var(--radius-ctl);
  border: 1px solid var(--border);
  background: #fff;
  padding: 6px;
  box-shadow: var(--ring-shadow), var(--shadow-sm);
}

.pay-qr figcaption { margin-top: .4rem; }

.pay-received { margin: .4rem 0 0; }

.pay-details {
  margin-top: 1.1rem;
  padding: .95rem 1.15rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--panel-2);
  box-shadow: inset 0 1px 0 var(--glass-ring);
}

.pay-details summary { cursor: pointer; font-weight: 600; }
.pay-details[open] summary { margin-bottom: .6rem; }

/* Coin picker on the store page. */
.coin-choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
  gap: .5rem;
  margin-top: .6rem;
}

.coin-choice { margin: 0; }

.coin-choices .btn {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  line-height: 1.25;
  padding-top: .55rem;
  padding-bottom: .55rem;
}

.coin-symbol { font-weight: 700; }
.coin-network { font-size: .72em; opacity: .8; font-weight: 400; }

.chain-note { margin-top: .8rem; }

/* ============================================================
   Support desk — help centre, ticket chat and the staff workspace.

   No new colour is introduced: every surface, ink and tint below comes
   from the tokens at :root, so the whole feature themes itself in dark
   mode along with the rest of the site. New geometry only.
   ============================================================ */

/* ---------- Status and priority chips ----------
   .tag is geometry only, so every family needs a fallback skin as well as
   its per-value ones — an unrecognised status must never render as bare
   mono text. */
.tag-ticket, .tag-prio { text-transform: uppercase; background: var(--panel-2); color: var(--muted); }
.tag-ticket-open { background: var(--tint-danger-strong); color: var(--danger); }
.tag-ticket-pending { background: var(--tint-warn); color: var(--warn); }
.tag-ticket-answered { background: var(--accent-soft); color: var(--accent-ink); }
.tag-ticket-solved { background: var(--tint-success); color: var(--success); }
.tag-ticket-closed { background: var(--panel-2); color: var(--muted); }
.tag-prio-low { background: var(--panel-2); color: var(--muted); }
.tag-prio-normal { background: var(--panel-2); color: var(--muted); }
.tag-prio-high { background: var(--tint-warn); color: var(--warn); }
.tag-prio-urgent { background: var(--tint-danger-strong); color: var(--danger); }
.tag-ticket_opened { background: var(--accent-soft); color: var(--accent-ink); }

/* ---------- Help centre ---------- */
.help-search { margin-bottom: 1.6rem; }
.help-search input[type="search"] { flex: 1; max-width: none; min-width: 14rem; }
.help-icon { font-size: 1.05em; }
.help-card h2 { font-size: 1.05rem; margin-bottom: .25rem; }
.help-cta { margin: 1.6rem 0 .4rem; }
.help-row { align-items: flex-start; }

.kb-layout { align-items: start; }
.kb-article { padding: 0; }
.kb-head { padding: 1.6rem 1.8rem 1.1rem; border-bottom: 1px solid var(--border); }
.kb-head h1 { font-size: clamp(1.4rem, 2.6vw, 1.9rem); letter-spacing: -.02em; margin-bottom: .4rem; }
.kb-body { padding: 1.6rem 1.8rem; color: var(--text-soft); line-height: 1.7; }
.kb-body h2 { font-family: var(--font-display); font-size: 1.15rem; color: var(--text); margin: 1.6rem 0 .6rem; }
.kb-body h3 { font-family: var(--font-display); font-size: 1rem; color: var(--text); margin: 1.2rem 0 .5rem; }
.kb-body h2:first-child, .kb-body h3:first-child { margin-top: 0; }
.kb-body p { margin-bottom: .9rem; }
.kb-body ul, .kb-body ol { margin: 0 0 1rem 1.3rem; }
.kb-body li { margin-bottom: .4rem; }
.kb-body code { font-family: var(--mono); font-size: .86em; background: var(--panel-2); padding: .12rem .4rem; border-radius: 6px; box-shadow: inset 0 0 0 1px var(--glass-ring); }
.kb-body pre code { background: none; padding: 0; }
.kb-body .kb-note {
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-card);
  padding: .85rem 1.05rem;
  margin: 1rem 0;
  box-shadow: inset 0 1px 0 var(--glass-ring);
}
.kb-foot { padding: 1.2rem 1.8rem 1.6rem; border-top: 1px solid var(--border); }
.kb-feedback { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; font-size: .92rem; }
.kb-rail h2 { margin-bottom: .4rem; }
.kb-rail .rail-sub, .ticket-rail .rail-sub { margin-top: 1.2rem; }
.kb-rail-cta { margin-top: 1rem; }

/* ---------- The three-step "try first" strip ---------- */
.support-steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem;
  margin-bottom: 2rem;
}
.support-step {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  background: var(--panel);
  border-radius: var(--radius-card);
  padding: 1.2rem 1.4rem;
  box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.support-step:hover { transform: translateY(-4px); box-shadow: var(--ring-shadow), var(--shadow); }
.support-step-n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem; height: 1.6rem;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-family: var(--mono);
  font-size: .78rem;
  font-weight: 700;
  margin-bottom: .3rem;
  box-shadow: inset 0 1px 0 var(--glass-hi), 0 4px 12px -6px var(--accent-glow);
}
.support-cta .panel-form { display: flex; flex-wrap: wrap; gap: .6rem; align-items: center; }
.support-cta .panel-form p { flex: 1 1 20rem; margin: 0; }

/* ---------- "Try this first" suggestion panel ---------- */
.try-first {
  background: var(--accent-soft);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-card);
  padding: 1.15rem 1.35rem;
  margin-bottom: 1.6rem;
  box-shadow: inset 0 1px 0 var(--glass-ring), var(--shadow-sm);
}
.try-first h2 { font-family: var(--mono); font-size: .8rem; text-transform: uppercase; letter-spacing: .12em; color: var(--muted); margin-bottom: .4rem; }
.try-first p { margin-bottom: .7rem; font-size: .9rem; }
.try-first-item {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  padding: .55rem 0;
  border-top: 1px solid var(--border);
  color: var(--text);
}
.try-first-item:hover .try-first-title { color: var(--accent-ink); }
.try-first-title { font-weight: 600; }
.try-first-inline { margin-bottom: 1.4rem; }

/* ---------- Ticket list rows ---------- */
.ticket-row { align-items: center; gap: .9rem; grid-template-columns: auto 1fr auto; }
.ticket-row .thread-nums { display: flex; align-items: center; gap: .3rem; flex-wrap: wrap; }
.ticket-tags { display: flex; gap: .3rem; flex-wrap: wrap; margin-top: .25rem; }
.ticket-tag { text-decoration: none; }

/* ---------- The chat ---------- */
.chat-panel { overflow: visible; }
.chat-live::before { content: "●"; color: var(--success); margin-right: .3rem; }
.chat-log {
  display: flex;
  flex-direction: column;
  gap: .8rem;
  padding: 1.2rem 1.3rem;
  max-height: 34rem;
  overflow-y: auto;
}
.chat-empty { padding: 1rem 0; }
/* Chat bubbles are chips, not panes: they nest inside the chat pane, so
   they take the tint and the rim but no backdrop pass of their own. */
.chat-msg {
  flex-shrink: 0;
  max-width: 46rem;
  padding: .75rem 1rem;
  border-radius: var(--radius-card);
  background: var(--panel-2);
  font-size: .93rem;
  scroll-margin-top: calc(var(--nav-h) + 10px);
}
/* The customer's own messages sit right and carry the accent; support sits
   left in a neutral surface. Both keep full-contrast text — an opacity dim
   would fail AA. */
.chat-msg-user { align-self: flex-end; background: var(--accent-soft); }
.chat-msg-staff { align-self: flex-start; background: var(--panel-2); border-left: 3px solid var(--accent); }
.chat-msg-system {
  align-self: center;
  background: none;
  border: 1px dashed var(--border-strong);
  color: var(--muted);
  font-size: .85rem;
  text-align: center;
  max-width: 34rem;
}
.chat-msg-note {
  align-self: stretch;
  max-width: none;
  background: var(--tint-warn);
  border-left: 3px solid var(--warn);
}
.chat-msg-new { animation: chat-in .25s ease-out; }
@keyframes chat-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .chat-msg-new { animation: none; } }

.chat-head { display: flex; align-items: baseline; justify-content: space-between; gap: .6rem; margin-bottom: .3rem; }
.chat-who { font-weight: 700; font-size: .88rem; }
.chat-time { font-size: .74rem; white-space: nowrap; }
.chat-body { color: var(--text-soft); }

.chat-composer { padding: 1.1rem 1.3rem; border-top: 1px solid var(--border); }
.chat-composer textarea { width: 100%; resize: vertical; }
.chat-composer-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .6rem;
  margin-top: .6rem;
  flex-wrap: wrap;
}
.composer-right { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; }
.chat-attach { display: inline-flex; align-items: center; gap: .5rem; cursor: pointer; }
.chat-attach-name { font-size: .82rem; }
.note-composer { background: var(--tint-warn); }
.note-composer textarea { background: var(--panel); }

/* ---------- Attachments ---------- */
.attach-list { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .6rem; }
.attach-item {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .3rem .7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-ctl);
  background: var(--panel-2);
  font-size: .82rem;
  color: var(--text);
  max-width: 100%;
  transition: border-color .18s ease, color .18s ease, box-shadow .24s ease;
}
.attach-item:hover { border-color: var(--accent); color: var(--accent-ink); }
.attach-image { border-style: dashed; }
.attach-icon { font-size: .95em; line-height: 1; }
.attach-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 14rem; }
.attach-size { font-size: .74rem; }

/* ---------- CSAT ---------- */
.csat {
  display: flex;
  align-items: center;
  gap: .7rem;
  flex-wrap: wrap;
  background: var(--panel);
  border-radius: var(--radius-card);
  padding: .95rem 1.25rem;
  margin-bottom: 1.4rem;
  box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.csat-label { font-weight: 600; }
.csat-done { color: var(--text-soft); }
.csat-stars { display: inline-flex; gap: .1rem; font-size: 1.2rem; color: var(--warn); letter-spacing: .1em; }
.csat-star {
  background: none;
  border: 0;
  padding: 0 .05rem;
  font-size: 1.35rem;
  line-height: 1;
  color: var(--border-strong);
  cursor: pointer;
}
.csat-star:hover, .csat-star:focus-visible { color: var(--warn); }
.csat input[type="text"] { flex: 1; min-width: 14rem; padding: .4rem .7rem; font-size: .87rem; }

/* ---------- Staff workspace ---------- */
.ticket-workspace { align-items: start; }
.ticket-thread { overflow: visible; }
.ticket-rails { display: flex; flex-direction: column; gap: 1.2rem; }
.ticket-rail { position: static; }
.ticket-rail-name { font-weight: 700; margin-bottom: .2rem; }
.ticket-controls { display: flex; gap: .6rem; flex-wrap: wrap; margin-bottom: 1.4rem; align-items: center; }
.ticket-controls select { width: auto; padding: .35rem .6rem; font-size: .85rem; }
.ticket-controls input[type="text"] { padding: .35rem .6rem; font-size: .85rem; min-width: 11rem; }
.ticket-danger { border-top: 1px solid var(--border); }
.ticket-danger .ticket-controls { margin-bottom: 0; }
.ticket-event {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  align-self: center;
  font-size: .8rem;
  color: var(--text-soft);
  padding: .1rem 0;
}
.note-del { float: right; margin-top: .3rem; }
.note-item { border-top: 1px solid var(--border); padding: .6rem 0; font-size: .9rem; }
.note-item:first-of-type { border-top: 0; }
.macro-item { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; border-top: 1px solid var(--border); padding: .5rem 0; }
.macro-item:first-of-type { border-top: 0; }
.macro-insert {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  flex: 1 1 8rem;
}
.macro-insert:hover { color: var(--accent-ink); }

.saved-views { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; margin-bottom: .8rem; }
.saved-view { display: inline-flex; align-items: center; }
.save-view-form { gap: .4rem; flex-wrap: wrap; }
.save-view-form input[type="text"] { padding: .4rem .7rem; font-size: .87rem; min-width: 12rem; }
.support-toolbar { margin-bottom: 1.2rem; }

/* ---------- AI assist ---------- */
.ai-panel { border-top: 1px solid var(--border); background: var(--panel-2); }
.ai-panel h3 { font-size: .95rem; margin-bottom: .5rem; }
.ai-summary-text { font-weight: 600; color: var(--text); margin-bottom: .6rem; }
.ai-panel ul { margin: .2rem 0 .8rem 1.2rem; }
.ai-panel li { margin-bottom: .25rem; }
.ai-actions { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .8rem; }
.ai-draft { border-top: 1px solid var(--border); padding: .6rem 0; }
.ai-draft summary { cursor: pointer; font-weight: 600; color: var(--text); }
.ai-draft-body {
  background: var(--panel);
  border-radius: var(--radius-card);
  padding: .85rem 1.05rem;
  margin: .6rem 0;
  font-size: .9rem;
}

.ai-drafts { margin-top: .8rem; }
.staff-composer textarea { font-size: .93rem; }

/* ---------- Ticket form ---------- */
.ticket-form textarea { width: 100%; resize: vertical; }
.ticket-form input[type="file"] { font-size: .87rem; }

@media (max-width: 1000px) {
  .kb-layout, .ticket-workspace { grid-template-columns: 1fr; }
  .chat-msg { max-width: 100%; }
}

/* ============================================================
   Status page.

   The animation here is load-bearing rather than decorative: a beacon
   pulses ONLY while something is actually wrong, so a glance at a pinned
   tab tells you whether to keep reading. Everything is keyframes on
   classes the server already decided, so it is right before /js/status.js
   loads — and the whole lot collapses under prefers-reduced-motion at the
   bottom of this block.
   ============================================================ */

/* ---------- Beacon: a dot, and expanding rings when it matters ---------- */
.beacon {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.15rem; height: 1.15rem;
  margin-right: .55rem;
  vertical-align: -.15rem;
  flex: none;
}
.beacon-dot {
  width: .62rem; height: .62rem;
  border-radius: 50%;
  background: var(--beacon);
  box-shadow: 0 0 0 1px var(--beacon-soft);
}
.beacon-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid var(--beacon);
  opacity: 0;
  animation: beacon-pulse 2.2s cubic-bezier(.2, .6, .3, 1) infinite;
}
.beacon-ring-2 { animation-delay: 1.1s; }

/* Tone drives one variable; every rule above reads it. */
.beacon-ok { --beacon: var(--success); --beacon-soft: var(--tint-success); }
.beacon-info { --beacon: var(--accent); --beacon-soft: var(--accent-tint); }
.beacon-warn { --beacon: var(--warn); --beacon-soft: var(--tint-warn); }
.beacon-down { --beacon: var(--danger); --beacon-soft: var(--tint-danger-strong); }

/* A resting green dot still breathes, very slightly — enough to read as
   "this page is live" without competing with a real alert. */
.beacon-ok .beacon-dot { animation: beacon-breathe 3.6s ease-in-out infinite; }
.beacon-live .beacon-dot { animation: beacon-flash 1.4s ease-in-out infinite; }

@keyframes beacon-pulse {
  0%   { transform: scale(.55); opacity: .75; }
  70%  { transform: scale(1.5); opacity: 0; }
  100% { transform: scale(1.5); opacity: 0; }
}
@keyframes beacon-breathe {
  0%, 100% { transform: scale(1); opacity: 1; }
  50%      { transform: scale(.86); opacity: .75; }
}
@keyframes beacon-flash {
  0%, 100% { transform: scale(1); opacity: 1; }
  50%      { transform: scale(1.18); opacity: .6; }
}

/* ---------- The headline banner ---------- */
.status-hero {
  position: relative;
  overflow: hidden;
  background: var(--panel);
  border-radius: var(--radius-xl);
  border-left: 4px solid var(--beacon, var(--success));
  padding: 1.7rem 1.9rem;
  margin-bottom: 2rem;
  box-shadow: var(--ring-shadow), var(--shadow);
}
.status-hero-ok { --beacon: var(--success); --beacon-soft: var(--tint-success); }
.status-hero-info { --beacon: var(--accent); --beacon-soft: var(--accent-tint); }
.status-hero-warn { --beacon: var(--warn); --beacon-soft: var(--tint-warn); }
.status-hero-down { --beacon: var(--danger); --beacon-soft: var(--tint-danger-strong); }

/* A slow tint sweep across the banner. It only runs when something is
   wrong — a permanently shimmering "all good" banner is just noise. */
.status-hero:not(.status-hero-ok)::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(100deg, transparent 35%, var(--beacon-soft) 50%, transparent 65%);
  transform: translateX(-100%);
  animation: status-sweep 4.5s ease-in-out infinite;
}
@keyframes status-sweep {
  0%   { transform: translateX(-100%); }
  60%  { transform: translateX(100%); }
  100% { transform: translateX(100%); }
}

.status-hero-inner { display: flex; align-items: flex-start; gap: .5rem; }
.status-hero .beacon { width: 1.5rem; height: 1.5rem; margin-top: .35rem; }
.status-hero .beacon-dot { width: .8rem; height: .8rem; }
.status-headline {
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 3vw, 1.9rem);
  font-weight: 600;
  letter-spacing: -.02em;
  margin-bottom: .3rem;
}
.status-blurb { color: var(--text-soft); margin: 0; }
.status-checked { display: flex; gap: .4rem; margin: 1rem 0 0; font-size: .85rem; }
.status-live { color: var(--success); font-weight: 600; }

.status-head { margin-bottom: 1rem; }
.status-page .hero-kicker { margin: 0; }
.status-section { margin-bottom: 2.4rem; }

/* ---------- Components ---------- */
.status-components {
  background: var(--panel);
  border-radius: var(--radius-card);
  box-shadow: var(--ring-shadow), var(--shadow);
  overflow: hidden;
}
.status-component { padding: 1.1rem 1.3rem; border-top: 1px solid var(--border); }
.status-component:first-child { border-top: 0; }
.status-component-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: .8rem; flex-wrap: wrap;
}
.status-component-name { display: inline-flex; align-items: center; font-weight: 600; }
.status-component-state { font-size: .85rem; font-weight: 600; white-space: nowrap; }
.status-state-ok { color: var(--success); }
.status-state-info { color: var(--accent-ink); }
.status-state-warn { color: var(--warn); }
.status-state-down { color: var(--danger); }
.status-component-desc { margin: .25rem 0 0; font-size: .88rem; }

/* When a live poll changes a row, flash it once so the change is not
   silently swapped in under someone's eyes. */
.status-changed { animation: status-flash 1.6s ease-out 1; }
@keyframes status-flash {
  0%   { background: var(--accent-tint); }
  100% { background: transparent; }
}

/* ---------- 90-day history bars ---------- */
.uptime-bars { display: flex; gap: 2px; margin-top: .8rem; height: 2rem; align-items: stretch; }
.uptime-bar {
  flex: 1 1 0; min-width: 2px; border-radius: 3px; background: var(--success); opacity: .78;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
  transition: opacity .16s ease, transform .16s ease;
}
.uptime-bar:hover { transform: scaleY(1.08); }
.uptime-bar:hover { opacity: 1; }
.uptime-ok { background: var(--success); }
.uptime-info { background: var(--accent); }
.uptime-warn { background: var(--warn); }
.uptime-down { background: var(--danger); }
.uptime-legend { display: flex; justify-content: space-between; gap: .6rem; margin-top: .4rem; font-size: .76rem; }
.uptime-pct { font-variant-numeric: tabular-nums; }

/* ---------- Incidents ---------- */
.incident {
  background: var(--panel);
  border-radius: var(--radius-card);
  padding: 1.25rem 1.45rem;
  margin-bottom: 1rem;
  box-shadow: var(--ring-shadow), var(--shadow-sm);
  scroll-margin-top: calc(var(--nav-h) + 10px);
}
.incident-open { border-left: 3px solid var(--danger); }
.incident-maintenance { border-left-color: var(--accent); }
.incident-closed { border-left: 3px solid var(--border-strong); }
.incident-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .8rem; flex-wrap: wrap; margin-bottom: .3rem;
}
.incident-title { font-family: var(--font-display); font-size: 1.08rem; font-weight: 600; }
.incident-tags { display: flex; gap: .3rem; flex-wrap: wrap; }
.incident-meta, .incident-window { font-size: .85rem; margin-bottom: .8rem; }
.incident-updates { list-style: none; margin: 0; padding: 0; }
.incident-update {
  position: relative;
  padding: .7rem 0 .7rem 1.1rem;
  border-left: 2px solid var(--border);
}
.incident-update::before {
  content: "";
  position: absolute; left: -5px; top: 1.05rem;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--border-strong);
}
.incident-update:first-child::before { background: var(--accent); }
.incident-update-state { font-weight: 700; font-size: .82rem; margin-right: .5rem; }
.incident-update-time { font-size: .78rem; }
.incident-update .post-text { margin-top: .3rem; font-size: .92rem; }

.tag-incident, .tag-impact { text-transform: uppercase; background: var(--panel-2); color: var(--muted); }
.tag-incident-investigating, .tag-incident-identified { background: var(--tint-danger-strong); color: var(--danger); }
.tag-incident-monitoring, .tag-incident-in_progress { background: var(--tint-warn); color: var(--warn); }
.tag-incident-resolved, .tag-incident-completed { background: var(--tint-success); color: var(--success); }
.tag-incident-scheduled { background: var(--accent-soft); color: var(--accent-ink); }
.tag-impact-major { background: var(--tint-warn); color: var(--warn); }
.tag-impact-critical { background: var(--tint-danger-strong); color: var(--danger); }
.tag-impact-none { background: var(--panel-2); color: var(--muted); }

/* ---------- The "we already know" banner on help/support pages ---------- */
.status-note {
  display: flex; align-items: flex-start; gap: .5rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-left: 3px solid var(--beacon, var(--warn));
  border-radius: var(--radius-card);
  padding: .9rem 1.15rem;
  margin-bottom: 1.4rem;
  font-size: .92rem;
  box-shadow: var(--ring-shadow), var(--shadow-sm);
}
.status-note-warn { --beacon: var(--warn); }
.status-note-down { --beacon: var(--danger); }
.status-note-info { --beacon: var(--accent); }
.status-note strong { color: var(--text); }

/* ---------- Admin ---------- */
.status-overview .panel-head h2 { display: inline-flex; align-items: center; }
.component-picker {
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: .75rem .95rem;
  display: flex; flex-wrap: wrap; gap: .4rem 1rem;
  background: var(--panel-2);
  box-shadow: inset 0 1px 0 var(--glass-ring);
}
.component-picker legend { padding: 0 .3rem; font-size: .82rem; }

@media (prefers-reduced-motion: reduce) {
  .beacon-ring,
  .beacon-ok .beacon-dot,
  .beacon-live .beacon-dot,
  .status-hero:not(.status-hero-ok)::after,
  .status-changed {
    animation: none;
  }
  .beacon-ring { opacity: .35; transform: scale(1.15); }
}

/* A clipped file input is still tabbable, so its visible label has to show
   the focus that landed on it — otherwise keyboard focus simply disappears. */
.chat-attach:focus-within .btn {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* CSAT stars are radios (implicit form submission would otherwise file a
   permanent one-star rating from the comment box), so the star is drawn by
   the label and lit by :checked and :hover. */
.csat-stars { border: 0; padding: 0; margin: 0; display: inline-flex; align-items: center; gap: .1rem; }
.csat-stars .csat-label { padding: 0; margin-right: .4rem; }
.csat-star {
  cursor: pointer;
  font-size: 1.35rem;
  line-height: 1;
  color: var(--border-strong);
  padding: 0 .05rem;
  transition: color .15s ease;
}
.csat-star:hover, .csat-stars:hover .csat-star { color: var(--warn); }
.csat-star:hover ~ .csat-star { color: var(--border-strong); }
.csat-star:has(input:checked) { color: var(--warn); }
.csat-star:has(input:checked) ~ .csat-star { color: var(--border-strong); }
.csat-star:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.ai-consent { margin: .2rem 0 .4rem; }
.ticket-subject { font-weight: 600; }

/* ============================================================
   CONTINUOUS CORNERS
   ------------------------------------------------------------
   An iOS corner is not a quarter-circle. It is a superellipse: the
   curvature ramps in and out instead of starting abruptly where the
   straight edge ends, which is why 14pt on iOS reads softer and less
   "bubbly" than 14px in a browser. `corner-shape: squircle` is exactly
   that curve — superellipse(4) — and it is the half of "iOS radius"
   that no amount of tuning the number can substitute for.

   Applied to everything: on an element with no border-radius a squircle
   corner of zero is still a square corner, so this is a no-op except
   where a radius is actually set.

   The exceptions are the shapes that are meant to be true arcs. A
   circle put through a superellipse stops being a circle, so avatars,
   pips, spinners and capsule badges opt back out.
   ============================================================ */
@supports (corner-shape: squircle) {
  * { corner-shape: squircle; }

  .avatar,
  .theme-toggle,
  .tag,
  .uid-badge,
  .support-step-n,
  .beacon-dot,
  .beacon-ring,
  .pay-spinner,
  .incident-update::before,
  .star-border::after,
  .hero-aurora::before,
  .hero-aurora::after,
  .hero-aurora .aurora-blob { corner-shape: round; }
}

/* ============================================================
   MATERIAL FALLBACKS
   ------------------------------------------------------------
   Two audiences never see the refraction: people who asked their OS to
   cut transparency, and browsers with no backdrop-filter. Both get an
   opaque pane with the same geometry rather than washed-out text on a
   see-through box.

   This block is deliberately the LAST thing in the file. The refracting
   surfaces declare their own blur strength further up (the nav capsule,
   the hero HUD, the dialog and its scrim), so an override that sat with
   the material spec would lose the cascade to every one of them.
   ============================================================ */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  :root { --panel: #f4f7fd; --panel-2: #e6ecf8; --glass: #f7f9fe; --band: #eef2fb; }
  :root[data-theme="dark"] { --panel: #101728; --panel-2: #0c1220; --glass: #0d1424; --band: #080d18; }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]):not([data-theme="dark"]) {
      --panel: #101728; --panel-2: #0c1220; --glass: #0d1424; --band: #080d18;
    }
  }
}

@media (prefers-reduced-transparency: reduce) {
  :root {
    --panel: #f4f7fd;
    --panel-2: #e6ecf8;
    --glass: #f7f9fe;
    --band: #eef2fb;
    --field-opacity: 0.35;
    --grain-opacity: 0;
  }
  :root[data-theme="dark"] {
    --panel: #101728;
    --panel-2: #0c1220;
    --glass: #0d1424;
    --band: #080d18;
    --field-opacity: 0.3;
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]):not([data-theme="dark"]) {
      --panel: #101728;
      --panel-2: #0c1220;
      --glass: #0d1424;
      --band: #080d18;
      --field-opacity: 0.3;
    }
  }
  /* The one place !important earns its keep: the request is "no see-through
     material anywhere", and it has to outrank every per-component blur. */
  *, *::before, *::after {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  /* Without its depth-of-field the dialog scrim has to do the separating on
     opacity alone. */
  .terms-gate { background: rgba(5, 7, 15, 0.72); }
  body::before { animation: none; }
}
