/* =============================================================================
   DIVINE PRIDE 2025 FRONTEND
   Theme and Component System
   
   CSS Variable naming:
   - Base tokens: spacing, radius, typography
   - Semantic tokens: bg, surface, text, border, accent, success, warning, danger
   - Component utilities: cards, tables, forms, buttons
   ============================================================================= */

/* ============================================================================
   BASE TOKENS
   ============================================================================ */

:root {
  /* Spacing Scale (4px base) */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;

  /* Border Radius */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-full: 9999px;


  /* Typography */
  /* Emoji fonts appended at the end — browsers do per-glyph fallback, so this only affects
     characters the earlier fonts don't cover (emoji, flags) and never changes normal text
     rendering. Without one of these explicitly listed, Windows renders flag emoji (paired
     regional-indicator codepoints) as two boxed letters ("GB", "FR") instead of ligating them
     into an actual flag glyph — this is what made the language picker's flags not show up. */
  --font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif, 'Segoe UI Emoji', 'Noto Color Emoji', 'Apple Color Emoji';
  --font-family-mono: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Courier New', monospace;
  
  --font-size-xs: 12px;
  --font-size-sm: 14px;
  --font-size-base: 16px;
  --font-size-lg: 18px;
  --font-size-xl: 20px;
  --font-size-2xl: 24px;
  --font-size-3xl: 32px;

  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;

  --line-height-tight: 1.2;
  --line-height-normal: 1.5;
  --line-height-relaxed: 1.75;

  /* Transitions */
  --transition-fast: 150ms ease-in-out;
  --transition-base: 200ms ease-in-out;
  --transition-slow: 300ms ease-in-out;

  /* Shadow */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
}

/* ============================================================================
   LIGHT THEME
   ============================================================================ */

:root,
[data-theme="light"] {
  /* Tells the browser to render native form chrome (number-input spin buttons, checkboxes,
     date pickers, etc.) using a light-aware palette — without this it defaults to always-light
     regardless of theme, which is why spin buttons looked like a mismatched light widget glued
     onto a dark-themed input on the dark/dark-blue themes below. */
  color-scheme: light;

  /* Background & Surface */
  --bg: #f5f7fb;
  --surface: #ffffff;
  --surface-2: #eef2f8;
  --surface-3: #e3ebf1;

  /* Text */
  --text: #1b2430;
  --text-muted: #5d6a7a;
  --text-subtle: #8a94a6;

  /* Borders & Dividers */
  --border: #d3dce8;
  --border-light: #e8ecf3;

  /* UI Colors */
  --accent: #0a67d8;
  --accent-strong: #084fa8;
  --accent-light: #e3f0ff;
  --accent-lighter: #f0f7ff;

  /* Status Colors */
  --success: #1f9d5a;
  --success-light: #e8f6f1;
  --warning: #b67500;
  --warning-light: #fef3e6;
  --danger: #bf2f3f;
  --danger-light: #fde8eb;
  --info: #0a67d8;
  --info-light: #e3f0ff;

  /* Element/Badge Colors — the actual in-game RO element colors (added 2026-08-07, replacing an
     earlier set of colors picked for site-theme contrast rather than game accuracy). Fixed/
     theme-invariant on purpose: these are the same colors regardless of light/dark/dark-blue site
     theme, unlike every other semantic color token on this page — see the per-badge text-color
     rules further down for how legibility is still handled per color (not per theme). */
  --element-neutral: #ffffff;
  --element-water: #043cfc;
  --element-earth: #4caa06;
  --element-fire: #fc0909;
  --element-wind: #c4ec14;
  --element-poison: #a011f5;
  --element-holy: #4dd6fc;
  --element-dark: #000000;
  --element-ghost: #8c6d20;
  --element-undead: #7c044c;

  --race-formless: #94a3b8;
  --race-undead: #6366f1;
  --race-brute: #d97706;
  --race-plant: #22c55e;
  --race-insect: #f59e0b;
  --race-fish: #06b6d4;
  --race-demon: #7c3aed;
  --race-human: #f87171;
  --race-angel: #fbbf24;
  --race-dragon: #ec4899;

  /* Tooltip — deliberately theme-invariant dark box + white text (not inverted per-theme),
     but the exact tone still needs to shift per theme: on the light theme a near-black box has
     plenty of contrast against the page, but that same near-black tone on the dark theme was
     nearly indistinguishable from --bg (#121212), reading as a barely-visible smudge instead of
     a popup. Each theme sets its own --tooltip-bg a couple of shades lighter than that theme's
     own --bg for a "clearly floating above the page" contrast, while staying dark enough that
     white text remains readable. */
  --tooltip-bg: #1a1a1a;
  --tooltip-border: rgba(255, 255, 255, 0.1);
}

/* Sharp-corners variant — a client-side-only visual preview toggle (localStorage "radius" key,
   see the anti-flash inline script in _Layout.cshtml and #radius-toggle in _Header.cshtml),
   independent of the light/dark/dark-blue theme. Not wired into AppContextVm/the server-side
   cookie like the color theme is — this is a quick side-by-side comparison tool, not a persisted
   account preference, so it deliberately stays purely client-side. Overrides all four radius
   tokens to 0, including --radius-full (used for genuinely circular elements like avatar badges)
   since the request was for corners to be sharp everywhere, not just on cards/buttons. */
[data-radius="sharp"] {
  --radius-sm: 0px;
  --radius-md: 0px;
  --radius-lg: 0px;
  --radius-full: 0px;
}

/* ============================================================================
   DARK THEME
   ============================================================================ */

[data-theme="dark"] {
  color-scheme: dark;

  /* Background & Surface */
  --bg: #121212;
  --surface: #1a1a1a;
  --surface-2: #222222;
  --surface-3: #2a2a2a;

  /* Text */
  --text: #e8e8e8;
  --text-muted: #a0a0a0;
  --text-subtle: #707070;

  /* Borders & Dividers */
  --border: #333333;
  --border-light: #282828;

  /* UI Colors */
  --accent: #46a0ff;
  --accent-strong: #7cbaff;
  --accent-light: #1e3a5f;
  --accent-lighter: #162230;

  /* Status Colors */
  --success: #39b975;
  --success-light: #1a2e22;
  --warning: #e4aa37;
  --warning-light: #2e2a1a;
  --danger: #ef6b7a;
  --danger-light: #2e1a1d;
  --info: #46a0ff;
  --info-light: #1a2636;

  /* Element/Badge Colors: fixed in-game colors defined once in :root, not overridden per theme —
     see the :root comment above. */

  --race-formless: #9ca3af;
  --race-undead: #a78bfa;
  --race-brute: #fb923c;
  --race-plant: #4ade80;
  --race-insect: #fbbf24;
  --race-fish: #22d3ee;
  --race-demon: #d8b4fe;
  --race-human: #fca5a5;
  --race-angel: #fded8e;
  --race-dragon: #f472b6;

  /* Lighter than --bg (#121212) so the tooltip visibly floats above the page instead of
     blending into it — see the :root comment above for why this can't just reuse --surface-3. */
  --tooltip-bg: #3a3a3a;
  --tooltip-border: rgba(255, 255, 255, 0.16);
}

