/* Shared app shell - nav, buttons, cards, tables, badges, modal/spinner -
 * for login.html/profile.html/admin.html and the nav strip on index.html.
 * Built on top of style.css + somnia-theme.css tokens (loaded before this). */

.app-nav {
  display: flex; align-items: center; gap: 22px;
  padding: 12px 14px; margin: 0 -14px 20px; border-bottom: 1px solid var(--line);
  position: relative; z-index: 1;
  /* Dreams UI's real "ghost" variant is transparent + backdrop blur, not a
   * flat fill - same treatment here so the nav reads cleanly over the
   * animated dot backdrop without turning into a solid bar. */
  background: rgba(10, 10, 10, .55);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.app-nav-brand { display: flex; align-items: center; gap: 9px; text-decoration: none; }
.app-nav-brand span { color: var(--fg-faint); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; }
.app-nav-tabs { display: flex; gap: 4px; flex: 1; }
.nav-tab {
  padding: 7px 13px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
  color: var(--fg-dim); text-decoration: none; transition: all .15s;
}
.nav-tab:hover { color: var(--fg); background: var(--panel-2); }
.nav-tab.on { color: var(--fg-strong); background: var(--panel-2); border: 1px solid var(--bd-2); }
.app-nav-auth { display: flex; align-items: center; gap: 8px; }
.nav-avatar {
  width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  background: var(--gold-dark); color: var(--fg-strong); font-size: 10.5px; font-weight: 700; font-family: var(--mono);
}
.nav-user { font-size: 12.5px; color: var(--fg-dim); }

/* Buttons */
.btn-primary, .btn-ghost, .btn-discord, .btn-danger {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 40px; padding: 0 18px; border-radius: 10px; font: 600 13px var(--sans);
  cursor: pointer; border: 1px solid transparent; transition: all .15s; text-decoration: none;
}
.btn-primary { background: var(--gold-dark); color: var(--fg-strong); }
.btn-primary:hover { background: var(--gold-mid); color: #0a0a0a; }
.btn-ghost { background: transparent; border-color: var(--bd-2); color: var(--fg-dim); }
.btn-ghost:hover { color: var(--fg); border-color: var(--bd-3); }
.btn-danger { background: transparent; border-color: rgba(220,11,74,.4); color: #ea6d92; }
.btn-danger:hover { background: rgba(220,11,74,.12); }
.btn-discord { background: #5865F2; color: #fff; width: 100%; }
.btn-discord:hover { background: #4752c4; }
.btn-primary.sm, .btn-ghost.sm { height: 30px; padding: 0 12px; font-size: 12px; border-radius: 8px; }
.btn-primary:disabled, .btn-ghost:disabled { opacity: .5; cursor: not-allowed; }

/* Referenced by five inputs across /profile, /admin and the Guardian apply
   card, and defined nowhere until now - each call site carried an identical
   inline copy of these rules, so the class looked like it worked. A sixth
   input added with the class alone would have rendered as an unstyled box,
   which is exactly how the white filter boxes happened. */
.text-input {
  background: var(--panel-3); border: 1px solid var(--bd-2); border-radius: 8px;
  padding: 8px 12px; color: var(--fg-strong); font: 400 13px var(--sans);
}
.text-input::placeholder { color: var(--fg-ghost); }
.text-input:focus { outline: none; border-color: var(--bd-3); }
.text-input:disabled { opacity: .5; cursor: not-allowed; }

/* Cards */
.card { background: var(--panel-2); border: 1px solid var(--bd); border-radius: 14px; padding: 18px 20px; }
.card-title { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--fg-faint); margin-bottom: 12px; }
.grid { display: grid; gap: 14px; }
.grid-2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0,1fr)); }
@media (max-width: 760px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr 1fr; } }

.stat-card { background: var(--panel-2); border: 1px solid var(--bd); border-radius: 12px; padding: 12px 14px; }
.stat-label { font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--fg-faint); margin-bottom: 6px; }
.stat-value { font-family: var(--mono); font-size: 20px; color: var(--fg-strong); font-weight: 700; }
.stat-sub { font-size: 11px; color: var(--fg-mute); font-weight: 400; margin-left: 4px; font-family: var(--sans); }

