/* ============================================================================
 * HoL Dune Portal — player-facing skin
 * Scope: body.portal-page (mirrors body.admin-page convention)
 * Design system: composes tokens from /admin/static/css/design-system.css.
 * NO hardcoded hex/rgb in this file — token vocabulary only.
 * Posture per P4-EXECUTION-BRIEF §6: lighter feel via softer tokens
 * (bg-elevated as page bg, sans-serif default, larger radius, more spacing).
 * Mobile-first; widens at 768px.
 * ============================================================================ */

/* ===========================================================================
 * DUNE-THEMATIC THEME SYSTEM (Phase A, 2026-06-05)
 * Two looks driven by <html data-theme>:
 *   night (default) - desert after dark; mirrors the in-game CHOAM exchange
 *                     (deep warm charcoal, spice-amber accents, gold numerics).
 *   day             - sun-bleached desert noon; warm parchment/sand surfaces.
 * We RE-POINT the design-system semantic tokens (--bg*, --text*, --accent*,
 * --border*) at portal scope so every existing component re-themes for free.
 * Palette hex belongs HERE in the token layer; component rules below stay
 * token-only. Premium portal-only tokens use the --p-* namespace.
 * --------------------------------------------------------------------------- */

/* NIGHT (default). data-theme is set on <html> by the no-FOUC script in base.html. */
html[data-theme="night"] body.portal-page,
body.portal-page {
  --bg:            #0c0a07;
  --bg-deep:       #080705;
  --bg-elevated:   #15110b;   /* area behind cards (old "page bg") */
  --bg-card:       #1b160e;   /* sandstone card surface */
  --border:        #352c1d;
  --border-strong: #4d3f29;
  --border-subtle: #241d13;
  --text:          #ece3d2;   /* warm parchment ink */
  --text-muted:    #9c8e74;
  --accent:        #d4891c;   /* spice */
  --accent-bright: #f5a23a;
  --accent-soft:   #a86916;
  --accent-glow:   rgba(212, 137, 28, 0.30);
  --green:         #5fcf6b;
  --red:           #d65a44;
  --yellow:        #e8c14a;
  --info:          #5aa9d6;
  --success-bg:    rgba(95, 207, 107, 0.10);
  --warning-bg:    rgba(232, 193, 74, 0.10);
  --error-bg:      rgba(214, 90, 68, 0.10);
  --info-bg:       rgba(90, 169, 214, 0.10);
  --shadow-card:    0 2px 10px rgba(0, 0, 0, 0.45);
  --shadow-overlay: 0 8px 28px rgba(0, 0, 0, 0.55);
  --shadow-modal:   0 16px 48px rgba(0, 0, 0, 0.65), 0 0 0 1px var(--border-strong);

  /* portal-only premium tokens */
  --p-violet:       #8a6bbf;          /* in-game selection highlight */
  --p-violet-soft:  rgba(138, 107, 191, 0.16);
  --p-rail-bg:      linear-gradient(180deg, #15110b 0%, #100c07 100%);
  --p-page-bg:      radial-gradient(125% 105% at 50% -8%, #1a140c 0%, #0c0a07 46%, #070603 100%);
  --p-hero-wash:    linear-gradient(135deg, rgba(212,137,28,0.16), rgba(138,107,191,0.10) 60%, transparent);
  --p-panel-edge:   inset 0 1px 0 rgba(245,162,58,0.06);
  --p-rule:         linear-gradient(90deg, var(--accent), transparent);
  --p-scrim:        rgba(8, 6, 3, 0.72);
}

/* DAY - sun-bleached desert noon. */
html[data-theme="day"] body.portal-page {
  --bg:            #e7d8b8;
  --bg-deep:       #d3bf95;
  --bg-elevated:   #e9dcc0;
  --bg-card:       #f6efdd;
  --border:        #cdb98f;
  --border-strong: #b69d6c;
  --border-subtle: #ddcca6;
  --text:          #2c2215;
  --text-muted:    #6f6147;
  --accent:        #b3700f;
  --accent-bright: #c9851a;
  --accent-soft:   #caa256;
  --accent-glow:   rgba(179, 112, 15, 0.22);
  --green:         #3a8f44;
  --red:           #b8472f;
  --yellow:        #a9821a;
  --info:          #2f7aa6;
  --success-bg:    rgba(58, 143, 68, 0.12);
  --warning-bg:    rgba(169, 130, 26, 0.14);
  --error-bg:      rgba(184, 71, 47, 0.12);
  --info-bg:       rgba(47, 122, 166, 0.12);
  --shadow-card:    0 2px 10px rgba(95, 70, 24, 0.16);
  --shadow-overlay: 0 8px 26px rgba(95, 70, 24, 0.22);
  --shadow-modal:   0 16px 44px rgba(95, 70, 24, 0.28), 0 0 0 1px var(--border-strong);

  --p-violet:       #6b4fa0;
  --p-violet-soft:  rgba(107, 79, 160, 0.14);
  --p-rail-bg:      linear-gradient(180deg, #efe4cb 0%, #e4d4b1 100%);
  --p-page-bg:      radial-gradient(125% 105% at 50% -8%, #f3e9d2 0%, #e7d8b8 50%, #d8c6a0 100%);
  --p-hero-wash:    linear-gradient(135deg, rgba(179,112,15,0.16), rgba(107,79,160,0.08) 60%, transparent);
  --p-panel-edge:   inset 0 1px 0 rgba(255,255,255,0.5);
  --p-rule:         linear-gradient(90deg, var(--accent), transparent);
  --p-scrim:        rgba(247, 239, 221, 0.78);
}

/* ATREIDES — emerald field, hawk gold. Dark mode, night base.
 * Palette grounded in the in-game Atreides banner: deep navy-green surfaces,
 * Atreides teal-emerald midtones, gold sigil accent. */
html[data-theme="atreides"] body.portal-page {
  --bg:            #090e0b;
  --bg-deep:       #060908;
  --bg-elevated:   #0e1610;
  --bg-card:       #131c15;
  --border:        #1d3020;
  --border-strong: #2c4532;
  --border-subtle: #141f16;
  --text:          #e4ede5;   /* cool off-white, faint green breath */
  --text-muted:    #6a8f6e;
  --accent:        #c49e4c;   /* Atreides hawk gold */
  --accent-bright: #d9b560;
  --accent-soft:   #967a38;
  --accent-glow:   rgba(196, 158, 76, 0.26);
  --green:         #50cf74;
  --red:           #d65a44;
  --yellow:        #e8c14a;
  --info:          #5aa9d6;
  --success-bg:    rgba(80, 207, 116, 0.10);
  --warning-bg:    rgba(232, 193, 74, 0.10);
  --error-bg:      rgba(214, 90, 68, 0.10);
  --info-bg:       rgba(90, 169, 214, 0.10);
  --shadow-card:    0 2px 10px rgba(0, 0, 0, 0.52);
  --shadow-overlay: 0 8px 28px rgba(0, 0, 0, 0.58);
  --shadow-modal:   0 16px 48px rgba(0, 0, 0, 0.68), 0 0 0 1px var(--border-strong);

  --p-violet:       #7f62b0;
  --p-violet-soft:  rgba(127, 98, 176, 0.14);
  --p-rail-bg:      linear-gradient(180deg, #0e1610 0%, #090e0b 100%);
  --p-page-bg:      radial-gradient(125% 105% at 50% -8%, #112015 0%, #090e0b 46%, #050807 100%);
  --p-hero-wash:    linear-gradient(135deg, rgba(18,78,52,0.20), rgba(196,158,76,0.10) 60%, transparent);
  --p-panel-edge:   inset 0 1px 0 rgba(196,158,76,0.06);
  --p-rule:         linear-gradient(90deg, var(--accent), transparent);
  --p-scrim:        rgba(6, 9, 8, 0.76);
  --p-house-sigil:  url("/admin/static/img/factions/atreides.png");
}

/* HARKONNEN — industrial black, blood red. Dark mode, night base.
 * Palette grounded in the in-game Harkonnen banner: true blacks, deep crimson
 * surfaces, and the game's cold blood-red accent. */
html[data-theme="harkonnen"] body.portal-page {
  --bg:            #0c0304;
  --bg-deep:       #080102;
  --bg-elevated:   #130507;
  --bg-card:       #190608;
  --border:        #330a0b;
  --border-strong: #4e1011;
  --border-subtle: #220709;
  --text:          #f0e5e5;   /* warm off-white, faint red warmth */
  --text-muted:    #9c6a6a;
  --accent:        #c42020;   /* Harkonnen blood — borders/rules/buttons */
  --accent-bright: #f04040;   /* lifted for text: 5.1:1 on bg-card, same hue */
  --accent-soft:   #8e1515;
  --accent-glow:   rgba(196, 32, 32, 0.28);
  --green:         #5fcf6b;
  --red:           #e05050;
  --yellow:        #e8c14a;
  --info:          #5aa9d6;
  --success-bg:    rgba(95, 207, 107, 0.10);
  --warning-bg:    rgba(232, 193, 74, 0.10);
  --error-bg:      rgba(224, 80, 80, 0.14);
  --info-bg:       rgba(90, 169, 214, 0.10);
  --shadow-card:    0 2px 10px rgba(0, 0, 0, 0.58);
  --shadow-overlay: 0 8px 30px rgba(0, 0, 0, 0.62);
  --shadow-modal:   0 16px 48px rgba(0, 0, 0, 0.72), 0 0 0 1px var(--border-strong);

  --p-violet:       #8a6bbf;
  --p-violet-soft:  rgba(138, 107, 191, 0.12);
  --p-rail-bg:      linear-gradient(180deg, #130507 0%, #0c0304 100%);
  --p-page-bg:      radial-gradient(125% 105% at 50% -8%, #1e0508 0%, #0c0304 46%, #060102 100%);
  --p-hero-wash:    linear-gradient(135deg, rgba(80,8,12,0.28), rgba(196,32,32,0.12) 60%, transparent);
  --p-panel-edge:   inset 0 1px 0 rgba(196,32,32,0.06);
  --p-rule:         linear-gradient(90deg, var(--accent), transparent);
  --p-scrim:        rgba(8, 1, 2, 0.78);
  --p-house-sigil:  url("/admin/static/img/factions/harkonnen.png");
}

/* Shared premium tokens (theme-independent). */
body.portal-page {
  --p-rail-w: 234px;
  --p-tabbar-h: 60px;
  --p-content-max: 1080px;
  --font-display: "Cinzel", "Trajan Pro", "Optima", "Palatino Linotype", Georgia, serif;
}

/* ---------------------------------------------------------------------------
 * Page shell
 * --------------------------------------------------------------------------- */
body.portal-page {
  margin: 0;
  min-height: 100vh;
  background: var(--p-page-bg) fixed, var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body.portal-page * {
  box-sizing: border-box;
}

body.portal-page a {
  color: var(--accent-bright);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  transition: color var(--motion-fast) var(--ease-in-out);
}

body.portal-page a:hover {
  color: var(--accent);
}

body.portal-page :focus-visible {
  outline: 2px solid var(--accent-bright);
  outline-offset: 3px;
  border-radius: var(--radius-md);
}

body.portal-page .sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

body.portal-page .mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
 * Header (player-facing — NOT the admin terminal chrome)
 * --------------------------------------------------------------------------- */
body.portal-page .portal-header {
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
  padding: var(--space-4) var(--space-5);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

body.portal-page .portal-header__brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
}

body.portal-page .portal-header__brand:hover {
  color: var(--accent-bright);
}

body.portal-page .portal-header__brand-mark {
  display: inline-block;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  object-fit: cover;
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent-glow);
}

body.portal-page .portal-header__user {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

body.portal-page .portal-header__user-name {
  color: var(--text);
  font-weight: 600;
}

/* ---------------------------------------------------------------------------
 * Layout
 * --------------------------------------------------------------------------- */
body.portal-page .portal-main {
  flex: 1;
  width: 100%;
  max-width: 560px;          /* single-column mobile-first */
  margin: 0 auto;
  padding: var(--space-6) var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

body.portal-page .portal-footer {
  background: var(--bg-card);
  border-top: 1px solid var(--border);
  padding: var(--space-5) var(--space-5);
  text-align: center;
  font-size: var(--text-sm);
  color: var(--text-muted);
}

body.portal-page .portal-footer a {
  color: var(--text-muted);
}

body.portal-page .portal-footer a:hover {
  color: var(--accent-bright);
}

/* Widen on tablet+ */
@media (min-width: 768px) {
  body.portal-page .portal-main {
    max-width: 720px;
    padding: var(--space-8) var(--space-7);
    gap: var(--space-7);
  }

  body.portal-page .portal-header {
    padding: var(--space-4) var(--space-7);
  }

  body.portal-page .portal-footer {
    padding: var(--space-6) var(--space-7);
  }
}

/* ---------------------------------------------------------------------------
 * Disclosure banner (mandatory verbatim copy on landing + dashboard)
 * --------------------------------------------------------------------------- */
body.portal-page .portal-banner {
  background: var(--info-bg);
  border: 1px solid var(--info);
  border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  font-size: var(--text-sm);
  color: var(--text);
  line-height: 1.6;
}

body.portal-page .portal-banner strong {
  color: var(--info);
  font-weight: 600;
}

/* ---------------------------------------------------------------------------
 * Card — generously padded, soft corners (vs admin's tight terminal cards)
 * --------------------------------------------------------------------------- */
body.portal-page .portal-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: var(--space-6);
  box-shadow: var(--shadow-card);
}

body.portal-page .portal-card + .portal-card {
  margin-top: 0;            /* gap handled by parent flex */
}

body.portal-page .portal-card__title {
  margin: 0 0 var(--space-3) 0;
  font-family: var(--font-sans);
  font-size: var(--text-xl);
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
}

body.portal-page .portal-card__subtitle {
  margin: 0 0 var(--space-5) 0;
  font-size: var(--text-sm);
  color: var(--text-muted);
  line-height: 1.6;
}

body.portal-page .portal-card__fine-print {
  margin-top: var(--space-5);
  margin-bottom: 0;
}

body.portal-page .portal-card__body > * + * {
  margin-top: var(--space-4);
}

@media (min-width: 768px) {
  body.portal-page .portal-card {
    padding: var(--space-7);
  }
  body.portal-page .portal-card__title {
    font-size: var(--text-2xl);
  }
}

/* ---------------------------------------------------------------------------
 * Buttons — 44px+ touch targets, softer corners
 * --------------------------------------------------------------------------- */
body.portal-page .portal-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 44px;
  padding: var(--space-3) var(--space-6);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: 600;
  line-height: 1.2;
  color: var(--text);
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--motion-fast) var(--ease-in-out),
              border-color var(--motion-fast) var(--ease-in-out),
              color var(--motion-fast) var(--ease-in-out),
              transform var(--motion-instant) var(--ease-in-out);
}

body.portal-page .portal-btn:hover {
  border-color: var(--accent-bright);
  background: color-mix(in srgb, var(--accent-bright) 8%, transparent);
}

body.portal-page .portal-btn:active {
  transform: translateY(1px);
}

body.portal-page .portal-btn:disabled,
body.portal-page .portal-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

body.portal-page .portal-btn[aria-busy="true"] {
  opacity: 0.7;
  cursor: progress;
}

body.portal-page .portal-btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--bg-deep);
}

body.portal-page .portal-btn--primary:hover {
  background: var(--accent-bright);
  border-color: var(--accent-bright);
  color: var(--bg-deep);
}

body.portal-page .portal-btn--discord {
  background: var(--info);
  border-color: var(--info);
  color: var(--bg-deep);
  font-weight: 700;
  width: 100%;
}

body.portal-page .portal-btn--discord:hover {
  background: var(--info);
  border-color: var(--info);
  color: var(--bg-deep);
  filter: brightness(1.1);
}

body.portal-page .portal-btn--ghost {
  border-color: var(--border);
  color: var(--text-muted);
}

body.portal-page .portal-btn--ghost:hover {
  border-color: var(--border-strong);
  color: var(--text);
  background: transparent;
}

body.portal-page .portal-btn--danger {
  color: var(--red);
  border-color: var(--red);
}

body.portal-page .portal-btn--danger:hover {
  background: var(--error-bg);
  color: var(--red);
}

body.portal-page .portal-btn--block {
  width: 100%;
}

body.portal-page .portal-btn--sm {
  min-height: 36px;
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
}

body.portal-page .portal-btn-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

@media (min-width: 768px) {
  body.portal-page .portal-btn-row {
    flex-direction: row;
    justify-content: flex-end;
    align-items: center;
  }
  body.portal-page .portal-btn-row--start {
    justify-content: flex-start;
  }
}

/* ---------------------------------------------------------------------------
 * Form fields — sans-serif, generous, mobile-first
 * --------------------------------------------------------------------------- */
body.portal-page .portal-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

body.portal-page .portal-field + .portal-field {
  margin-top: var(--space-4);
}

body.portal-page .portal-label {
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text);
  letter-spacing: 0;
  text-transform: none;
}

body.portal-page .portal-input,
body.portal-page input[type="text"],
body.portal-page input[type="search"],
body.portal-page input[type="number"],
body.portal-page input[type="email"] {
  width: 100%;
  min-height: 44px;
  padding: var(--space-3) var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  transition: border-color var(--motion-fast) var(--ease-in-out);
}

body.portal-page .portal-input:hover {
  border-color: var(--border-strong);
}

body.portal-page .portal-input:focus {
  outline: none;
  border-color: var(--accent);
}

body.portal-page .portal-input[aria-invalid="true"] {
  border-color: var(--red);
}

body.portal-page .portal-field__hint {
  font-size: var(--text-xs);
  color: var(--text-muted);
}

body.portal-page .portal-field__hint--error {
  color: var(--red);
}

/* Radio group — large touch targets, card-like choices */
body.portal-page .portal-radio-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

body.portal-page .portal-radio {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 56px;
  padding: var(--space-3) var(--space-4);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  color: var(--text);
  transition: border-color var(--motion-fast) var(--ease-in-out),
              background var(--motion-fast) var(--ease-in-out);
}

body.portal-page .portal-radio:hover {
  border-color: var(--border-strong);
}

body.portal-page .portal-radio input[type="radio"] {
  width: 20px;
  height: 20px;
  margin: 0;
  accent-color: var(--accent);
  flex-shrink: 0;
}

body.portal-page .portal-radio:has(input[type="radio"]:checked) {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}

body.portal-page .portal-radio:has(input[type="radio"]:focus-visible) {
  outline: 2px solid var(--accent-bright);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
 * Inline message (success / error / warning / info)
 * --------------------------------------------------------------------------- */
body.portal-page .portal-msg {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  font-size: var(--text-sm);
  line-height: 1.6;
}

body.portal-page .portal-msg--success {
  background: var(--success-bg);
  border-color: var(--green);
  color: var(--green);
}

body.portal-page .portal-msg--warning {
  background: var(--warning-bg);
  border-color: var(--yellow);
  color: var(--yellow);
}

body.portal-page .portal-msg--error {
  background: var(--error-bg);
  border-color: var(--red);
  color: var(--red);
}

body.portal-page .portal-msg--info {
  background: var(--info-bg);
  border-color: var(--info);
  color: var(--info);
}

/* ---------------------------------------------------------------------------
 * Quiz layout
 * --------------------------------------------------------------------------- */
body.portal-page .portal-quiz__progress {
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  margin-bottom: var(--space-3);
}

body.portal-page .portal-quiz__question {
  margin: 0 0 var(--space-5) 0;
  font-family: var(--font-sans);
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--text);
  line-height: 1.4;
}

body.portal-page .portal-quiz__question-block {
  padding: var(--space-5) 0;
  border-top: 1px solid var(--border);
}

body.portal-page .portal-quiz__question-block:first-of-type {
  padding-top: 0;
  border-top: 0;
}

/* ---------------------------------------------------------------------------
 * Character picker — search + result list
 * --------------------------------------------------------------------------- */
body.portal-page .portal-search {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

@media (min-width: 768px) {
  body.portal-page .portal-search {
    flex-direction: row;
  }
  body.portal-page .portal-search .portal-input {
    flex: 1;
  }
}

body.portal-page .portal-char-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

body.portal-page .portal-char-list__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}

body.portal-page .portal-char-list__name {
  font-family: var(--font-mono);
  font-size: var(--text-base);
  color: var(--text);
  word-break: break-word;
}

body.portal-page .portal-char-list__meta {
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* ---------------------------------------------------------------------------
 * Dashboard — linked-character summary
 * --------------------------------------------------------------------------- */
body.portal-page .portal-dash__hero {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

body.portal-page .portal-dash__char-name {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-2xl);
  font-weight: 700;
  color: var(--accent-bright);
  letter-spacing: -0.01em;
  word-break: break-word;
}

body.portal-page .portal-dash__handle {
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* ---- unified player vitals card (identity + crest + live stats) ---- */
body.portal-page .portal-vitals__head {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}

body.portal-page .portal-vitals__id {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

/* Faction emblem disc (white-on-transparent PNG tinted to house color). */
body.portal-page .portal-vitals__crest {
  flex: 0 0 auto;
  width: 72px;
  height: 72px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-strong);
  background: var(--bg);
}
body.portal-page .portal-vitals__crest img {
  width: 56px;
  height: 56px;
  object-fit: contain;
}
/* House Atreides reads green; House Harkonnen reads red. Tint the white PNG. */
body.portal-page .portal-vitals__crest--atreides {
  border-color: rgba(120, 190, 120, 0.5);
  background: rgba(120, 190, 120, 0.08);
}
body.portal-page .portal-vitals__crest--atreides img {
  filter: brightness(0) saturate(100%) invert(74%) sepia(18%) saturate(640%) hue-rotate(70deg) brightness(95%);
}
body.portal-page .portal-vitals__crest--harkonnen {
  border-color: rgba(210, 90, 80, 0.5);
  background: rgba(210, 90, 80, 0.08);
}
body.portal-page .portal-vitals__crest--harkonnen img {
  filter: brightness(0) saturate(100%) invert(45%) sepia(60%) saturate(2200%) hue-rotate(330deg) brightness(95%);
}
body.portal-page .portal-vitals__crest--none {
  color: var(--text-muted);
  font-size: var(--text-2xl);
}

/* online/offline status pill */
body.portal-page .portal-pill {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px 10px;
  border-radius: var(--radius-full);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  border: 1px solid var(--border-strong);
  color: var(--text-muted);
}
body.portal-page .portal-pill--online {
  color: var(--accent-bright);
  border-color: var(--accent);
  background: var(--accent-glow, rgba(255, 176, 0, 0.08));
}

/* account-link management: relink + unlink actions side by side */
body.portal-page .portal-link-manage__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3, 0.75rem);
  margin-top: var(--space-3, 0.75rem);
}
body.portal-page .portal-link-manage__form {
  margin: 0;
}

/* two-card row that collapses to a stack on mobile */
body.portal-page .portal-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}
@media (min-width: 768px) {
  body.portal-page .portal-row {
    grid-template-columns: 1fr 1fr;
    align-items: start;
  }
}

body.portal-page .portal-dash__stats {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}

@media (min-width: 768px) {
  body.portal-page .portal-dash__stats {
    grid-template-columns: repeat(3, 1fr);
  }
}

body.portal-page .portal-stat {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

body.portal-page .portal-stat__label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

body.portal-page .portal-stat__icon {
  width: 16px;
  height: 16px;
  object-fit: contain;
  opacity: 0.85;
  flex: 0 0 auto;
}

body.portal-page .portal-stat__value {
  font-family: var(--font-mono);
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  word-break: break-word;
}

body.portal-page .portal-stat__value--empty {
  color: var(--text-muted);
  font-weight: 400;
  font-style: italic;
}

/* Multi-character list (when discord_id has >1 link) */
body.portal-page .portal-link-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

body.portal-page .portal-link-list__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
}

body.portal-page .portal-link-list__item--active {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}

body.portal-page .portal-link-list__name {
  font-family: var(--font-mono);
  color: var(--text);
}

body.portal-page .portal-link-list__since {
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* ---------------------------------------------------------------------------
 * Error state
 * --------------------------------------------------------------------------- */
body.portal-page .portal-error {
  text-align: center;
  padding: var(--space-6) var(--space-4);
}

body.portal-page .portal-error__icon {
  font-size: var(--text-3xl);
  color: var(--accent);
  margin-bottom: var(--space-4);
  line-height: 1;
}

body.portal-page .portal-error__title {
  margin: 0 0 var(--space-3) 0;
  font-family: var(--font-sans);
  font-size: var(--text-xl);
  font-weight: 600;
  color: var(--text);
}

body.portal-page .portal-error__body {
  margin: 0 auto var(--space-5) auto;
  max-width: 44ch;
  color: var(--text-muted);
  line-height: 1.6;
}

body.portal-page .portal-error__countdown {
  display: inline-block;
  margin-top: var(--space-3);
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--yellow);
  background: var(--warning-bg);
  border: 1px solid var(--yellow);
  border-radius: var(--radius-md);
  font-variant-numeric: tabular-nums;
}

body.portal-page .portal-error__back {
  margin-top: var(--space-5);
}

/* ---------------------------------------------------------------------------
 * Discord icon (svg mask, no img tag needed)
 * --------------------------------------------------------------------------- */
body.portal-page .portal-discord-icon {
  display: inline-block;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

/* ---------------------------------------------------------------------------
 * Landsraad rewards page (/portal/landsraad)
 * --------------------------------------------------------------------------- */
body.portal-page .portal-breadcrumb {
  margin-bottom: var(--space-4);
}

body.portal-page .portal-link {
  color: var(--accent);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: 600;
  transition: color var(--motion-fast) var(--ease-in-out);
}

body.portal-page .portal-link:hover {
  color: var(--accent-bright);
}

body.portal-page .portal-landsraad__houses {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

body.portal-page .portal-landsraad__house {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

body.portal-page .portal-landsraad__house[open] {
  border-color: var(--border-strong);
}

body.portal-page .portal-landsraad__house-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4);
  cursor: pointer;
  list-style: none;
  user-select: none;
}

body.portal-page .portal-landsraad__house-summary::-webkit-details-marker {
  display: none;
}

body.portal-page .portal-landsraad__house-summary::before {
  content: "▸";
  color: var(--text-muted);
  font-size: var(--text-sm);
  transition: transform var(--motion-fast) var(--ease-in-out);
}

body.portal-page .portal-landsraad__house[open] .portal-landsraad__house-summary::before {
  transform: rotate(90deg);
}

body.portal-page .portal-landsraad__house-head {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

body.portal-page .portal-landsraad__house-name {
  font-weight: 600;
  color: var(--text);
}

body.portal-page .portal-landsraad__house-rep {
  font-size: var(--text-xs);
  font-weight: 400;
  color: var(--text-muted);
  line-height: 1.4;
}

body.portal-page .portal-landsraad__house-meta {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-sm);
}

body.portal-page .portal-landsraad__solari {
  color: var(--accent-bright);
  font-weight: 600;
}

body.portal-page .portal-landsraad__count {
  color: var(--text-muted);
}

body.portal-page .portal-landsraad__items {
  list-style: none;
  margin: 0;
  padding: 0 var(--space-4) var(--space-3) calc(var(--space-4) + var(--space-4));
  border-top: 1px solid var(--border);
}

body.portal-page .portal-landsraad__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  font-size: var(--text-sm);
  color: var(--text);
  border-bottom: 1px solid var(--border);
}

body.portal-page .portal-landsraad__item:last-child {
  border-bottom: none;
}

body.portal-page .portal-landsraad__item--solari .portal-landsraad__item-name {
  color: var(--accent-bright);
  font-weight: 600;
}

body.portal-page .portal-landsraad__item-amount {
  color: var(--text-muted);
  flex-shrink: 0;
}

/* ---------------------------------------------------------------------------
 * Landsraad BOARD (in-game-style house grid + hover tooltip + detail drawer)
 * --------------------------------------------------------------------------- */
body.portal-page .ls-board {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
}
@media (min-width: 560px) {
  body.portal-page .ls-board { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 860px) {
  body.portal-page .ls-board { grid-template-columns: repeat(5, 1fr); }
}

body.portal-page .ls-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-2);
  min-height: 116px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  cursor: pointer;
  font: inherit;
  color: var(--text);
  text-align: center;
  transition: transform var(--motion-fast) var(--ease-in-out),
              border-color var(--motion-fast) var(--ease-in-out),
              background var(--motion-fast) var(--ease-in-out),
              box-shadow var(--motion-fast) var(--ease-in-out);
}

body.portal-page .ls-tile:hover,
body.portal-page .ls-tile:focus-visible {
  transform: translateY(-2px);
  border-color: var(--accent);
  background: var(--bg-elevated);
  box-shadow: 0 6px 18px -8px var(--accent-glow, rgba(0, 0, 0, 0.5));
  outline: none;
}

body.portal-page .ls-tile--rewards {
  border-color: var(--border-strong);
  background: var(--bg-elevated);
}
body.portal-page .ls-tile--rewards:hover,
body.portal-page .ls-tile--rewards:focus-visible {
  border-color: var(--accent-bright);
}
body.portal-page .ls-tile--empty {
  opacity: 0.55;
}
body.portal-page .ls-tile--empty:hover,
body.portal-page .ls-tile--empty:focus-visible {
  opacity: 1;
}

body.portal-page .ls-tile__badge {
  position: absolute;
  top: -7px;
  right: -7px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  display: grid;
  place-items: center;
  background: var(--accent);
  color: var(--bg-deep, #000);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 700;
  border-radius: var(--radius-full);
  box-shadow: 0 0 0 2px var(--bg-card);
}

body.portal-page .ls-tile__sigil {
  position: relative;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: var(--text-sm);
  letter-spacing: 0.02em;
  color: var(--text-muted);
  z-index: 0;
}
body.portal-page .ls-tile__sigil::before {
  content: "";
  position: absolute;
  inset: 3px;
  transform: rotate(45deg);
  border: 1px solid var(--border-strong);
  background: rgba(255, 255, 255, 0.02);
  border-radius: 3px;
  z-index: -1;
}
body.portal-page .ls-tile--rewards .ls-tile__sigil {
  color: var(--accent-bright);
}
body.portal-page .ls-tile--rewards .ls-tile__sigil::before {
  border-color: var(--accent);
  background: var(--accent-glow, rgba(255, 176, 0, 0.08));
}

/* Real game house crest (white-on-transparent PNG). Sits where the monogram
   sigil would; dimmed on empty houses (inherits .ls-tile--empty opacity),
   amber-tinted on houses with rewards to match the highlighted tile. */
body.portal-page .ls-tile__crest {
  width: 46px;
  height: 46px;
  object-fit: contain;
  opacity: 0.85;
  transition: opacity var(--motion-fast) var(--ease-in-out),
              filter var(--motion-fast) var(--ease-in-out);
}
body.portal-page .ls-tile:hover .ls-tile__crest,
body.portal-page .ls-tile:focus-visible .ls-tile__crest {
  opacity: 1;
}
body.portal-page .ls-tile--rewards .ls-tile__crest {
  opacity: 1;
  filter: drop-shadow(0 0 4px var(--accent-glow, rgba(255, 176, 0, 0.35)));
}

body.portal-page .ls-tile__name {
  font-size: var(--text-xs);
  font-weight: 600;
  line-height: 1.2;
  color: var(--text);
  overflow-wrap: anywhere;
}

/* ---- shared item list (tooltip + drawer) ---- */
body.portal-page .ls-items {
  list-style: none;
  margin: var(--space-2) 0 0 0;
  padding: 0;
}
body.portal-page .ls-items__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 3px 0;
  font-size: var(--text-sm);
}
body.portal-page .ls-items__row--solari .ls-items__name { color: var(--accent-bright); font-weight: 600; }
body.portal-page .ls-items__name { color: var(--text); }
body.portal-page .ls-items__amt { color: var(--text-muted); flex-shrink: 0; }
body.portal-page .ls-items__more { font-size: var(--text-xs); color: var(--text-muted); padding-top: 3px; }

/* ---- hover tooltip ---- */
body.portal-page .ls-tooltip {
  position: fixed;
  z-index: 1100;
  max-width: 280px;
  padding: var(--space-3) var(--space-4);
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.7);
  pointer-events: none;
}
body.portal-page .ls-tooltip__name { font-weight: 700; color: var(--text); margin-bottom: 2px; }
body.portal-page .ls-tooltip__empty { font-size: var(--text-sm); color: var(--text-muted); }
body.portal-page .ls-tooltip__hint {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--text-muted);
  font-style: italic;
}