/* Dark theme: override badge text for light-colored backgrounds */
[data-theme="dark"] .badge-race-plant,
[data-theme="dark"] .badge-race-insect,
[data-theme="dark"] .badge-race-human,
[data-theme="dark"] .badge-race-angel {
  color: #1b2430;
  text-shadow: none;
}

/* ============================================================================
   DARK BLUE THEME
   ============================================================================ */

[data-theme="dark-blue"] {
  color-scheme: dark;

  /* Background & Surface */
  --bg: #0f1520;
  --surface: #151d2b;
  --surface-2: #1d2738;
  --surface-3: #252e3f;

  /* Text */
  --text: #e8edf5;
  --text-muted: #a9b7cc;
  --text-subtle: #7d8a98;

  /* Borders & Dividers */
  --border: #2b3850;
  --border-light: #1f2937;

  /* UI Colors */
  --accent: #46a0ff;
  --accent-strong: #7cbaff;
  --accent-light: #1e3a5f;
  --accent-lighter: #0f2847;

  /* Status Colors */
  --success: #39b975;
  --success-light: #1f3a2a;
  --warning: #e4aa37;
  --warning-light: #3a3021;
  --danger: #ef6b7a;
  --danger-light: #3a1f24;
  --info: #46a0ff;
  --info-light: #1e3a5f;

  /* Element/Badge Colors: fixed in-game colors defined once in :root, not overridden per theme —
     see the :root comment above. */

  --race-formless: #9ca3af;
  --race-undead: #a78bfa;
  --race-brute: #fb923c;
  --race-plant: #4ade80;
  --race-insect: #fbbf24;
  --race-fish: #22d3ee;
  --race-demon: #d8b4fe;
  --race-human: #fca5a5;
  --race-angel: #fded8e;
  --race-dragon: #f472b6;

  /* Lighter than --bg (#0f1520) so the tooltip visibly floats above the page. */
  --tooltip-bg: #2c384c;
  --tooltip-border: rgba(255, 255, 255, 0.14);
}

/* Dark-blue theme: override badge text for light-colored backgrounds */
[data-theme="dark-blue"] .badge-race-plant,
[data-theme="dark-blue"] .badge-race-insect,
[data-theme="dark-blue"] .badge-race-human,
[data-theme="dark-blue"] .badge-race-angel {
  color: #1b2430;
  text-shadow: none;
}

/* ============================================================================
   GLOBAL STYLES
   ============================================================================ */

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-family: var(--font-family-base);
  font-size: var(--font-size-base);
  line-height: var(--line-height-normal);
  color: var(--text);
  background-color: var(--bg);
  transition: background-color var(--transition-base), color var(--transition-base);
}

/* ============================================================================
   TYPOGRAPHY
   ============================================================================ */

h1 {
  font-size: var(--font-size-3xl);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-tight);
  margin-bottom: var(--space-4);
}

h2 {
  font-size: var(--font-size-2xl);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-tight);
  margin-bottom: var(--space-3);
}

h3 {
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-tight);
  margin-bottom: var(--space-3);
}

p {
  margin-bottom: var(--space-3);
}

a {
  color: var(--accent);
  text-decoration: none;
  cursor: pointer;
  transition: color var(--transition-fast);
}

a:hover {
  color: var(--accent-strong);
  text-decoration: underline;
}

a:active {
  opacity: 0.8;
}

/* ============================================================================
   LAYOUT COMPONENTS
   ============================================================================ */

/* Container */
.container {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 var(--space-4);
}

.container-header-wide {
  max-width: 90%;
  padding-left: var(--space-5);
  padding-right: var(--space-5);
}

@media (max-width: 640px) {
  .container {
    padding: 0 var(--space-3);
  }

  .container-header-wide {
    padding-left: var(--space-3);
    padding-right: var(--space-3);
  }
}

/* Grid layout */
.grid {
  display: grid;
  gap: var(--space-4);
}

.grid-cols-2 {
  grid-template-columns: repeat(2, 1fr);
}

.grid-cols-3 {
  grid-template-columns: repeat(3, 1fr);
}

.grid-cols-4 {
  grid-template-columns: repeat(4, 1fr);
}

@media (max-width: 768px) {
  .grid-cols-2,
  .grid-cols-3,
  .grid-cols-4 {
    grid-template-columns: 1fr;
  }
}

/* Flex utilities */
.flex {
  display: flex;
}

.flex-between {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* ============================================================================
   CARDS & SURFACES
   ============================================================================ */

.card {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  box-shadow: var(--shadow-sm);
  transition: all var(--transition-base);
}

.card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--border-light);
}

.card-clickable {
  cursor: pointer;
}

.card-compact {
  padding: var(--space-3);
}

.card-lg {
  padding: var(--space-6);
}

/* ============================================================================
   BUTTONS & CONTROLS
   ============================================================================ */

button,
.btn {
  font-family: var(--font-family-base);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  padding: var(--space-2) var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: all var(--transition-fast);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  white-space: nowrap;
}

.btn-primary {
  background-color: var(--accent);
  color: white;
  border-color: var(--accent);
}

.btn-primary:hover {
  background-color: var(--accent-strong);
  border-color: var(--accent-strong);
}

.btn-primary:active {
  opacity: 0.8;
}

.btn-secondary {
  background-color: var(--surface-2);
  color: var(--text);
  border-color: var(--border);
}

.btn-secondary:hover {
  background-color: var(--surface-3);
  border-color: var(--border-light);
}

.btn-ghost {
  background-color: transparent;
  color: var(--text);
  border-color: transparent;
}

.btn-ghost:hover {
  background-color: var(--surface-2);
}

button:disabled,
.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ============================================================================
   FORM CONTROLS
   ============================================================================ */

input,
select,
textarea {
  font-family: var(--font-family-base);
  font-size: var(--font-size-sm);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--surface);
  color: var(--text);
  transition: all var(--transition-fast);
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
}

input::placeholder {
  color: var(--text-muted);
}

