/* ===========================================================================
   reconet.cc - design system
   Palette and accent come from the logo: steel blue on near-black.
   Type: Space Grotesk for display (geometric, matches the mark), Inter for UI.
   =========================================================================== */

:root {
  --bg:            #08090c;
  --bg-elevated:   #0b0d11;
  --surface:       rgba(255, 255, 255, .028);
  --surface-2:     rgba(255, 255, 255, .052);
  --surface-3:     rgba(255, 255, 255, .085);

  --border:        rgba(255, 255, 255, .075);
  --border-strong: rgba(255, 255, 255, .13);

  --text:          #e9ecf1;
  --text-dim:      #b3bbc8;
  --muted:         #8d96a6;
  --faint:         #5d6675;

  --accent:        #4a90e2;
  --accent-hot:    #2f7ad6;
  --accent-soft:   rgba(74, 144, 226, .14);

  --danger:        #f2686b;
  --danger-soft:   rgba(242, 104, 107, .12);
  --ok:            #4ec98a;
  --ok-soft:       rgba(78, 201, 138, .12);
  --warn:          #e8b34a;

  --font-display:  'Space Grotesk', 'Segoe UI', system-ui, sans-serif;
  --font-body:     'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;

  --radius:        12px;
  --radius-lg:     16px;
  --wrap:          1120px;
  --header-h:      64px;

  --shadow:        0 18px 40px -22px rgba(0, 0, 0, .9);
  --ring:          0 0 0 3px rgba(74, 144, 226, .18);

  /* space to leave at the bottom of a page for the fixed soundtrack bar */
  --bar-clear:     72px;
}

* { box-sizing: border-box; }

html { color-scheme: dark; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* One soft blue wash behind the top of every page. Fixed, so scrolling never
   runs into a hard edge halfway down. */
body::before {
  content: '';
  position: fixed;
  inset: 0 0 auto 0;
  height: 520px;
  background:
    radial-gradient(760px 340px at 18% -12%, rgba(74, 144, 226, .13), transparent 70%),
    radial-gradient(620px 300px at 88% -18%, rgba(47, 122, 214, .09), transparent 72%);
  pointer-events: none;
  z-index: 0;
}

main { flex: 1 0 auto; position: relative; z-index: 1; }

a { color: var(--accent); text-decoration: none; }
a:hover { color: #6ba7ea; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -.022em;
  line-height: 1.16;
  margin: 0 0 .5em;
  color: var(--text);
}

h1 { font-size: clamp(30px, 4.6vw, 46px); }
h2 { font-size: 24px; }
h3 { font-size: 17px; }
p  { margin: 0 0 1em; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 26px;
}

/* ---------------------------------------------------------------- header -- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(8, 9, 12, .74);
  backdrop-filter: blur(16px) saturate(150%);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  border-bottom: 1px solid var(--border);
}

.site-header .wrap {
  display: flex;
  align-items: center;
  gap: 26px;
  height: var(--header-h);
}

.brand { display: flex; align-items: center; flex: 0 0 auto; }
.brand:hover { color: inherit; }

.brand-mark { height: 34px; width: auto; display: block; }


.nav { display: flex; align-items: center; gap: 2px; margin-right: auto; }

.nav a {
  padding: 8px 13px;
  border-radius: 9px;
  font-size: 14px;
  font-weight: 500;
  color: var(--muted);
  transition: color .15s, background .15s;
}
.nav a:hover { color: var(--text); background: var(--surface-2); }
.nav a.active { color: var(--text); background: var(--surface-2); }

.nav-auth {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 0 0 auto;
  font-size: 14px;
}
.nav-auth a { color: var(--muted); font-weight: 500; }
.nav-auth a:hover { color: var(--text); }
.nav-auth .who { color: var(--faint); font-size: 13px; }
.nav-auth .who b { color: var(--text-dim); font-weight: 600; }

/* ------------------------------------------------------------------ hero -- */

.hero { padding: 76px 0 60px; }

/* Hero brand lockup. The full ".cc" wordmark art puts NET in a dark navy that
   disappears on this background, so the plain wordmark is used and ".cc" is
   set in the accent colour, which keeps the contrast and the domain. */
.hero-brand {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  margin-bottom: 30px;
}
.hero-brand img { width: clamp(230px, 32vw, 348px); height: auto; display: block; }
.hero-brand .cc {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(28px, 4.2vw, 45px);
  line-height: 1;
  letter-spacing: -.04em;
  color: var(--accent);
  padding-bottom: clamp(3px, .7vw, 9px);
}

.hero h1 { max-width: 20ch; }

.hero .lede {
  font-size: 16.5px;
  line-height: 1.7;
  color: var(--muted);
  max-width: 56ch;
  margin-bottom: 30px;
}

.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; }

/* The landing is one centred block: the wordmark, the two ways in, and a quiet
   line of real numbers. Nothing explains the board — a closed door needs no
   copy, and once there is anything to count the numbers do the talking. */
main:has(.hero-fill) { display: flex; flex-direction: column; }
.hero-fill {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* No min-height fallback here on purpose. Any guess at the available height
     that comes out too large makes the hero taller than main, the document
     scrolls, and the footer sinks under the fixed bar -- which is exactly what
     a "safe-looking" calc(100vh - ...) did. Without :has() the block simply
     does not stretch, which degrades quietly instead of overflowing. */
  padding: 48px 0;
}
.hero-fill .hero-brand { margin-bottom: 34px; }

.hero-live {
  margin: 26px 0 0;
  font-size: 13px;
  letter-spacing: .02em;
  color: var(--faint);
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 18px;
}
.eyebrow::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent);
}

/* ---------------------------------------------------------------- layout -- */


.page-head { padding: 46px 0 26px; }
.page-head h1 { font-size: clamp(26px, 3.4vw, 34px); margin-bottom: 8px; }
.page-head .sub { color: var(--muted); font-size: 15px; margin: 0; }

.grid { display: grid; gap: 16px; }

/* ----------------------------------------------------------------- cards -- */

.card, .panel {
  background: linear-gradient(180deg, rgba(255,255,255,.034), rgba(255,255,255,.012));
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.panel-body { padding: 20px 22px; }

.card-head, .panel-head {
  padding: 14px 22px;
  border-bottom: 1px solid var(--border);
  background: rgba(255, 255, 255, .018);
  font-family: var(--font-display);
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--text-dim);
}