/* ---- detail drawer ---- */
body.portal-page .ls-drawer-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(0, 0, 0, 0.55);
  opacity: 0;
  transition: opacity var(--motion-fast) var(--ease-in-out);
}
body.portal-page .ls-drawer-overlay--open { opacity: 1; }

body.portal-page .ls-drawer {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 1001;
  height: 100%;
  width: min(440px, 92vw);
  display: flex;
  flex-direction: column;
  background: var(--bg-card);
  border-left: 1px solid var(--border-strong);
  box-shadow: -16px 0 40px -16px rgba(0, 0, 0, 0.8);
  transform: translateX(100%);
  transition: transform 0.2s var(--ease-in-out);
}
body.portal-page .ls-drawer--open { transform: translateX(0); }

body.portal-page .ls-drawer__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--border);
}
body.portal-page .ls-drawer__title {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--text);
}
body.portal-page .ls-drawer__close {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text-muted);
  font-size: var(--text-lg);
  line-height: 1;
  cursor: pointer;
  transition: color var(--motion-fast) var(--ease-in-out),
              border-color var(--motion-fast) var(--ease-in-out);
}
body.portal-page .ls-drawer__close:hover { color: var(--text); border-color: var(--border-strong); }

body.portal-page .ls-drawer__body {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--space-5) var(--space-6);
}
body.portal-page .ls-drawer__rep {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--border);
}
body.portal-page .ls-drawer__rep-label {
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}
body.portal-page .ls-drawer__rep-loc { color: var(--text); line-height: 1.5; }

body.portal-page .ls-drawer__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
body.portal-page .ls-drawer__chip {
  padding: 3px var(--space-3);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
body.portal-page .ls-drawer__chip--solari {
  color: var(--accent-bright);
  border-color: var(--accent);
}
body.portal-page .ls-drawer__hint { font-size: var(--text-sm); color: var(--text-muted); margin: 0 0 var(--space-2) 0; }
body.portal-page .ls-drawer__empty { color: var(--text-muted); }

body.portal-page .ls-drawer__section {
  margin: var(--space-5) 0 var(--space-3) 0;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
body.portal-page .ls-drawer__body > .ls-drawer__section:first-child,
body.portal-page .ls-drawer__rep + .ls-drawer__section { margin-top: 0; }

/* ---- previously-collected history (amount-0 rows) ---- */
body.portal-page .ls-items--claimed { opacity: 0.72; }
body.portal-page .ls-items__row--claimed .ls-items__name { color: var(--text-muted); }
body.portal-page .ls-items__row--claimed .ls-items__amt { color: var(--text-muted); font-weight: 400; }

/* ---- reward ladder (current-term, in-game board view) ---- */
body.portal-page .ls-ladder__progress { margin-bottom: var(--space-4); }
body.portal-page .ls-ladder__progress-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: var(--space-2);
  font-size: var(--text-xs);
}
body.portal-page .ls-ladder__progress-label {
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}
body.portal-page .ls-ladder__progress-val { color: var(--text); }
body.portal-page .ls-ladder__bar {
  height: 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  overflow: hidden;
}
body.portal-page .ls-ladder__bar-fill {
  height: 100%;
  background: var(--accent);
  border-radius: var(--radius-full);
  transition: width 0.3s var(--ease-in-out);
}

/* ============================================================================
 * Landsraad LIVE TERM BOARD (.lb-*) — the public great-house standings board.
 * Distinct from the per-player rewards board (.ls-*) above. Tile chrome uses
 * design-system tokens so House themes recolor it for free; the two GREAT-HOUSE
 * accents (Atreides green / Harkonnen red) are semantic faction identity and
 * reuse the same hexes the guild directory established (.gd-faction--*).
 * ========================================================================== */
body.portal-page .lb {
  --lb-atreides: #2f8f57;
  --lb-atreides-soft: rgba(47, 143, 87, 0.14);
  --lb-harkonnen: #d65a44;
  --lb-harkonnen-soft: rgba(214, 90, 68, 0.14);
}

/* ---- term header + countdown ---- */
body.portal-page .lb__head { margin-bottom: var(--space-5); }
body.portal-page .lb__termline {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
}
body.portal-page .lb__testtag {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1px 6px;
  vertical-align: middle;
}
body.portal-page .lb__countdown {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
}
body.portal-page .lb__countdown-label {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}
body.portal-page .lb__countdown-val {
  font-size: var(--text-md, 1rem);
  font-weight: 700;
  color: var(--accent-bright);
}
body.portal-page .lb__countdown--ended .lb__countdown-val { color: var(--text-muted); }
body.portal-page .lb__countdown-abs { display: none; }

/* ---- 3-column layout: rail | board | rail ---- */
body.portal-page .lb__layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
  align-items: start;
}
@media (min-width: 900px) {
  body.portal-page .lb__layout {
    grid-template-columns: minmax(168px, 210px) 1fr minmax(168px, 210px);
  }
}

/* ---- faction rails ---- */
body.portal-page .lb-rail {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-4);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  text-align: center;
}
body.portal-page .lb-rail--atreides { border-top: 2px solid var(--lb-atreides); }
body.portal-page .lb-rail--harkonnen { border-top: 2px solid var(--lb-harkonnen); }
body.portal-page .lb-rail__crest {
  width: 56px; height: 56px;
  display: grid; place-items: center;
}
body.portal-page .lb-rail__crest img { width: 56px; height: 56px; object-fit: contain; }
body.portal-page .lb-rail--atreides .lb-rail__crest { filter: drop-shadow(0 0 6px var(--lb-atreides-soft)); }
body.portal-page .lb-rail--harkonnen .lb-rail__crest { filter: drop-shadow(0 0 6px var(--lb-harkonnen-soft)); }
body.portal-page .lb-rail__crest-fallback {
  width: 100%; height: 100%;
  display: grid; place-items: center;
  font-family: var(--font-mono); font-weight: 700; font-size: var(--text-lg);
  color: var(--text-muted);
  border: 1px solid var(--border-strong); border-radius: var(--radius-md);
}
body.portal-page .lb-rail__name {
  font-size: var(--text-sm); font-weight: 600; color: var(--text); margin: 0;
}
body.portal-page .lb-rail__score {
  font-size: 2.4rem; font-weight: 800; line-height: 1; margin: var(--space-1) 0 0 0;
}
body.portal-page .lb-rail--atreides .lb-rail__score { color: var(--lb-atreides); }
body.portal-page .lb-rail--harkonnen .lb-rail__score { color: var(--lb-harkonnen); }
body.portal-page .lb-rail__score-label {
  font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-muted); margin: 0;
}
body.portal-page .lb-rail__contrib {
  width: 100%; margin-top: var(--space-3);
  padding-top: var(--space-3); border-top: 1px solid var(--border);
}
body.portal-page .lb-rail__contrib-head {
  font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-muted); margin: 0 0 var(--space-2) 0;
}
body.portal-page .lb-rail__guilds {
  list-style: none; margin: 0; padding: 0; counter-reset: lbg;
}
body.portal-page .lb-rail__guild {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-2); padding: 2px 0; font-size: var(--text-sm);
  counter-increment: lbg;
}
body.portal-page .lb-rail__guild-name {
  color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
body.portal-page .lb-rail__guild-name::before {
  content: counter(lbg) ". "; color: var(--text-muted); font-family: var(--font-mono);
}
body.portal-page .lb-rail__guild-amt { color: var(--text-muted); flex-shrink: 0; }
body.portal-page .lb-rail__vp {
  width: 100%; margin-top: var(--space-3); padding-top: var(--space-3);
  border-top: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 2px;
}
body.portal-page .lb-rail__vp-label {
  font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-muted);
}
body.portal-page .lb-rail__vp-val { font-size: var(--text-lg); font-weight: 700; color: var(--accent-bright); }

/* ---- the 5x5 tile grid ---- */
body.portal-page .lb-board {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-2);
}
body.portal-page .lb-tile {
  position: relative;
  display: flex; flex-direction: column; align-items: center;
  gap: 4px;
  padding: var(--space-3) 4px var(--space-2);
  min-height: 104px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer; font: inherit; color: var(--text); text-align: center;
  overflow: hidden;
  transition: transform var(--motion-fast) var(--ease-in-out),
              border-color var(--motion-fast) var(--ease-in-out),
              background var(--motion-fast) var(--ease-in-out);
}
body.portal-page .lb-tile:hover,
body.portal-page .lb-tile:focus-visible {
  transform: translateY(-2px);
  border-color: var(--accent);
  background: var(--bg-elevated);
  outline: none;
}
body.portal-page .lb-tile--contested { opacity: 0.92; }
body.portal-page .lb-tile--decided { background: var(--bg-elevated); }
body.portal-page .lb-tile--atreides { border-color: var(--lb-atreides); }
body.portal-page .lb-tile--harkonnen { border-color: var(--lb-harkonnen); }
/* winner corner flag */
body.portal-page .lb-tile__flag {
  position: absolute; top: 0; right: 0;
  width: 0; height: 0;
  border-style: solid; border-width: 0 18px 18px 0;
}
body.portal-page .lb-tile--atreides .lb-tile__flag { border-color: transparent var(--lb-atreides) transparent transparent; }
body.portal-page .lb-tile--harkonnen .lb-tile__flag { border-color: transparent var(--lb-harkonnen) transparent transparent; }
/* sysselraad gold ring */
body.portal-page .lb-tile--sysselraad { box-shadow: inset 0 0 0 2px var(--accent); }
body.portal-page .lb-tile__syss {
  position: absolute; top: 3px; left: 5px;
  font-size: 9px; color: var(--accent-bright); line-height: 1;
}
body.portal-page .lb-tile__crest { width: 40px; height: 40px; object-fit: contain; opacity: 0.9; }
body.portal-page .lb-tile:hover .lb-tile__crest { opacity: 1; }
body.portal-page .lb-tile__sigil {
  width: 40px; height: 40px; display: grid; place-items: center;
  font-family: var(--font-mono); font-weight: 700; font-size: var(--text-xs);
  color: var(--text-muted);
}
body.portal-page .lb-tile__name {
  font-size: var(--text-xs); font-weight: 600; line-height: 1.15;
  color: var(--text); overflow-wrap: anywhere;
}
body.portal-page .lb-tile__bars {
  display: flex; flex-direction: column; gap: 2px; width: 100%; margin-top: auto;
}
body.portal-page .lb-tile__bar {
  height: 3px; width: 100%;
  background: var(--bg-deep, rgba(0,0,0,0.4));
  border-radius: var(--radius-full); overflow: hidden;
}
body.portal-page .lb-tile__bar-fill { height: 100%; border-radius: var(--radius-full); }
body.portal-page .lb-tile__bar--atreides .lb-tile__bar-fill { background: var(--lb-atreides); }
body.portal-page .lb-tile__bar--harkonnen .lb-tile__bar-fill { background: var(--lb-harkonnen); }
body.portal-page .lb-tile__bar.is-leading { box-shadow: 0 0 0 1px rgba(255,255,255,0.12); }

/* ---- recent-terms history strip ---- */
body.portal-page .lb__history {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin: var(--space-5) 0 0 0; font-size: var(--text-xs); color: var(--text-muted);
}
body.portal-page .lb__history-dot {
  width: 10px; height: 10px; border-radius: var(--radius-full);
  display: inline-block; border: 1px solid var(--border-strong);
}
body.portal-page .lb__history-dot--atreides { background: var(--lb-atreides); }
body.portal-page .lb__history-dot--harkonnen { background: var(--lb-harkonnen); }