/* Checkbox skin — overrides the generic input rule above (higher specificity via [type=]),
   since that rule's padding/border-radius/background were meant for text-like inputs and made
   plain checkboxes look like a small padded rectangle rather than a proper checkbox. */
input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  padding: 0;
  margin: 0;
  border: 1px solid var(--border);
  border-radius: 4px;
  background-color: var(--surface);
  cursor: pointer;
  position: relative;
  flex-shrink: 0;
  vertical-align: middle;
}

input[type="checkbox"]:hover {
  border-color: var(--accent);
}

input[type="checkbox"]:checked {
  background-color: var(--accent);
  border-color: var(--accent);
}

input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 1px;
  width: 4px;
  height: 8px;
  border: solid white;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

input[type="checkbox"]:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-light);
}

/* ============================================================================
   BADGES & CHIPS
   ============================================================================ */

.badge {
  display: inline-block;
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  white-space: nowrap;
}

.badge-primary {
  background-color: var(--accent-light);
  color: var(--accent);
}

.badge-secondary {
  background-color: var(--surface-3);
  color: var(--text-muted);
}

.badge-success {
  background-color: var(--success-light);
  color: var(--success);
}

.badge-warning {
  background-color: var(--warning-light);
  color: var(--warning);
}

.badge-danger {
  background-color: var(--danger-light);
  color: var(--danger);
}

/* ============================================================================
   MODAL (admin edit dialogs)
   ============================================================================ */

.admin-modal-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: 1000;
  align-items: flex-start;
  justify-content: center;
  padding: var(--space-3);
  overflow-y: auto;
}

.admin-modal-backdrop.open {
  display: flex;
}

.admin-modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 98vw;
  max-width: 1900px;
  height: 98vh;
  max-height: 98vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.admin-modal.admin-modal-md {
  max-width: 960px;
}

/* Every admin modal's real DOM is .admin-modal > form > (.admin-modal-header,
   .admin-modal-body, .admin-modal-footer) — the <form> itself has no styling, so it was never a
   flex item's *sibling* concern, it was the ONLY direct flex child of .admin-modal. That made
   every flex property on -header/-body/-footer completely inert: they aren't flex items of
   .admin-modal at all, they're plain block children of a plain <form>. Confirmed by measuring
   actual computed layout (Puppeteer) rather than assuming — .admin-modal-body's textbook-correct
   `flex: 1 1 0%; min-height: 0` had zero effect (scrollHeight == clientHeight, no shrink
   happened) until this rule made the <form> itself participate in the flex-column chain. */
.admin-modal > form {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  overflow: hidden;
}

.admin-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.admin-modal-body {
  padding: var(--space-5);
  overflow-y: auto;
  /* The canonical "scrollable middle section of a flex column" recipe is flex: 1 (grow/shrink
     from a zero basis, i.e. size purely from available space, not content) + min-height: 0
     (flex items default to min-height: auto, which still refuses to shrink below content size
     even with flex-shrink — this removes that floor). Without flex: 1, this item was never
     actually told to size itself off "remaining space after header/footer" at all — it sized to
     its own content, so it (and then .admin-modal, once it also got overflow: hidden) just
     clipped content with no way to scroll to it, instead of creating a real scroll region. */
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-5);
}

/* Grid items default to min-width: auto, which refuses to shrink a column below the
   min-content width of what's inside it — a <textarea> full of long unbroken text (RO
   description markup, machine-translated text with no natural wrap points) can blow the
   column out past its track even though the textarea itself has width: 100%. min-width: 0
   lets the track (and everything in it) actually shrink to fit. */
.admin-modal-body > * {
  min-width: 0;
}

.admin-modal-body.admin-modal-body-3col {
  grid-template-columns: 1fr 2fr 2fr;
}

.admin-modal-body.admin-modal-body-tabs {
  display: block;
}

@media (max-width: 1200px) {
  .admin-modal-body.admin-modal-body-3col {
    grid-template-columns: 1fr 1fr;
  }

  .admin-modal-body.admin-modal-body-3col > :first-child {
    grid-column: 1 / -1;
  }
}

@media (max-width: 900px) {
  .admin-modal-body,
  .admin-modal-body.admin-modal-body-3col {
    grid-template-columns: 1fr;
  }

  .admin-modal-body.admin-modal-body-3col > :first-child {
    grid-column: auto;
  }
}

.admin-modal-footer {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

.admin-modal-close {
  background: none;
  border: none;
  font-size: var(--font-size-xl);
  color: var(--text-muted);
  cursor: pointer;
  line-height: 1;
  padding: var(--space-1);
}

.admin-tab-bar {
  display: flex;
  gap: var(--space-1);
  flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-3);
}

.admin-tab {
  padding: var(--space-2) var(--space-3);
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-muted);
  border-bottom: 2px solid transparent;
  font-size: var(--font-size-sm);
}

.admin-tab.active {
  color: var(--accent);
  border-bottom: 2px solid var(--accent);
}

/* ============================================================================
   TOAST NOTIFICATIONS — see showToast() in site.js.
   ============================================================================ */

.toast-container {
  position: fixed;
  bottom: var(--space-6);
  right: var(--space-6);
  z-index: 3000;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.toast {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: var(--space-3) var(--space-4);
  color: var(--text);
  font-size: var(--font-size-sm);
  max-width: 320px;
  animation: toast-in 0.15s ease-out;
}

.toast.toast-success {
  border-left-color: var(--success);
}

.toast.toast-error {
  border-left-color: var(--danger);
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ============================================================================
   ACHIEVEMENT UNLOCKED BANNER — see showAchievementBanner() in site.js.
   Full-width, front-most bar mirroring the in-game client's UIAchBalloonText
   (a full-width window added to the front of the window stack with centered,
   drop-shadowed text) — gold/amber to match the in-game achievement color,
   plus a diagonal shine sweep for a bit of extra "cool effect" polish the
   original plain-text balloon didn't need (that one leaned on the game's own
   fanfare sound + surrounding UI chrome for impact; this has neither).
   ============================================================================ */

.achievement-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3500;
  overflow: hidden;
  background: linear-gradient(180deg, #ffd76a 0%, #e8a827 55%, #c98a12 100%);
  border-bottom: 2px solid #a5730a;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
  transform: translateY(-100%);
  transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.achievement-banner.achievement-banner-visible {
  transform: translateY(0);
}

.achievement-banner-shine {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    transparent 30%,
    rgba(255, 255, 255, 0.55) 45%,
    rgba(255, 255, 255, 0.55) 50%,
    transparent 65%
  );
  background-size: 250% 100%;
  background-position: 120% 0;
  animation: achievement-banner-shine-sweep 1.6s ease-out 0.4s;
  pointer-events: none;
}

@keyframes achievement-banner-shine-sweep {
  from {
    background-position: 120% 0;
  }
  to {
    background-position: -20% 0;
  }
}

.achievement-banner-content {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  max-width: 720px;
  margin: 0 auto;
  padding: var(--space-3) var(--space-5);
  text-align: center;
}

.achievement-banner-icon {
  font-size: 2.25rem;
  line-height: 1;
  filter: drop-shadow(0 2px 2px rgba(0, 0, 0, 0.4));
}

.achievement-banner-text {
  min-width: 0;
}

.achievement-banner-title {
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #4a2f00;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.35);
}

.achievement-banner-name {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-bold);
  color: #2b1a00;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}

.achievement-banner-desc {
  font-size: var(--font-size-sm);
  color: #5a3d05;
}

.achievement-banner-points {
  flex-shrink: 0;
  background: rgba(43, 26, 0, 0.85);
  color: #ffd76a;
  font-weight: var(--font-weight-bold);
  font-size: var(--font-size-sm);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  white-space: nowrap;
}

@media (max-width: 640px) {
  .achievement-banner-content {
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3);
  }

  .achievement-banner-icon {
    font-size: 1.75rem;
  }
}