/* Badges */
.badge { display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px; font-family: var(--mono); letter-spacing: .04em; padding: 3px 9px; border-radius: 999px; border: 1px solid var(--bd-2); }
.badge.ok { color: var(--green); border-color: rgba(0,250,137,.35); }
.badge.warn { color: var(--amber); border-color: rgba(255,122,0,.4); }
.badge.bad { color: #ea6d92; border-color: rgba(220,11,74,.4); }
.badge.muted { color: var(--fg-faint); }

/* Tables */
.dtable { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.dtable th { text-align: left; font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg-faint); padding: 9px 10px; border-bottom: 1px solid var(--line-3); }
.dtable td { padding: 9px 10px; border-bottom: 1px solid var(--line); color: var(--fg-dim); vertical-align: middle; }
.dtable tr:hover td { background: rgba(255,255,255,.015); }
.dtable td.strong { color: var(--fg); font-weight: 600; }
.table-scroll { overflow-x: auto; }

/* Forms */
.field-label { display: block; font-size: 11px; color: var(--fg-faint); margin-bottom: 6px; }
.field-input { width: 100%; height: 40px; padding: 0 12px; border-radius: 10px; background: var(--panel-3); border: 1px solid var(--bd); color: var(--fg); font: inherit; }
.field-input:focus { outline: none; border-color: var(--gold-dark); }

/* Auth card + mock OAuth flow */
.auth-shell { min-height: 78vh; display: flex; align-items: center; justify-content: center; }
.auth-card { width: 380px; max-width: 92vw; background: var(--panel-2); border: 1px solid var(--bd); border-radius: 16px; padding: 32px 28px; text-align: center; }
.auth-card .brand-lockup { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.auth-card p.sub { color: var(--fg-faint); font-size: 12.5px; margin: 6px 0 24px; }
.auth-card .fine { color: var(--fg-ghost); font-size: 10.5px; margin-top: 16px; line-height: 1.6; }

.mock-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,.7); display: none;
  align-items: center; justify-content: center; z-index: 100;
}
.mock-overlay.show { display: flex; }
.mock-panel { width: 360px; max-width: 90vw; background: var(--panel-2); border: 1px solid var(--bd-2); border-radius: 14px; padding: 24px; }
.mock-panel .spinner {
  width: 26px; height: 26px; border-radius: 50%; margin: 0 auto 16px;
  border: 3px solid var(--bd-2); border-top-color: var(--gold-mid);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.mock-panel .discord-consent { text-align: left; }
.mock-panel .discord-consent h3 { margin: 0 0 4px; font-size: 15px; color: var(--fg-strong); }
.mock-panel .discord-consent p { margin: 0 0 14px; font-size: 12px; color: var(--fg-faint); }
.mock-panel .scope-list { list-style: none; margin: 0 0 18px; padding: 0; font-size: 12.5px; color: var(--fg-dim); }
.mock-panel .scope-list li { padding: 6px 0; border-bottom: 1px solid var(--line); }
.mock-panel .consent-actions { display: flex; gap: 8px; }
.mock-panel .consent-actions .btn-primary, .mock-panel .consent-actions .btn-ghost { flex: 1; }

.section-title { font-size: 13px; font-weight: 700; color: var(--fg-strong); margin: 28px 0 12px; }
.section-title:first-child { margin-top: 0; }
.hint { color: var(--fg-faint); font-size: 11.5px; line-height: 1.6; }
/* .mockup-tag removed 2026-08-31 with its last user. It was fixed to the
   bottom-right of the viewport, so it hovered over the page while everything
   else scrolled - fine for a build banner on a mockup, wrong for a live app.
   Leaving the rule behind would let the next person reach for a class that
   pins text over the UI without noticing that is what it does. */

/* --- Filter bar (admin review queue) ---------------------------------
   Mono to match the tables these filter, and sized to the .sm buttons they
   sit beside. appearance:none on the selects is the load-bearing bit: the
   native control renders as a light chrome widget that ignores the dark
   theme entirely, which is what made these look like stray browser boxes. */
.filter-field {
  height: 30px;
  padding: 0 10px;
  background: var(--panel-3);
  border: 1px solid var(--bd-2);
  border-radius: 8px;
  color: var(--fg);
  font: 400 12px var(--mono);
  outline: none;
  transition: border-color .15s, color .15s;
}
.filter-field::placeholder { color: var(--fg-faint); }
.filter-field:hover { border-color: var(--bd-3); }
.filter-field:focus { border-color: var(--gold-dark); color: var(--fg-strong); }

select.filter-field {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 26px;
  cursor: pointer;
  /* Chevron drawn in, since removing the native appearance also removes the
     native arrow. */
  background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23999999' stroke-width='1.4' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 9px center;
}
/* The dropdown list itself is OS-drawn; without this it opens white on macOS. */
select.filter-field option { background: #1c1c1c; color: #d3d3d3; }

/* --- Pager ------------------------------------------------------------ */
.pager-btn {
  min-width: 30px; height: 30px; padding: 0 9px;
  background: transparent;
  border: 1px solid var(--bd-2);
  border-radius: 8px;
  color: var(--fg-mute);
  font: 400 12px var(--mono);
  cursor: pointer;
  transition: all .15s;
}
.pager-btn:hover:not(:disabled) { color: var(--fg-strong); border-color: var(--bd-3); }
.pager-btn:disabled { opacity: .35; cursor: not-allowed; }
.pager-btn[aria-current="page"] {
  background: var(--panel-3);
  border-color: var(--gold-dark);
  color: var(--fg-strong);
}

/* --- Inline explainer (admin) ----------------------------------------
   Collapsed by default: a mod who already knows this should not have to
   scroll past it every time, and one who doesn't shouldn't have to ask. */
.explainer { border: 1px solid var(--bd-2); border-radius: 10px; background: var(--panel); margin: 12px 0 4px; }
.explainer > summary {
  cursor: pointer; list-style: none; padding: 9px 14px;
  font: 400 12px var(--mono); color: var(--fg-mute); user-select: none;
}
.explainer > summary::-webkit-details-marker { display: none; }
.explainer > summary::before { content: "▸ "; color: var(--fg-faint); }
.explainer[open] > summary::before { content: "▾ "; }
.explainer > summary:hover { color: var(--fg-strong); }
.explainer-body { padding: 2px 16px 16px; font-size: 13px; color: var(--fg-dim); line-height: 1.65; }
.explainer-body h4 {
  font: 600 11px var(--mono); letter-spacing: .12em; text-transform: uppercase;
  color: var(--fg-faint); margin: 16px 0 6px;
}
.explainer-body h4:first-child { margin-top: 4px; }
.explainer-body p { margin: 0 0 8px; }
.explainer-body code {
  font: 400 12px var(--mono); background: var(--panel-3);
  border: 1px solid var(--bd-2); border-radius: 5px; padding: 1px 6px; color: var(--fg-strong);
}
.explainer-body ul { margin: 0 0 8px; padding-left: 18px; }
.explainer-body li { margin-bottom: 5px; }
.explainer-body strong { color: var(--fg-strong); font-weight: 600; }

/* Board pagers (mindshare tables). */
.if-pager { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin: 10px 0 4px; }
.if-pager:empty { display: none; }

/* --- Duel page --------------------------------------------------------
   Two posts side by side, each the whole click target. Judging 300 pairs
   means the button IS the card; hunting for a small control 300 times is
   what makes people stop after twenty. */
.duel-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 760px) { .duel-grid { grid-template-columns: 1fr; } }

.duel-card {
  display: flex; flex-direction: column; gap: 10px;
  text-align: left; width: 100%; min-height: 210px;
  background: var(--panel-2); border: 1px solid var(--bd-2); border-radius: 14px;
  padding: 18px 20px; cursor: pointer; color: var(--fg);
  font: 400 14px/1.6 var(--sans, inherit);
  transition: border-color .15s, background .15s, transform .06s;
}
.duel-card:hover:not(:disabled) { border-color: var(--gold-dark); background: var(--panel-3); }
.duel-card:active:not(:disabled) { transform: translateY(1px); }
.duel-card:disabled { opacity: .5; cursor: progress; }
.duel-card:focus-visible { outline: 2px solid var(--gold-mid); outline-offset: 2px; }

.duel-meta {
  display: flex; justify-content: space-between; gap: 10px; align-items: baseline;
  font: 400 11px var(--mono); color: var(--fg-faint);
  text-transform: uppercase; letter-spacing: .1em;
}
.duel-meta .strong { color: var(--fg-strong); text-transform: none; letter-spacing: 0; font-size: 13px; }
/* Long threads must not make one card tower over the other; the scroll keeps
   both comparable at a glance. */
.duel-text { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 320px; overflow-y: auto; flex: 1; }

/* --- Admin: REP breakdown modal ---------------------------------------
   Wider than .mock-panel because this is a reading surface, not a prompt:
   a mod is working through a table of posts inside it, and reflowing that
   into 360px made the columns unreadable. */
.bd-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,.78);
  display: flex; align-items: center; justify-content: center;
  z-index: 200; padding: 24px 16px;
}
.bd-panel {
  width: 980px; max-width: 100%;
  /* Bounded, and scrolls its own body. Left to grow with its content the
     panel ran past the bottom of the screen and took the page scrollbar with
     it, so closing it meant scrolling back up to find the button. */
  max-height: calc(100vh - 48px);
  display: flex; flex-direction: column;
  background: var(--panel-2); border: 1px solid var(--bd-3); border-radius: 14px;
  outline: none;
  /* Sets its own colour rather than inheriting the page's. The panel is
     fixed-position over everything, so whatever it happened to inherit is not
     a property of where it renders - and the default is black on a black
     panel. */
  color: var(--fg-dim);
}
.bd-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding: 18px 22px; border-bottom: 1px solid var(--line);
  background: var(--panel-2); border-radius: 14px 14px 0 0; flex: none;
}
.bd-who { display: flex; gap: 12px; align-items: center; }
.bd-avatar { width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--bd-3); }
.bd-head h3 {
  margin: 0 0 2px; font-size: 16px; color: var(--fg-strong);
  display: flex; align-items: center; gap: 8px;
}
.bd-head .hint { margin: 0; }
.bd-body { padding: 18px 22px 24px; overflow-y: auto; flex: 1 1 auto; }
.bd-loading, .bd-error { padding: 40px 22px; text-align: center; color: var(--fg-faint); font-size: 13px; }
.bd-error { color: var(--red); }