/* ---- tile detail drawer (mirrors .ls-drawer) ---- */
body.portal-page .lb-drawer-overlay {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(0, 0, 0, 0.55); opacity: 0;
  transition: opacity var(--motion-fast) var(--ease-in-out);
}
body.portal-page .lb-drawer-overlay--open { opacity: 1; }
body.portal-page .lb-drawer {
  position: fixed; top: 0; right: 0; z-index: 1001;
  height: 100%; width: min(440px, 92vw);
  display: flex; flex-direction: column;
  background: var(--bg-card); border-left: 1px solid var(--border-strong);
  box-shadow: -16px 0 40px -16px rgba(0, 0, 0, 0.8);
  transform: translateX(100%); transition: transform 0.2s var(--ease-in-out);
}
body.portal-page .lb-drawer--open { transform: translateX(0); }
body.portal-page .lb-drawer__header {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--border);
}
body.portal-page .lb-drawer__title { margin: 0; font-size: var(--text-lg); font-weight: 700; color: var(--text); }
body.portal-page .lb-drawer__close {
  flex-shrink: 0; width: 32px; height: 32px; display: grid; place-items: center;
  background: transparent; border: 1px solid var(--border); border-radius: var(--radius-md);
  color: var(--text-muted); font-size: var(--text-lg); line-height: 1; cursor: pointer;
}
body.portal-page .lb-drawer__close:hover { color: var(--text); border-color: var(--border-strong); }
body.portal-page .lb-drawer__body { padding: var(--space-5) var(--space-6); overflow-y: auto; }
body.portal-page .lb-drawer__meta { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4); }
body.portal-page .lb-drawer__chip {
  font-size: var(--text-xs); padding: 3px 9px; border-radius: var(--radius-full);
  background: var(--bg); border: 1px solid var(--border); color: var(--text-muted);
}
body.portal-page .lb-drawer__chip--atreides { color: var(--lb-atreides); border-color: var(--lb-atreides); background: var(--lb-atreides-soft); }
body.portal-page .lb-drawer__chip--harkonnen { color: var(--lb-harkonnen); border-color: var(--lb-harkonnen); background: var(--lb-harkonnen-soft); }
body.portal-page .lb-drawer__chip--syss { color: var(--accent-bright); border-color: var(--accent); }
body.portal-page .lb-drawer__rep { margin-bottom: var(--space-4); font-size: var(--text-sm); }
body.portal-page .lb-drawer__rep-label {
  display: block; font-size: var(--text-xs); text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 2px;
}
body.portal-page .lb-drawer__rep-loc { color: var(--text); line-height: 1.5; }
body.portal-page .lb-drawer__section {
  font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-muted); margin: var(--space-4) 0 var(--space-2) 0;
}
body.portal-page .lb-drawer__body > .lb-drawer__meta + .lb-drawer__section { margin-top: 0; }

/* progress block (both factions) */
body.portal-page .lb-prog__goal {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: var(--text-xs); color: var(--text-muted); margin-bottom: var(--space-2);
}
body.portal-page .lb-prog__row { margin-bottom: var(--space-3); }
body.portal-page .lb-prog__rowhead {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: var(--text-sm); margin-bottom: 3px;
}
body.portal-page .lb-prog__row--atreides .lb-prog__faction { color: var(--lb-atreides); font-weight: 600; }
body.portal-page .lb-prog__row--harkonnen .lb-prog__faction { color: var(--lb-harkonnen); font-weight: 600; }
body.portal-page .lb-prog__amt { color: var(--text-muted); }
body.portal-page .lb-prog__bar {
  height: 7px; background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius-full); overflow: hidden;
}
body.portal-page .lb-prog__bar-fill { height: 100%; border-radius: var(--radius-full); transition: width 0.3s var(--ease-in-out); }
body.portal-page .lb-prog__row--atreides .lb-prog__bar-fill { background: var(--lb-atreides); }
body.portal-page .lb-prog__row--harkonnen .lb-prog__bar-fill { background: var(--lb-harkonnen); }

body.portal-page .lb-drawer__mine {
  display: flex; justify-content: space-between; align-items: baseline;
  margin: var(--space-2) 0 0 0; padding: var(--space-2) var(--space-3);
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-md);
}
body.portal-page .lb-drawer__mine-label { font-size: var(--text-sm); color: var(--text-muted); }
body.portal-page .lb-drawer__mine-val { color: var(--accent-bright); font-weight: 700; }

/* term reward ladder */
body.portal-page .lb-ladder { list-style: none; margin: 0; padding: 0; }
body.portal-page .lb-ladder__row {
  display: grid; grid-template-columns: 16px auto 1fr; align-items: baseline;
  gap: var(--space-2); padding: 4px 0; font-size: var(--text-sm);
  border-bottom: 1px solid var(--border);
}
body.portal-page .lb-ladder__row:last-child { border-bottom: 0; }
body.portal-page .lb-ladder__mark { color: var(--accent-bright); font-weight: 700; }
body.portal-page .lb-ladder__row--reached { color: var(--text); }
body.portal-page .lb-ladder__threshold { color: var(--text-muted); }
body.portal-page .lb-ladder__reward { color: var(--text); }
body.portal-page .lb-ladder__qty { color: var(--text-muted); }

/* ---- section divider between board + rewards ---- */
body.portal-page .portal-section-title {
  font-size: var(--text-lg); font-weight: 700; color: var(--text);
  margin: var(--space-7, 2rem) 0 var(--space-4) 0;
  padding-bottom: var(--space-2); border-bottom: 1px solid var(--border);
}