/* ============================================================================
   QUICK JUMP (Alt+G palette) — global, always mounted in _Layout.cshtml.
   Higher z-index than .admin-modal-backdrop (1000) so it can be opened on top of an
   already-open admin modal.
   ============================================================================ */

.quickjump-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: 2000;
  align-items: flex-start;
  justify-content: center;
  padding: var(--space-3);
  padding-top: 12vh;
}

.quickjump-backdrop.open {
  display: flex;
}

.quickjump-panel {
  width: min(640px, 92vw);
  max-height: 70vh;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.quickjump-input-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.quickjump-input-row svg {
  flex-shrink: 0;
  color: var(--text-muted);
}

.quickjump-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  color: var(--text);
  font-size: var(--font-size-lg);
  outline: none;
}

.quickjump-results {
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}

.quickjump-result {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  cursor: pointer;
  color: var(--text);
  text-decoration: none;
  border-bottom: 1px solid var(--border-light);
}

.quickjump-result:last-child {
  border-bottom: none;
}

.quickjump-result.active {
  background: var(--surface-2);
}

.quickjump-result-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.quickjump-result-type {
  flex-shrink: 0;
  font-size: var(--font-size-xs);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  padding: 2px 6px;
}

.quickjump-empty,
.quickjump-hint {
  padding: var(--space-4);
  color: var(--text-muted);
  font-size: var(--font-size-sm);
  text-align: center;
}

.quickjump-footer {
  padding: var(--space-2) var(--space-4);
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: var(--font-size-xs);
  flex-shrink: 0;
}

.color-btn {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: #fff;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  padding: 0;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
}

/* Element badges */
[class*="badge-element-"] {
  font-weight: var(--font-weight-medium);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  color: white;
  font-size: var(--font-size-xs);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

.badge-element-water { background-color: var(--element-water); }
.badge-element-earth { background-color: var(--element-earth); }
.badge-element-fire { background-color: var(--element-fire); }
.badge-element-poison { background-color: var(--element-poison); }
.badge-element-dark { background-color: var(--element-dark); }
.badge-element-ghost { background-color: var(--element-ghost); }
.badge-element-undead { background-color: var(--element-undead); }

/* These three in-game colors are light enough that the base white text (with its drop shadow)
   isn't legible — dark text needed regardless of site theme, since the colors themselves are
   fixed/theme-invariant now. */
.badge-element-wind { background-color: var(--element-wind); color: #1b2430; text-shadow: none; }
.badge-element-holy { background-color: var(--element-holy); color: #1b2430; text-shadow: none; }
.badge-element-neutral { background-color: var(--element-neutral); color: #1b2430; text-shadow: none; border: 1px solid var(--border); }

/* Element "dot" — the in-game convention (a colored dot + the level digit) used by
   Views/Shared/_ElementDot.cshtml, added 2026-08-07 to replace text badges like "Undead 4"
   wherever a monster's own element is shown (as opposed to badge-element-* pills, still used
   for the Element resistance table's per-attacking-element rows, which have no level concept). */
.element-dot {
  display: inline-block;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  vertical-align: middle;
  border: 1px solid var(--border);
}

.element-dot-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.element-dot-level {
  font-weight: var(--font-weight-semibold);
  font-size: var(--font-size-sm);
}

/* Race badges */
[class*="badge-race-"] {
  font-weight: var(--font-weight-medium);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  color: white;
  font-size: var(--font-size-xs);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

.badge-race-formless { background-color: var(--race-formless); }
.badge-race-undead { background-color: var(--race-undead); }
.badge-race-brute { background-color: var(--race-brute); }
.badge-race-plant { background-color: var(--race-plant); }
.badge-race-insect { background-color: var(--race-insect); }
.badge-race-fish { background-color: var(--race-fish); }
.badge-race-demon { background-color: var(--race-demon); }
.badge-race-human { background-color: var(--race-human); }
.badge-race-angel { background-color: var(--race-angel); }
.badge-race-dragon { background-color: var(--race-dragon); }

/* ============================================================================
   TABLES
   ============================================================================ */

table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--space-4) 0;
}

thead {
  background-color: var(--surface-2);
  border-bottom: 2px solid var(--border);
}

th {
  padding: var(--space-3);
  text-align: left;
  font-weight: var(--font-weight-semibold);
  color: var(--text);
  font-size: var(--font-size-sm);
}

td {
  padding: var(--space-3);
  border-bottom: 1px solid var(--border-light);
}

tbody tr:hover {
  background-color: var(--surface-2);
}

table.sortable th {
  cursor: pointer;
  user-select: none;
  position: relative;
  padding-right: calc(var(--space-3) + 20px);
  white-space: nowrap;
}

table.sortable th:after {
  content: '\2195';
  opacity: 0.3;
  position: absolute;
  right: var(--space-3);
  font-size: 0.75em;
}

table.sortable th.sort-asc:after {
  content: '\25B2';
  opacity: 1;
}

table.sortable th.sort-desc:after {
  content: '\25BC';
  opacity: 1;
}

/* Table density modifiers */
table.density-compact th,
table.density-compact td {
  padding: var(--space-1) var(--space-2);
  font-size: var(--font-size-xs);
}

table.density-comfortable th,
table.density-comfortable td {
  padding: var(--space-4) var(--space-3);
}

/* ============================================================================
   AD SLOTS (Layout-safe)
   ============================================================================ */

.ad-slot {
  width: 100%;
  overflow: hidden;
  border-radius: var(--radius-md);
  background-color: var(--surface-2);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: var(--font-size-sm);
  min-height: 90px;
}

.ad-slot--rectangle {
  min-height: 250px;
  max-width: 300px;
}

.ad-slot--mobile {
  min-height: 100px;
}

.ad-slot--mpu {
  min-height: 250px;
  max-width: 300px;
}

/* Fallback placeholder */
.ad-slot[data-placeholder]::before {
  content: attr(data-placeholder);
}

/* ============================================================================
   HEADER
   ============================================================================ */

/* Scoped to .site-header, not a bare `header` tag selector — that used to also match content-
   level <header> elements (e.g. a news article's title row on the homepage), which inherited
   `position: sticky` + `z-index: 100` unintentionally and rendered on top of the nav dropdowns
   (same z-index, later in DOM order wins the stacking tie). */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background-color: var(--surface);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
}

.header-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  padding: var(--space-3) 0;
  gap: var(--space-3);
}

.header-logo {
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-bold);
  color: var(--accent);
  text-decoration: none;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.header-logo:hover {
  color: var(--accent-strong);
}

/* Logo composed live from a single icon + real text (added 2026-08-07, replacing two flattened
   "lockup" PNGs that baked the wordmark into the image itself — swapping the actual logo mark
   meant regenerating those composites, which isn't something this codebase can do; a live
   composition means the icon file alone can be swapped going forward). The icon's own background
   works on every site theme unmodified, so — unlike the old two-PNG-per-theme setup — nothing
   here needs a per-theme swap. */
.header-logo-icon {
  height: 38px;
  width: 38px;
  border-radius: var(--radius-md);
  flex-shrink: 0;
}

.header-logo-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  line-height: 1.2;
}