.bd-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1px; background: var(--line); border: 1px solid var(--line);
  border-radius: 10px; overflow: hidden; margin-bottom: 18px;
}
.bd-stat { background: var(--panel-3); padding: 12px 14px; }
.bd-stat-label { font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--fg-faint); }
.bd-stat-value { font-family: var(--mono); font-size: 20px; color: var(--fg-strong); margin-top: 4px; font-variant-numeric: tabular-nums; }
.bd-stat-sub { font-size: 11px; color: var(--fg-mute); margin-top: 3px; line-height: 1.35; }

.bd-h { font-size: 12px; font-weight: 700; color: var(--fg-strong); margin: 24px 0 8px; }
.bd-warn {
  margin: 0 0 14px; padding: 10px 12px; border-radius: 8px;
  background: rgba(255,122,0,.08); border: 1px solid rgba(255,122,0,.3);
  color: var(--fg-dim); font-size: 12px; line-height: 1.55;
}

/* The subtraction that turns approved REP into the leaderboard score. Shown
   as an actual sum because "why is my score lower than my posts add up to"
   is the single most common question the halving produces. */
.bd-build { font-family: var(--mono); font-size: 12.5px; margin-bottom: 8px; color: var(--fg-dim); }
.bd-build > div { display: flex; justify-content: space-between; gap: 16px; padding: 6px 0; }
.bd-build > div > b { font-variant-numeric: tabular-nums; color: var(--fg-strong); }
.bd-build-sub { color: var(--fg-mute); }
.bd-build-total { border-top: 1px solid var(--line-3); font-weight: 700; }