/* ---- specialization tracks card (account dashboard) ---- */
body.portal-page .portal-spec__list {
  list-style: none;
  margin: var(--space-4) 0 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
body.portal-page .portal-spec__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}
body.portal-page .portal-spec__name {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text);
}
body.portal-page .portal-spec__icon {
  width: 18px;
  height: 18px;
  object-fit: contain;
  flex: 0 0 auto;
}
body.portal-page .portal-spec__lvl {
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
body.portal-page .portal-spec__cap { color: var(--text-muted); font-weight: 400; }
body.portal-page .portal-spec__bar {
  height: 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  overflow: hidden;
}
body.portal-page .portal-spec__bar-fill {
  height: 100%;
  background: var(--accent);
  border-radius: var(--radius-full);
  transition: width 0.3s var(--ease-in-out);
}

/* ---- journey & exploration card (account dashboard) ---- */
body.portal-page .portal-journey__arcs {
  list-style: none;
  margin: var(--space-4) 0 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
body.portal-page .portal-journey__arc {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--text);
  padding: 3px 9px;
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  white-space: nowrap;
}
body.portal-page .portal-journey__stats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}
body.portal-page .portal-journey__stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
body.portal-page .portal-journey__num {
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--accent-bright);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
body.portal-page .portal-journey__lbl {
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* ---- faction standing card (account dashboard) ---- */
body.portal-page .portal-faction__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-4) 0 var(--space-3) 0;
}
body.portal-page .portal-faction__crest {
  flex: 0 0 auto;
  width: 52px; height: 52px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: 1px solid var(--border);
}
body.portal-page .portal-faction__crest img { width: 44px; height: 44px; object-fit: contain; }
body.portal-page .portal-faction__crest--atreides  { background: rgba(60,140,90,0.16); }
body.portal-page .portal-faction__crest--harkonnen { background: rgba(170,50,50,0.16); }
body.portal-page .portal-faction__id { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
body.portal-page .portal-faction__name { font-size: var(--text-lg); font-weight: 700; color: var(--text); }
body.portal-page .portal-faction__rank { font-size: var(--text-sm); color: var(--text-muted); }
body.portal-page .portal-faction__standing {
  margin-left: auto;
  display: flex; align-items: center; gap: 5px;
  font-size: var(--text-lg); font-weight: 700; color: var(--text);
  font-variant-numeric: tabular-nums;
}
body.portal-page .portal-faction__bar {
  height: 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  overflow: hidden;
}
body.portal-page .portal-faction__bar-fill {
  height: 100%;
  background: var(--accent);
  border-radius: var(--radius-full);
  transition: width 0.3s var(--ease-in-out);
}

/* ---- Deep Desert spice map ---- */
body.portal-page .spice-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
  font-size: var(--text-sm);
  color: var(--text-muted);
}
body.portal-page .spice-legend__item { display: flex; align-items: center; gap: 7px; }
body.portal-page .spice-dot {
  width: 12px; height: 12px; border-radius: 50%; display: inline-block; flex: 0 0 auto;
}
body.portal-page .spice-dot--large  { background: #f0a020; box-shadow: 0 0 8px 1px rgba(240,160,32,0.6); }
body.portal-page .spice-dot--medium { background: #c87f2a; }
body.portal-page .spice-dot--small  { background: #8a6a3a; }

body.portal-page .spice-grid-wrap { overflow-x: auto; }
body.portal-page .spice-grid {
  border-collapse: collapse;
  margin: 0 auto;
  table-layout: fixed;
}
body.portal-page .spice-grid th {
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--text-muted);
  text-align: center;
  padding: 4px;
}
body.portal-page .spice-grid__corner { width: 28px; }
body.portal-page .spice-cell {
  position: relative;
  width: 40px; height: 40px;
  border: 1px solid var(--border);
  background: var(--bg);
  text-align: center;
  vertical-align: middle;
  padding: 0;
}
body.portal-page .spice-cell--large  { background: rgba(240,160,32,0.14); border-color: rgba(240,160,32,0.5); }
body.portal-page .spice-cell--medium { background: rgba(200,127,42,0.10); }
body.portal-page .spice-cell--small  { background: rgba(138,106,58,0.08); }
body.portal-page .spice-cell .spice-dot { margin: 0 auto; }

/* live active Large field: gold glow + pulsing ring overlay */
body.portal-page .spice-cell--active {
  background: rgba(255,196,64,0.30);
  border-color: #ffd166;
  box-shadow: inset 0 0 0 1px #ffd166, 0 0 10px 1px rgba(255,196,64,0.55);
}
body.portal-page .spice-cell__live {
  position: absolute; inset: 0; margin: auto;
  width: 12px; height: 12px; border-radius: 50%;
  background: #ffd166; box-shadow: 0 0 8px 2px rgba(255,209,102,0.9);
  animation: spice-live-pulse 1.6s ease-in-out infinite;
}
@keyframes spice-live-pulse {
  0%,100% { transform: scale(0.7); opacity: 0.85; }
  50%     { transform: scale(1.15); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  body.portal-page .spice-cell__live { animation: none; }
}
@media (max-width: 520px) {
  body.portal-page .spice-cell { width: 30px; height: 30px; }
}

/* live active-field banner */
body.portal-page .spice-active-banner { border-color: rgba(255,196,64,0.45); }
body.portal-page .spice-active-banner__title {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 8px; font-size: 1.05rem; color: #ffd166;
}
body.portal-page .spice-active-banner__pulse {
  width: 11px; height: 11px; border-radius: 50%;
  background: #ffd166; box-shadow: 0 0 8px 2px rgba(255,209,102,0.85);
  animation: spice-live-pulse 1.6s ease-in-out infinite;
}
body.portal-page .spice-active-banner__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
body.portal-page .spice-active-banner__item { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
body.portal-page .spice-active-banner__dim {
  font-weight: 600; font-size: 0.78rem; padding: 1px 8px; border-radius: 999px;
  border: 1px solid var(--border);
}
body.portal-page .spice-active-banner__dim--pve { color: #6fcf97; border-color: rgba(111,207,151,0.5); }
body.portal-page .spice-active-banner__dim--pvp { color: #eb6f6f; border-color: rgba(235,111,111,0.5); }
body.portal-page .spice-active-banner__conf {
  font-size: 0.72rem; opacity: 0.85; padding: 0 6px; border-radius: 999px; border: 1px solid var(--border);
}
body.portal-page .spice-active-banner__conf--confirmed { color: #6fcf97; font-weight: 600; }
body.portal-page .spice-active-banner__conf--high { color: #6fcf97; }
body.portal-page .spice-active-banner__conf--medium { color: #f0c674; }
body.portal-page .spice-active-banner__conf--low,
body.portal-page .spice-active-banner__conf--none { color: #b0905a; }

body.portal-page .ls-ladder__rows { list-style: none; margin: 0; padding: 0; }
body.portal-page .ls-ladder__row {
  display: grid;
  grid-template-columns: 20px auto 1fr;
  align-items: baseline;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--text-sm);
  opacity: 0.55;
}
body.portal-page .ls-ladder__row:last-child { border-bottom: none; }
body.portal-page .ls-ladder__row--reached { opacity: 1; }
body.portal-page .ls-ladder__mark {
  display: grid;
  place-items: center;
  color: var(--accent-bright);
  font-size: var(--text-sm);
  font-weight: 700;
}
body.portal-page .ls-ladder__threshold { color: var(--text-muted); flex-shrink: 0; }
body.portal-page .ls-ladder__reward { color: var(--text); overflow-wrap: anywhere; }
body.portal-page .ls-ladder__qty { color: var(--accent-bright); }

@media (prefers-reduced-motion: reduce) {
  body.portal-page .ls-tile,
  body.portal-page .ls-drawer,
  body.portal-page .ls-drawer-overlay { transition: none; }
  body.portal-page .ls-tile:hover,
  body.portal-page .ls-tile:focus-visible { transform: none; }
}

/* =========================================================================
   Storage containers (GET /portal/containers)
   Reuses the .ls-drawer / .ls-drawer-overlay shell from the Landsraad board.
   ========================================================================= */
body.portal-page .cont-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
}
@media (min-width: 560px) {
  body.portal-page .cont-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 860px) {
  body.portal-page .cont-grid { grid-template-columns: repeat(4, 1fr); }
}

body.portal-page .cont-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  gap: 2px;
  padding: var(--space-4) var(--space-3);
  min-height: 96px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  cursor: pointer;
  font: inherit;
  color: var(--text);
  text-align: left;
  transition: transform var(--motion-fast) var(--ease-in-out),
              border-color var(--motion-fast) var(--ease-in-out),
              background var(--motion-fast) var(--ease-in-out),
              box-shadow var(--motion-fast) var(--ease-in-out);
}
body.portal-page .cont-tile:hover,
body.portal-page .cont-tile:focus-visible {
  transform: translateY(-2px);
  border-color: var(--accent);
  background: var(--bg-elevated);
  box-shadow: 0 6px 18px -8px var(--accent-glow, rgba(0, 0, 0, 0.5));
  outline: none;
}
body.portal-page .cont-tile--filled { border-color: var(--border-strong); background: var(--bg-elevated); }
body.portal-page .cont-tile--empty { opacity: 0.6; }
body.portal-page .cont-tile--empty:hover,
body.portal-page .cont-tile--empty:focus-visible { opacity: 1; }

/* CHOAM bank tile — pinned first, accented as the account-wide store. */
body.portal-page .cont-tile--bank {
  opacity: 1;
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-elevated));
}
body.portal-page .cont-tile--bank .cont-tile__count {
  background: var(--accent);
  color: var(--bg-deep);
}

/* Vehicle storage tiles — readable (Hagga/Overland) get a subtle distinct edge. */
body.portal-page .cont-tile--vehicle { border-color: var(--border-strong); }
/* Deep Desert vehicles: cargo not in the DB, so non-interactive + muted. */
body.portal-page .cont-tile--unavailable {
  opacity: 0.55;
  cursor: not-allowed;
  border-style: dashed;
}
body.portal-page .cont-tile--unavailable:hover { opacity: 0.7; }
body.portal-page .cont-tile__count--na { background: var(--border-strong); color: var(--text-muted); }
body.portal-page .cont-tile__map--na { color: var(--text-muted); font-style: italic; }

/* Tile icon (storage container / vehicle render) — the visual hero of the tile;
   the type name drops to a small subtitle when an icon is present. */
body.portal-page .cont-tile__icon {
  display: block;
  width: 56px;
  height: 56px;
  margin: 2px auto 4px;
  object-fit: contain;
  filter: drop-shadow(0 2px 4px rgba(0,0,0,0.5));
}
body.portal-page .cont-tile--unavailable .cont-tile__icon { opacity: 0.6; }
body.portal-page .cont-tile__name--sub {
  font-size: var(--text-xs);
  color: var(--text-muted);
  font-weight: 500;
}

body.portal-page .cont-tile__count {
  position: absolute;
  top: -7px;
  right: -7px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  display: grid;
  place-items: center;
  background: var(--accent);
  color: var(--bg-deep, #000);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 700;
  border-radius: var(--radius-full);
  box-shadow: 0 0 0 2px var(--bg-card);
}
body.portal-page .cont-tile--empty .cont-tile__count { background: var(--border-strong); color: var(--text-muted); }

body.portal-page .cont-tile__name {
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.25;
  color: var(--text);
  overflow-wrap: anywhere;
}
body.portal-page .cont-tile__type {
  font-size: var(--text-xs);
  color: var(--text-muted);
}
body.portal-page .cont-tile__map {
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  font-family: var(--font-mono);
  color: var(--text-muted);
  opacity: 0.85;
}

/* ---- items inside the drawer ---- */
body.portal-page .cont-drawer__loading { padding: var(--space-4) 0; color: var(--text-muted); }
body.portal-page .cont-items__meta {
  font-size: var(--text-sm);
  color: var(--text-muted);
  margin-bottom: var(--space-3);
}
body.portal-page .cont-items__stale {
  margin-left: var(--space-2);
  padding: 1px 6px;
  font-size: var(--text-xs);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  color: var(--text-muted);
}
body.portal-page .cont-items__filter { margin-bottom: var(--space-3); }
body.portal-page .cont-items__search {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text);
  font: inherit;
  font-size: var(--text-sm);
}
body.portal-page .cont-items__search:focus { outline: none; border-color: var(--accent); }

body.portal-page .cont-items { list-style: none; margin: 0; padding: 0; }
body.portal-page .cont-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border);
}
body.portal-page .cont-item:last-child { border-bottom: 0; }
body.portal-page .cont-item__icon {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  object-fit: contain;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 3px;
}
body.portal-page .cont-item__name {
  flex: 1 1 auto;
  font-size: var(--text-sm);
  color: var(--text);
  overflow-wrap: anywhere;
}
body.portal-page .cont-item__meta {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
body.portal-page .cont-item__qty { font-family: var(--font-mono); color: var(--text-muted); }
body.portal-page .cont-item__quality {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 700;
  padding: 1px 5px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-strong);
  color: var(--text-muted);
}
/* Quality tiers: common -> legendary. --qr-fill drives the radial grade
   gauge (grade/5 of the circle), matching the in-game tile indicator. */
body.portal-page .quality-tier-1 { color: #9aa6b2; border-color: #9aa6b2; --qr-fill: 72deg; }
body.portal-page .quality-tier-2 { color: #4caf78; border-color: #4caf78; --qr-fill: 144deg; }
body.portal-page .quality-tier-3 { color: #4f8cc9; border-color: #4f8cc9; --qr-fill: 216deg; }
body.portal-page .quality-tier-4 { color: #9a6fd0; border-color: #9a6fd0; --qr-fill: 288deg; }
body.portal-page .quality-tier-5 { color: var(--accent-bright); border-color: var(--accent); --qr-fill: 360deg; }

/* Durability meter — labeled "DUR", fills green (full) -> amber -> red (damaged),
   with a % readout. The is-low/is-mid/is-high state lives on the parent so both
   the fill and the % text take the same colour. */
body.portal-page .cont-item__dura {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
body.portal-page .cont-item__dura-tag {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--text-muted);
}
body.portal-page .cont-item__dura-bar {
  width: 64px;
  height: 7px;
  background: var(--bg-deep, rgba(0,0,0,0.4));
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  overflow: hidden;
}
body.portal-page .cont-item__dura-fill { display: block; height: 100%; background: var(--green, #4caf78); }
body.portal-page .cont-item__dura-pct {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 700;
  min-width: 30px;
  text-align: right;
  color: var(--green, #4caf78);
}
body.portal-page .cont-item__dura.is-high .cont-item__dura-fill { background: var(--green, #4caf78); }
body.portal-page .cont-item__dura.is-high .cont-item__dura-pct  { color: var(--green, #4caf78); }
body.portal-page .cont-item__dura.is-mid  .cont-item__dura-fill { background: var(--accent, #e0a000); }
body.portal-page .cont-item__dura.is-mid  .cont-item__dura-pct  { color: var(--accent-bright, #e0a000); }
body.portal-page .cont-item__dura.is-low  .cont-item__dura-fill { background: var(--red, #d05050); }
body.portal-page .cont-item__dura.is-low  .cont-item__dura-pct  { color: var(--red, #d05050); }

body.portal-page .cont-items__empty-filter { color: var(--text-muted); font-size: var(--text-sm); padding-top: var(--space-3); }

body.portal-page .cont-items__pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
}
body.portal-page .cont-items__pager-label { font-size: var(--text-xs); color: var(--text-muted); }

/* ---- quality grade badge on the item icon (Mk6 / unique only; quality 1-5) ---- */
body.portal-page .cont-item__icon-wrap {
  position: relative;
  flex-shrink: 0;
  display: inline-flex;
  line-height: 0;
}
body.portal-page .cont-item__grade {
  position: absolute;
  bottom: -5px;
  right: -5px;
  width: 19px;
  height: 19px;
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  color: var(--text);                 /* overridden by quality-tier-N */
  /* Radial grade gauge, like the in-game tile: a ring that fills grade/5
     in the tier color (--qr-fill from quality-tier-N), faint track for the
     unfilled remainder, solid disc under the number. */
  background:
    radial-gradient(circle, var(--bg-card) 0 57%, transparent 58%),
    conic-gradient(currentColor var(--qr-fill, 360deg), rgba(128, 128, 128, 0.35) 0);
  border-radius: 50%;
  box-shadow: 0 0 0 1.5px var(--bg-card);
}
/* Inline variant: same gauge sitting in a flex row (market price ladder). */
body.portal-page .cont-item__grade--inline { position: static; flex-shrink: 0; }

/* ---- wider, adaptive layout on desktop (narrow stays narrow on mobile) ---- */
@media (min-width: 1024px) {
  body.portal-page .portal-main { max-width: 900px; }
}
@media (min-width: 1366px) {
  body.portal-page .portal-main { max-width: 1040px; }
}
@media (min-width: 1100px) {
  body.portal-page .cont-grid { grid-template-columns: repeat(5, 1fr); }
}
/* roomier item drawer on desktop so icon + name + DUR meter have space */
@media (min-width: 900px) {
  body.portal-page .ls-drawer { width: min(560px, 92vw); }
}

/* ---- cross-container item search ---- */
body.portal-page .cont-search__input {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  color: var(--text);
  font: inherit;
  font-size: var(--text-base);
}
body.portal-page .cont-search__input:focus { outline: none; border-color: var(--accent); }
body.portal-page .cont-search__panel:not(:empty) { margin-top: var(--space-4); }
body.portal-page .cont-search__hint { color: var(--text-muted); font-size: var(--text-sm); margin: 0; }
body.portal-page .cont-search__count {
  color: var(--text-muted);
  font-size: var(--text-sm);
  margin: 0 0 var(--space-3) 0;
}
body.portal-page .cont-search__results { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
body.portal-page .cont-search__item {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-3) var(--space-4);
}
body.portal-page .cont-search__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
body.portal-page .cont-search__name { flex: 1 1 auto; font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
body.portal-page .cont-search__total { flex-shrink: 0; color: var(--accent-bright); font-weight: 700; }
body.portal-page .cont-search__boxes {
  list-style: none;
  margin: var(--space-3) 0 0 0;
  padding: var(--space-3) 0 0 calc(40px + var(--space-3));
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
body.portal-page .cont-search__box {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  font-size: var(--text-sm);
}
body.portal-page .cont-search__box-name { color: var(--text); }
body.portal-page .cont-search__box-type { color: var(--text-muted); font-size: var(--text-xs); }
body.portal-page .cont-search__box-qty { margin-left: auto; color: var(--text-muted); flex-shrink: 0; }

/* ---- container hover peek tooltip (reuses .ls-tooltip shell) ---- */
body.portal-page .cont-tip__type { font-size: var(--text-xs); color: var(--text-muted); margin-bottom: var(--space-2); }
body.portal-page .cont-tip__items { list-style: none; margin: var(--space-2) 0 0 0; padding: 0; }
body.portal-page .cont-tip__item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 2px 0;
  font-size: var(--text-sm);
}
body.portal-page .cont-tip__item-name { color: var(--text); }
body.portal-page .cont-tip__item-qty { color: var(--text-muted); flex-shrink: 0; font-family: var(--font-mono); }
body.portal-page .cont-tip__more { font-size: var(--text-xs); color: var(--text-muted); padding-top: 3px; }

/* ---- CHOAM exchange browser (/portal/market) ---- */
body.portal-page .market-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-4);
}
body.portal-page .market-chip {
  padding: var(--space-2) var(--space-4);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-full);
  color: var(--text);
  font: inherit;
  font-size: var(--text-sm);
  cursor: pointer;
  transition: border-color var(--motion-fast) var(--ease-in-out),
              color var(--motion-fast) var(--ease-in-out);
}
body.portal-page .market-chip:hover { border-color: var(--accent); color: var(--accent-bright); }
body.portal-page .market-chip:focus-visible { outline: 2px solid var(--accent-bright); }
body.portal-page .market-chip--active {
  border-color: var(--accent);
  color: var(--accent-bright);
  background: var(--bg-elevated);
}
body.portal-page .market-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
body.portal-page .market-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-3) var(--space-4);
}
body.portal-page .market-row__name { flex: 1 1 auto; font-weight: 600; color: var(--text); overflow-wrap: anywhere; min-width: 0; }
body.portal-page .market-row__badges { display: inline-flex; gap: 4px; flex-shrink: 0; }
body.portal-page .market-badge {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 1px 6px;
  border-radius: var(--radius-full);
  border: 1px solid currentColor;
}
body.portal-page .market-badge--npc { color: var(--accent-bright); }
body.portal-page .market-badge--player { color: var(--text-muted); }
body.portal-page .market-row__listings { flex-shrink: 0; color: var(--text-muted); font-size: var(--text-sm); }
body.portal-page .market-row__qty { flex-shrink: 0; color: var(--text-muted); }
body.portal-page .market-row__price { flex-shrink: 0; color: var(--accent-bright); font-weight: 700; }
body.portal-page .market-row__solari { color: var(--text-muted); font-weight: 400; }
@media (max-width: 560px) {
  body.portal-page .market-row { flex-wrap: wrap; }
  body.portal-page .market-row__name { flex-basis: calc(100% - 56px); }
  body.portal-page .market-row__listings { margin-left: calc(40px + var(--space-3)); }
}

/* ---- browse: sort control + clickable rows + price-ladder drawer ---- */
body.portal-page .market-sort {
  display: flex; align-items: center; gap: var(--space-2);
  margin-top: var(--space-3); flex-wrap: wrap;
}
body.portal-page .market-sort__label {
  font-size: var(--text-sm); color: var(--text-muted); margin-right: 2px;
}
body.portal-page .market-sort__btn {
  font: inherit; font-size: var(--text-sm); cursor: pointer;
  background: var(--bg); color: var(--text-muted);
  border: 1px solid var(--border); border-radius: var(--radius-full);
  padding: 4px 12px; transition: color .15s, border-color .15s, background .15s;
}
body.portal-page .market-sort__btn:hover { color: var(--accent-bright); border-color: var(--accent); }
body.portal-page .market-sort__btn:focus-visible { outline: 2px solid var(--accent-bright); }
body.portal-page .market-sort__btn--active {
  color: var(--accent-bright); border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

/* result rows are now buttons that open the item drawer */
body.portal-page .market-row--button {
  width: 100%; text-align: left; font: inherit; cursor: pointer;
  transition: border-color .15s, background .15s, transform .05s;
}
body.portal-page .market-row--button:hover {
  border-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, var(--bg));
}
body.portal-page .market-row--button:focus-visible { outline: 2px solid var(--accent-bright); }
body.portal-page .market-row--button:active { transform: translateY(1px); }
body.portal-page .market-row__chevron { flex-shrink: 0; color: var(--text-muted); font-size: 18px; line-height: 1; }

/* item detail (price ladder) inside the drawer */
body.portal-page .market-detail__head { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-4); }
body.portal-page .market-detail__icon { flex-shrink: 0; }
body.portal-page .market-detail__name { margin: 0; font-size: var(--text-lg); color: var(--text); overflow-wrap: anywhere; }
body.portal-page .market-detail__count { margin: 2px 0 0; font-size: var(--text-sm); color: var(--text-muted); }
body.portal-page .market-ladder { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
body.portal-page .market-ladder__row {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-md);
}
body.portal-page .market-ladder__seller { flex-shrink: 0; }
/* Quality grade pill on ladder rows — same tier color ramp as storage
   (quality-tier-1..5 set color+border-color); "Base" stays muted. */
body.portal-page .market-ladder__grade {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 700;
  padding: 1px 6px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-strong);
  color: var(--text-muted);
}
body.portal-page .market-ladder__grade--base { opacity: 0.75; }
body.portal-page .market-botbuy__p2p {
  display: block;
  color: var(--text-muted);
  font-size: var(--text-xs);
  margin-top: 2px;
}
body.portal-page .market-ladder__qty { flex: 1 1 auto; color: var(--text-muted); }
body.portal-page .market-ladder__price { flex-shrink: 0; color: var(--accent-bright); font-weight: 700; }

/* ---- match the main lastsietch.com font stack (cleaner system-first body) ---- */
body.portal-page {
  --font-sans: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", system-ui, sans-serif;
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
}

/* ===========================================================================
 * PHASE A APP SHELL (2026-06-05) - rail / topbar / tabbar / nav / theme toggle
 * Mobile-first: bottom tab bar + sticky top bar. Desktop (>=900px): fixed left
 * rail, content offset. Appended last so it wins the cascade over legacy rules.
 * ========================================================================= */

/* Skip link */
body.portal-page .portal-skip {
  position: absolute;
  left: var(--space-3);
  top: -3rem;
  z-index: 60;
  background: var(--accent);
  color: #0c0a07;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  font-weight: 700;
  text-decoration: none;
  transition: top var(--motion-fast) var(--ease-in-out);
}
body.portal-page .portal-skip:focus { top: var(--space-3); }

/* Shell wrapper holds main + footer; sticks footer to the bottom. */
body.portal-page .portal-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
body.portal-page .portal-shell--unauth { min-height: 100vh; }

/* Give the content room to clear the mobile chrome. */
body.portal-page .portal-main { flex: 1 1 auto; }

/* -------- Mobile top bar -------- */
body.portal-page .portal-topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--p-scrim);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
body.portal-page .portal-topbar__brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--text-md);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text);
  text-decoration: none;
}
body.portal-page .portal-topbar__brand-mark {
  width: 30px; height: 30px;
  border-radius: var(--radius-full);
  object-fit: cover;
  border: 2px solid var(--accent-soft);
  box-shadow: 0 0 10px var(--accent-glow);
}

/* -------- Mobile bottom tab bar -------- */
body.portal-page .portal-tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 45;
  display: flex;
  height: var(--p-tabbar-h);
  padding-bottom: env(safe-area-inset-bottom, 0);
  background: var(--p-scrim);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-top: 1px solid var(--border-strong);
  box-shadow: var(--shadow-overlay);
}
body.portal-page .portal-tab {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  text-decoration: none;
  color: var(--text-muted);
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  position: relative;
  transition: color var(--motion-fast) var(--ease-in-out);
}
body.portal-page .portal-tab__icon { width: 22px; height: 22px; display: block; }
body.portal-page .portal-tab__icon svg { width: 100%; height: 100%; }
body.portal-page .portal-tab__label { line-height: 1; }
body.portal-page .portal-tab.is-active { color: var(--accent-bright); }
body.portal-page .portal-tab.is-active::before {
  content: "";
  position: absolute;
  top: 0; left: 50%;
  transform: translateX(-50%);
  width: 26px; height: 2px;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
}

/* -------- Mobile "More" overflow sheet (Orders / Landsraad / Guilds) -------- */
body.portal-page .portal-tab--more {
  background: none;
  border: 0;
  cursor: pointer;
  font-family: inherit;
}
body.portal-page .portal-moresheet {
  position: fixed;
  right: var(--space-3);
  bottom: calc(var(--p-tabbar-h) + env(safe-area-inset-bottom, 0px) + var(--space-3));
  z-index: 46;
  display: flex;
  flex-direction: column;
  min-width: 190px;
  padding: var(--space-2);
  background: var(--p-scrim);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-overlay);
}
body.portal-page .portal-moresheet[hidden] { display: none; }
body.portal-page .portal-moresheet__link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  text-decoration: none;
  color: var(--text-muted);
  font-size: var(--text-sm);
  font-weight: 600;
  border-radius: var(--radius-md);
  transition: color var(--motion-fast) var(--ease-in-out);
}
body.portal-page .portal-moresheet__link:hover,
body.portal-page .portal-moresheet__link.is-active { color: var(--accent-bright); }
body.portal-page .portal-moresheet__link .portal-tab__icon { width: 20px; height: 20px; }

/* -------- PWA install hint (one-time, dismissible; injected by portal.js) ----- */
body.portal-page .portal-installhint {
  position: fixed;
  left: var(--space-3);
  right: var(--space-3);
  bottom: calc(var(--p-tabbar-h) + env(safe-area-inset-bottom, 0px) + var(--space-3));
  z-index: 60;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--p-scrim);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-overlay);
  color: var(--text-muted);
  font-size: var(--text-sm);
}
body.portal-page .portal-installhint__mark {
  width: 28px;
  height: 28px;
  border-radius: var(--radius-full);
  flex: 0 0 auto;
}
body.portal-page .portal-installhint__text { flex: 1 1 auto; }
body.portal-page .portal-installhint__action {
  flex: 0 0 auto;
  padding: var(--space-2) var(--space-4);
  background: var(--accent);
  color: #0c0a07;
  border: 0;
  border-radius: var(--radius-md);
  font-weight: 700;
  font-size: var(--text-sm);
  cursor: pointer;
}
body.portal-page .portal-installhint__close {
  flex: 0 0 auto;
  background: none;
  border: 0;
  color: var(--text-muted);
  font-size: 20px;
  line-height: 1;
  padding: var(--space-1) var(--space-2);
  cursor: pointer;
}

/* -------- Desktop left rail -------- */
body.portal-page .portal-rail { display: none; }

body.portal-page .portal-rail__brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-5) var(--space-6);
  text-decoration: none;
  color: var(--text);
}
body.portal-page .portal-rail__brand-mark {
  width: 40px; height: 40px;
  border-radius: var(--radius-full);
  object-fit: cover;
  border: 2px solid var(--accent-soft);
  box-shadow: 0 0 14px var(--accent-glow);
  flex-shrink: 0;
}
body.portal-page .portal-rail__brand-text {
  font-family: var(--font-sans);
  font-size: var(--text-md);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

body.portal-page .portal-rail__nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 0 var(--space-3);
}

/* Shared nav link (rail) */
body.portal-page .portal-navlink {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-3);
  border-radius: var(--radius-md);
  color: var(--text-muted);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.01em;
  position: relative;
  transition: background var(--motion-fast) var(--ease-in-out),
              color var(--motion-fast) var(--ease-in-out);
}
body.portal-page .portal-navlink__icon { width: 20px; height: 20px; flex-shrink: 0; display: block; }
body.portal-page .portal-navlink__icon svg { width: 100%; height: 100%; }
body.portal-page .portal-navlink__label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.portal-page a.portal-navlink:hover {
  color: var(--text);
  background: var(--border-subtle);
}
body.portal-page .portal-navlink.is-active {
  color: var(--accent-bright);
  background: var(--accent-glow);
}
body.portal-page .portal-navlink.is-active::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  transform: translateY(-50%);
  width: 3px; height: 60%;
  border-radius: var(--radius-full);
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
}
body.portal-page .portal-navlink--soon {
  cursor: default;
  opacity: 0.5;
}
body.portal-page .portal-navlink__soon {
  margin-left: auto;
  font-size: var(--text-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  padding: 1px var(--space-2);
}

body.portal-page .portal-rail__foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-3) var(--space-5);
  border-top: 1px solid var(--border-subtle);
}
body.portal-page .portal-navlink--account .portal-navlink__icon {
  border-radius: var(--radius-full);
  background: var(--accent-glow);
  padding: 3px;
}
body.portal-page .portal-rail__logout { margin: 0; }
body.portal-page .portal-rail__logout-btn { width: 100%; }

/* -------- House theme picker (4-option dropdown; replaces binary toggle) -------- */
body.portal-page .portal-themepicker {
  position: relative;
}
body.portal-page .portal-themepicker__btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  color: var(--text-muted);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--motion-fast) var(--ease-in-out),
              color var(--motion-fast) var(--ease-in-out);
}
body.portal-page .portal-themepicker__btn:hover,
body.portal-page .portal-themepicker__btn[aria-expanded="true"] {
  color: var(--text);
  border-color: var(--border-strong);
}
body.portal-page .portal-themepicker__btn[aria-expanded="true"] {
  border-color: var(--accent);
}
/* Swatch: 12px dot showing the active theme's palette identity. */
body.portal-page .portal-themepicker__swatch {
  width: 12px; height: 12px;
  border-radius: var(--radius-full);
  flex-shrink: 0;
  display: inline-block;
  border: 1px solid rgba(255,255,255,0.12);
}
body.portal-page .portal-themepicker__swatch--night    { background: #1b150e; border-color: #352c1d; }
body.portal-page .portal-themepicker__swatch--day      { background: #e7d8b8; border-color: #b69d6c; }
body.portal-page .portal-themepicker__swatch--atreides { background: linear-gradient(135deg, #155c42 50%, #c49e4c 50%); border-color: #2c4532; }
body.portal-page .portal-themepicker__swatch--harkonnen{ background: #c42020; border-color: #4e1011; }

body.portal-page .portal-themepicker__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.portal-page .portal-themepicker__chevron {
  flex-shrink: 0;
  opacity: 0.55;
  transition: transform var(--motion-fast) var(--ease-in-out);
}
body.portal-page .portal-themepicker__btn[aria-expanded="true"] .portal-themepicker__chevron {
  transform: rotate(180deg);
  opacity: 0.85;
}

/* Dropdown list: floats above the trigger in the rail (upward). */
body.portal-page .portal-themepicker__menu {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 0; right: 0;
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-overlay);
  padding: var(--space-1) 0;
  list-style: none;
  margin: 0;
  z-index: 200;
}
/* Mobile topbar: menu opens downward. */
body.portal-page .portal-themepicker__menu--down {
  bottom: auto;
  top: calc(100% + 4px);
}
body.portal-page .portal-themepicker__opt {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  outline: none;
  user-select: none;
  transition: background var(--motion-fast) var(--ease-in-out),
              color var(--motion-fast) var(--ease-in-out);
}
body.portal-page .portal-themepicker__opt:hover,
body.portal-page .portal-themepicker__opt:focus {
  background: var(--border-subtle);
  color: var(--text);
}
body.portal-page .portal-themepicker__opt[aria-selected="true"] {
  color: var(--accent-bright);
}

/* Bare topbar variant: icon-only trigger, no label/chevron. */
body.portal-page .portal-themepicker--bare .portal-themepicker__btn {
  border: none;
  background: transparent;
  padding: var(--space-2);
  width: auto;
  color: var(--text-muted);
}
body.portal-page .portal-themepicker--bare .portal-themepicker__swatch {
  width: 20px; height: 20px;
}
body.portal-page .portal-themepicker--bare .portal-themepicker__label,
body.portal-page .portal-themepicker--bare .portal-themepicker__chevron { display: none; }
body.portal-page .portal-themepicker--bare .portal-themepicker__menu--down {
  left: auto; right: 0;
  width: 180px;
}
@media (prefers-reduced-motion: reduce) {
  body.portal-page .portal-themepicker__btn,
  body.portal-page .portal-themepicker__chevron,
  body.portal-page .portal-themepicker__opt { transition: none; }
}

/* -------- Desktop breakpoint: rail in, mobile chrome out -------- */
@media (min-width: 900px) {
  body.portal-page .portal-topbar,
  body.portal-page .portal-tabbar,
  body.portal-page .portal-moresheet,
  body.portal-page .portal-installhint { display: none; }

  body.portal-page .portal-rail {
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0; left: 0; bottom: 0;
    width: var(--p-rail-w);
    z-index: 50;
    background: var(--p-rail-bg);
    border-right: 1px solid var(--border-strong);
    box-shadow: 2px 0 16px rgba(0,0,0,0.18);
  }
  body.portal-page .portal-shell { margin-left: var(--p-rail-w); }
  body.portal-page .portal-main { max-width: var(--p-content-max); }
}

/* ===========================================================================
 * PHASE A PREMIUM POLISH - layered over legacy components (wins the cascade)
 * ========================================================================= */

/* Headers match the modern lastsietch.com look: Inter bold, sentence case.
   Cinzel is reserved as a single flourish on the hero brand line only. */
body.portal-page .portal-card__title,
body.portal-page .portal-dash__char-name {
  font-family: var(--font-sans);
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* Cards: warmer surface, a hairline spice top-rule, refined hover lift. */
body.portal-page .portal-card {
  position: relative;
  border-radius: var(--radius-lg);
  background:
    linear-gradient(180deg, rgba(255,255,255,0.015), transparent 40%),
    var(--bg-card);
  box-shadow: var(--shadow-card), var(--p-panel-edge);
  overflow: hidden;
}
body.portal-page .portal-card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--p-rule);
  opacity: 0.55;
}

/* Hero vitals card: spice/violet wash echoing the in-game detail panel. */
body.portal-page .portal-vitals {
  background:
    var(--p-hero-wash),
    linear-gradient(180deg, rgba(255,255,255,0.02), transparent 40%),
    var(--bg-card);
}
body.portal-page .portal-vitals .portal-dash__char-name {
  font-size: var(--text-2xl);
}

/* Numerics read as gold, like the exchange. */
body.portal-page .portal-stat__value,
body.portal-page .portal-faction__standing { color: var(--text); }
body.portal-page .portal-vitals .portal-stat__value { font-variant-numeric: tabular-nums; }

/* Disclosure banner: re-tone from "info blue" to a quiet sand notice. */
body.portal-page .portal-banner {
  background: linear-gradient(180deg, rgba(255,255,255,0.02), transparent), var(--bg-card);
  border-color: var(--border);
  border-left: 3px solid var(--accent);
  color: var(--text-muted);
}
body.portal-page .portal-banner strong { color: var(--accent-bright); }

/* Primary/ghost buttons echo the exchange's gold action button. */
body.portal-page .portal-btn--ghost {
  border: 1px solid var(--border-strong);
  background: var(--bg-elevated);
}
body.portal-page .portal-btn--ghost:hover {
  border-color: var(--accent);
  color: var(--accent-bright);
}

/* Online pill: warm glow. */
body.portal-page .portal-pill--online {
  box-shadow: 0 0 0 1px var(--green), 0 0 10px rgba(95,207,107,0.25);
}

/* ===========================================================================
 * PHASE A PAGE-SPECIFIC POLISH (2026-06-05) - market rows, storage tiles, drawers
 * Tuned toward the in-game CHOAM exchange row: framed icon, name, NPC/player
 * badge, listings, x qty, gold price, chevron. Appended last (wins cascade).
 * ========================================================================= */

/* -------- Market: listing rows read like the in-game exchange table -------- */
body.portal-page .market-list { gap: var(--space-2); }
body.portal-page .market-row {
  width: 100%;
  text-align: left;
  background: linear-gradient(180deg, rgba(255,255,255,0.015), transparent 60%), var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
  transition: border-color var(--motion-fast) var(--ease-in-out),
              transform var(--motion-fast) var(--ease-out),
              box-shadow var(--motion-fast) var(--ease-in-out);
}
body.portal-page .market-row--button:hover,
body.portal-page .market-row--button:focus-visible {
  border-color: var(--accent);
  transform: translateY(-1px);
  box-shadow: var(--shadow-card), 0 0 0 1px var(--accent-glow);
}
/* Framed item icon, like the exchange thumbnail. */
body.portal-page .market-row .cont-item__icon-wrap {
  flex-shrink: 0;
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  background: var(--bg-deep);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
body.portal-page .market-row .cont-item__icon { width: 34px; height: 34px; object-fit: contain; }
body.portal-page .market-row__name { font-size: var(--text-base); letter-spacing: 0.01em; }
body.portal-page .market-row__price { font-size: var(--text-md); color: var(--accent-bright); }
body.portal-page .market-row__chevron {
  flex-shrink: 0;
  color: var(--text-muted);
  font-size: var(--text-lg);
  transition: transform var(--motion-fast) var(--ease-out), color var(--motion-fast) var(--ease-in-out);
}
body.portal-page .market-row--button:hover .market-row__chevron { color: var(--accent); transform: translateX(2px); }
body.portal-page .market-badge {
  background: var(--bg-deep);
  border-color: var(--border-strong);
}
body.portal-page .market-badge--npc { color: var(--accent-bright); border-color: var(--accent-soft); }
body.portal-page .market-badge--botbuy { color: var(--accent-bright); }

/* NPC buyer line in the item drawer: what the market-maker pays per unit. */
body.portal-page .market-botbuy {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 8px;
  margin: 10px 0;
  padding: 8px 10px;
  background: var(--bg-deep);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
}
body.portal-page .market-botbuy__text { margin: 0; }
body.portal-page .market-botbuy__tier {
  display: inline-block;
  margin-left: 6px;
  color: var(--accent-bright);
  white-space: nowrap;
}
body.portal-page .market-botbuy__hint {
  flex-basis: 100%;
  margin: 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* Category + sort chips: pill filters echoing the in-game grade/category pills. */
body.portal-page .market-chip,
body.portal-page .market-sort__btn {
  border-radius: var(--radius-full);
  transition: border-color var(--motion-fast) var(--ease-in-out),
              color var(--motion-fast) var(--ease-in-out),
              background var(--motion-fast) var(--ease-in-out);
}
body.portal-page .market-sort__btn:hover { border-color: var(--accent); color: var(--accent-bright); }
body.portal-page .market-sort__btn--active,
body.portal-page .market-chip--active {
  border-color: var(--accent);
  color: var(--accent-bright);
  background: var(--accent-glow);
}

/* -------- Storage: tiles get the sandstone-panel treatment -------- */
body.portal-page .cont-tile {
  border-radius: var(--radius-md);
  background: linear-gradient(180deg, rgba(255,255,255,0.02), transparent 55%), var(--bg-card);
  transition: border-color var(--motion-fast) var(--ease-in-out),
              transform var(--motion-fast) var(--ease-out),
              box-shadow var(--motion-fast) var(--ease-in-out);
}
body.portal-page .cont-tile--filled:hover,
body.portal-page .cont-tile:focus-visible {
  border-color: var(--accent);
  transform: translateY(-2px);
  box-shadow: var(--shadow-overlay), 0 0 0 1px var(--accent-glow);
}

/* -------- Drawer (shared ls-drawer): sandstone surface + spice header rule -------- */
body.portal-page .ls-drawer {
  background: linear-gradient(180deg, rgba(255,255,255,0.02), transparent 30%), var(--bg-card);
  box-shadow: var(--shadow-modal);
}
body.portal-page .ls-drawer__header { border-bottom: 1px solid var(--border); }
body.portal-page .ls-drawer__title { font-weight: 700; letter-spacing: -0.01em; }
body.portal-page .market-detail__name { font-weight: 700; letter-spacing: -0.01em; }

/* Market price ladder rows: align like the exchange, gold price. Keep the
   horizontal padding (the earlier card style) so the price + Solari icon never
   clip against the right edge of the drawer. */
body.portal-page .market-ladder__row {
  padding: var(--space-2) var(--space-3);
}
body.portal-page .market-ladder__price {
  color: var(--accent-bright);
  font-size: var(--text-base);
  display: inline-flex;
  align-items: center;
}

/* Inline Solari coin icon replacing the literal " S" suffix on prices. */
body.portal-page .market-solari-ico {
  width: 0.95em;
  height: 0.95em;
  margin-left: 4px;
  vertical-align: -0.12em;
  flex-shrink: 0;
}
body.portal-page .market-row__price {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
}

/* Drawer head: icon · (name + count) · copy pushed to the right. */
body.portal-page .market-detail__heading { flex: 1 1 auto; min-width: 0; }
body.portal-page .market-detail__head .market-copy { margin-left: auto; flex-shrink: 0; }

/* ===========================================================================
 * PHASE A HERO BANNER (2026-06-05) - fal.ai brand art, theme-swapped
 * Cinematic Arrakis key art on the Character page; night = starlit sietch,
 * day = sunlit dunes. Bottom scrim fades into the page so cards stay readable.
 * ========================================================================= */
body.portal-page .portal-hero {
  position: relative;
  min-height: 156px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  padding: var(--space-5);
  background-color: var(--bg-deep);
  background-size: cover;
  background-position: center 42%;
  box-shadow: var(--shadow-card);
}
html[data-theme="night"] body.portal-page .portal-hero {
  background-image: linear-gradient(0deg, rgba(8,6,3,0.92) 2%, rgba(8,6,3,0.30) 45%, rgba(8,6,3,0.10) 100%),
                    url("/admin/static/img/portal/hero-night.jpg");
}
html[data-theme="day"] body.portal-page .portal-hero {
  background-image: linear-gradient(0deg, rgba(231,216,184,0.92) 2%, rgba(231,216,184,0.25) 48%, rgba(231,216,184,0.05) 100%),
                    url("/admin/static/img/portal/hero-day.jpg");
}
body.portal-page .portal-hero__inner { position: relative; z-index: 1; }
body.portal-page .portal-hero__kicker {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--accent-bright);
  margin-bottom: var(--space-1);
}
body.portal-page .portal-hero__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text);
  text-shadow: 0 2px 12px rgba(0,0,0,0.5);
}
html[data-theme="day"] body.portal-page .portal-hero__title { text-shadow: 0 1px 2px rgba(255,255,255,0.5); }
body.portal-page .portal-hero__sub {
  margin: var(--space-1) 0 0;
  font-size: var(--text-sm);
  color: var(--text-muted);
}
@media (min-width: 768px) {
  body.portal-page .portal-hero { min-height: 220px; padding: var(--space-6) var(--space-7); }
  body.portal-page .portal-hero__title { font-size: var(--text-2xl); }
}

/* Optional action row inside a hero (containers "Open Storage Manager"). */
body.portal-page .portal-hero__actions { margin: var(--space-3) 0 0; }

/* Slim hero: page identity without eating vertical space (map renderer,
 * spice map). Same art + typography, about half the height. */
body.portal-page .portal-hero--slim { min-height: 96px; }
@media (min-width: 768px) {
  body.portal-page .portal-hero--slim { min-height: 128px; padding: var(--space-5) var(--space-7); }
  body.portal-page .portal-hero--slim .portal-hero__title { font-size: var(--text-xl); }
}

/* Per-page hero art (2026-06-10) — fal.ai key art, theme-swapped like the
 * default Character hero. Each page keeps the same scrim so text stays
 * readable; only the artwork changes. */
html[data-theme="night"] body.portal-page .portal-hero--maps {
  background-image: linear-gradient(0deg, rgba(8,6,3,0.92) 2%, rgba(8,6,3,0.30) 45%, rgba(8,6,3,0.10) 100%),
                    url("/admin/static/img/portal/hero-maps-night.jpg");
}
html[data-theme="day"] body.portal-page .portal-hero--maps {
  background-image: linear-gradient(0deg, rgba(231,216,184,0.92) 2%, rgba(231,216,184,0.25) 48%, rgba(231,216,184,0.05) 100%),
                    url("/admin/static/img/portal/hero-maps-day.jpg");
}
html[data-theme="night"] body.portal-page .portal-hero--storage {
  background-image: linear-gradient(0deg, rgba(8,6,3,0.92) 2%, rgba(8,6,3,0.30) 45%, rgba(8,6,3,0.10) 100%),
                    url("/admin/static/img/portal/hero-storage-night.jpg");
}
html[data-theme="day"] body.portal-page .portal-hero--storage {
  background-image: linear-gradient(0deg, rgba(231,216,184,0.92) 2%, rgba(231,216,184,0.25) 48%, rgba(231,216,184,0.05) 100%),
                    url("/admin/static/img/portal/hero-storage-day.jpg");
}
html[data-theme="night"] body.portal-page .portal-hero--market {
  background-image: linear-gradient(0deg, rgba(8,6,3,0.92) 2%, rgba(8,6,3,0.30) 45%, rgba(8,6,3,0.10) 100%),
                    url("/admin/static/img/portal/hero-market-night.jpg");
}
html[data-theme="day"] body.portal-page .portal-hero--market {
  background-image: linear-gradient(0deg, rgba(231,216,184,0.92) 2%, rgba(231,216,184,0.25) 48%, rgba(231,216,184,0.05) 100%),
                    url("/admin/static/img/portal/hero-market-day.jpg");
}
html[data-theme="night"] body.portal-page .portal-hero--orders {
  background-image: linear-gradient(0deg, rgba(8,6,3,0.92) 2%, rgba(8,6,3,0.30) 45%, rgba(8,6,3,0.10) 100%),
                    url("/admin/static/img/portal/hero-orders-night.jpg");
}
html[data-theme="day"] body.portal-page .portal-hero--orders {
  background-image: linear-gradient(0deg, rgba(231,216,184,0.92) 2%, rgba(231,216,184,0.25) 48%, rgba(231,216,184,0.05) 100%),
                    url("/admin/static/img/portal/hero-orders-day.jpg");
}
html[data-theme="night"] body.portal-page .portal-hero--landsraad {
  background-image: linear-gradient(0deg, rgba(8,6,3,0.92) 2%, rgba(8,6,3,0.30) 45%, rgba(8,6,3,0.10) 100%),
                    url("/admin/static/img/portal/hero-landsraad-night.jpg");
}
html[data-theme="day"] body.portal-page .portal-hero--landsraad {
  background-image: linear-gradient(0deg, rgba(231,216,184,0.92) 2%, rgba(231,216,184,0.25) 48%, rgba(231,216,184,0.05) 100%),
                    url("/admin/static/img/portal/hero-landsraad-day.jpg");
}
html[data-theme="night"] body.portal-page .portal-hero--guilds {
  background-image: linear-gradient(0deg, rgba(8,6,3,0.92) 2%, rgba(8,6,3,0.30) 45%, rgba(8,6,3,0.10) 100%),
                    url("/admin/static/img/portal/hero-guilds-night.jpg");
}
html[data-theme="day"] body.portal-page .portal-hero--guilds {
  background-image: linear-gradient(0deg, rgba(231,216,184,0.92) 2%, rgba(231,216,184,0.25) 48%, rgba(231,216,184,0.05) 100%),
                    url("/admin/static/img/portal/hero-guilds-day.jpg");
}
html[data-theme="night"] body.portal-page .portal-hero--solido {
  background-image: linear-gradient(0deg, rgba(8,6,3,0.92) 2%, rgba(8,6,3,0.30) 45%, rgba(8,6,3,0.10) 100%),
                    url("/admin/static/img/portal/hero-solido-night.jpg");
}
html[data-theme="day"] body.portal-page .portal-hero--solido {
  background-image: linear-gradient(0deg, rgba(231,216,184,0.92) 2%, rgba(231,216,184,0.25) 48%, rgba(231,216,184,0.05) 100%),
                    url("/admin/static/img/portal/hero-solido-day.jpg");
}

/* House themes reuse the night hero artwork with a House-tinted gradient wash.
 * Atreides: emerald-green scrim at bottom, slight teal at top edge.
 * Harkonnen: near-black scrim, faint crimson bleed at top edge.
 * Both keep the same contrast floor as night so text stays fully readable. */
html[data-theme="atreides"] body.portal-page .portal-hero {
  background-image: linear-gradient(0deg, rgba(7,12,9,0.96) 2%, rgba(11,20,14,0.44) 45%, rgba(18,58,36,0.12) 100%),
                    url("/admin/static/img/portal/hero-night.jpg");
}
html[data-theme="atreides"] body.portal-page .portal-hero--maps {
  background-image: linear-gradient(0deg, rgba(7,12,9,0.96) 2%, rgba(11,20,14,0.44) 45%, rgba(18,58,36,0.12) 100%),
                    url("/admin/static/img/portal/hero-maps-night.jpg");
}
html[data-theme="atreides"] body.portal-page .portal-hero--storage {
  background-image: linear-gradient(0deg, rgba(7,12,9,0.96) 2%, rgba(11,20,14,0.44) 45%, rgba(18,58,36,0.12) 100%),
                    url("/admin/static/img/portal/hero-storage-night.jpg");
}
html[data-theme="atreides"] body.portal-page .portal-hero--market {
  background-image: linear-gradient(0deg, rgba(7,12,9,0.96) 2%, rgba(11,20,14,0.44) 45%, rgba(18,58,36,0.12) 100%),
                    url("/admin/static/img/portal/hero-market-night.jpg");
}
html[data-theme="atreides"] body.portal-page .portal-hero--orders {
  background-image: linear-gradient(0deg, rgba(7,12,9,0.96) 2%, rgba(11,20,14,0.44) 45%, rgba(18,58,36,0.12) 100%),
                    url("/admin/static/img/portal/hero-orders-night.jpg");
}
html[data-theme="atreides"] body.portal-page .portal-hero--landsraad {
  background-image: linear-gradient(0deg, rgba(7,12,9,0.96) 2%, rgba(11,20,14,0.44) 45%, rgba(18,58,36,0.12) 100%),
                    url("/admin/static/img/portal/hero-landsraad-night.jpg");
}
html[data-theme="atreides"] body.portal-page .portal-hero--guilds {
  background-image: linear-gradient(0deg, rgba(7,12,9,0.96) 2%, rgba(11,20,14,0.44) 45%, rgba(18,58,36,0.12) 100%),
                    url("/admin/static/img/portal/hero-guilds-night.jpg");
}
html[data-theme="atreides"] body.portal-page .portal-hero--solido {
  background-image: linear-gradient(0deg, rgba(7,12,9,0.96) 2%, rgba(11,20,14,0.44) 45%, rgba(18,58,36,0.12) 100%),
                    url("/admin/static/img/portal/hero-solido-night.jpg");
}

html[data-theme="harkonnen"] body.portal-page .portal-hero {
  background-image: linear-gradient(0deg, rgba(8,1,2,0.97) 2%, rgba(19,4,6,0.50) 45%, rgba(46,6,9,0.14) 100%),
                    url("/admin/static/img/portal/hero-night.jpg");
}
html[data-theme="harkonnen"] body.portal-page .portal-hero--maps {
  background-image: linear-gradient(0deg, rgba(8,1,2,0.97) 2%, rgba(19,4,6,0.50) 45%, rgba(46,6,9,0.14) 100%),
                    url("/admin/static/img/portal/hero-maps-night.jpg");
}
html[data-theme="harkonnen"] body.portal-page .portal-hero--storage {
  background-image: linear-gradient(0deg, rgba(8,1,2,0.97) 2%, rgba(19,4,6,0.50) 45%, rgba(46,6,9,0.14) 100%),
                    url("/admin/static/img/portal/hero-storage-night.jpg");
}
html[data-theme="harkonnen"] body.portal-page .portal-hero--market {
  background-image: linear-gradient(0deg, rgba(8,1,2,0.97) 2%, rgba(19,4,6,0.50) 45%, rgba(46,6,9,0.14) 100%),
                    url("/admin/static/img/portal/hero-market-night.jpg");
}
html[data-theme="harkonnen"] body.portal-page .portal-hero--orders {
  background-image: linear-gradient(0deg, rgba(8,1,2,0.97) 2%, rgba(19,4,6,0.50) 45%, rgba(46,6,9,0.14) 100%),
                    url("/admin/static/img/portal/hero-orders-night.jpg");
}
html[data-theme="harkonnen"] body.portal-page .portal-hero--landsraad {
  background-image: linear-gradient(0deg, rgba(8,1,2,0.97) 2%, rgba(19,4,6,0.50) 45%, rgba(46,6,9,0.14) 100%),
                    url("/admin/static/img/portal/hero-landsraad-night.jpg");
}
html[data-theme="harkonnen"] body.portal-page .portal-hero--guilds {
  background-image: linear-gradient(0deg, rgba(8,1,2,0.97) 2%, rgba(19,4,6,0.50) 45%, rgba(46,6,9,0.14) 100%),
                    url("/admin/static/img/portal/hero-guilds-night.jpg");
}
html[data-theme="harkonnen"] body.portal-page .portal-hero--solido {
  background-image: linear-gradient(0deg, rgba(8,1,2,0.97) 2%, rgba(19,4,6,0.50) 45%, rgba(46,6,9,0.14) 100%),
                    url("/admin/static/img/portal/hero-solido-night.jpg");
}

/* ===================================================================== *
 * Market price-alert watchlist (nav bell, watch control, watchlist page)
 * ===================================================================== */

/* Nav bell badge (desktop rail count + mobile tab dot). */
body.portal-page .portal-navlink__badge {
  margin-left: auto;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: 700;
  line-height: 1;
  color: #1a1206;
  background: var(--accent);
  border-radius: var(--radius-full);
  box-shadow: 0 0 8px var(--accent-glow);
}
body.portal-page .portal-tab__icon { position: relative; }
body.portal-page .portal-tab__badge {
  position: absolute;
  top: -2px;
  right: -4px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--accent);
  box-shadow: 0 0 6px var(--accent-glow);
}

/* "Watch this item" control inside the market drawer. */
body.portal-page .market-watch {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
}
body.portal-page .market-watch__title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text);
}
body.portal-page .market-watch__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
body.portal-page .market-watch__input {
  flex: 1 1 auto;
  min-width: 0;
}
body.portal-page .market-watch__solari {
  font-family: var(--font-mono);
  color: var(--text-muted);
}
body.portal-page .market-watch__msg {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  min-height: 1.2em;
  color: var(--text-muted);
}
body.portal-page .market-watch__msg--ok { color: var(--green); }
body.portal-page .market-watch__msg--warn { color: var(--accent-bright); }