.header-logo-title {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-bold);
  color: var(--text);
  white-space: nowrap;
}

.header-logo-tagline {
  font-size: 10px;
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
}

.header-select {
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--surface-2);
  color: var(--text);
  font-size: var(--font-size-xs);
}

/* Language picker — a custom .nav-dropdown button instead of a native <select>, since flag icons
   need to be real <svg>, and an <option> can only ever hold plain text. */
.language-trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  cursor: pointer;
  font-family: var(--font-family-base);
}

.language-menu-list {
  flex-direction: column;
  min-width: 160px;
  max-height: 320px;
  overflow-y: auto;
}

.language-option {
  display: flex;
  width: 100%;
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--font-family-base);
  text-align: left;
  color: var(--text);
}

.language-option.active {
  color: var(--accent);
  font-weight: var(--font-weight-semibold);
}

.flag-icon {
  flex-shrink: 0;
  border-radius: 2px;
  outline: 1px solid var(--border-light);
  outline-offset: -0.5px;
}

.search-box {
  position: relative;
  display: flex;
  align-items: center;
  flex: 1;
  min-width: 160px;
  max-width: 280px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background-color: var(--surface-2);
  overflow: hidden;
}

.search-box input[type="text"] {
  flex: 1;
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  border: none;
  background: transparent;
  color: var(--text);
  font-size: var(--font-size-sm);
  outline: none;
}

.search-desc-toggle {
  display: flex;
  align-items: center;
  gap: 3px;
  padding: var(--space-1) var(--space-2);
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  border-left: 1px solid var(--border-light);
}

.header-nav {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
  gap: var(--space-3);
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
}

.header-nav-item {
  color: var(--text-muted);
  text-decoration: none;
  font-weight: var(--font-weight-medium);
  font-size: var(--font-size-sm);
  padding: var(--space-2) 0;
  border-bottom: 2px solid transparent;
  transition: all var(--transition-fast);
  white-space: nowrap;
}

.nav-dropdown-trigger {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
}

.header-nav-item:hover,
.header-nav-item.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* Navigation dropdown */
.nav-dropdown {
  position: relative;
}

.nav-dropdown-menu {
  display: none;
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  padding-top: var(--space-2);
  z-index: 100;
}

.nav-dropdown.open .nav-dropdown-menu {
  display: block;
}

.nav-dropdown-columns {
  display: flex;
  gap: var(--space-1);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  padding: var(--space-3);
  min-width: 340px;
}

.nav-dropdown-column {
  display: flex;
  flex-direction: column;
  min-width: 150px;
}

.nav-dropdown-item {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  border-radius: var(--radius-sm);
  white-space: nowrap;
}

.nav-dropdown-item a {
  color: var(--text);
  text-decoration: none;
  transition: color var(--transition-fast);
}

.nav-dropdown-item a:hover {
  color: var(--accent);
}

.nav-dropdown-item:hover {
  background: var(--surface-2);
}

.nav-dropdown-sub {
  padding-left: var(--space-7);
  font-weight: var(--font-weight-normal);
  color: var(--text-muted);
  font-size: var(--font-size-xs);
}

/* Non-interactive group label (e.g. Admin dropdown's Dashboard/Datamining/Import columns) —
   overrides .nav-dropdown-item's hover highlight since a <span> here isn't a link. */
.nav-dropdown-heading {
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  color: var(--text-subtle);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  cursor: default;
}

.nav-dropdown-heading:hover {
  background: none;
}

.nav-dropdown-sub:hover {
  color: var(--accent);
}

.nav-dropdown-icon {
  display: inline-block;
  width: 1.2em;
  text-align: center;
}

/* Styled tooltip — CSS-only (no JS component), replaces the bare browser title="" tooltip
   wherever a themed one is wanted. Usage: <span class="tooltip" data-tooltip="text">...</span> */
.tooltip {
  position: relative;
  display: inline-block;
}

.tooltip::after {
  /* line-height reset: several callers (Map/Npc Detail marker pins) wrap the trigger in a
     line-height: 0 container to remove the inline-image gap; without resetting it here that
     0 inherits into this pseudo-element and collapses multi-line (pre-line) tooltip text into
     an overlapping stack instead of separate lines. */
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  padding: var(--space-1) var(--space-2);
  background: var(--tooltip-bg, #1a1a1a);
  border: 1px solid var(--tooltip-border, rgba(255, 255, 255, 0.1));
  color: #fff;
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
  line-height: normal;
  white-space: nowrap;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--transition-fast);
  z-index: 200;
}

.tooltip:hover::after,
.tooltip:focus-within::after {
  opacity: 1;
  visibility: visible;
}

/* Multi-line variant — combine with .tooltip: <span class="tooltip tooltip-multiline"
   data-tooltip="line 1&#10;line 2">...</span>. Relies on literal newline characters in the
   data-tooltip attribute value (valid in HTML) plus white-space: pre-line to render them. */