.bd-excluded { list-style: none; margin: 0; padding: 0; font-size: 12.5px; color: var(--fg-dim); }
.bd-excluded li { padding: 6px 0; border-bottom: 1px solid var(--line); }
.bd-excluded li:last-child { border-bottom: none; }
.bd-excluded b { font-family: var(--mono); color: var(--fg-strong); margin-right: 4px; }

.bd-posts td { vertical-align: top; }
.bd-linkish {
  background: none; border: none; padding: 0; text-align: left; cursor: pointer;
  color: var(--fg-dim); font: inherit; line-height: 1.45;
}
.bd-linkish:hover { color: var(--fg-strong); }
.bd-row-meta { font-size: 10.5px; color: var(--fg-faint); margin-top: 3px; }
.bd-row-open td { background: var(--panel-3); }
.bd-detail td { background: var(--panel-3); border-top: none; }
.bd-detail-body { display: flex; flex-direction: column; gap: 10px; padding: 4px 0 10px; }
.bd-quote {
  margin: 0; padding-left: 10px; border-left: 2px solid var(--gold-mid);
  color: var(--fg-dim); font-size: 12.5px; line-height: 1.6; white-space: pre-wrap;
}
.bd-rationale { margin: 0; font-size: 12px; color: var(--fg-mute); line-height: 1.6; }
.bd-rationale strong { color: var(--fg-dim); }
.bd-detail-facts { display: flex; flex-wrap: wrap; gap: 4px 14px; font-family: var(--mono); font-size: 11px; color: var(--fg-faint); }
.bd-override { margin: 0; font-size: 11.5px; color: var(--amber); }
.bd-linkout { font-size: 11.5px; color: var(--gold-hi); text-decoration: none; }
.bd-linkout:hover { text-decoration: underline; }