/* Market BUY: player's bank line, per-row Buy button, confirm panel, result. */
body.portal-page .market-detail__bank {
  margin: 0 0 var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
}
body.portal-page .market-ladder__buy {
  flex-shrink: 0;
  margin-left: var(--space-2);
}
body.portal-page .market-buy {
  margin-top: var(--space-4);
  padding: var(--space-3);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md, 8px);
  background: var(--surface-2, rgba(255, 255, 255, 0.03));
}
body.portal-page .market-buy__title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--text);
}
body.portal-page .market-buy__line {
  margin: 0 0 var(--space-2);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--text);
}
body.portal-page .market-buy__unit { color: var(--text-muted); }
body.portal-page .market-buy__qtyrow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
body.portal-page .market-buy__qtylabel { font-size: var(--text-sm); color: var(--text-muted); }
/* Bounded width + shrinkable so the confirm panel never overflows the drawer
   (cont-search__input sets width:100%; clamp it here). */
body.portal-page .market-buy__qty { width: 6rem; max-width: 100%; flex: 0 1 6rem; min-width: 0; }
body.portal-page .market-buy__stack { font-size: var(--text-sm); color: var(--text-muted); }
body.portal-page .market-buy__total {
  margin: 0 0 var(--space-2);
  font-weight: 700;
  color: var(--accent-bright);
  display: inline-flex;
  align-items: center;
}
body.portal-page .market-buy__from,
body.portal-page .market-buy__deliver {
  margin: 0 0 var(--space-2);
  font-size: var(--text-sm);
  color: var(--text-muted);
}
body.portal-page .market-buy__actions {
  display: flex;
  gap: var(--space-2);
  justify-content: flex-end;
}
body.portal-page .market-buy__msg {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  min-height: 1.2em;
  color: var(--text-muted);
}
body.portal-page .market-buy__msg--warn { color: var(--accent-bright); }
body.portal-page .market-buy-result {
  margin: 0 0 var(--space-3);
  padding: var(--space-3);
  border-radius: var(--radius-md, 8px);
  border: 1px solid var(--border-subtle);
  font-size: var(--text-sm);
}
body.portal-page .market-buy-result--ok {
  border-color: var(--green);
  color: var(--text);
}
body.portal-page .market-buy-result--err {
  border-color: var(--accent-bright);
  color: var(--text);
}
body.portal-page .market-buy-result__msg { margin: 0; }
body.portal-page .market-buy-result__bank {
  margin: var(--space-2) 0 0;
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
}

/* List-on-Exchange (sell) "List" action on each storage item row. */
body.portal-page .cont-item__sell { flex-shrink: 0; }

/* Centered modal for listing a storage item on the exchange. Sits above the
   storage drawer (which uses ls-drawer); the overlay dims the whole page. */
body.portal-page .ls-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  opacity: 0;
  transition: opacity 0.18s ease;
  z-index: 1200;
}
body.portal-page .ls-modal-overlay--open { opacity: 1; }
body.portal-page .ls-modal {
  position: fixed;
  top: 50%;
  left: 50%;
  width: min(460px, calc(100vw - 2 * var(--space-4)));
  max-height: calc(100vh - 2 * var(--space-4));
  overflow-x: hidden;
  overflow-y: auto;
  box-sizing: border-box;
  transform: translate(-50%, -48%);
  opacity: 0;
  background: var(--surface, #15171c);
  border: 1px solid var(--border-strong, #2a2e36);
  border-radius: var(--radius-lg, 12px);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45);
  transition: opacity 0.18s ease, transform 0.18s ease;
  z-index: 1201;
}
body.portal-page .ls-modal--open { opacity: 1; transform: translate(-50%, -50%); }
body.portal-page .ls-modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
}
body.portal-page .ls-modal__title { margin: 0; font-size: var(--text-md); font-weight: 700; }
body.portal-page .ls-modal__body { padding: var(--space-4); }