.tooltip-multiline::after {
  white-space: pre-line;
  text-align: left;
  min-width: 220px;
  max-width: 320px;
}

/* "RO style" variant — matches the legacy site's own .dp-tooltip-outer/.dp-tooltip-inner
   classes (Content/css/tooltip.css). Legacy is actually two nested boxes: an outer box
   (padding: 1px, background: rgba(0,0,0,.8)) wrapping an inner box (padding: 3px, border: 1px
   solid #fff) — so the white border sits inset by a 1px translucent-black ring, not flush
   against the outer edge. Reproduced here with a single pseudo-element via box-shadow (the
   halo) plus border (the inset white line), since ::after can't nest two real boxes.
   (An earlier version of this guessed at a bordered nameplate with a colored name line and a
   pointer from a screenshot alone — the actual legacy DOM/CSS the user pasted afterward showed
   it's much simpler than that guess.) Combine with the base .tooltip class, same as
   .tooltip-multiline.
   width: max-content (not min-width) is required, not cosmetic: ::after is absolutely
   positioned with only `left` set (from the base .tooltip::after rule), so its shrink-to-fit
   auto-width is computed against the small trigger span's own width (e.g. a 24-48px icon) —
   for short icon tooltips that collapses to just a few px, forcing pre-line's wrapping to
   break text one word per line ("Can be put in cart" stacked vertically) before the later
   translateX(-50%) re-centers it. width: max-content sizes to the natural content width
   instead, only wrapping past max-width. */
.tooltip-ro::after {
  background: rgba(0, 0, 0, 0.8);
  border: 1px solid #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.8);
  color: #fff;
  border-radius: 4px;
  width: max-content;
  max-width: 220px;
  white-space: pre-line;
  text-align: center;
}

/* Horizontally-scrollable tab bar — Item/Monster/Quest/Npc/Map/Skill Detail all build their tab
   strip as a plain flex row with no wrapping, so on a narrow viewport tabs past the edge become
   unreachable (visibly cut off, no way to scroll to them) once there are enough of them — Item
   Detail's 8+ conditional tabs hit this first. This class only changes the container's overflow
   behavior; each page keeps its own inline flex/gap/border-bottom styling on the same element
   (combine as class="tab-bar" alongside the existing inline style=""). */
.tab-bar {
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}

.tab-bar > .tab-button {
  flex-shrink: 0;
}

.header-controls {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
  justify-content: flex-end;
}

@media (max-width: 1200px) {
  .header-content {
    align-items: flex-start;
  }

  .header-nav {
    order: 3;
    flex: 1 1 100%;
    justify-content: flex-start;
    gap: var(--space-2);
  }

  .header-controls {
    flex: 1 1 auto;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  .search-box {
    max-width: 220px;
  }

  .header-nav-item {
    font-size: var(--font-size-xs);
  }
}

@media (max-width: 960px) {
  .header-logo-tagline {
    display: none;
  }

  .header-controls {
    justify-content: flex-start;
  }

  .search-box {
    flex: 1 1 220px;
    max-width: none;
  }

  .header-auth {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
  }
}

@media (max-width: 768px) {
  .header-nav {
    display: none;
  }

  /* Toggled by #mobile-nav-toggle (_Header.cshtml) — stacks the Community/Database/Tools/
     Gallery/Admin nav as a full-width column under the header row instead of the desktop
     centered horizontal bar, since there's no room for that here and the nav was previously
     just unreachable on mobile (`hide-mobile`) with no alternative entry point at all. */
  .header-nav.mobile-open {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    width: 100%;
    order: 4;
    gap: 0;
    border-top: 1px solid var(--border);
    margin-top: var(--space-2);
    padding-top: var(--space-2);
  }

  .header-nav.mobile-open .nav-dropdown {
    width: 100%;
  }

  .header-nav.mobile-open .header-nav-item {
    display: block;
    width: 100%;
    padding: var(--space-3) var(--space-2);
    border-bottom: 1px solid var(--border-light);
  }

  /* Desktop dropdown menus float absolutely, centered under their trigger — on a narrow
     viewport that overflows the screen edge, so they're flattened into an inline, indented
     section directly under their trigger instead. Some of these (the Database dropdown) use
     inline style="display: flex" row wrappers in the markup itself, which can only be
     overridden from a stylesheet with !important. */
  .header-nav.mobile-open .nav-dropdown-menu {
    position: static;
    transform: none;
    padding-top: 0;
  }

  .header-nav.mobile-open .nav-dropdown-columns,
  .header-nav.mobile-open .nav-dropdown-columns > div {
    flex-direction: column !important;
    min-width: 0;
    width: 100%;
    box-shadow: none;
    border: none;
    border-radius: 0;
    padding-left: var(--space-4);
  }

  .header-controls {
    width: 100%;
  }

  .header-search-form {
    flex-wrap: wrap;
  }

  .header-search-input {
    min-width: 0;
  }
}

/* Header auth links */
.header-auth {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: var(--space-2);
  padding-left: var(--space-3);
  border-left: 1px solid var(--border);
}

.header-auth-link {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--text);
  text-decoration: none;
  font-size: var(--font-size-sm);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  transition: color var(--transition-fast);
}

.header-auth-link:hover {
  color: var(--accent);
}

.header-auth-icon {
  font-size: var(--font-size-lg);
}

.header-auth-logout {
  color: var(--text-muted);
  font-size: var(--font-size-xs);
}

.btn-sm {
  padding: var(--space-1) var(--space-3);
  font-size: var(--font-size-sm);
}

/* ============================================================================
   FILTER PANEL
   ============================================================================ */

.filter-panel {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
}

.filter-group {
  margin-bottom: var(--space-5);
}

.filter-group:last-child {
  margin-bottom: 0;
}

.filter-group-title {
  font-weight: var(--font-weight-semibold);
  margin-bottom: var(--space-3);
  font-size: var(--font-size-sm);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.chip {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background-color: var(--surface-2);
  color: var(--text);
  cursor: pointer;
  font-size: var(--font-size-sm);
  transition: all var(--transition-fast);
}

.chip:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.chip.active {
  background-color: var(--accent);
  border-color: var(--accent);
  color: white;
}

/* ============================================================================
   RESPONSIVE UTILITIES
   ============================================================================ */

@media (max-width: 768px) {
  .hide-mobile {
    display: none;
  }
}

@media (min-width: 769px) {
  .hide-desktop {
    display: none;
  }
}

/* ============================================================================
   UTILITY CLASSES
   ============================================================================ */

.text-center {
  text-align: center;
}

.text-muted {
  color: var(--text-muted);
}

.text-subtle {
  color: var(--text-subtle);
}

.font-bold {
  font-weight: var(--font-weight-bold);
}

.font-semibold {
  font-weight: var(--font-weight-semibold);
}

.mt-1 { margin-top: var(--space-1); }
.mt-2 { margin-top: var(--space-2); }
.mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); }