.bd-pill {
  display: inline-block; padding: 2px 7px; border-radius: 20px;
  font-size: 10px; letter-spacing: .04em; text-transform: uppercase;
  border: 1px solid var(--bd-3); color: var(--fg-mute);
}
.bd-approved { color: var(--green); border-color: rgba(0,250,137,.35); }
.bd-rejected { color: var(--red); border-color: rgba(220,11,74,.35); }
.bd-pending  { color: var(--amber); border-color: rgba(255,122,0,.35); }
.bd-tag {
  display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 20px;
  background: var(--line-3); color: var(--fg-mute); font-size: 10px; font-family: var(--mono);
}
.bd-tag.warn { background: rgba(255,122,0,.15); color: var(--amber); }

/* The search that opens all of the above. */
.bd-search { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.bd-search .text-input { flex: 1; min-width: 200px; }

/* Activity over the window. Answers "did they earn this steadily or in one
   afternoon", which the totals alone cannot - and which is the shape a farming
   pattern shows up in. */
.bd-days { display: flex; align-items: flex-end; gap: 2px; height: 44px; margin: 4px 0 6px; }
.bd-day {
  flex: 1; min-width: 2px; background: var(--gold-dark); border-radius: 1px 1px 0 0;
}
.bd-day.empty { background: var(--line-3); }
.bd-day.top { background: var(--gold-mid); }
.bd-days-axis {
  display: flex; justify-content: space-between;
  font-family: var(--mono); font-size: 10px; color: var(--fg-faint);
}

.bd-pager {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 10px;
}
.bd-pager .hint { margin: 0; font-family: var(--mono); }

/* The score-to-REP calculator. Sits inside the breakdown modal because the
   answer depends on the person: REP is round(score/10) x a tier multiplier
   that the score itself decides, so "what is a 4 worth" has no single value. */
.bd-calc { border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; }
.bd-calc-in { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; margin-bottom: 10px; }
.bd-calc-in > label {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--fg-mute);
}
.bd-calc-in .text-input { width: 88px; font-family: var(--mono); text-align: right; }
.bd-calc-check { cursor: pointer; }
.bd-calc-check input { accent-color: var(--gold-mid); }
.bd-calc-out { font-family: var(--mono); font-size: 12.5px; color: var(--fg-dim); }
.bd-calc-out > div { display: flex; justify-content: space-between; gap: 16px; padding: 5px 0; }
.bd-calc-out > div > b { font-variant-numeric: tabular-nums; color: var(--fg-strong); }
.bd-calc-total { border-top: 1px solid var(--line); }
.bd-calc-total b { color: var(--gold-hi); }
.bd-calc .hint { margin: 8px 0 0; }