body.portal-page .sell-modal__item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
}
body.portal-page .sell-modal__item-name { font-weight: 700; color: var(--text); overflow-wrap: anywhere; }
body.portal-page .sell-modal__item-stack { font-size: var(--text-sm); color: var(--text-muted); }
body.portal-page .sell-modal__field { margin: 0 0 var(--space-3); }
body.portal-page .sell-modal__label {
  display: block;
  margin: 0 0 var(--space-1);
  font-size: var(--text-sm);
  color: var(--text-muted);
}
body.portal-page .sell-modal__inputrow {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
body.portal-page .sell-modal__inputrow .sell-modal__num {
  flex: 1 1 auto; width: auto; min-width: 0; max-width: 100%; box-sizing: border-box;
}
body.portal-page .sell-modal__hint {
  flex: 0 0 auto; white-space: nowrap; font-size: var(--text-sm); color: var(--text-muted);
}
body.portal-page .sell-modal__inputrow { min-width: 0; }
body.portal-page .sell-modal__inputrow .market-solari-ico { flex: 0 0 auto; }
body.portal-page .sell-modal__durations {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
body.portal-page .sell-modal__dur--active {
  border-color: var(--accent) !important;
  color: var(--accent-bright) !important;
}
body.portal-page .sell-modal__summary {
  margin: var(--space-4) 0 var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md, 8px);
  background: var(--surface-2, rgba(255, 255, 255, 0.03));
}
body.portal-page .sell-modal__sumrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin: 0;
}
body.portal-page .sell-modal__sumrow dt { color: var(--text-muted); font-size: var(--text-sm); }
body.portal-page .sell-modal__sumrow dd {
  margin: 0;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
}
body.portal-page .sell-modal__sumrow--fee { margin-top: var(--space-2); }
body.portal-page .sell-modal__sumrow--fee dd { color: var(--accent-bright); }
body.portal-page .sell-modal__note {
  margin: 0 0 var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-muted);
}
body.portal-page .sell-modal__actions {
  display: flex;
  gap: var(--space-2);
  justify-content: flex-end;
}
body.portal-page .sell-modal__msg {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  min-height: 1.2em;
  color: var(--text-muted);
}
body.portal-page .sell-modal__msg--warn { color: var(--accent-bright); }
body.portal-page .sell-modal__result:not(:empty) { margin-top: var(--space-3); }

/* Watchlist page: fired alerts + active watches. */
body.portal-page .watch-count {
  margin-left: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
body.portal-page .watch-alerts,
body.portal-page .watch-list {
  list-style: none;
  margin: var(--space-3) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
body.portal-page .watch-alert,
body.portal-page .watch-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-card);
}
body.portal-page .watch-alert--new {
  border-color: var(--accent-soft);
  background: var(--accent-glow);
}
body.portal-page .watch-alert__icon,
body.portal-page .watch-row__icon { flex: 0 0 auto; }
body.portal-page .watch-alert__body,
body.portal-page .watch-row__main { flex: 1 1 auto; min-width: 0; }
body.portal-page .watch-alert__line { margin: 0; font-size: var(--text-sm); }
body.portal-page .watch-alert__muted,
body.portal-page .watch-row__now { color: var(--text-muted); }
body.portal-page .watch-alert__when {
  margin: 2px 0 0;
  font-size: var(--text-2xs);
  color: var(--text-muted);
}
body.portal-page .watch-row__name {
  margin: 0;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.portal-page .watch-row__prices {
  margin: 2px 0 0;
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
  font-size: var(--text-sm);
}
body.portal-page .watch-chip,
body.portal-page .watch-status {
  flex: 0 0 auto;
  font-size: var(--text-2xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border-radius: var(--radius-full);
  padding: 2px var(--space-2);
  border: 1px solid var(--border);
  color: var(--text-muted);
}
body.portal-page .watch-chip--new,
body.portal-page .watch-status--met {
  color: var(--green);
  border-color: var(--green);
}
body.portal-page .watch-status--waiting {
  color: var(--accent-bright);
  border-color: var(--accent-soft);
}
body.portal-page .watch-row__remove { margin: 0; flex: 0 0 auto; }

/* Copy item name (drawer header) — the listing text isn't selectable. */
body.portal-page .market-detail__nameline {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
body.portal-page .market-copy {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: color var(--motion-fast) var(--ease-in-out),
              border-color var(--motion-fast) var(--ease-in-out);
}
body.portal-page .market-copy svg { width: 16px; height: 16px; }
body.portal-page .market-copy:hover {
  color: var(--accent-bright);
  border-color: var(--accent-soft);
}
body.portal-page .market-copy--done {
  color: var(--green);
  border-color: var(--green);
}
body.portal-page .market-copy--fail {
  color: var(--accent-bright);
  border-color: var(--accent-bright);
}

/* Market category tabs (in-game top categories) — horizontal scroll on mobile. */
body.portal-page .market-tabs {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-3);
  overflow-x: auto;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
  padding-bottom: var(--space-1);
}
body.portal-page .market-tab {
  flex: 0 0 auto;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
  white-space: nowrap;
  color: var(--text-muted);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  cursor: pointer;
  transition: color var(--motion-fast) var(--ease-in-out),
              border-color var(--motion-fast) var(--ease-in-out),
              background var(--motion-fast) var(--ease-in-out);
}
body.portal-page .market-tab:hover {
  color: var(--text);
  border-color: var(--accent-soft);
}
body.portal-page .market-tab--active {
  color: var(--accent-bright);
  background: var(--accent-glow);
  border-color: var(--accent-soft);
}

/* Load-more button: full-width, centered, under the listings. */
body.portal-page .market-loadmore {
  display: block;
  width: 100%;
  margin: var(--space-3) 0 var(--space-1);
}

/* ---- My Orders: tabbed Active / Completed / History ---- */
body.portal-page .orders-tabs {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
  overflow-x: auto;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
  padding-bottom: var(--space-1);
}
body.portal-page .orders-tab {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
  white-space: nowrap;
  color: var(--text-muted);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  cursor: pointer;
  transition: color var(--motion-fast) var(--ease-in-out),
              border-color var(--motion-fast) var(--ease-in-out),
              background var(--motion-fast) var(--ease-in-out);
}
body.portal-page .orders-tab:hover { color: var(--text); border-color: var(--accent-soft); }
body.portal-page .orders-tab--active {
  color: var(--accent-bright);
  background: var(--accent-glow);
  border-color: var(--accent-soft);
}
body.portal-page .orders-tab__count {
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 0 6px;
  border-radius: var(--radius-full);
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text-muted);
}
body.portal-page .orders-tab--active .orders-tab__count { color: var(--accent-bright); border-color: var(--accent-soft); }

body.portal-page .orders-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
body.portal-page .orders-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-3) var(--space-4);
}
body.portal-page .orders-row .cont-item__icon { width: 34px; height: 34px; object-fit: contain; }
body.portal-page .orders-row__name {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
}
body.portal-page .orders-row__q {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  padding: 1px 6px;
}
body.portal-page .orders-row__sub { font-size: var(--text-sm); font-weight: 400; color: var(--text-muted); }
body.portal-page .orders-row__qty { flex-shrink: 0; color: var(--text-muted); }
body.portal-page .orders-row__price { flex-shrink: 0; color: var(--text); font-weight: 600; }
body.portal-page .orders-row__total { flex-shrink: 0; color: var(--accent-bright); font-weight: 700; }
body.portal-page .orders-row__when { flex-shrink: 0; color: var(--text-muted); font-size: var(--text-sm); }

/* Completed/history status pill, coloured by completion_type. */
body.portal-page .orders-status {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 1px 6px;
  border-radius: var(--radius-full);
  border: 1px solid currentColor;
}
body.portal-page .orders-status--ct5 { color: var(--accent-bright); }      /* purchased / bought */
body.portal-page .orders-status--ct4 { color: #5fbf7f; }                   /* sold */
body.portal-page .orders-status--ct3 { color: var(--text-muted); }         /* canceled */

body.portal-page .orders-row__action { flex-shrink: 0; }
/* Shared action result/notice slot at the top of the My Orders card. */
body.portal-page .orders-msg {
  margin: 0 0 var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  border: 1px solid var(--border);
  background: var(--bg);
}
body.portal-page .orders-msg--ok { color: #5fbf7f; border-color: rgba(95, 191, 127, 0.4); }
body.portal-page .orders-msg--warn { color: var(--warning, #d9a441); border-color: rgba(217, 164, 65, 0.4); }
body.portal-page .sell-modal__from { color: var(--text-muted); font-weight: 400; }

@media (max-width: 560px) {
  body.portal-page .orders-row { flex-wrap: wrap; }
  body.portal-page .orders-row__name { flex-basis: calc(100% - 56px); }
  body.portal-page .orders-row__when { margin-left: calc(34px + var(--space-3)); }
}

/* ---- market: kind filter + sort grouped on one row ---- */
body.portal-page .market-controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  margin-top: var(--space-3);
}

/* ---- market: schematic / blueprint distinction ---- */
/* "Schematic" badge — cyan, matching the holographic icon treatment. */
body.portal-page .market-badge--schematic {
  color: #58c6e8;
}
/* Holographic frame over the (base-item) icon for a schematic listing: the game
   itself overlays a blueprint frame at render time, so we approximate that with
   a cyan tint + grid + glow rather than a per-item texture (none exist to scrape). */
body.portal-page .cont-item__icon-wrap--schematic {
  position: relative;
  border-radius: var(--radius-md);
  box-shadow: inset 0 0 0 1px rgba(88, 198, 232, 0.55),
              0 0 8px rgba(88, 198, 232, 0.30);
  background:
    linear-gradient(rgba(88, 198, 232, 0.10), rgba(88, 198, 232, 0.10)),
    repeating-linear-gradient(0deg, transparent 0 3px, rgba(88, 198, 232, 0.13) 3px 4px);
}
body.portal-page .cont-item__icon-wrap--schematic .cont-item__icon {
  filter: saturate(0.7) brightness(1.05) drop-shadow(0 0 2px rgba(88, 198, 232, 0.6));
  mix-blend-mode: screen;
  opacity: 0.92;
}
body.portal-page .cont-item__icon-wrap--schematic::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(135deg, rgba(88, 198, 232, 0.18), transparent 60%);
  pointer-events: none;
}

/* ---- price alerts: in-card "add an alert" search + pick + price ---- */
body.portal-page .watch-add { position: relative; margin-bottom: var(--space-4); }
body.portal-page .watch-add__search { width: 100%; }
/* The flex rules below would otherwise override the [hidden] attribute's
   display:none, so the results dropdown + chosen row would show empty on load.
   Keep [hidden] authoritative. */
body.portal-page .watch-add__results[hidden],
body.portal-page .watch-add__chosen[hidden] { display: none; }
body.portal-page .watch-add__results {
  list-style: none;
  margin: var(--space-1) 0 0;
  padding: var(--space-1);
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  max-height: 320px;
  overflow-y: auto;
  position: absolute;
  left: 0;
  right: 0;
  z-index: 20;
  box-shadow: var(--shadow-lg, 0 8px 24px rgba(0, 0, 0, 0.4));
}
body.portal-page .watch-add__result {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 0;
  border-radius: var(--radius-md);
  cursor: pointer;
  text-align: left;
  color: var(--text);
}
body.portal-page .watch-add__result:hover,
body.portal-page .watch-add__result:focus-visible {
  background: var(--accent-glow);
  outline: none;
}
body.portal-page .watch-add__result .cont-item__icon { width: 28px; height: 28px; object-fit: contain; }
body.portal-page .watch-add__result-name { flex: 1 1 auto; min-width: 0; font-weight: 600; overflow-wrap: anywhere; }
body.portal-page .watch-add__result-price { flex-shrink: 0; color: var(--accent-bright); }
body.portal-page .watch-add__chosen {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin-top: var(--space-2);
  padding: var(--space-3);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
body.portal-page .watch-add__chosen .cont-item__icon { width: 30px; height: 30px; object-fit: contain; }
body.portal-page .watch-add__name { font-weight: 600; flex: 1 1 8rem; min-width: 0; overflow-wrap: anywhere; }
body.portal-page .watch-add__pricelabel { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--text-muted); font-size: var(--text-sm); }
body.portal-page .watch-add__price { width: 7rem; }
body.portal-page .watch-add__msg { margin: var(--space-2) 0 0; font-size: var(--text-sm); min-height: 1em; }
body.portal-page .watch-add__msg--warn { color: var(--warning, #d9a441); }
body.portal-page .watch-add__msg--ok { color: #5fbf7f; }

/* =========================================================================
   Storage Manager (GET /portal/storage) — 3-panel offline-only manager.
   Reuses .portal-card / .cont-tile / .market-buy-result / .sell-modal tokens.
   Phase 1: transfer control + read-only grids (no drag-drop yet).
   ========================================================================= */
body.portal-page .storage-banner {
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
  border-left: 3px solid var(--border-strong);
}
body.portal-page .storage-banner--locked { border-left-color: var(--accent-bright); }
body.portal-page .storage-banner--warn { border-left-color: var(--warning, #d9a441); }
body.portal-page .storage-banner--ok { border-left-color: var(--green, #5fbf7f); }

body.portal-page .storage-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
  align-items: start;
}
/* Body: bank | selected container, both wide enough for a 5-up grid. */
body.portal-page .storage-body {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
  align-items: start;
}
@media (min-width: 900px) {
  body.portal-page .storage-body {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  }
}

body.portal-page .storage-panel { margin: 0; }
body.portal-page .storage-panel__subtitle {
  margin: var(--space-4) 0 var(--space-2);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-muted);
}

/* ---- bank balance strip ---- */
body.portal-page .storage-bank__balance {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3);
  margin-bottom: var(--space-3);
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-elevated));
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
}
body.portal-page .storage-bank__sol-ico { width: 26px; height: 26px; object-fit: contain; }
body.portal-page .storage-bank__amount { font-size: var(--text-lg, 1.25rem); font-weight: 700; color: var(--text); }
body.portal-page .storage-bank__label { font-size: var(--text-sm); color: var(--text-muted); }

/* ---- transfer control ---- */
body.portal-page .storage-xfer { margin-bottom: var(--space-4); }
body.portal-page .storage-xfer--disabled { opacity: 0.6; }
body.portal-page .storage-xfer__hint {
  margin: var(--space-1) 0 var(--space-3);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
body.portal-page .storage-xfer__arrows {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
body.portal-page .storage-xfer__btn { flex: 1 1 auto; }
body.portal-page .storage-xfer__sweep { width: 100%; }
body.portal-page .storage-xfer__msg {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  min-height: 1.2em;
  color: var(--text-muted);
}
body.portal-page .storage-xfer__msg--warn { color: var(--accent-bright); }
body.portal-page .storage-xfer__msg--ok { color: var(--green, #5fbf7f); }
body.portal-page .storage-xfer__result:not(:empty) { margin-top: var(--space-3); }

/* ---- top container strip: single row of 5 + prev/next arrows ---- */
body.portal-page .storage-conts-rail {
  display: flex;
  align-items: stretch;
  gap: var(--space-2);
}
body.portal-page .storage-conts-viewport {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  scroll-behavior: smooth;
  scroll-snap-type: x mandatory;
}
body.portal-page .storage-conts {
  display: flex;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: var(--space-2);
}
/* exactly 5 tiles visible; the rest scroll into view via the arrows. Compact
   padding + smaller icon so the row stays short (the bank/detail panels sit
   right below it). scroll-snap lands each page on a tile edge. */
body.portal-page .storage-conts .cont-tile {
  flex: 0 0 calc((100% - 4 * var(--space-2)) / 5);
  min-width: 0;
  min-height: 0;
  padding: var(--space-3) var(--space-3) var(--space-2);
  border-radius: var(--radius-md);
  scroll-snap-align: start;
}
body.portal-page .storage-conts .cont-tile__icon { width: 44px; height: 44px; margin: 0 auto 4px; }
body.portal-page .storage-conts .cont-tile__name { line-height: 1.2; }
body.portal-page .storage-conts .cont-tile__map { margin-top: 2px; }
/* Badge pokes outside the tile by default; the viewport clips overflow, so keep
   it inside the tile corner here. */
body.portal-page .storage-conts .cont-tile__count { top: 5px; right: 5px; }
body.portal-page .storage-conts-arrow {
  flex: 0 0 auto;
  width: 34px;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  line-height: 1;
  color: var(--text);
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background 0.15s ease, opacity 0.15s ease;
}
body.portal-page .storage-conts-arrow:hover { background: color-mix(in srgb, var(--accent) 16%, var(--bg-elevated)); }
body.portal-page .storage-conts-arrow[hidden] { display: none; }
body.portal-page .storage-conts-arrow:disabled { opacity: 0.35; cursor: default; }
@media (max-width: 640px) {
  /* on narrow screens show ~2.5 tiles so the row stays usable */
  body.portal-page .storage-conts .cont-tile { flex: 0 0 calc((100% - 1.5 * var(--space-2)) / 2.5); }
}
body.portal-page .cont-tile--selected {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-elevated));
  box-shadow: 0 0 0 1px var(--accent);
}

/* ---- slot grids (bank + selected container) ---- */
/* One scroll container per panel. The right panel's static host is NOT a
   scroller; the injected items fragment carries the single .storage-grid-scroll
   (avoids the nested double scrollbar). */
body.portal-page .storage-grid-scroll {
  max-height: 460px;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 2px;
}
body.portal-page .storage-detail-host { min-height: 64px; }
/* minmax(0, 1fr) lets the 5 tracks shrink below content width so the row wraps
   instead of overflowing horizontally in a narrow panel. */
body.portal-page .storage-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--space-2);
}
body.portal-page .storage-grid__note {
  margin: var(--space-2) 0;
  font-size: var(--text-sm);
  color: var(--text-muted);
}
body.portal-page .storage-slot {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 3px;
  padding: var(--space-1);
  min-height: 74px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
body.portal-page .storage-slot--empty {
  background: color-mix(in srgb, var(--border) 20%, transparent);
  border-style: dashed;
  min-height: 74px;
}
body.portal-page .storage-slot--filled { border-color: var(--border-strong); }
/* Icon + its count/grade badges live in a positioned thumb so the badges anchor
   to the icon, never over the name below. */
body.portal-page .storage-slot__thumb {
  position: relative;
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
}
body.portal-page .storage-slot__icon {
  width: 38px;
  height: 38px;
  object-fit: contain;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}
body.portal-page .storage-slot__qty {
  position: absolute;
  bottom: -3px;
  right: -4px;
  font-size: 0.62rem;
  font-weight: 700;
  color: var(--text);
  background: var(--bg-deep, #000);
  padding: 0 3px;
  border-radius: var(--radius-full);
  line-height: 1.4;
}
body.portal-page .storage-slot__grade {
  position: absolute;
  top: -3px;
  left: -4px;
  width: 16px;
  height: 16px;
  display: grid;
  place-items: center;
  font-size: 0.55rem;
  font-weight: 700;
  line-height: 1;
  /* Same radial grade gauge as cont-item__grade, sized for the dense grid. */
  background:
    radial-gradient(circle, var(--bg-card) 0 55%, transparent 56%),
    conic-gradient(currentColor var(--qr-fill, 360deg), rgba(128, 128, 128, 0.35) 0);
  border-radius: 50%;
  box-shadow: 0 0 0 1px var(--bg-card);
}
body.portal-page .storage-slot__name {
  width: 100%;
  font-size: 0.6rem;
  line-height: 1.15;
  color: var(--text-muted);
  text-align: center;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  word-break: break-word;
}

/* ---- Containers card header: title left, compact item search right ---- */
/* One row so the card <h2> and the cross-container search box share a line;
   wraps to stacked on narrow widths. The input reuses .cont-search__input. */
body.portal-page .storage-panel__head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-3);
}
body.portal-page .storage-panel__head > :first-child { margin: 0; }
body.portal-page .storage-panel__head .cont-search__panel { flex: 1 1 100%; }
/* The search box is compact (auto-grows) on the title row; full-width once it
   wraps under the title. */
body.portal-page .storage-panel__search {
  display: flex;
  flex-wrap: wrap;
  flex: 1 1 240px;
  min-width: 0;
  margin-left: auto;
}
body.portal-page .storage-panel__head .cont-search__input {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--text-sm);
  padding: var(--space-2) var(--space-3);
}

/* ---- filled-slot affordance: reads as clickable (opens the action popover) ---- */
body.portal-page .storage-slot--filled {
  cursor: pointer;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}
body.portal-page .storage-slot--filled:hover {
  border-color: var(--accent);
  box-shadow: 0 4px 12px -6px var(--accent-glow);
}
body.portal-page .storage-slot--filled:focus-visible {
  outline: 2px solid var(--accent-bright);
  outline-offset: 2px;
}

/* ---- per-slot action popover (List on Exchange / Add price alert) ---- */
/* JS-built once, repositioned per click via position:fixed. Hidden by default;
   .storage-slot-pop--open reveals it above the grid. */
body.portal-page .storage-slot-pop {
  position: fixed;
  z-index: 1100;
  min-width: 180px;
  padding: var(--space-1);
  display: none;
  flex-direction: column;
  gap: 2px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-overlay);
}
body.portal-page .storage-slot-pop[hidden] { display: none; }
body.portal-page .storage-slot-pop--open { display: flex; }
body.portal-page .storage-slot-pop__action {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm, 6px);
  color: var(--text);
  font: inherit;
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
body.portal-page .storage-slot-pop__action:hover,
body.portal-page .storage-slot-pop__action:focus-visible {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent-bright);
  outline: none;
}
body.portal-page .storage-slot-pop__action:disabled {
  color: var(--text-muted);
  cursor: default;
  background: transparent;
}
body.portal-page .storage-slot-pop__note {
  margin: 0;
  padding: var(--space-2) var(--space-3);
  max-width: 230px;
  font-size: var(--text-sm);
  color: var(--text-muted);
}
body.portal-page .storage-slot-pop__note[hidden] { display: none; }
body.portal-page .storage-slot-pop__note--warn { color: var(--warning, #d9a441); }

/* ---- search-to-slot highlight pulse (self-fades after ~1.6s) ---- */
body.portal-page .storage-slot--highlight {
  animation: storage-slot-pulse 1.6s ease-out 1;
}
@keyframes storage-slot-pulse {
  0%   { box-shadow: 0 0 0 0 var(--accent-glow); border-color: var(--accent-bright); }
  30%  { box-shadow: 0 0 0 3px var(--accent-glow); border-color: var(--accent-bright); }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* ---- right-panel caption ---- */
body.portal-page .storage-panel__caption {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-2);
  font-size: var(--text-sm);
  color: var(--text-muted);
}
body.portal-page .storage-panel__slots { font-family: var(--font-mono); font-size: var(--text-xs); }

/* ============================================================================
   Maps — hub + coordinate-accurate map renderer (DD / Hagga)
   ========================================================================== */

/* sand texture shared by DD backdrop + hub card art */
body.portal-page .map-backdrop--sand,
body.portal-page .map-hub-card__sand {
  background-color: #c89653;
  background-image:
    repeating-linear-gradient(118deg, rgba(150,100,45,0.06) 0 7px, transparent 7px 26px),
    repeating-linear-gradient(64deg, rgba(110,72,32,0.05) 0 9px, transparent 9px 34px),
    radial-gradient(circle at 22% 28%, rgba(120,80,30,0.16) 0 2px, transparent 3px),
    radial-gradient(circle at 68% 62%, rgba(120,80,30,0.13) 0 2px, transparent 3px),
    radial-gradient(circle at 45% 82%, rgba(140,95,40,0.11) 0 3px, transparent 4px),
    radial-gradient(ellipse at 50% 0%, #d8a862 0%, #c89048 55%, #b67c38 100%);
  background-size: auto, auto, 90px 90px, 130px 130px, 70px 70px, 100% 100%;
}

/* ---- hub ---- */
body.portal-page .map-hub-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-4); margin-top: var(--space-4);
}
body.portal-page .map-hub-card {
  position: relative; display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  overflow: hidden; text-decoration: none; color: var(--text);
  background: var(--bg-card); box-shadow: var(--shadow-card);
  transition: transform .15s ease, border-color .15s ease;
}
body.portal-page .map-hub-card:hover {
  transform: translateY(-2px); border-color: var(--accent);
}
body.portal-page .map-hub-card__art {
  position: relative; aspect-ratio: 16/9; overflow: hidden;
}
body.portal-page .map-hub-card__art img,
body.portal-page .map-hub-card__sand {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
body.portal-page .map-hub-card__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(12,10,7,0.75), transparent 60%);
}
body.portal-page .map-hub-card__body { padding: var(--space-3) var(--space-4); }
body.portal-page .map-hub-card__title {
  font-family: 'Cinzel', serif; font-size: var(--text-lg); margin: 0 0 var(--space-2);
}
body.portal-page .map-hub-card__chips { display: flex; flex-wrap: wrap; gap: var(--space-1); }
body.portal-page .map-hub-card__chip {
  font-size: var(--text-xs); font-family: var(--font-mono);
  padding: 2px 8px; border-radius: var(--radius-full);
  background: rgba(212,137,28,0.12); border: 1px solid var(--border);
  color: var(--text-muted);
}
body.portal-page .map-hub-card__chip--spice {
  color: #1b160e; background: #f0a020; border-color: #f0a020; font-weight: 600;
}

/* ---- renderer card ---- */
body.portal-page .map-card { padding: var(--space-4); }
body.portal-page .map-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); margin-bottom: var(--space-3); flex-wrap: wrap;
}
body.portal-page .map-toolbar__title { display: flex; align-items: center; gap: var(--space-3); }
body.portal-page .map-card__title { font-family: 'Cinzel', serif; font-size: var(--text-xl); margin: 0; }