.mb-1 { margin-bottom: var(--space-1); }
.mb-2 { margin-bottom: var(--space-2); }
.mb-3 { margin-bottom: var(--space-3); }
.mb-4 { margin-bottom: var(--space-4); }

.gap-2 { gap: var(--space-2); }
.gap-3 { gap: var(--space-3); }
.gap-4 { gap: var(--space-4); }

/* ============================================================================
   LAYOUT WITH SIDEBAR
   ============================================================================ */

.layout-with-sidebar {
  display: grid;
  grid-template-columns: 1fr 280px;
  gap: var(--space-6);
  margin-top: var(--space-4);
  align-items: start;
}

.layout-main {
  min-width: 0;
}

.layout-main > :first-child {
  margin-top: 0;
}

.layout-sidebar {
  min-width: 0;
}

@media (max-width: 1024px) {
  .layout-with-sidebar {
    grid-template-columns: 1fr;
  }
}

/* ============================================================================
   SIDEBAR COMPONENTS
   ============================================================================ */

.sidebar-section {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  margin-bottom: var(--space-4);
}

.sidebar-title {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--text);
  margin-bottom: var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border-light);
}

.sidebar-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.sidebar-list-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border-light);
  font-size: var(--font-size-sm);
}

.sidebar-list-item:last-child {
  border-bottom: none;
}

.sidebar-list-item a {
  color: var(--text);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sidebar-list-item a:hover {
  color: var(--accent);
}

.sidebar-icon {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  image-rendering: pixelated;
}

.sidebar-pagination {
  display: flex;
  gap: var(--space-1);
  margin-top: var(--space-3);
  justify-content: center;
}

.sidebar-page {
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.sidebar-page:hover {
  background-color: var(--surface-2);
}

.sidebar-page.active {
  background-color: var(--accent);
  color: white;
}

/* ============================================================================
   TRADE FLAG ICONS
   ============================================================================ */

.trade-icon {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  transition: opacity var(--transition-fast);
}

.trade-icon svg {
  display: block;
}

.trade-icon-label {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  text-align: center;
}

/* ============================================================================
   API DOCUMENTATION
   ============================================================================ */

.api-doc-toc {
  position: sticky;
  /* --site-header-height is set by site.js from .site-header's real (breakpoint-dependent)
     rendered height — without it, this nav sticks relative to the viewport top, which is
     already occupied by the equally-sticky .site-header (z-index: 100), so the nav's own top
     portion ends up scrolling underneath the header instead of stopping below it. The fixed
     px fallback only matters for the brief moment before JS runs. */
  top: calc(var(--site-header-height, 80px) + var(--space-4));
  align-self: start;
  max-height: calc(100vh - var(--site-header-height, 80px) - var(--space-6));
  overflow-y: auto;
}

.api-doc-toc-link {
  display: block;
  padding: var(--space-1) 0;
  font-size: var(--font-size-sm);
  color: var(--text-muted);
  text-decoration: none;
}

.api-doc-toc-link:hover {
  color: var(--accent);
  text-decoration: none;
}

.api-doc-section {
  padding: var(--space-6) 0;
  border-bottom: 1px solid var(--border-light);
}

.api-doc-section:last-child {
  border-bottom: none;
}

.api-doc-code-inline {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-sm);
  background-color: var(--surface-2);
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-light);
  color: var(--accent);
}

.api-doc-code-block {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-sm);
  line-height: 1.6;
  background-color: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  overflow-x: auto;
  white-space: pre;
  margin: var(--space-3) 0;
}

/* JSON syntax highlighting for "Example Response" blocks — applied client-side (see ApiDoc.cshtml's
   Scripts section) to any .api-doc-code-block whose content starts with "{"/"[", so the plain
   "Example Request" (HTTP request line + headers) blocks are left untouched. Colors reuse the same
   semantic tokens as the rest of the theme (already light/dark/dark-blue aware) rather than a
   fixed highlight-library palette. */
.api-doc-json-key {
  color: var(--accent);
}

.api-doc-json-string {
  color: var(--success);
}

.api-doc-json-number {
  color: var(--warning);
}

.api-doc-json-boolean {
  color: var(--info);
}

.api-doc-json-null {
  color: var(--text-muted);
}

.api-doc-endpoint-header {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.api-doc-method {
  display: inline-block;
  font-family: var(--font-family-mono);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-bold);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.api-doc-method-get {
  background-color: var(--success-light);
  color: var(--success);
  border: 1px solid var(--success);
}

.api-doc-method-post {
  background-color: var(--info-light);
  color: var(--info);
  border: 1px solid var(--info);
}

.api-doc-path {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-lg);
  color: var(--text);
}

/* ============================================================================
   COMBAT LOG ANALYZER
   ============================================================================ */

.combatlog-tabs {
  display: flex;
  gap: 0;
  border-bottom: 2px solid var(--border);
  margin-bottom: 0;
}

.combatlog-tab {
  padding: var(--space-3) var(--space-4);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--text-muted);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  cursor: pointer;
  transition: all var(--transition-fast);
}

.combatlog-tab:hover {
  color: var(--text);
  background-color: var(--surface-2);
}

.combatlog-tab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.combatlog-tab-panel {
  display: none;
}

.combatlog-tab-panel.active {
  display: block;
}

.combatlog-empty {
  padding: var(--space-6);
  text-align: center;
}

/* ============================================================================
   BATTLE REPORTS
   ============================================================================ */

/* Upload dropzone */
.report-upload-dropzone {
  border: 2px dashed var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-8) var(--space-4);
  text-align: center;
  cursor: pointer;
  transition: all var(--transition-fast);
}

.report-upload-dropzone:hover,
.report-upload-dropzone.dragover {
  border-color: var(--accent);
  background-color: var(--accent-lighter);
}