/* --------------------------------------------------------------- buttons -- */

.btn, button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 11px 20px;
  border-radius: 10px;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 550;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s, border-color .15s, filter .15s, transform .06s;
}

button:hover:not(:disabled), .btn:hover {
  background: var(--surface-3);
  border-color: var(--border-strong);
  color: var(--text);
}

.btn-primary, button.primary {
  background: linear-gradient(180deg, var(--accent), var(--accent-hot));
  color: #fff;
  border-color: rgba(255, 255, 255, .16);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), 0 8px 22px -12px rgba(74, 144, 226, .85);
}
.btn-primary:hover, button.primary:hover { filter: brightness(1.09); color: #fff; }

.btn-ghost, button.ghost { background: var(--surface-2); border-color: var(--border-strong); }
.btn-ghost:hover, button.ghost:hover { background: var(--surface-3); color: var(--text); }

.btn:active, button:active { transform: translateY(1px); }

.btn[disabled], button[disabled] {
  opacity: .5;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.btn.small, button.small { padding: 7px 13px; font-size: 13px; border-radius: 8px; }

/* ----------------------------------------------------------------- forms -- */

.field { margin-bottom: 20px; }

.field label {
  display: block;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-dim);
  margin-bottom: 3px;
}

.field .req {
  display: block;
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .04em;
  color: var(--faint);
  margin-bottom: 9px;
}

.field .hint {
  display: block;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--faint);
  margin-top: 7px;
}

input[type="text"], input[type="email"], input[type="password"], textarea, select {
  width: 100%;
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  padding: 11px 13px;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.5;
  transition: border-color .15s, box-shadow .15s, background .15s;
}

input::placeholder, textarea::placeholder { color: var(--faint); }

input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
  background: #0a0c10;
}

input[aria-invalid="true"], textarea[aria-invalid="true"] { border-color: rgba(242, 104, 107, .6); }

textarea { min-height: 128px; resize: vertical; }

select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 19px) 50%, calc(100% - 14px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 40px;
}

.check {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--muted);
  cursor: pointer;
}
.check input[type="checkbox"] {
  flex: 0 0 auto;
  width: 17px; height: 17px;
  margin: 2px 0 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.flabel {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-dim);
  padding-top: 12px;
}
.flabel .req {
  display: block;
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 500;
  color: var(--faint);
  margin-top: 2px;
}

@media (max-width: 660px) {
  .flabel { padding-top: 0; }
}

/* --------------------------------------------------------- notices/errors -- */

.err { color: var(--danger); font-size: 12.5px; margin-top: 6px; }
.err:empty { display: none; }
.good { color: var(--ok); font-size: 12.5px; margin-top: 6px; }

.notice {
  padding: 12px 15px;
  border-radius: 10px;
  font-size: 13.5px;
  line-height: 1.55;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-dim);
  margin-bottom: 18px;
}
.notice.info-box { border-color: rgba(74, 144, 226, .34); background: var(--accent-soft); }
.notice.err-box  { border-color: rgba(242, 104, 107, .38); background: var(--danger-soft); color: #f8b6b7; }
.notice.ok-box   { border-color: rgba(78, 201, 138, .34); background: var(--ok-soft); }

.captcha-slot {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 13px 15px;
  background: var(--surface);
}

.empty { padding: 34px 22px; text-align: center; color: var(--faint); font-size: 14px; }

/* -------------------------------------------------------------- auth page -- */

/* One centred card on an ambient field. body is already a 100vh flex column, so
   `main` growing to fill is what centres the card in the space between the
   header and the footer — no hard-coded header height to drift out of date. */
.auth-page {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  padding: 48px 20px;
  isolation: isolate;
}

/* The brand glow behind the glass. Fixed rather than absolute so it stays put on
   a short page, and negative-z so it never intercepts a click. */
.auth-page::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(620px 360px at 50% 38%, rgba(59, 130, 246, .22), transparent 72%),
    radial-gradient(900px 420px at 50% 104%, rgba(59, 130, 246, .12), transparent 70%);
}

.auth-card {
  position: relative;
  width: 380px;
  max-width: 100%;
  padding: 40px;
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 16px;
  background: rgba(255, 255, 255, .03);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  box-shadow: 0 32px 80px rgba(0, 0, 0, .55), inset 0 1px 0 rgba(255, 255, 255, .045);
  animation: auth-in .5s cubic-bezier(.4, 0, .2, 1) both;
  /* auto margins centre on both axes — and, unlike align-items: center, this
     cannot push a tall card's top edge out of reach on a short screen. */
  margin: auto;
}

@keyframes auth-in {
  from { opacity: 0; transform: translateY(15px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---- fields: muted label stacked over an animated underline ---- */

.auth-field { margin-bottom: 24px; }

.auth-label {
  display: block;
  margin-bottom: 7px;
  color: #888;
  font-size: 12.5px;
  letter-spacing: .04em;
}

/* The line sits on the wrapper, not the input, so it spans the full row
   (including the show/hide control) and animates as a single element. */
.auth-line {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 12px;
  border-bottom: 1px solid rgba(255, 255, 255, .15);
}
/* The brand-blue underline that grows out of the left on focus. */
.auth-line::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: #3b82f6;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .3s cubic-bezier(.4, 0, .2, 1),
              box-shadow .3s cubic-bezier(.4, 0, .2, 1);
}
.auth-line:focus-within::after {
  transform: scaleX(1);
  box-shadow: 0 0 12px rgba(59, 130, 246, .8), 0 1px 3px rgba(59, 130, 246, .9);
}

/* Scoped to .auth-card so it outranks the base `input[type="text"]` rule at
   0,1,1 — a lone class loses to it and the box comes back. */
.auth-card .auth-input {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
  padding: 5px 0 9px;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: 15px;
  line-height: 1.4;
}
.auth-card .auth-input:focus {
  outline: none;
  border-color: transparent;
  box-shadow: none;
  background: none;
}
.auth-card .auth-input::placeholder { color: var(--faint); }

/* Chrome's autofill fill would punch a solid block through the glass, so the
   repaint is deferred far past any plausible session. */
.auth-card .auth-input:-webkit-autofill,
.auth-card .auth-input:-webkit-autofill:hover,
.auth-card .auth-input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--text);
  caret-color: var(--text);
  transition: background-color 600000s 0s, color 600000s 0s;
}