body.portal-page .map-instance-switch {
  display: inline-flex; border: 1px solid var(--border); border-radius: var(--radius-full);
  overflow: hidden;
}
body.portal-page .map-instance-btn {
  border: 0; background: transparent; color: var(--text-muted);
  font-family: var(--font-mono); font-size: var(--text-sm);
  padding: 4px 14px; cursor: pointer; transition: background .12s, color .12s;
}
body.portal-page .map-instance-btn.is-active { background: var(--accent); color: #1b160e; font-weight: 600; }

body.portal-page .map-toolbar__zoom { display: inline-flex; gap: var(--space-1); }
body.portal-page .map-zoom-btn {
  width: 34px; height: 34px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-card); color: var(--text); font-size: 1.1rem; cursor: pointer;
  line-height: 1; display: grid; place-items: center;
}
body.portal-page .map-zoom-btn:hover { border-color: var(--accent); color: var(--accent-bright); }

/* ---- spice banner (melange violet) ---- */
body.portal-page .map-spice-banner {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3); margin-bottom: var(--space-3);
  border: 1px solid rgba(168,98,232,0.45); border-radius: var(--radius-md);
  background: rgba(150,72,221,0.10); font-size: var(--text-sm);
}
body.portal-page .map-spice-banner__pulse {
  width: 10px; height: 10px; border-radius: 50%; background: #b76cff;
  box-shadow: 0 0 0 0 rgba(168,98,232,0.6); animation: mapSpicePulse 1.8s infinite;
}
@keyframes mapSpicePulse {
  0% { box-shadow: 0 0 0 0 rgba(168,98,232,0.55); }
  70% { box-shadow: 0 0 0 9px rgba(168,98,232,0); }
  100% { box-shadow: 0 0 0 0 rgba(168,98,232,0); }
}

/* ---- viewport / stage ---- */
body.portal-page .map-viewport {
  position: relative; width: 100%; max-width: 760px; margin: 0 auto;
  aspect-ratio: 1/1; overflow: hidden; border: 1px solid var(--border);
  border-radius: var(--radius-md); background: #0c0a07; cursor: grab;
  touch-action: none;
}
body.portal-page .map-viewport.is-dragging { cursor: grabbing; }
body.portal-page .map-stage { position: absolute; top: 0; left: 0; transform-origin: 0 0; }
body.portal-page .map-backdrop { position: absolute; inset: 0; }
body.portal-page .map-canvas, body.portal-page .map-overlay { position: absolute; inset: 0; width: 100%; height: 100%; }
body.portal-page .map-overlay { pointer-events: none; }
body.portal-page .map-loading {
  position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--text-muted); font-family: var(--font-mono); font-size: var(--text-sm);
}
body.portal-page .map-loading[hidden] { display: none; }

/* svg grid + labels */
body.portal-page .map-grid line { stroke: rgba(20,14,6,0.35); stroke-width: 1; }
body.portal-page .map-grid-label {
  fill: rgba(30,20,8,0.6); font-size: 18px; font-family: var(--font-mono);
  text-anchor: middle; dominant-baseline: middle;
}
/* spice overlay (melange violet — candidate sites translucent, the active blow
   bright + glowing + pulsing) */
body.portal-page .map-spice-candidate {
  fill: rgba(157,78,221,0.38); stroke: #c89bff; stroke-width: 2;
  filter: drop-shadow(0 0 3px rgba(168,98,232,0.6));
}
body.portal-page .map-spice-active {
  fill: #b14dff; stroke: #f0d9ff; stroke-width: 2.5;
  filter: drop-shadow(0 0 7px rgba(177,77,255,0.95));
  animation: mapSpiceActiveGlow 2.2s ease-in-out infinite;
}
@keyframes mapSpiceActiveGlow {
  0%, 100% { filter: drop-shadow(0 0 5px rgba(177,77,255,0.75)); }
  50%      { filter: drop-shadow(0 0 12px rgba(199,125,255,1)); }
}
/* expanding "blow" ring under the active diamond */
body.portal-page .map-spice-pulse {
  fill: rgba(157,78,221,0.28); animation: mapBlow 2.2s ease-out infinite;
  transform-box: fill-box; transform-origin: center;
}
@keyframes mapBlow {
  0%   { opacity: .55; transform: scale(0.6); }
  70%  { opacity: 0;   transform: scale(1.5); }
  100% { opacity: 0;   transform: scale(1.5); }
}
/* medium spice fields (Part A): a smaller, dimmer amber diamond, distinct from the
   violet Large candidate/active markers. Static-per-cycle (the full set at once). */
body.portal-page .map-spice-medium {
  fill: rgba(168,98,232,0.22); stroke: #c89bff; stroke-width: 1.5;
  filter: drop-shadow(0 0 2px rgba(168,98,232,0.5));
}

/* ---- sandworm danger overlay ---- */
/* worm marker = the in-game threat indicator: a worm-head arrow + a live
   seismograph waveform, colored yellow -> orange -> red by threat. The trace
   wiggles (SMIL, set in JS); a submerged worm is a calm flat line. Strokes use
   non-scaling-stroke so the glyph stays crisp through map zoom. Age fade is
   applied inline by the JS (group opacity). */