.report-upload-dropzone-content {
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Player chip */
/* Player name shown as a clickable drill-down trigger (e.g. "Damage of Player X") */
.report-player-link {
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  font-size: inherit;
  font-family: inherit;
  cursor: pointer;
}

.report-player-link:hover {
  text-decoration: underline;
}

/* Job class icon */
.report-job-icon {
  width: 24px;
  height: 24px;
  vertical-align: middle;
  flex-shrink: 0;
}

/* Report tabs */
.report-tabs {
  display: flex;
  gap: 0;
  border-bottom: 2px solid var(--border);
  margin-top: var(--space-4);
  overflow-x: auto;
  overflow-y: hidden;
}

.report-tab {
  padding: var(--space-3) var(--space-4);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--text-muted);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  cursor: pointer;
  white-space: nowrap;
  transition: all var(--transition-fast);
}

.report-tab:hover {
  color: var(--text);
  background-color: var(--surface-2);
}

.report-tab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.report-tab-panel {
  display: none;
  margin-top: var(--space-4);
}

.report-tab-panel.active {
  display: block;
}

/* Horizontal bar chart rows */
.report-bar-row {
  display: grid;
  grid-template-columns: 180px minmax(0, 1fr) minmax(90px, max-content);
  gap: var(--space-3);
  align-items: center;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border-light);
}

.report-bar-row:last-child {
  border-bottom: none;
}

.report-bar-label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.report-bar-track {
  height: 20px;
  background-color: var(--surface-2);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.report-bar-fill {
  height: 100%;
  border-radius: var(--radius-sm);
  transition: width 0.6s ease;
  min-width: 2px;
}

.report-bar-damage {
  background-color: var(--danger);
}

.report-bar-healing {
  background-color: var(--success);
}

.report-bar-warning {
  background-color: var(--warning);
}

.report-bar-value {
  text-align: right;
  font-family: var(--font-family-mono);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  white-space: nowrap;
}

@media (max-width: 768px) {
  .report-bar-row {
    grid-template-columns: 120px minmax(0, 1fr) minmax(70px, max-content);
  }
}

/* Forum-sourced HTML (Views/Home/Index.cshtml's news articles, rendered via Html.Raw from the
   IPS4 API's raw post content — see IForumNewsService) renders inside the site's normal content
   flow, but the global `* { margin: 0; padding: 0; }` reset (near the top of this file) strips
   <ul>/<ol>'s default padding-left, which is what makes room for the marker to sit outside the
   text — without it, bullets/numbers rendered flush against the container edge instead of
   indented. Scoped to .news-content rather than a bare `ul, ol` rule so this doesn't change list
   rendering anywhere else on the site (nothing else currently renders raw third-party HTML). */
.news-content ul,
.news-content ol {
  padding-left: 1.5em;
  margin: var(--space-3) 0;
}

.news-content li {
  margin-bottom: var(--space-1);
}

.news-content p {
  margin: var(--space-3) 0;
}

.news-content h1,
.news-content h2,
.news-content h3,
.news-content h4 {
  margin: var(--space-4) 0 var(--space-2);
}

/* ============================================================================
   BREADCRUMB (Views/Gallery/Server.cshtml, Album.cshtml)
   ============================================================================ */

/* Unstyled previously — bootstrap.css (the source of the .breadcrumb/.breadcrumb-item names)
   isn't loaded on this site, only theme.css is, so the bare <ol class="breadcrumb"> rendered as
   a plain numbered list (one entry per line) instead of a compact horizontal trail. */
.breadcrumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  list-style: none;
  gap: var(--space-1);
  margin-bottom: var(--space-4);
  font-size: var(--font-size-sm);
}

.breadcrumb-item {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--text-muted);
}

.breadcrumb-item + .breadcrumb-item::before {
  content: '/';
  color: var(--text-subtle);
}

.breadcrumb-item a {
  color: var(--text-muted);
  text-decoration: none;
}

.breadcrumb-item a:hover {
  color: var(--accent);
  text-decoration: underline;
}

.breadcrumb-item.active {
  color: var(--text);
  font-weight: var(--font-weight-medium);
}

/* ============================================================================
   GALLERY (Views/Gallery/Index.cshtml, Server.cshtml, Album.cshtml)
   ============================================================================ */

/* Also unstyled previously, same root cause as .breadcrumb above — .gallery-grid had no
   display: grid, and .card-link/.card-body/.card-title had no layout rules, so the server/date
   picker cards fell back to block display and rendered as a full-width list, one per line,
   instead of a browsable grid. */
.gallery-jump {
  display: block;
  width: 100%;
  max-width: 320px;
  margin-bottom: var(--space-4);
}

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.gallery-grid .card {
  padding: 0;
  overflow: hidden;
}

.card-link {
  display: block;
  color: inherit;
  text-decoration: none;
}

.card-body {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
}

.card-title {
  font-weight: var(--font-weight-medium);
  color: var(--text);
}

.card-link:hover .card-title {
  color: var(--accent);
}

.badge-admin {
  background-color: var(--warning-light);
  color: var(--warning);
}

/* ============================================================================
   GALLERY ALBUM (Views/Gallery/Album.cshtml)
   ============================================================================ */

/* Ported from the legacy site's Content/css/divinepride.css (.gallery block) — this class was
   never carried over here, so .gallery-item fell back to default `display: block` and every
   thumbnail rendered one per row instead of wrapping into a grid. The masonry-style row-span
   sizing in Album.cshtml's inline <script> (reading grid-auto-rows/grid-row-gap) also silently
   no-ops without this CSS to compute those values from. */
.gallery {
  display: grid;
  grid-column-gap: var(--space-2);
  grid-row-gap: var(--space-2);
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
  grid-auto-rows: auto;
  margin-bottom: var(--space-4);
}

.gallery img {
  max-width: 100%;
  display: block;
  box-shadow: 0 0 6px var(--accent);
  transition: box-shadow var(--transition-slow);
}

.gallery img:hover {
  box-shadow: 0 0 24px var(--accent);
}

.gallery .content {
  padding: var(--space-1);
}

.gallery .gallery-item {
  transition: transform var(--transition-slow);
  cursor: pointer;
}

.gallery .gallery-item:hover {
  transform: scale(1.025);
}

@media (max-width: 600px) {
  .gallery {
    grid-template-columns: repeat(auto-fill, minmax(30%, 1fr));
  }
}

@media (max-width: 400px) {
  .gallery {
    grid-template-columns: repeat(auto-fill, minmax(50%, 1fr));
  }
}

/* Lightbox — Album.cshtml's script toggles .full on a clicked .gallery-item */
.gallery-item.full {
  position: fixed;
  inset: 0;
  z-index: 1000;
}

.gallery-item.full .content {
  background-color: rgba(0, 0, 0, 0.85);
  height: 100%;
  width: 100%;
  display: grid;
  padding: 0;
}

.gallery-item.full .content img {
  max-width: 100%;
  max-height: 100%;
  margin: auto;
  box-shadow: none;
}