.auth-card .auth-show {
  flex: 0 0 auto;
  padding: 0 0 9px;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--faint);
  font-family: inherit;
  font-size: 12px;
  letter-spacing: .04em;
  cursor: pointer;
  transition: color .2s ease;
}
.auth-card .auth-show:hover {
  background: none;
  color: #3b82f6;
}

.auth-hint {
  margin-top: 7px;
  color: var(--faint);
  font-size: 12px;
}

.auth-field .err { margin-top: 7px; }

/* ---- switch ---- */

.auth-row { margin-bottom: 24px; }

.auth-toggle {
  display: flex;
  align-items: center;
  gap: 12px;
  color: #888;
  font-size: 13.5px;
  line-height: 1.4;
  cursor: pointer;
}
.auth-toggle input {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  flex: 0 0 auto;
  width: 38px;
  height: 21px;
  margin: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, .12);
  cursor: pointer;
  transition: background .3s cubic-bezier(.4, 0, .2, 1);
}
.auth-toggle input::after {
  content: '';
  position: absolute;
  top: 2.5px;
  left: 2.5px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #9aa3b2;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .45);
  transition: transform .3s cubic-bezier(.4, 0, .2, 1),
              background .3s cubic-bezier(.4, 0, .2, 1);
}
.auth-toggle input:checked { background: #3b82f6; }
.auth-toggle input:checked::after { transform: translateX(17px); background: #fff; }
.auth-toggle input:focus-visible { outline: 2px solid #3b82f6; outline-offset: 3px; }

/* ---- submit: text, centred, with a glow that slides in underneath ---- */

/* Scoped to .auth-card deliberately. The base `button:hover:not(:disabled)` rule
   is specificity 0,2,1, so it outranks a plain `.auth-submit:hover` (0,2,0) and
   quietly paints a hover background and border colour back on — a grey box
   appearing behind the word. Anchoring to the card (0,3,0) also clears the base
   border-radius, which stays invisible at rest but shows the moment a background
   exists. The show/hide control below has the same problem. */
.auth-card .auth-submit {
  position: relative;
  display: block;
  margin: 34px auto 0;
  padding: 8px 4px;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: var(--text);
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color .3s cubic-bezier(.4, 0, .2, 1),
              transform .3s cubic-bezier(.4, 0, .2, 1);
}
.auth-card .auth-submit::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 3px;
  width: 100%;
  height: 1px;
  background: #3b82f6;
  box-shadow: 0 0 10px rgba(59, 130, 246, .9);
  transform: translateX(-50%) scaleX(0);
  transform-origin: center;
  transition: transform .3s cubic-bezier(.4, 0, .2, 1);
}
.auth-card .auth-submit:hover {
  background: none;
  border-color: transparent;
  box-shadow: none;
  color: #3b82f6;
  transform: translateY(-2px);
}
.auth-card .auth-submit:hover::after { transform: translateX(-50%) scaleX(1); }
.auth-card .auth-submit:active { transform: translateY(0); }
.auth-card .auth-submit:disabled {
  background: none;
  color: var(--faint);
  cursor: default;
  transform: none;
}
.auth-card .auth-submit:disabled::after { transform: translateX(-50%) scaleX(0); }

.auth-links {
  display: flex;
  justify-content: center;
  gap: 22px;
  margin-top: 18px;
  font-size: 12.5px;
}
.auth-links a { color: var(--faint); transition: color .2s ease; }
.auth-links a:hover { color: #3b82f6; }

/* The footer's own top margin would otherwise shorten main's box by 40px and
   leave the card sitting visibly high. */
/* Auth pages centre their card in main, so the footer's height is part of that
   geometry: growing it would drag the card off centre. Zeroing the top padding
   pays for the clearance below and leaves the total height unchanged. */
.auth-page + .site-footer { margin-top: 0; padding-top: 0; }

@media (max-width: 460px) {
  .auth-card { padding: 30px 22px; }
  .auth-page { padding: 32px 16px; }
}

/* Anyone who has asked their OS for less motion gets none of it. */
@media (prefers-reduced-motion: reduce) {
  .auth-card { animation: none; }
  .auth-line::after,
  .auth-toggle input,
  .auth-toggle input::after,
  .auth-submit,
  .auth-submit::after { transition: none; }
}

/* Two-factor secret and recovery codes. */
.secret-box {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 14px 16px;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--bg-elevated);
}
.secret-box code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 15px;
  letter-spacing: .06em;
  color: var(--text);
  overflow-wrap: anywhere;
}

.recovery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 9px;
}
.recovery-grid code {
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: var(--bg-elevated);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 14px;
  letter-spacing: .06em;
  text-align: center;
  color: var(--text);
}

table.board { width: 100%; border-collapse: collapse; font-size: 14px; }

table.board thead th {
  text-align: left;
  padding: 12px 18px;
  font-family: var(--font-display);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--faint);
  background: rgba(255, 255, 255, .02);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

table.board td {
  padding: 15px 18px;
  border-bottom: 1px solid rgba(255, 255, 255, .05);
  vertical-align: top;
  color: var(--text-dim);
}

table.board tbody tr { transition: background .12s; }
table.board tbody tr:hover { background: rgba(255, 255, 255, .022); }
table.board tbody tr:last-child td { border-bottom: none; }

table.board td.title { color: var(--text); }
table.board td.title > a {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -.012em;
  color: var(--text);
}
table.board td.title > a:hover { color: var(--accent); }

.right  { text-align: right; }
.nowrap { white-space: nowrap; }
.sub    { font-size: 12.5px; color: var(--faint); margin-top: 4px; }
td .sub { margin-top: 5px; }

/* ----------------------------------------------------------------- pills -- */

.pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 100px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .055em;
  text-transform: uppercase;
  vertical-align: 1px;
  background: var(--surface-3);
  color: var(--muted);
  border: 1px solid var(--border);
}
/* Roles are text, not chips. admin / mod / support are groups, so the whole
   name takes the group colour and glows a little; the [tag] after it is the
   label and inherits the same colour. No fill, no border, no bubble -- a box
   around a rank reads as another button and competes with the name it belongs
   to. Colours follow the house convention: red admin, green mod, blue support. */