body.portal-page .map-worm__wave {
  fill: none; stroke: #e8c34a; stroke-width: 3;
  stroke-linejoin: round; stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 1.5px rgba(0,0,0,0.7));
}
body.portal-page .map-worm__arrow {
  fill: #e8c34a; stroke: rgba(0,0,0,0.6); stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
/* threat tiers: yellow (surfaced) -> orange (enraged) -> red (breaching) */
body.portal-page .map-worm.is-submerged .map-worm__wave,
body.portal-page .map-worm.is-submerged .map-worm__arrow {
  stroke: #9a865a; fill: #9a865a; opacity: 0.7;
}
body.portal-page .map-worm.is-surfaced .map-worm__wave  { stroke: #e8c34a; }
body.portal-page .map-worm.is-surfaced .map-worm__arrow { fill: #e8c34a; }
body.portal-page .map-worm.is-enraged  .map-worm__wave  { stroke: #e8843a; stroke-width: 3.4; }
body.portal-page .map-worm.is-enraged  .map-worm__arrow { fill: #e8843a; }
body.portal-page .map-worm.is-breaching .map-worm__wave  { stroke: #e0402e; stroke-width: 4; }
body.portal-page .map-worm.is-breaching .map-worm__arrow { fill: #e0402e; }
body.portal-page .map-worm.is-breaching { animation: mapWormFlash 0.55s steps(2) infinite; }
@keyframes mapWormFlash { 0%,100% { opacity: 1; } 50% { opacity: 0.5; } }
@media (prefers-reduced-motion: reduce) {
  body.portal-page .map-worm.is-breaching { animation: none; }
  body.portal-page .map-worm__wave > animate { display: none; }
}

/* worm danger banner (sandy/red, distinct from the violet spice banner) */
body.portal-page .map-worm-banner {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3); margin-bottom: var(--space-3);
  border: 1px solid rgba(224,138,58,0.45); border-radius: var(--radius-md);
  background: rgba(200,110,40,0.10); font-size: var(--text-sm);
}
body.portal-page .map-worm-banner.is-danger {
  border-color: rgba(224,88,58,0.6); background: rgba(200,50,40,0.12);
}
body.portal-page .map-worm-banner__icon { font-size: 1.05rem; line-height: 1; }
body.portal-page .map-worm-banner__toggle {
  margin-left: auto; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-card); color: var(--text-muted); cursor: pointer;
  font-size: var(--text-xs); font-family: var(--font-mono); padding: 2px 8px;
}
body.portal-page .map-worm-banner__toggle.is-on { color: var(--accent-bright); border-color: var(--accent); }

/* ---- personal sandworm proximity warning (harvester safety) ---- */
body.portal-page .map-worm-proximity {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3); margin-bottom: var(--space-3);
  border: 1px solid var(--border); border-radius: var(--radius-md);
  font-size: var(--text-sm); font-weight: 600;
}
body.portal-page .map-worm-proximity[hidden] { display: none; }
body.portal-page .map-worm-proximity__wave { flex: none; line-height: 0; }
body.portal-page .map-worm-proximity__trace {
  fill: none; stroke-width: 2.4; stroke-linejoin: round; stroke-linecap: round;
}
body.portal-page .map-worm-proximity__arrow { stroke: none; }
/* tiers: clear (calm) -> caution (yellow) -> warn (orange) -> danger (red, flashing) */
body.portal-page .map-worm-proximity.is-clear {
  border-color: rgba(110,150,90,0.4); background: rgba(110,150,90,0.08); color: var(--text-muted);
}
body.portal-page .map-worm-proximity.is-clear .map-worm-proximity__trace,
body.portal-page .map-worm-proximity.is-clear .map-worm-proximity__arrow { stroke: #7da35a; fill: #7da35a; }
body.portal-page .map-worm-proximity.is-caution {
  border-color: rgba(232,195,74,0.5); background: rgba(232,195,74,0.10);
}
body.portal-page .map-worm-proximity.is-caution .map-worm-proximity__trace,
body.portal-page .map-worm-proximity.is-caution .map-worm-proximity__arrow { stroke: #e8c34a; fill: #e8c34a; }
body.portal-page .map-worm-proximity.is-warn {
  border-color: rgba(232,132,58,0.6); background: rgba(232,132,58,0.12);
}
body.portal-page .map-worm-proximity.is-warn .map-worm-proximity__trace,
body.portal-page .map-worm-proximity.is-warn .map-worm-proximity__arrow { stroke: #e8843a; fill: #e8843a; }
body.portal-page .map-worm-proximity.is-danger {
  border-color: rgba(224,64,46,0.75); background: rgba(224,64,46,0.16); color: #ffd9d2;
  animation: mapWormFlash 0.55s steps(2) infinite;
}
body.portal-page .map-worm-proximity.is-danger .map-worm-proximity__trace,
body.portal-page .map-worm-proximity.is-danger .map-worm-proximity__arrow { stroke: #ff3b2e; fill: #ff3b2e; }
@media (prefers-reduced-motion: reduce) {
  body.portal-page .map-worm-proximity.is-danger { animation: none; }
}

/* tooltip */
body.portal-page .map-tooltip {
  position: absolute; z-index: 5; pointer-events: none;
  background: rgba(12,10,7,0.95); color: #ece3d2; border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 3px 8px; font-size: var(--text-xs);
  font-family: var(--font-mono); white-space: nowrap;
}

/* legend */
body.portal-page .map-legend {
  display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3);
}
body.portal-page .map-legend__item {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-full);
  background: var(--bg-card); color: var(--text); font-size: var(--text-xs);
  padding: 3px 10px; transition: opacity .12s;
}
body.portal-page .map-legend__item.is-off { opacity: 0.4; }
body.portal-page .map-legend__swatch { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
body.portal-page .map-legend__count { color: var(--text-muted); font-family: var(--font-mono); }

/* per-player overlay (own position / bases / vehicles) — control chips */
body.portal-page .map-me-controls {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  margin-top: var(--space-3);
}
body.portal-page .map-me-controls__label {
  font-size: var(--text-xs); color: var(--text-muted); text-transform: uppercase;
  letter-spacing: .06em; margin-right: 2px;
}
body.portal-page .map-me-chip {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-full);
  background: var(--bg-card); color: var(--text); font-size: var(--text-xs);
  padding: 3px 10px; transition: opacity .12s;
}
body.portal-page .map-me-chip.is-off { opacity: 0.4; }
body.portal-page .map-me-chip.is-empty { opacity: 0.35; }
body.portal-page .map-me-chip__count { color: var(--text-muted); font-family: var(--font-mono); }
body.portal-page .map-me-chip__swatch { width: 11px; height: 11px; display: inline-block; }
body.portal-page .map-me-chip__swatch--self { border-radius: 50%; background: #46c2ff; box-shadow: 0 0 0 2px rgba(70,194,255,.3); }
body.portal-page .map-me-chip__swatch--base { background: #6fe0a0; clip-path: polygon(50% 0, 100% 38%, 100% 100%, 0 100%, 0 38%); }
body.portal-page .map-me-chip__swatch--vehicle { border-radius: 3px; background: #d8b878; }

/* per-player overlay — svg markers */
body.portal-page .map-me-pin__body { fill: #46c2ff; stroke: #eaf7ff; stroke-width: 1.5; }
body.portal-page .map-me-pin__dot { fill: #0c2030; }
body.portal-page .map-me-pin.is-online .map-me-pin__body { filter: drop-shadow(0 0 5px rgba(70,194,255,.95)); }
body.portal-page .map-me-pin.is-offline { opacity: 0.5; }
body.portal-page .map-me-pin.is-offline .map-me-pin__body { fill: #7fa3b8; }
body.portal-page .map-me-pulse {
  fill: rgba(70,194,255,0.22); animation: mapBlow 2s ease-out infinite;
  transform-box: fill-box; transform-origin: center;
}
body.portal-page .map-me-base__body { fill: rgba(111,224,160,0.85); stroke: #0e2a1c; stroke-width: 1.2; }
body.portal-page .map-me-base.is-outpost .map-me-base__body { fill: rgba(111,224,160,0.55); }
body.portal-page .map-me-vehicle__icon { filter: drop-shadow(0 1px 2px rgba(0,0,0,.7)); }
body.portal-page .map-me-vehicle__dot { fill: #d8b878; stroke: #2a1f10; stroke-width: 1; }

/* ============================================================================
 * MAP FILTER OVERHAUL (T#4) — collapsible sidebar, per-type tree, presets
 * T#5 additions: sandstorm banner, Shai-Hulud flash + audio, worm-banner right
 * T#4: click popup, waypoints, PvP boundary line
 * ========================================================================== */

/* ---- map-body: viewport + sidebar side-by-side on desktop -------------- */
/* Mobile-first column: the map takes the full width, the filter sidebar stacks
   below it. Only >=900px goes side-by-side (a row layout at phone widths let the
   full-width sidebar crush the viewport to a sliver in the PWA). */
body.portal-page .map-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  align-items: stretch;
  margin-bottom: var(--space-3);
}
@media (min-width: 900px) {
  body.portal-page .map-body {
    flex-direction: row;
    align-items: flex-start;
  }
}
body.portal-page .map-body .map-viewport {
  flex: 1 1 auto;
  min-width: 0;
  max-width: none;
  margin: 0;
}

/* ---- collapsible sidebar ----------------------------------------------- */
body.portal-page .map-sidebar {
  display: flex;
  flex-direction: column;
  gap: 0;
  width: 100%;
  order: 2;          /* below viewport on mobile */
}
@media (min-width: 900px) {
  body.portal-page .map-sidebar {
    flex: 0 0 220px;
    max-height: 760px;
    overflow-y: auto;
    overflow-x: hidden;   /* overflow-y:auto alone computes overflow-x to auto -> phantom horizontal scrollbar */
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-card);
    order: 1;
  }
}
@media (max-width: 899.98px) {
  /* Stacked under the map: same card chrome as desktop, and the layer tree
     scrolls inside itself so a long legend doesn't bury waypoints/page. */
  body.portal-page .map-sidebar {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-card);
  }
  body.portal-page .map-legend {
    max-height: 40vh;
    overflow-y: auto;
    overflow-x: hidden;
  }
}
body.portal-page .map-sidebar__section {
  padding: var(--space-3);
  border-bottom: 1px solid var(--border);
}
body.portal-page .map-sidebar__section:last-child { border-bottom: 0; }
body.portal-page .map-sidebar__section-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  margin-bottom: var(--space-2);
}
body.portal-page .map-sidebar__hint {
  font-size: var(--text-xs);
  color: var(--text-muted);
  margin: 0 0 var(--space-2) 0;
  line-height: 1.5;
}
body.portal-page .map-sidebar__hint kbd {
  font-size: 10px;
  padding: 0 4px;
  border: 1px solid var(--border-strong);
  border-radius: 3px;
  background: var(--bg);
}

/* Filter row + quick buttons */
body.portal-page .map-sidebar__filter-row {
  margin-bottom: var(--space-2);
}
body.portal-page .map-sidebar__search {
  width: 100%;
  padding: 5px var(--space-3);
  font: inherit;
  font-size: var(--text-xs);
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
body.portal-page .map-sidebar__search:focus { outline: none; border-color: var(--accent); }
body.portal-page .map-sidebar__quick {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: var(--space-2);
}
body.portal-page .map-sidebar__quick-btn {
  font: inherit;
  font-size: 10px;
  font-weight: 600;
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--bg);
  color: var(--text-muted);
  cursor: pointer;
  transition: color .12s, border-color .12s;
}
body.portal-page .map-sidebar__quick-btn:hover { color: var(--text); border-color: var(--border-strong); }
body.portal-page .map-sidebar__quick-btn--accent {
  color: var(--accent-bright); border-color: var(--accent);
}

/* PvP boundary checkbox row */
body.portal-page .map-sidebar__boundary-row {
  margin-bottom: var(--space-2);
}
body.portal-page .map-sidebar__boundary-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-xs);
  color: var(--text-muted);
  cursor: pointer;
  user-select: none;
}
body.portal-page .map-sidebar__boundary-label input { accent-color: var(--accent); }

/* ---- legend: category → type tree ------------------------------------- */
body.portal-page .map-legend {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-top: 0;
}
body.portal-page .map-legend__cat {
  width: 100%;          /* flex item won't stretch below its rows' min-content; clamp so long type labels ellipsis instead of overflowing the sidebar */
  border-radius: var(--radius-sm);
  overflow: hidden;
}
body.portal-page .map-legend__cat.is-off { opacity: 0.45; }
body.portal-page .map-legend__cat-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  font: inherit;
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--text);
  padding: 5px var(--space-2);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background .1s;
}
body.portal-page .map-legend__cat-btn:hover { background: var(--bg); }
body.portal-page .map-legend__expand {
  flex: 0 0 auto;
  font-size: 9px;
  color: var(--text-muted);
  transition: transform .15s;
}
body.portal-page .map-legend__cat:not(.is-collapsed) .map-legend__expand { transform: rotate(90deg); }
body.portal-page .map-legend__swatch {
  flex: 0 0 auto;
  width: 9px; height: 9px;
  border-radius: 50%;
  display: inline-block;
}
body.portal-page .map-legend__cat-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.portal-page .map-legend__count { color: var(--text-muted); font-family: var(--font-mono); font-size: 10px; flex-shrink: 0; }
body.portal-page .map-legend__types {
  display: flex;
  flex-direction: column;
  padding: 0 0 var(--space-1) var(--space-3);
}
body.portal-page .map-legend__type {
  display: flex;
  align-items: center;
  gap: 5px;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  font: inherit;
  font-size: 11px;
  color: var(--text-muted);
  padding: 3px var(--space-2);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background .1s, color .1s;
}
body.portal-page .map-legend__type:hover { background: var(--bg); color: var(--text); }
body.portal-page .map-legend__type.is-off { opacity: 0.35; }
body.portal-page .map-legend__type-icon {
  width: 16px; height: 16px; object-fit: contain; flex: 0 0 auto;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.45));
}
body.portal-page .map-legend__type-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- PvP boundary line (SVG) ------------------------------------------ */
body.portal-page .map-pvp-boundary {
  stroke: rgba(200, 90, 80, 0.7);
  stroke-width: 2;
  stroke-dasharray: 14 7;
}
body.portal-page .map-pvp-label {
  font-size: 10px;
  font-family: var(--font-mono);
  font-weight: 700;
  text-anchor: middle;
  dominant-baseline: middle;
}
body.portal-page .map-pvp-label--pvp { fill: rgba(200, 90, 80, 0.85); }
body.portal-page .map-pvp-label--pve { fill: rgba(95, 160, 95, 0.85); }

/* ---- waypoints --------------------------------------------------------- */
body.portal-page .map-wp-section { }
body.portal-page .map-wp-section__count { font-family: var(--font-mono); font-size: 10px; }
body.portal-page .map-wp-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 200px;
  overflow-y: auto;
}
body.portal-page .map-wp-empty { font-size: 11px; color: var(--text-muted); padding: var(--space-1) 0; }
body.portal-page .map-wp-item {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 11px;
  color: var(--text);
  padding: 3px var(--space-1);
  border-radius: var(--radius-sm);
}
body.portal-page .map-wp-item__icon { flex: 0 0 auto; color: #f5a23a; font-size: 9px; }
body.portal-page .map-wp-item__note {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
  color: var(--text-muted);
  transition: color .1s;
}
body.portal-page .map-wp-item__note:hover { color: var(--accent-bright); }
body.portal-page .map-wp-item__del {
  flex: 0 0 auto;
  background: none;
  border: 0;
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
  opacity: 0.5;
  transition: opacity .1s, color .1s;
}
body.portal-page .map-wp-item__del:hover { opacity: 1; color: var(--red); }

/* Waypoint pin SVG marker */
body.portal-page .map-wp-pin {
  fill: #f5a23a;
  stroke: #1b160e;
  stroke-width: 1.2;
  filter: drop-shadow(0 1px 3px rgba(0,0,0,0.6));
}
body.portal-page .map-wp-pin__dot { fill: #1b160e; }

/* ---- click popup ------------------------------------------------------- */
body.portal-page .map-popup {
  position: absolute;
  z-index: 10;
  min-width: 180px;
  max-width: 260px;
  padding: var(--space-3) var(--space-4);
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-overlay);
  font-size: var(--text-sm);
  pointer-events: auto;
}
body.portal-page .map-popup[hidden] { display: none; }
body.portal-page .map-popup__close {
  position: absolute;
  top: 6px; right: 8px;
  background: none; border: 0;
  color: var(--text-muted); font-size: 16px; line-height: 1; cursor: pointer;
  padding: 0;
}
body.portal-page .map-popup__close:hover { color: var(--text); }
body.portal-page .map-popup__name {
  font-weight: 700;
  font-size: var(--text-sm);
  color: var(--text);
  margin-bottom: 3px;
  padding-right: 20px;
}
body.portal-page .map-popup__cat {
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: var(--space-2);
}
body.portal-page .map-popup__coords {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
  margin-bottom: var(--space-2);
}
body.portal-page .map-popup__copy {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  transition: color .12s, border-color .12s;
}
body.portal-page .map-popup__copy:hover { color: var(--accent-bright); border-color: var(--accent); }
body.portal-page .map-popup__alt { font-size: 11px; color: var(--text-muted); margin-top: var(--space-1); }

/* ---- T#5: sandstorm ETA banner ----------------------------------------- */
body.portal-page .map-sandstorm-banner {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-3);
  border: 1px solid rgba(90, 169, 214, 0.45);
  border-radius: var(--radius-md);
  background: rgba(90, 169, 214, 0.08);
  font-size: var(--text-sm);
}
body.portal-page .map-sandstorm-banner[hidden] { display: none; }
body.portal-page .map-sandstorm-banner__icon { font-size: 1.05rem; line-height: 1; flex: none; }
body.portal-page .map-storm-dim {
  font-weight: 700;
  color: var(--text-muted);
}
body.portal-page .map-storm-eta {
  font-family: var(--font-mono);
  font-weight: 700;
  color: var(--info, #5aa9d6);
}
/* Active storm: amber, urgent. Set when any dimension is mid-sweep. */
body.portal-page .map-sandstorm-banner--active {
  border-color: rgba(212, 137, 28, 0.55);
  background: rgba(212, 137, 28, 0.12);
}
body.portal-page .map-storm-active {
  font-family: var(--font-mono);
  font-weight: 700;
  color: var(--accent, #d4891c);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

/* ---- Player counter (toolbar): this-map total + server-wide online ----- */
body.portal-page .map-players-counter {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1, 4px);
  margin-right: var(--space-2);
  padding: 0.2rem 0.5rem;
  border: 1px solid var(--border, #2a2a35);
  border-radius: var(--radius-md, 6px);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
  white-space: nowrap;
}
body.portal-page .map-players-counter[hidden] { display: none; }
body.portal-page .map-players-counter__icon { font-size: 0.9rem; line-height: 1; }

/* ---- T#5: worm banner right-side group (toggle + audio) ---------------- */
body.portal-page .map-worm-banner__right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--space-1);
}
body.portal-page .map-worm-banner__audio {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  color: var(--text-muted);
  cursor: pointer;
  font-size: var(--text-xs);
  font-family: var(--font-mono);
  padding: 2px 8px;
  transition: color .12s, border-color .12s;
}
body.portal-page .map-worm-banner__audio.is-on {
  color: var(--accent-bright);
  border-color: var(--accent);
}

/* ---- T#5: worm-proximity danger flash + audio note override ------------ */
/* Override the shared animation to use the new dedicated keyframes */
@keyframes mapWormDangerFlash {
  0%, 100% { opacity: 1; background: rgba(224,64,46,0.16); }
  50%       { opacity: 0.82; background: rgba(224,64,46,0.30); }
}
body.portal-page .map-worm-proximity.is-danger {
  animation: mapWormDangerFlash 0.55s steps(2) infinite;
}
@media (prefers-reduced-motion: reduce) {
  body.portal-page .map-worm-proximity.is-danger { animation: none; }
}

/* ===========================================================================
 * GUILDS  —  /portal/guilds directory + recruitment board + /portal/guilds/{id}  —  /portal/guilds directory + recruitment board + /portal/guilds/{id}
 * Read-only directory (game DB) + portal-side recruiting flag. Faction-accented.
 * ------------------------------------------------------------------------- */
body.portal-page .gd-faction--atreides   { --gd-accent: #2f8f57; --gd-accent-soft: rgba(47,143,87,0.14); }
body.portal-page .gd-faction--harkonnen  { --gd-accent: #d65a44; --gd-accent-soft: rgba(214,90,68,0.14); }
body.portal-page .gd-faction--smuggler   { --gd-accent: #d4891c; --gd-accent-soft: rgba(212,137,28,0.14); }
body.portal-page .gd-faction--unaligned  { --gd-accent: #9c8e74; --gd-accent-soft: rgba(156,142,116,0.12); }

/* faction + status pills */
body.portal-page .gd-pill--atreides  { color: #6fc888; border-color: rgba(47,143,87,0.60); background: rgba(47,143,87,0.12); }
body.portal-page .gd-pill--harkonnen { color: #e88a76; border-color: rgba(214,90,68,0.55);  background: rgba(214,90,68,0.10); }
body.portal-page .gd-pill--smuggler  { color: var(--accent-bright); border-color: var(--accent); background: var(--accent-glow); }
body.portal-page .gd-pill--unaligned { color: var(--text-muted); border-color: var(--border-strong); }
body.portal-page .gd-pill--recruiting {
  color: var(--green); border-color: rgba(95,207,107,0.55); background: rgba(95,207,107,0.12);
}
body.portal-page .gd-pill--role100 { color: var(--accent-bright); border-color: var(--accent); background: var(--accent-glow); }
body.portal-page .gd-pill--role50  { color: #c9b6e6; border-color: rgba(138,107,191,0.55); background: var(--p-violet-soft); }
body.portal-page .gd-pill--role1   { color: var(--text-muted); border-color: var(--border-strong); }

/* recruiting board */
body.portal-page .gd-reclist {
  display: grid; grid-template-columns: 1fr; gap: var(--space-3);
}
@media (min-width: 768px) { body.portal-page .gd-reclist { grid-template-columns: 1fr 1fr; } }
body.portal-page .gd-reccard {
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-3); border-radius: var(--radius-md, 10px);
  border: 1px solid var(--border); border-left: 3px solid var(--gd-accent, var(--accent));
  background: var(--bg-elevated); text-decoration: none; color: var(--text);
  transition: border-color .15s ease, transform .15s ease, background .15s ease;
}
body.portal-page .gd-reccard:hover { background: var(--gd-accent-soft, var(--accent-glow)); transform: translateY(-1px); }
body.portal-page .gd-reccard__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
body.portal-page .gd-reccard__name { font-weight: 700; font-size: var(--text-md, 1rem); }
body.portal-page .gd-reccard__blurb { color: var(--text-muted); font-size: var(--text-sm); line-height: 1.4; }
body.portal-page .gd-reccard__foot { display: flex; justify-content: space-between; gap: var(--space-2); color: var(--text-muted); font-size: var(--text-xs); }
body.portal-page .gd-reccard__contact { color: var(--accent-bright); }

/* CSS-only rankings tabs */
body.portal-page .gd-tabs { position: relative; }
body.portal-page .gd-tabs__radio { position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; }
body.portal-page .gd-tabs__labels { display: inline-flex; gap: var(--space-1); margin-bottom: var(--space-3); border-bottom: 1px solid var(--border); }
body.portal-page .gd-tab {
  padding: var(--space-2) var(--space-3); cursor: pointer; color: var(--text-muted);
  font-weight: 600; font-size: var(--text-sm); border-bottom: 2px solid transparent; margin-bottom: -1px;
}
body.portal-page .gd-tab:hover { color: var(--text); }
body.portal-page #gd-tab-overall:checked ~ .gd-tabs__labels label[for="gd-tab-overall"],
body.portal-page #gd-tab-session:checked ~ .gd-tabs__labels label[for="gd-tab-session"] {
  color: var(--accent-bright); border-bottom-color: var(--accent);
}
body.portal-page .gd-tabs__panel { display: none; }
body.portal-page #gd-tab-overall:checked ~ .gd-tabs__panel--overall { display: block; }
body.portal-page #gd-tab-session:checked ~ .gd-tabs__panel--session { display: block; }
body.portal-page .gd-tabs__radio:focus-visible ~ .gd-tabs__labels label { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ranking list */
body.portal-page .gd-rank { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
body.portal-page .gd-rank__row { display: grid; grid-template-columns: 2rem 1fr auto auto; align-items: center; gap: var(--space-2); padding: var(--space-2); border-radius: var(--radius-sm, 8px); }
body.portal-page .gd-rank__row:nth-child(odd) { background: var(--bg-elevated); }
body.portal-page .gd-rank__pos { font-family: var(--font-mono); font-weight: 700; color: var(--accent-bright); text-align: center; }
body.portal-page .gd-rank__name { font-weight: 600; color: var(--text); text-decoration: none; }
body.portal-page .gd-rank__name:hover { color: var(--accent-bright); text-decoration: underline; }
body.portal-page .gd-rank__amt { color: var(--text-muted); font-size: var(--text-sm); }

/* faction-grouped directory */
body.portal-page .gd-faction-card { border-top: 2px solid var(--gd-accent, var(--accent)); }
body.portal-page .gd-faction-card__count { font-size: var(--text-sm); font-weight: 500; color: var(--text-muted); margin-left: var(--space-2); }
body.portal-page .gd-grid { display: grid; grid-template-columns: 1fr; gap: var(--space-3); }
@media (min-width: 768px) { body.portal-page .gd-grid { grid-template-columns: 1fr 1fr; } }
body.portal-page .gd-card {
  display: flex; flex-direction: column; gap: var(--space-1);
  padding: var(--space-3); border-radius: var(--radius-md, 10px);
  border: 1px solid var(--border); background: var(--bg-elevated);
  text-decoration: none; color: var(--text); transition: border-color .15s ease, transform .15s ease;
}
body.portal-page .gd-card:hover { border-color: var(--gd-accent, var(--accent)); transform: translateY(-1px); }
body.portal-page .gd-card__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
body.portal-page .gd-card__name { font-weight: 700; }
body.portal-page .gd-card__meta { display: flex; gap: var(--space-3); color: var(--text-muted); font-size: var(--text-xs); }
body.portal-page .gd-card__lead { color: var(--text-muted); font-size: var(--text-xs); }

/* detail page */
body.portal-page .gd-about { line-height: 1.6; color: var(--text); white-space: pre-wrap; }
body.portal-page .gd-roster { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
body.portal-page .gd-roster__row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: var(--space-2); border-radius: var(--radius-sm, 8px); }
body.portal-page .gd-roster__row:nth-child(odd) { background: var(--bg-elevated); }
body.portal-page .gd-roster__name { font-weight: 600; }

/* recruitment editor */
body.portal-page .gd-editcard { border: 1px solid var(--accent-soft); }
body.portal-page .gd-editform { display: flex; flex-direction: column; gap: var(--space-4); }
body.portal-page .gd-editform__toggle { display: flex; align-items: center; gap: var(--space-2); cursor: pointer; }
body.portal-page .gd-editform__field { display: flex; flex-direction: column; gap: var(--space-2); }
body.portal-page .gd-editform__label { font-weight: 600; font-size: var(--text-sm); }
body.portal-page .gd-editform__hint { font-weight: 400; color: var(--text-muted); }
body.portal-page .gd-editform__textarea,
body.portal-page .gd-editform__input {
  width: 100%; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm, 8px);
  border: 1px solid var(--border-strong); background: var(--bg-deep); color: var(--text);
  font-family: inherit; font-size: var(--text-sm); resize: vertical;
}
body.portal-page .gd-editform__textarea:focus,
body.portal-page .gd-editform__input:focus { outline: none; border-color: var(--accent); }
body.portal-page .gd-editform__actions { display: flex; justify-content: flex-end; }

/* GUILDS: main factions side-by-side + faction crest in the section header */
body.portal-page .gd-factions { display: grid; grid-template-columns: 1fr; gap: var(--space-4); align-items: start; }
@media (min-width: 900px) {
  body.portal-page .gd-factions { grid-template-columns: 1fr 1fr; }
  /* faction card is now ~half width -> stack its guild cards 1-col */
  body.portal-page .gd-factions .gd-grid { grid-template-columns: 1fr; }
}
body.portal-page .gd-faction-card__title { display: flex; align-items: center; gap: var(--space-2); }
body.portal-page .gd-faction-card__crest { width: 36px; height: 36px; object-fit: contain; flex: none; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.55)); }
body.portal-page .gd-faction-card__count { margin-left: auto; }

/* ===========================================================================
 * PHASE 1 CINEMATIC (2026-06-11)
 * View Transitions (cross-document), hero banner hover, parallax canvas.
 * Every motion block is wrapped in prefers-reduced-motion so nothing fires
 * when the user has asked for less movement.
 * =========================================================================== */

/* Opt all portal→portal link navigations into cross-document View Transitions.
 * Ignored verbatim by browsers that don't support the at-rule. */
@view-transition { navigation: auto; }

/* Root page transition: new content rises gently, old content fades up-out.
 * Named pairs (portal-page-hero, map-hub-*) fall back to browser-default
 * crossfade unless styled below. */
@keyframes portal-vt-enter {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes portal-vt-leave {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-3px); }
}

@media (prefers-reduced-motion: no-preference) {
  ::view-transition-new(root) {
    animation: portal-vt-enter 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
  }
  ::view-transition-old(root) {
    animation: portal-vt-leave 0.18s cubic-bezier(0.4, 0, 1, 1) both;
    z-index: 0;
  }

  /* Hero-to-hero morph between pages: slower fade so the banner art blends
   * smoothly across navigations (account ↔ market ↔ maps hub etc.). */
  ::view-transition-old(portal-page-hero),
  ::view-transition-new(portal-page-hero) {
    animation-duration: 0.42s;
    animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
  }
}

/* Hard kill: no animation at all when reduced motion is requested.
 * Belt + suspenders — the JS file already returns early, but CSS must
 * honour the preference independently. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation-duration: 0.01ms !important;
  }
}

/* Named cross-page hero morph — assign to every portal-hero so navigating
 * between any two portal pages morphs the banner art (same name = paired). */
body.portal-page .portal-hero {
  view-transition-name: portal-page-hero;
}
/* Maps hub card → map detail: the card art gets a unique name per key
 * (applied via style= in maps.html); the slim hero on map.html carries the
 * matching name so the card "expands" into the hero on navigation.
 * The inline style override wins over the rule above (higher specificity). */

/* ---------------------------------------------------------------------------
 * Premium hero hover — spice-amber glow border + warmth blush from below.
 * CSS-only, no JS. Applies to all 12 per-page hero banners.
 *
 * Stacking inside .portal-hero (position:relative, overflow:hidden):
 *   layer 0 – background-image (photo + gradient scrim)  [CSS bg, z-index n/a]
 *   layer 1 – canvas injected by portal-cinematic.js     [z-index: 0]
 *   layer 2 – ::after amber warmth overlay               [z-index: 0, after canvas]
 *   layer 3 – .portal-hero__inner                        [z-index: 1]
 * --------------------------------------------------------------------------- */
body.portal-page .portal-hero {
  transition: box-shadow 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Amber warmth blush — invisible at rest, fades in on hover. */
body.portal-page .portal-hero::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background: radial-gradient(
    ellipse 120% 55% at 50% 100%,
    rgba(212, 137, 28, 0)    0%,
    rgba(212, 137, 28, 0) 100%
  );
  transition: background 0.40s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Hero inner content breathes upward on hover. */
body.portal-page .portal-hero__inner {
  transition: transform 0.30s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Hover state: amber border ring + soft bottom glow + inner lift. */
body.portal-page .portal-hero:hover {
  box-shadow: var(--shadow-card),
              0 0 0 1px var(--accent),
              0 6px 32px var(--accent-glow);
}
body.portal-page .portal-hero:hover::after {
  background: radial-gradient(
    ellipse 120% 55% at 50% 100%,
    rgba(212, 137, 28, 0.09) 0%,
    rgba(212, 137, 28, 0)   70%
  );
}
body.portal-page .portal-hero:hover .portal-hero__inner {
  transform: translateY(-2px);
}

/* Day theme: cooler accent, slightly softer blush. */
html[data-theme="day"] body.portal-page .portal-hero:hover::after {
  background: radial-gradient(
    ellipse 120% 55% at 50% 100%,
    rgba(179, 112, 15, 0.07) 0%,
    rgba(179, 112, 15, 0)   70%
  );
}

/* House hover blush adapts to house accent colour. */
html[data-theme="atreides"] body.portal-page .portal-hero:hover::after {
  background: radial-gradient(
    ellipse 120% 55% at 50% 100%,
    rgba(196, 158, 76, 0.08) 0%,
    rgba(196, 158, 76, 0)   70%
  );
}
html[data-theme="harkonnen"] body.portal-page .portal-hero:hover::after {
  background: radial-gradient(
    ellipse 120% 55% at 50% 100%,
    rgba(196, 32, 32, 0.10) 0%,
    rgba(196, 32, 32, 0)    70%
  );
}

/* Kill all hover motion for users who prefer reduced motion. */
@media (prefers-reduced-motion: reduce) {
  body.portal-page .portal-hero,
  body.portal-page .portal-hero::after,
  body.portal-page .portal-hero__inner {
    transition: none !important;
    transform:  none !important;
    animation:  none !important;
  }
}

/* ===========================================================================
 * HOUSE THEMES — sigil watermarks + faction opt-in band (2026-06-11)
 * =========================================================================== */

/* Rail watermark: game-extracted House sigil, ghosted at the center of the
 * left rail. Visible on desktop only (rail is hidden on mobile). The rail is
 * position:fixed so ::after is relative to the rail viewport. */
@media (min-width: 900px) {
  html[data-theme="atreides"] body.portal-page .portal-rail::after,
  html[data-theme="harkonnen"] body.portal-page .portal-rail::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: 268px;   /* clear of the foot: theme picker + account chip + sign-out */
    transform: translateX(-50%);
    width: 92px; height: 92px;
    background: var(--p-house-sigil) no-repeat center / contain;
    opacity: 0.05;
    pointer-events: none;
  }
}

/* Hero corner mark: small sigil in the top-right of every hero banner.
 * Uses ::before (::after is reserved for the cinematic hover blush).
 * z-index: 1 keeps it above the parallax canvas but the hero__inner text
 * sits at the bottom (flex-end), so there is no visual overlap. */
html[data-theme="atreides"] body.portal-page .portal-hero::before,
html[data-theme="harkonnen"] body.portal-page .portal-hero::before {
  content: "";
  position: absolute;
  top: var(--space-3);
  right: var(--space-4);
  width: 44px; height: 44px;
  background: var(--p-house-sigil) no-repeat center / contain;
  opacity: 0.16;
  pointer-events: none;
  z-index: 1;
}

/* "Wear your House colors?" opt-in banner — one-time, dismissible.
 * Lives between the rail/topbar and the main page shell. Hidden by default;
 * JS shows it when a House-faction account hasn't dismissed it and isn't
 * already on a House theme. */
body.portal-page .portal-houseband {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-5);
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
  font-size: var(--text-sm);
  animation: portal-houseband-in 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
}
body.portal-page .portal-houseband[hidden] { display: none; }
@keyframes portal-houseband-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
body.portal-page .portal-houseband__crest {
  width: 22px; height: 22px;
  flex-shrink: 0;
  background: no-repeat center / contain;
  opacity: 0.80;
}
body.portal-page .portal-houseband__crest--atreides {
  background-image: url("/admin/static/img/factions/atreides.png");
}
body.portal-page .portal-houseband__crest--harkonnen {
  background-image: url("/admin/static/img/factions/harkonnen.png");
}
body.portal-page .portal-houseband__msg {
  flex: 1;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
body.portal-page .portal-houseband__msg strong { color: var(--text); }
body.portal-page .portal-houseband__accept {
  flex-shrink: 0;
  padding: var(--space-1) var(--space-3);
  background: var(--accent-glow);
  border: 1px solid var(--accent-soft);
  border-radius: var(--radius-md);
  color: var(--accent-bright);
  font: inherit;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background var(--motion-fast) var(--ease-in-out),
              color var(--motion-fast) var(--ease-in-out);
}
body.portal-page .portal-houseband__accept:hover {
  background: var(--accent);
  color: #090e0b;
}
body.portal-page .portal-houseband__dismiss {
  flex-shrink: 0;
  background: none;
  border: none;
  color: var(--text-muted);
  padding: var(--space-1) var(--space-2);
  font: inherit;
  font-size: var(--text-lg);
  line-height: 1;
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: color var(--motion-fast) var(--ease-in-out);
}
body.portal-page .portal-houseband__dismiss:hover { color: var(--text); }

@media (prefers-reduced-motion: reduce) {
  body.portal-page .portal-houseband { animation: none; }
}