.uname.r-admin,
.uname.r-admin .ulink {
  color: #ff3b3b;
  text-shadow: 0 0 9px rgba(255, 59, 59, .55), 0 0 22px rgba(255, 59, 59, .25);
}
.uname.r-mod,
.uname.r-mod .ulink {
  color: #3ddc84;
  text-shadow: 0 0 9px rgba(61, 220, 132, .5), 0 0 22px rgba(61, 220, 132, .22);
}
.uname.r-support,
.uname.r-support .ulink {
  color: #5aa9ff;
  text-shadow: 0 0 9px rgba(90, 169, 255, .55), 0 0 22px rgba(90, 169, 255, .25);
}

/* The [role] label. It carries no colour of its own -- it inherits the group
   colour from .uname, so the name and the tag can never drift apart. */
.rtag { font-weight: 600; }

/* beta is a stage, not a rank: plain unbracketed text after the name, with a
   soft silver lift rather than a colour of its own. */
.btag {
  color: #cfd8e6;
  font-weight: 600;
  text-shadow: 0 0 8px rgba(214, 226, 245, .45);
}

/* A plain member's name, linked to their profile. */
a.ulink { color: var(--text); font-weight: 500; }
a.ulink:hover { color: var(--accent); }

/* Board state, which really is a chip -- it labels the thread, not a person. */
.pill.pinned { background: rgba(232,179,74,.13); color: #e5c077; border-color: rgba(232,179,74,.3); }
.pill.locked { background: var(--surface-3); color: var(--muted); }

/* ---------------------------------------------------------- category nav -- */

/* Tabs, as words. The active one is the only one that is white, and a hairline
   under it says which shelf you are on -- no pill, no fill, nothing to hover that
   changes shape under the pointer. */
.cat-nav {
  display: flex; flex-wrap: wrap; gap: 24px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--border);
}
.cat-nav a {
  padding: 6px 0 11px; margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  font-size: 14px; font-weight: 550;
  transition: color .15s, border-color .15s;
}
.cat-nav a:hover { color: var(--text); }
.cat-nav a.active { color: var(--text); border-bottom-color: var(--accent); }

/* The category index: a shelf of categories, each saying what belongs in it,
   rather than a flat row of names you have to guess at. The row is the target, so
   the whole row reacts -- and the counts sit in their own column so they line up
   down the shelf instead of wandering with the length of each description. */
.board.cats td.title > a {
  font-family: var(--font-display); font-size: 16px; font-weight: 600;
  color: var(--text);
}
.board.cats tr:hover td.title > a { color: #93c0f2; }
.board.cats td.title .sub {
  margin-top: 6px; max-width: 68ch; line-height: 1.55; color: var(--muted);
}
.board.cats tr { transition: background .15s; }
.board.cats tr:hover { background: var(--surface); }
.board.cats td.title { padding: 18px; }
.board.cats td:last-child { width: 150px; text-align: right; padding: 18px; }
.board.cats td:last-child .sub { line-height: 1.7; }
/* The "back to <group>" line above a thread list. */
.board-wrap > a.sub, #boardBack:not(:empty) { display: block; margin-bottom: 14px; }


.board-bar {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 22px;
  flex-wrap: wrap;
}
.board-bar h1 { font-size: 27px; margin: 0 0 5px; }
.board-bar .sub { color: var(--muted); font-size: 14px; }

/* ---------------------------------------------------------------- thread -- */

.post { display: grid; grid-template-columns: 176px minmax(0, 1fr); }
.post + .post { border-top: 1px solid var(--border); }

.post .side {
  padding: 20px 22px;
  background: rgba(255, 255, 255, .016);
  border-right: 1px solid var(--border);
}
.post .side .name {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  word-break: break-word;
}
.post .side .meta { font-size: 12px; color: var(--faint); margin-top: 5px; }

.post .body { padding: 20px 24px; }
.post .stamp {
  font-size: 11px;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 10px;
}

@media (max-width: 680px) {
  .post { grid-template-columns: minmax(0, 1fr); }
  .post .side { border-right: none; border-bottom: 1px solid var(--border); }
}

/* Post bodies are user text: keep newlines, never let one run off the side. */
.content {
  font-size: 14.5px;
  line-height: 1.72;
  color: var(--text-dim);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.content.muted { color: var(--muted); }

/* --------------------------------------------------------- post formatting -- */

/* The toolbar is a row of words, so it gets the same treatment as every other
   action: no boxes, no fills. */
.fmt-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 12px; }
.fmt-bar .lnk { font-size: 13px; }
.fmt-bar .lnk.on { color: var(--text); }

.fmt-preview {
  margin-top: 14px; padding: 14px 16px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
  font-size: 14.5px; line-height: 1.72; color: var(--text-dim);
  white-space: pre-wrap; overflow-wrap: anywhere;
}

/* Rendered markup. Classes only -- the CSP forbids inline styles. */
.fmt-code {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 13px; line-height: 1.6;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 8px; padding: 12px 14px; margin: 12px 0;
  color: var(--text); white-space: pre; overflow-x: auto;
}
.fmt-inline {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 13px; background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 5px; padding: 1px 5px; color: var(--text);
}
.fmt-quote {
  margin: 12px 0; padding: 2px 0 2px 14px;
  border-left: 2px solid var(--border-strong); color: var(--muted);
}
.fmt-list { margin: 12px 0; padding-left: 22px; }
.fmt-list li { margin: 4px 0; }
.fmt-link { color: var(--accent); text-decoration: none; }
.fmt-link:hover { color: var(--accent-hot); text-decoration: underline; }
.content strong { color: var(--text); font-weight: 600; }
.content u { text-decoration-color: var(--muted); text-underline-offset: 3px; }

/* The fixed colour palette. Named, not free-form: nine classes on a dark board
   stay readable, and every one of them is legible against the panel. */
.fc-red    { color: #ff6b6b; }
.fc-orange { color: #ffa657; }
.fc-yellow { color: #ffd76e; }
.fc-green  { color: #6ee7a8; }
.fc-teal   { color: #5eead4; }
.fc-blue   { color: #7cb8ff; }
.fc-purple { color: #c4a6ff; }
.fc-pink   { color: #ff9ecb; }
.fc-grey   { color: #9aa6b8; }

.fmt-img {
  display: block; max-width: 100%; height: auto; margin: 12px 0;
  border: 1px solid var(--border); border-radius: var(--radius);
}

/* Hid-until boxes. The open one is a quiet indent; the locked one has to read as
   a closed door rather than an error, because nothing has gone wrong. */
.fmt-hide { margin: 12px 0; padding-left: 14px; border-left: 2px solid var(--accent); }
.fmt-locked {
  margin: 12px 0; padding: 14px 16px; text-align: center;
  border: 1px dashed var(--border-strong); border-radius: var(--radius);
  color: var(--muted); font-size: 13.5px;
}

/* ---- where to post ------------------------------------------------------- */

/* A list of places, not a wall of buttons: each row is a name with its
   description under it, and the only thing that changes on hover is the name.
   No boxes, no fills -- the same rule every other action on the site follows. */
.where { width: min(460px, calc(100vw - 32px)); }
.where-list { padding: 8px 26px 4px; }

.where-row {
  display: block; width: 100%; text-align: left;
  padding: 14px 0; margin: 0;
  border: 0; border-bottom: 1px solid var(--border);
  border-radius: 0; background: none; box-shadow: none;
  font: inherit; cursor: pointer;
  /* The base button rule sets white-space: nowrap and line-height: 1, which is
     right for a one-word button and wrong for a row that contains a sentence --
     without this the description is silently clipped at the panel edge. */
  white-space: normal; line-height: 1.5;
}
.where-row:last-child { border-bottom: 0; }
.where-name {
  display: block; font-family: var(--font-display);
  font-size: 14.5px; font-weight: 600; color: var(--text);
}
.where-row:hover .where-name { color: #93c0f2; }
.where-sub { display: block; margin-top: 5px; font-size: 12.5px; color: var(--muted); line-height: 1.5; }

.where-in { color: var(--text); }

/* The colour palette, revealed by the word "color". */
.fmt-colors { display: flex; flex-wrap: wrap; gap: 12px; width: 100%; margin-top: 4px; }
.fmt-colors .lnk { font-size: 12.5px; }

.acts .lnk.like { font-size: 12.5px; }
.acts .lnk.like.on { color: var(--accent-hot); }
.acts .like-count { font-size: 12.5px; color: var(--muted); }

/* ---------------------------------------------------------------- footer -- */

.site-footer {
  flex: 0 0 auto;
  position: relative;
  z-index: 1;
  border-top: 1px solid var(--border);
  /* The soundtrack bar is fixed to the bottom of the viewport, so the footer's
     own line has to clear it or the bar sits over the domain name (and, once
     the bar spans the width on a phone, over the links too). */
  padding: 30px 0 var(--bar-clear);
  margin-top: 40px;
  font-size: 13px;
  color: var(--faint);
}
.site-footer .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
  justify-content: space-between;
}
.site-footer nav { display: flex; gap: 18px; flex-wrap: wrap; }
.site-footer a { color: var(--muted); }
.site-footer a:hover { color: var(--text); }

/* ----------------------------------------------------------- long-form -- */

/* Rules, terms, privacy: numbered headings with bulleted clauses. */
.prose { max-width: 78ch; }
.prose h2 { margin: 28px 0 10px; font-size: 15px; color: var(--text); }
.prose h2:first-child { margin-top: 0; }
.prose ul { margin: 0; padding-left: 18px; color: var(--muted); }
.prose li { margin-bottom: 7px; line-height: 1.7; }
.prose b { color: var(--text-dim); font-weight: 600; }
.prose p { color: var(--muted); }

/* --------------------------------------------------------------- profile -- */

.btn-sm { padding: 7px 14px; font-size: 12.5px; }

.profile { display: flex; align-items: center; gap: 22px; padding: 42px 0 20px; }
.profile-avatar {
  flex: 0 0 auto;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.avatar-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar-letter {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 600;
  color: var(--muted);
}

.profile-name { margin: 0 0 10px; font-size: clamp(22px, 3vw, 30px); }
.profile-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
  color: var(--muted);
}
.profile-meta b { color: var(--text-dim); font-weight: 600; }

.profile-bio {
  max-width: 68ch;
  padding-bottom: 12px;
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-dim);
  /* A bio keeps the line breaks someone typed; drop them and it reads as one
     run-on paragraph. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.profile-edit { margin-top: 24px; }
.bio-input { min-height: 0; }
.profile-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 12px; }
.profile-msg { font-size: 13px; color: var(--muted); }
.profile-msg.ok { color: var(--ok); }
.profile-msg.err { color: var(--danger); }

/* ---- profile, continued ------------------------------------------------- */

/* The way back out. A profile is reachable from a post, from a name card and
   from a direct link, so there has to be an obvious way to leave it. */
.back { display: inline-block; margin: 24px 0 0; color: var(--muted); }
.back:hover { color: var(--text); }

.profile-cta { margin-top: 14px; }

/* Contributions: the two things a member actually produces, side by side. */
.profile-cols {
  display: grid; grid-template-columns: 1fr 1fr; gap: 18px;
  margin-top: 22px; align-items: start;
}

.act-list { list-style: none; margin: 0; padding: 0; }
.act-list li { padding: 10px 0; border-top: 1px solid var(--border); }
.act-list li:first-child { border-top: 0; padding-top: 0; }
.act-list a { font-weight: 500; }
.act-list .sub { display: block; margin-top: 4px; }

.warn-list li { display: flex; flex-direction: column; gap: 3px; }

.staff-row {
  display: grid; grid-template-columns: 86px 1fr; gap: 12px; align-items: start;
  padding: 13px 0; border-top: 1px solid var(--border);
}
.staff-row:first-of-type { border-top: 0; }
.staff-label {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: var(--muted); padding-top: 7px;
}
.staff-ctl { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.staff-ctl .ainput { flex: 1; min-width: 150px; }
.staff-ctl-list { display: block; width: 100%; }

/* A warning or a timeout, on the member's own panel. Amber, not red: it is a
   mark on the account, not an accusation, and it has to be readable. */
.warn-box { border-color: rgba(232, 179, 74, .3); background: rgba(232, 179, 74, .07); }
.warn-box .warn-list { margin-top: 10px; }

/* The one destructive control on the site. It should not look like "save". */
.btn-danger { background: var(--danger-soft); border-color: rgba(242, 104, 107, .35); color: var(--danger); }
.btn-danger:hover { background: rgba(242, 104, 107, .2); color: #ff8b8e; }

@media (max-width: 760px) {
  .profile-cols { grid-template-columns: 1fr; }
  .staff-row { grid-template-columns: 1fr; gap: 6px; }
  .staff-label { padding-top: 0; }
}

@media (max-width: 560px) {
  .profile { flex-direction: column; align-items: flex-start; gap: 16px; padding-top: 30px; }
}

/* ----------------------------------------------------------------- utils -- */

.muted { color: var(--muted); }
.faint { color: var(--faint); }
.small { font-size: 13px; }
.mb-0 { margin-bottom: 0; }

/* The [hidden] attribute only hides an element when nothing else sets display on
   it — any layout rule with an explicit display silently defeats it. Make it
   unconditional so it cannot be quietly overridden later. */
[hidden] { display: none !important; }
.hidden { display: none !important; }

/* Big centred splash for 404 and other dead ends. */
.splash { padding: 110px 0 90px; text-align: center; }
.splash h1 { font-size: clamp(52px, 12vw, 104px); margin-bottom: 6px; letter-spacing: -.05em; }
.splash p { color: var(--muted); max-width: 46ch; margin: 0 auto 26px; }

/* Legal copy reads better narrower and less bright. */
.prose { max-width: 74ch; }
.prose h2 { font-size: 19px; margin: 34px 0 10px; }
.prose p, .prose li { color: var(--text-dim); font-size: 14.5px; line-height: 1.75; }
.prose ul { padding-left: 20px; }
.prose li { margin-bottom: 7px; }
.prose .updated { color: var(--faint); font-size: 13px; }

::selection { background: rgba(74, 144, 226, .3); }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ---------------------------------------------------------------------------
   Layout utilities.

   The CSP is `style-src 'self'`, which blocks inline `style=` attributes
   outright - the browser drops them with a console error. These classes are
   what those attributes became, so the layout is carried by the stylesheet
   instead of by per-element markup.
--------------------------------------------------------------------------- */

.fs-13 { font-size: 13px; }
.fs-18 { font-size: 18px; }

.mb-0  { margin-bottom: 0; }
.mb-6  { margin-bottom: 6px; }
.mb-10 { margin-bottom: 10px; }
.mb-14 { margin-bottom: 14px; }
.mb-16 { margin-bottom: 16px; }
.mb-20 { margin-bottom: 20px; }

.mt-12 { margin-top: 12px; }
.mt-18 { margin-top: 18px; }
.my-10-18 { margin: 10px 0 18px; }

.maxw-680 { max-width: 680px; }
.pb-18 { padding-bottom: 18px; }

.uppercase { text-transform: uppercase; }
/* Keeps a heading in the document outline without drawing it: the auth pages
   dropped their visible "login" / "register" headings, but a page still needs
   one for screen readers and for anything parsing the structure. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.ok-text { color: var(--ok); }
.d-flex { display: flex; }
.gap-10 { gap: 10px; }
.wrap { flex-wrap: wrap; }

/* ------------------------------------------------------ site soundtrack -- */

.player {
  position: fixed;
  left: 18px;
  bottom: 18px;
  z-index: 40;
  min-width: 300px;
  max-width: calc(100vw - 36px);
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 14px;
  background: rgba(10, 12, 16, .74);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .55);
  animation: auth-in .5s cubic-bezier(.4, 0, .2, 1) both;
}

.player-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
}

/* The one and only control. Everything else about the soundtrack is automatic,
   so this is the whole interface. Scoped under .player because the base
   `button:hover:not(:disabled)` rule is specificity 0,2,1 and would otherwise
   paint its own hover background over this one. */
.player .player-mute {
  flex: 0 0 auto;
  padding: 4px 9px;
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 999px;
  background: none;
  box-shadow: none;
  color: var(--faint);
  font-family: inherit;
  font-size: 11px;
  letter-spacing: .05em;
  cursor: pointer;
  transition: color .25s ease, border-color .25s ease;
}
.player .player-mute:hover {
  color: #3b82f6;
  border-color: rgba(59, 130, 246, .5);
  background: none;
}
.player .player-mute.is-on {
  color: #3b82f6;
  border-color: rgba(59, 130, 246, .45);
}

.player .player-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: #888;
  font-family: inherit;
  font-size: 12px;
  text-align: left;
  white-space: nowrap;
  text-overflow: ellipsis;
  cursor: pointer;
  transition: color .2s ease;
}
.player .player-name:hover {
  color: var(--text);
  background: none;
  border-color: transparent;
}
.player .player-name.is-open { color: var(--text); }

.player-panel {
  border-bottom: 1px solid rgba(255, 255, 255, .07);
  padding: 10px 12px 12px;
}
.player-frame-host { width: 240px; border-radius: 8px; overflow: hidden; background: #000; }
.player-frame { display: block; width: 240px; height: 135px; border: 0; }

/* ---- the words, behind everything ------------------------------------- */

/* Negative z puts the layer above the page's own background (which propagates
   from body to the canvas) but below all in-flow content, so the words read as
   texture instead of washing over the text. Every line is stacked into the same
   grid cell, which is what lets one fade out while the next fades in. */
.player-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  display: grid;
  place-items: center;
  padding: 0 8vw;
  overflow: hidden;
  pointer-events: none;
}
.player-bg-line {
  grid-area: 1 / 1;
  max-width: 1100px;
  color: rgba(255, 255, 255, .09);
  font-family: var(--font-display);
  font-size: clamp(26px, 4.6vw, 62px);
  font-weight: 600;
  line-height: 1.15;
  text-align: center;
  text-wrap: balance;
  animation: lyric-in .7s cubic-bezier(.22, 1, .36, 1) both;
}
.player-bg-line.is-out {
  animation: lyric-out .55s cubic-bezier(.4, 0, .2, 1) both;
}

/* Rises into place out of a blur, then lifts away the same way. */
@keyframes lyric-in {
  from { opacity: 0; transform: translateY(26px) scale(.98); filter: blur(8px); }
  to   { opacity: 1; transform: translateY(0) scale(1);     filter: blur(0); }
}
@keyframes lyric-out {
  from { opacity: 1; transform: translateY(0) scale(1);      filter: blur(0); }
  to   { opacity: 0; transform: translateY(-26px) scale(1.02); filter: blur(8px); }
}

@media (max-width: 460px) {
  .player { left: 12px; right: 12px; bottom: 12px; min-width: 0; }
  .player-frame-host, .player-frame { width: 100%; }
  .player-frame { height: auto; aspect-ratio: 16 / 9; }
}

@media (prefers-reduced-motion: reduce) {
  .player, .player-bg-line, .player-bg-line.is-out { animation: none; }
}

/* ---------------------------------------------------------------------------
   Modal dialog.

   Used for the two-factor prompt: the login page itself carries no code field,
   so an account without 2FA never sees one. <dialog> gives native focus
   trapping, Esc-to-close and an inert page behind it.
--------------------------------------------------------------------------- */

.modal {
  width: min(400px, calc(100vw - 32px));
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 16px;
  background: rgba(255, 255, 255, .03);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  color: var(--text);
  box-shadow: 0 32px 80px rgba(0, 0, 0, .6), inset 0 1px 0 rgba(255, 255, 255, .045);
}
.modal[open] { animation: auth-in .4s cubic-bezier(.4, 0, .2, 1) both; }
.modal::backdrop {
  background: rgba(4, 5, 8, .74);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

.modal-head {
  padding: 16px 26px;
  border-bottom: 1px solid var(--border);
  background: rgba(255, 255, 255, .022);
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-dim);
}

.modal-body {
  padding: 22px 26px 4px;
}
.modal-body .flabel {
  display: block;
  margin-bottom: 7px;
}
.modal-body input[type="text"],
.modal-body input[type="password"] {
  width: 100%;
}

.modal-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 14px 26px 24px;
}

/* ------------------------------------------------------------ user card -- */

/* Only the inside is card-specific; .modal supplies the shell, the backdrop,
   Esc-to-close and the focus trap. */

.ucard-top { display: flex; align-items: center; gap: 14px; padding: 20px 24px 14px; }

.ucard-av {
  width: 52px; height: 52px; flex: 0 0 52px; border-radius: 50%;
  object-fit: cover; border: 1px solid var(--border-strong);
  background: var(--surface-2);
}
.ucard-av.blank {
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-size: 19px; font-weight: 700; color: var(--muted);
}

.ucard-id { min-width: 0; }
.ucard-name { font-family: var(--font-display); font-size: 17px; font-weight: 700; }
.ucard-meta { margin-top: 3px; font-size: 12px; color: var(--muted); }

.ucard-bio {
  padding: 0 24px 14px; font-size: 13px; line-height: 1.55; color: var(--text-dim);
  white-space: pre-wrap; overflow-wrap: anywhere;
}

.ucard-stats {
  display: flex; gap: 20px; padding: 0 24px 16px;
  font-size: 12px; color: var(--muted);
}
.ucard-stats b { color: var(--text); font-weight: 600; }

.ucard .modal-actions { border-top: 1px solid var(--border); background: rgba(255, 255, 255, .015); }
.ucard .modal-actions .btn { flex: 1; }


/* --------------------------------------------------------------- admin -- */

/* .panel is flush by default (overflow:hidden, no padding), which is right when
   it wraps a table that should run to the edges -- but it clips a heading.
   Panels that carry their own heading get this instead. */
.panel.pad { padding: 20px 22px; }

.panel h2 {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: lowercase;
  color: var(--muted);
  margin: 0 0 16px;
}

.admin-form {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
  margin-bottom: 20px;
}
.admin-form label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.admin-form input {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  transition: border-color 0.2s ease;
}
.admin-form input:focus { outline: none; border-color: var(--accent); }

.rselect {
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: 7px;
  color: var(--text);
  padding: 5px 8px;
  font: inherit;
  font-size: 12px;
}
.rselect:focus { outline: none; border-color: var(--accent); }

.rcheck { accent-color: var(--accent); width: 15px; height: 15px; cursor: pointer; }

/* Upload progress for the loader release form. A native <progress> so the
   per-element width can live in markup without a style attribute the CSP would
   drop; only the appearance is themed here. */
.uprogress {
  width: 100%; max-width: 340px; height: 6px;
  appearance: none; -webkit-appearance: none;
  border: 1px solid var(--border); border-radius: 999px;
  background: rgba(255, 255, 255, .04); overflow: hidden;
}
.uprogress::-webkit-progress-bar { background: transparent; }
.uprogress::-webkit-progress-value { background: var(--accent); }
.uprogress::-moz-progress-bar { background: var(--accent); }

/* A file input is not covered by the shared input rule (which names text,
   email and password), so give it the same frame and theme the native button. */
.ufile {
  width: 100%;
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  padding: 9px 12px;
  color: var(--text-dim);
  font: inherit;
  font-size: 13px;
}
.ufile::file-selector-button {
  margin-right: 12px; padding: 6px 12px;
  border: 1px solid var(--border-strong); border-radius: 8px;
  background: var(--surface-2); color: var(--text);
  font: inherit; font-size: 12.5px; cursor: pointer;
}
.ufile::file-selector-button:hover { background: var(--surface-3); }

.invite-code {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--text);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 3px 7px;
}

.uid { margin-left: 8px; font-size: 11px; }
.sub.live { color: var(--ok); }
.sub.err  { color: var(--danger); }

tr.is-me td { background: rgba(255, 255, 255, 0.02); }

@media (max-width: 640px) {
  .panel h2 { margin-bottom: 12px; }
  .admin-form label input { width: 100%; }
}


/* ------------------------------------------------------- post approval -- */

/* Green means a staff member read this and their name is on it. Amber means
   nobody has, and the hover says so in as many words. Both are text with a
   glow, matching the role marks -- a chip here would read as a button. */
.appr {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.03em;
  cursor: help;
}
.appr.ok {
  color: #3ddc84;
  text-shadow: 0 0 8px rgba(61, 220, 132, .5);
}
.appr.wait {
  color: #e8b34a;
  text-shadow: 0 0 8px rgba(232, 179, 74, .42);
}

/* "new since your last visit" */
.newdot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px rgba(59, 130, 246, .85);
  vertical-align: middle;
}

.acts {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 12px;
}
.lnk {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 12px;
  color: var(--muted);
  cursor: pointer;
}
.lnk:hover { color: var(--text); }
.lnk.ok:hover { color: #3ddc84; }
.lnk.danger:hover { color: #ff5a5a; }
.lnk:disabled { opacity: .5; cursor: default; }
.lnk.on { color: #ffb300; }        /* the reveal toggle, which is a state not an action */

/* the database console */
.sqlbox {
  width: 100%;
  min-height: 92px;
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 13px;
  line-height: 1.6;
  resize: vertical;
}
/* A wide result must scroll inside its own panel rather than push the page. */
.sqlwrap { overflow-x: auto; }
.sqlwrap .board { min-width: 100%; white-space: nowrap; }
.tlink { margin-right: 4px; }
.tablen { margin-right: 14px; font-variant-numeric: tabular-nums; }

/* The same "just a word" treatment, for the one action a page is really offering.
   A filled button here competes with the content it is sitting next to. */
.lnk.em { font-size: 14px; font-weight: 550; color: var(--accent); }
.lnk.em:hover { color: #93c0f2; }
.lnk.em:disabled { color: var(--muted); opacity: .55; }

.editbox {
  width: 100%;
  box-sizing: border-box;
  min-height: 110px;
}

/* Panel flags: ghost = unlisted operator account, banned = status. */
.uid.ghost { color: #a78bfa; }
.uid.banned { color: #ff5a5a; }


/* ---- self panel ---- */
.self-top { display: flex; align-items: center; gap: 16px; }
.self-edit { margin-left: auto; }
.avatar-lg { width: 68px; height: 68px; border-radius: 14px; object-fit: cover; display: block; flex: 0 0 auto; }
.avatar-none {
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.05); border: 1px solid var(--border);
  color: var(--muted); font-family: var(--font-display); font-size: 26px;
}

.self-name { font-family: var(--font-display); font-size: 21px; font-weight: 600; letter-spacing: -.02em; }

.facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 14px 24px; margin-top: 22px; padding-top: 20px; border-top: 1px solid var(--border);
}
.fact { display: flex; flex-direction: column; gap: 4px; }
.fact-k { font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }
.fact-v { font-size: 14px; color: var(--text); }

.row-actions { display: flex; gap: 10px; margin-top: 20px; }

.mint-row { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; flex-wrap: wrap; }

.code-cell { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 13px; color: var(--text); }

.chip-row { display: flex; flex-wrap: wrap; gap: 6px 14px; }

.panel-sub {
  font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .08em;
  color: var(--muted); margin: 22px 0 10px;
}

.oktext { color: #3ddc84; }

.excerpt { margin-top: 4px; }

.tbl-wrap { overflow-x: auto; }

/* ---------------------------------------------------------------- staff log -- */
.tabs { display: flex; gap: 4px; }
.tab {
  padding: 7px 15px; border: 1px solid var(--border); border-radius: 9px;
  background: transparent; color: var(--muted); font: inherit; font-size: 13px;
  cursor: pointer; transition: color .15s, background .15s, border-color .15s;
}
.tab:hover { color: var(--text); }
.tab.active { color: var(--text); background: rgba(255,255,255,.05); border-color: rgba(255,255,255,.16); }

.filter-bar { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-bottom: 16px; }
.filter-bar .ainput { width: 130px; }
.filter-bar select.ainput, .filter-bar select { width: auto; min-width: 150px; }

table.board.logs td.detail { max-width: 420px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
table.board.logs td { font-size: 13px; }
.nowrap { white-space: nowrap; }
.ua { color: var(--muted); font-size: 12px; cursor: help; }
.chips { display: flex; flex-wrap: wrap; gap: 4px 12px; }

.lc-warn { color: #e8b34a; }
.lc-good { color: #3ddc84; }

/* ------------------------------------------------------------ messages -- */
.pm-wrap { display: grid; grid-template-columns: 320px 1fr; gap: 18px; align-items: start; }
.pm-side {
  border: 1px solid var(--border); border-radius: 14px; overflow: hidden;
  background: var(--card);
}
.pm-side-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 13px 16px; border-bottom: 1px solid var(--border);
}
.pm-item {
  display: block; padding: 12px 16px; border-bottom: 1px solid var(--border);
  color: inherit; cursor: pointer;
}
.pm-item:last-child { border-bottom: none; }
.pm-item:hover { background: rgba(255,255,255,.03); }
.pm-item.active { background: rgba(59,130,246,.10); }
.pm-item-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.pm-excerpt {
  color: var(--muted); font-size: 12.5px; margin-top: 3px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pm-when { font-size: 11px; margin-top: 3px; }

.pm-main {
  border: 1px solid var(--border); border-radius: 14px; background: var(--card);
  min-height: 420px; display: flex; flex-direction: column;
}
.pm-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 18px; border-bottom: 1px solid var(--border);
  font-family: var(--font-display); font-size: 14px;
}
.pm-stream {
  flex: 1; overflow-y: auto; max-height: 52vh; padding: 16px 18px;
  display: flex; flex-direction: column; gap: 14px;
}
.pm-msg { max-width: 78%; }
.pm-msg.mine { align-self: flex-end; }
.pm-meta { font-size: 11.5px; margin-bottom: 4px; }
.pm-msg.mine .pm-meta { text-align: right; }
.pm-body {
  background: rgba(255,255,255,.04); border: 1px solid var(--border);
  border-radius: 12px; padding: 10px 13px; font-size: 14px;
  white-space: pre-wrap; word-break: break-word;
}
.pm-msg.mine .pm-body { background: rgba(59,130,246,.12); border-color: rgba(59,130,246,.3); }
.pm-compose { border-top: 1px solid var(--border); padding: 14px 18px; }
.pm-compose .editbox { min-height: 84px; }
.pm-compose-row { display: flex; align-items: center; gap: 12px; margin-top: 10px; }
.pm-new { border-top: none; }
.pm-new .ainput { margin-bottom: 12px; }

.nav-badge {
  display: inline-block; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 9px; background: var(--accent); color: #fff;
  font-size: 11px; line-height: 17px; text-align: center; vertical-align: middle;
}

@media (max-width: 760px) {
  .pm-wrap { grid-template-columns: 1fr; }
  .pm-msg { max-width: 92%; }
}
