/* ============================================
   VISIBLEMILES — UI Styles
   HUD, action bar, frames, panels, overlays
   ============================================ */

/* Register --cooldown-angle as an animatable <angle> so CSS @keyframes
   can interpolate conic-gradient at native framerate (60fps). Without this,
   custom properties are opaque strings and can't be animated. */
@property --cooldown-angle {
  syntax: '<angle>';
  initial-value: 360deg;
  inherits: false;
}

@keyframes cooldown-sweep {
  from { --cooldown-angle: 0deg; }
  to { --cooldown-angle: 360deg; }
}

/* ============================================
   GUI LAYER
   Single wrapper for all UI - enables clean toggle
   and establishes stacking context for all GUI elements
   ============================================ */
#gui-layer {
  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  transform: translate3d(0, 0, 0);
  transition: opacity var(--fade-snappy) ease-out;
  contain: layout style;
}

/* 
   POINTER-EVENTS: Direct children of #gui-layer manage their own.
   
   Click-through containers (children opt-in):
   - #left-panel-column: none (map.css) → children: auto
   - #right-panel-column: none (map.css) → children: auto
   - #bottom-ui: none → complex hierarchy
   - #resize-overlay: none (only visible during resize)
   - #tab-resume-overlay: none (sibling of #gui-layer under #game; only visible briefly after tab return)
   
   Interactive elements (explicitly set auto):
   - #fps-counter: auto (map.css)
   - #dialogue-panel: auto
   - #dialogue-shroud.visible: auto
   - #settings-menu: auto (explicit — show() does not override inherited none)
   - #settings-shroud.visible: auto
   - #worldmap-overlay: auto (explicit — show() does not override inherited none)
   - #toast-debug-panel: auto
   - .gui-modal: auto
   
   Do NOT add a blanket #gui-layer > * rule - it overrides individual rules.
*/

/* GUI hidden state (Cmd/Ctrl + \) */
#gui-layer.hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none !important;
}

#gui-layer.hidden > * {
  pointer-events: none !important;
}

/* ============================================
   GUI TOOLTIP
   Unified tooltip style for all GUI elements
   Usage: Add .gui-tooltip class, position with CSS,
   toggle visibility on parent :hover
   ============================================ */
.gui-tooltip {
  position: absolute;
  background: var(--bg-panel);
  padding: var(--gui-padding-sm) var(--gui-padding);
  font-family: var(--font-display);
  font-size: var(--font-size-sm);
  color: var(--text-primary);
  white-space: nowrap;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--fade-snappy) ease, visibility var(--fade-snappy) ease;
  pointer-events: auto;
  z-index: 100;
}

.tooltip-dismissed > .gui-tooltip {
  opacity: 0 !important;
  visibility: hidden !important;
}

/* Common tooltip positions */
.gui-tooltip.above {
  bottom: calc(100% + var(--gui-padding-sm));
  left: 50%;
  transform: translate3d(-50%, 0, 0);
}

.gui-tooltip.below {
  top: calc(100% + var(--gui-padding-sm));
  left: 50%;
  transform: translate3d(-50%, 0, 0);
}

.gui-tooltip.left {
  right: calc(100% + var(--gui-padding-sm));
  top: 50%;
  transform: translate3d(0, -50%, 0);
}

.gui-tooltip.right {
  left: calc(100% + var(--gui-padding-sm));
  top: 50%;
  transform: translate3d(0, -50%, 0);
}

/* ============================================
   GUI PANEL - UNIFIED DRAGGABLE PANEL SYSTEM
   All draggable panels use .gui-panel class
   ============================================ */

/* Base behavior for all GUI panels (drag/resize/dock) */
.gui-panel {
  position: relative; /* Docked panels stay in flow */
  /* GPU layer via 3D transform context */
  backface-visibility: hidden;
  transform: translate3d(0, 0, 0);
}

/* Visual styles for column panels (not frame wrappers) */
.gui-panel:not(.frame-wrapper) {
  background: var(--bg-panel-alpha);
  font-family: var(--font-display);
  min-width: 240px;
}

.gui-panel.hidden {
  display: none;
}

/* Undocked (floating) state */
.gui-panel.undocked {
  position: fixed;
  z-index: 30;
  pointer-events: auto;
}

.gui-panel.undocked:not(.frame-wrapper) {
  box-shadow: var(--shadow-md);
}

/* Actively dragging */
.gui-panel.dragging {
  cursor: grabbing;
  z-index: 40;
}

.gui-panel.dragging:not(.frame-wrapper) {
  box-shadow: var(--shadow-xl);
}

/* Resizing state */
.gui-panel.resizing {
  cursor: se-resize;
}

/* Near dock zone indicator */
.gui-panel.near-dock .redock-indicator {
  opacity: 1;
}

/* Panel header (drag handle) */
.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--gui-padding);
  background: var(--alpha-white-03);
  border-bottom: 1px solid var(--frame-border);
  cursor: grab;
  user-select: none;
}

.panel-header:active {
  cursor: grabbing;
}

.panel-footer {
  padding: var(--gui-padding);
  background: var(--alpha-white-03);
  border-top: 1px solid var(--frame-border);
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  text-align: center;
}

#minimap-label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  text-align: left;
}

#currency-display {
  color: var(--color-gold);
  font-variant-numeric: tabular-nums;
}
#currency-display::before {
  content: '⬡ ';
}

.panel-title {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.panel-controls {
  display: flex;
  gap: 0.25rem;
}

.panel-btn {
  width: 24px;
  height: 24px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-muted);
  font-size: var(--font-size-md);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity var(--fade-snappy) ease, background-color var(--fade-snappy) ease;
}

.gui-panel.undocked .panel-btn {
  opacity: 0.6;
}

.panel-btn:focus {
  opacity: 0.6;
}

.panel-btn:hover,
.panel-btn:focus-visible {
  opacity: 1;
  background: var(--alpha-white-10);
}

/* Resize handles - corners */
.resize-handle-se,
.resize-handle-sw,
.resize-handle-ne,
.resize-handle-nw {
  position: absolute;
  width: 14px;
  height: 14px;
  opacity: 0;
  transition: opacity var(--fade-snappy) ease;
  z-index: 10;
}

.resize-handle-se::after,
.resize-handle-sw::after,
.resize-handle-ne::after,
.resize-handle-nw::after {
  content: '';
  position: absolute;
  width: 6px;
  height: 6px;
  opacity: 0.5;
}

/* Corner positions and cursors */
.resize-handle-se {
  bottom: 2px;
  right: 2px;
  cursor: se-resize;
}
.resize-handle-se::after {
  bottom: 0;
  right: 0;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
}

.resize-handle-sw {
  bottom: 2px;
  left: 2px;
  cursor: sw-resize;
}
.resize-handle-sw::after {
  bottom: 0;
  left: 0;
  border-left: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
}

.resize-handle-ne {
  top: 2px;
  right: 2px;
  cursor: ne-resize;
}
.resize-handle-ne::after {
  top: 0;
  right: 0;
  border-right: 2px solid var(--text-muted);
  border-top: 2px solid var(--text-muted);
}

.resize-handle-nw {
  top: 2px;
  left: 2px;
  cursor: nw-resize;
}
.resize-handle-nw::after {
  top: 0;
  left: 0;
  border-left: 2px solid var(--text-muted);
  border-top: 2px solid var(--text-muted);
}

/* Resize handles - edge centers */
.resize-handle-n,
.resize-handle-s,
.resize-handle-e,
.resize-handle-w {
  position: absolute;
  opacity: 0;
  transition: opacity var(--fade-snappy) ease;
  z-index: 10;
}

/* Horizontal handles (top/bottom) */
.resize-handle-n,
.resize-handle-s {
  left: 50%;
  transform: translate3d(-50%, 0, 0);
  width: 40px;
  height: 10px;
  cursor: ns-resize;
}

/* Vertical handles (left/right) */
.resize-handle-e,
.resize-handle-w {
  top: 50%;
  transform: translate3d(0, -50%, 0);
  width: 10px;
  height: 40px;
  cursor: ew-resize;
}

/* Edge handle visual indicator (bar) */
.resize-handle-n::after,
.resize-handle-s::after,
.resize-handle-e::after,
.resize-handle-w::after {
  content: '';
  position: absolute;
  background: var(--text-muted);
  opacity: 0.5;
}

/* Horizontal bar for top/bottom */
.resize-handle-n::after,
.resize-handle-s::after {
  left: 50%;
  transform: translate3d(-50%, 0, 0);
  width: 24px;
  height: 2px;
}

/* Vertical bar for left/right */
.resize-handle-e::after,
.resize-handle-w::after {
  top: 50%;
  transform: translate3d(0, -50%, 0);
  width: 2px;
  height: 24px;
}

/* Edge handle positions */
.resize-handle-n {
  top: 0;
}
.resize-handle-n::after {
  top: 2px;
}

.resize-handle-s {
  bottom: 0;
}
.resize-handle-s::after {
  bottom: 2px;
}

.resize-handle-e {
  right: 0;
}
.resize-handle-e::after {
  right: 2px;
}

.resize-handle-w {
  left: 0;
}
.resize-handle-w::after {
  left: 2px;
}

/* Show resize handles on hover or while actively dragging */
.gui-panel:hover .resize-handle-se,
.gui-panel:hover .resize-handle-sw,
.gui-panel:hover .resize-handle-ne,
.gui-panel:hover .resize-handle-nw,
.gui-panel:hover .resize-handle-n,
.gui-panel:hover .resize-handle-s,
.gui-panel:hover .resize-handle-e,
.gui-panel:hover .resize-handle-w,
.gui-panel.dragging .resize-handle-se,
.gui-panel.dragging .resize-handle-sw,
.gui-panel.dragging .resize-handle-ne,
.gui-panel.dragging .resize-handle-nw,
.gui-panel.dragging .resize-handle-n,
.gui-panel.dragging .resize-handle-s,
.gui-panel.dragging .resize-handle-e,
.gui-panel.dragging .resize-handle-w {
  opacity: 1;
}

/* Redock indicator */
.redock-indicator {
  position: absolute;
  inset: -2px;
  border: 2px dashed var(--accent);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--fade-snappy) ease;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--redock-bg);
}

.redock-indicator span {
  background: var(--bg-panel);
  padding: 0.25rem 0.5rem;
  font-size: var(--font-size-xs);
  color: var(--accent);
}

/* Character sheet CSS removed — replaced by characterpanel.css */

/* Charge bar background (shared with unit frames) */
.charge-bar { background: var(--player-charge-bg); }

/* ============================================
   QUEST TRACKER
   ============================================ */
#quest-tracker {
  position: relative; /* Stay in flex flow when docked */
  background: var(--bg-panel-alpha);
  min-width: 240px;
  max-width: 400px;
  /* GPU layer for smooth drag/resize */
  backface-visibility: hidden;
  transform: translate3d(0, 0, 0);
  font-family: var(--font-display);
}

/* When undocked (dragged), take out of flex flow */
#quest-tracker.undocked {
  position: fixed;
}

#quest-list {
  display: flex;
  flex-direction: column;
  gap: var(--gui-gap);
  max-height: 200px;
  overflow-y: auto;
  padding: var(--gui-padding);
}

.quest-item {
  padding: var(--gui-padding) 0;
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
}

.quest-item.active {
  color: var(--warning);
}

.quest-item .quest-name {
  display: block;
  font-weight: 600;
  margin-bottom: 0.15rem;
}

.quest-item .quest-objective {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  padding-left: 0.5rem;
}

.quest-item .quest-objective::before { content: '◦ '; }
.quest-item .quest-objective.complete::before {
  content: '✓ ';
  color: var(--success);
}

.quest-item.active {
  cursor: pointer;
  border-left: 2px solid transparent;
  padding-left: calc(var(--gui-padding) - 2px);
}
.quest-item.tracked {
  border-left-color: var(--accent);
}
.quest-item.tracked .quest-name {
  color: var(--accent);
}

/* ============================================
   COMBAT LOG
   ============================================ */
#combat-log-container {
  position: relative;
  min-width: 240px;
  background: var(--bg-panel-alpha);
}

#combat-log-container.hidden {
  display: none;
}

/* When undocked, use fixed positioning */
#combat-log-container.undocked {
  position: fixed;
}

#combat-log {
  padding: var(--gui-padding);
  max-height: 150px;
  overflow-y: auto;
  font-family: var(--font-display);
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
}

.combat-log-line {
  padding: var(--gui-padding) 0;
  border-bottom: 1px solid var(--alpha-white-03);
}

.combat-log-line:last-child {
  border-bottom: none;
}

.combat-log-damage-dealt { color: oklch(0.78 0.14 50); }
.combat-log-damage-taken { color: oklch(0.72 0.18 25); }
.combat-log-debuff { color: oklch(0.72 0.15 330); }
.combat-log-healing { color: oklch(0.78 0.16 145); }
.combat-log-death { color: oklch(0.60 0.10 25); }
.combat-log-xp { color: oklch(0.82 0.12 85); }
.combat-log-loot { color: oklch(0.78 0.10 200); }
.combat-log-ability { color: var(--text-secondary); }

.combat-log-filter-bar {
  display: flex;
  gap: 2px;
  padding: 3px var(--gui-padding);
  border-bottom: 1px solid var(--alpha-white-05);
}

.combat-log-filter {
  position: relative;
  font: inherit;
  font-size: var(--font-size-xs);
  background: none;
  border: 1px solid var(--alpha-white-10);
  border-radius: 3px;
  color: var(--text-muted);
  padding: 1px 6px;
  cursor: pointer;
}

.combat-log-filter::after {
  content: '';
  position: absolute;
  inset: -10px -6px;
  min-height: 44px;
  min-width: 44px;
}

.combat-log-filter.active {
  color: var(--text-primary);
  border-color: var(--alpha-white-20);
  background: var(--alpha-white-05);
}

#combat-log-container.hide-damage .combat-log-damage-dealt,
#combat-log-container.hide-damage .combat-log-damage-taken,
#combat-log-container.hide-damage .combat-log-debuff { display: none; }
#combat-log-container.hide-healing .combat-log-healing { display: none; }
#combat-log-container.hide-xp .combat-log-xp,
#combat-log-container.hide-xp .combat-log-loot { display: none; }
#combat-log-container.hide-system .combat-log-system,
#combat-log-container.hide-system .combat-log-ability,
#combat-log-container.hide-system .combat-log-death { display: none; }

/* ============================================
   PARTY FRAMES (wireframe stub)
   ============================================ */

#party-frames {
  position: relative;
  min-width: 180px;
  max-width: 200px;
  pointer-events: auto;
}

#party-frames.hidden {
  display: none;
}

.party-frame-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.party-member {
  display: flex;
  align-items: center;
  gap: var(--gui-gap);
  padding: var(--gui-padding-sm) var(--gui-padding);
  background: var(--bg-panel-alpha);
  border: 1px solid var(--alpha-white-05);
  border-radius: 3px;
  cursor: pointer;
  transition: border-color var(--ui-transition);
}

.party-member:hover {
  border-color: var(--accent);
}

.party-member-portrait {
  width: 28px;
  height: 28px;
  border: 1px dashed var(--border-default);
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  flex-shrink: 0;
  background: var(--frame-inner);
}

.party-member-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.party-member-name {
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  font-weight: 600;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.party-member-hp {
  height: 4px;
  background: var(--player-hp-bg);
  border-radius: 2px;
  overflow: hidden;
}

.party-member-hp-fill {
  height: 100%;
  width: 100%;
  background: var(--player-hp-color);
  border-radius: 2px;
  /* scaleX (not width) so HP changes animate on the compositor, not via per-frame
     layout. --hp-scale (0-1) is set by partyFrames.js. */
  transform: scaleX(var(--hp-scale, 1));
  transform-origin: left center;
  transition: transform var(--ui-transition);
}

/* ============================================
   CHAT WINDOW (wireframe stub)
   ============================================ */

#chat-window {
  position: relative;
  min-width: 240px;
  max-width: 320px;
  background: var(--bg-panel-alpha);
  border: 1px solid var(--alpha-white-05);
  border-radius: 4px;
  display: flex;
  flex-direction: column;
}

.chat-tabs {
  display: flex;
  border-bottom: 1px solid var(--alpha-white-05);
  flex-shrink: 0;
}

.chat-tab {
  flex: 1;
  background: none;
  border: none;
  padding: var(--gui-padding-sm) var(--gui-padding);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--ui-transition);
  border-bottom: 2px solid transparent;
}

.chat-tab:hover {
  color: var(--text-secondary);
}

.chat-tab.active {
  color: var(--text-primary);
  border-bottom-color: var(--accent);
}

.chat-messages {
  flex: 1;
  min-height: 100px;
  max-height: 160px;
  overflow-y: auto;
  padding: var(--gui-padding);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  color: var(--text-secondary);
  line-height: 1.5;
  contain: layout paint;
}


.chat-input-row {
  border-top: 1px solid var(--alpha-white-05);
  padding: var(--gui-padding-sm);
  display: flex;
  align-items: center;
}

.chat-channel-badge {
  background: none;
  border: none;
  padding: 0 var(--gui-padding-sm);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
  line-height: 1;
  max-width: 8em;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-primary);
}
.chat-channel-badge:disabled { opacity: 0.5; cursor: not-allowed; }
.chat-channel-badge[data-channel="say"]     { color: var(--text-primary); }
.chat-channel-badge[data-channel="zone"]    { color: var(--accent); }
.chat-channel-badge[data-channel="whisper"] { color: var(--punch-plum); }
.chat-channel-badge[data-channel="emote"]   { color: var(--punch-amber); }
.chat-channel-badge[data-channel="party"]   { color: var(--color-jade); }

.chat-input {
  flex: 1;
  min-width: 0;
  padding: var(--gui-padding-sm) var(--gui-padding);
  background: var(--frame-inner);
  border: 1px solid var(--alpha-white-08);
  border-radius: 3px;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  outline: none;
  transition: border-color var(--ui-transition);
}

.chat-input::placeholder {
  color: var(--text-muted);
}

.chat-input:focus {
  border-color: var(--accent);
}

.chat-input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.chat-input:focus[data-chat-mode="whisper"] { border-color: var(--punch-plum); }
.chat-input:focus[data-chat-mode="emote"]   { border-color: var(--punch-amber); }

.chat-input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ─── Chat messages: scrollbar ─── */

.chat-messages {
  scrollbar-width: thin;
  scrollbar-color: var(--alpha-white-08) transparent;
}

/* ─── Chat messages: per-message layout ─── */

.chat-message {
  padding: 1px 0;
  line-height: 1.5;
  word-break: break-word;
  transition: opacity var(--fade-slow) ease;
}

.chat-messages.chat-faded .chat-message {
  opacity: 0.25;
}

#chat-window:hover .chat-messages.chat-faded .chat-message,
#chat-window:focus-within .chat-messages.chat-faded .chat-message {
  opacity: 1;
}

.chat-timestamp {
  color: var(--text-disabled);
  font-size: var(--font-size-xs);
}

.chat-channel {
  font-size: var(--font-size-xs);
  font-weight: 600;
}

.chat-channel--say { color: var(--text-primary); }
.chat-channel--zone { color: var(--accent); }
.chat-channel--whisper { color: var(--punch-plum); }
.chat-channel--party { color: var(--color-jade); }
.chat-channel--system { color: var(--text-muted); font-style: italic; font-weight: 400; }
.chat-channel--emote { color: var(--punch-amber); font-style: italic; }

/* ─── Player Context Menu ─── */

.player-context-menu {
  position: fixed;
  z-index: 9998;
  min-width: 120px;
  background: var(--bg-panel);
  border: 1px solid var(--alpha-white-08);
  border-radius: 4px;
  box-shadow: var(--shadow-md);
  padding: 2px 0;
  display: none;
}

.player-context-menu.visible {
  display: block;
}

.context-menu-item {
  display: block;
  width: 100%;
  padding: 6px 12px;
  background: none;
  border: none;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--font-size-xs);
  text-align: left;
  cursor: pointer;
  transition: background var(--ui-transition);
}

.context-menu-item:hover {
  background: var(--alpha-white-05);
}

.chat-sender {
  font-weight: 600;
  cursor: pointer;
}

.chat-sender:hover,
.chat-sender:focus-visible {
  text-decoration: underline;
}

.chat-text {
  font-size: var(--font-size-xs);
}

/* ─── Chat font size overrides (settings) ─── */

.chat-font-medium .chat-tab,
.chat-font-medium .chat-messages,
.chat-font-medium .chat-input,
.chat-font-medium .chat-channel-badge,
.chat-font-medium .chat-timestamp,
.chat-font-medium .chat-channel,
.chat-font-medium .chat-text,
.chat-font-medium .context-menu-item {
  font-size: var(--font-size-sm);
}

.chat-font-large .chat-tab,
.chat-font-large .chat-messages,
.chat-font-large .chat-input,
.chat-font-large .chat-channel-badge,
.chat-font-large .chat-timestamp,
.chat-font-large .chat-channel,
.chat-font-large .chat-text,
.chat-font-large .context-menu-item {
  font-size: var(--font-size-md);
}

/* ─── Large Text (Accessibility) ─── */

#game.ui-text-large {
  --font-size-2xs: 0.65rem;
  --font-size-xs:  0.75rem;
  --font-size-sm:  0.85rem;
  --font-size-md:  0.95rem;
  --font-size-lg:  1.05rem;
  --font-size-xl:  1.15rem;
  --font-size-2xl: 1.4rem;
  --font-size-3xl: 1.75rem;
  --font-size-4xl: 2.3rem;
}

#game.ui-text-large .xp-level-box {
  width: 28px;
  min-width: 28px;
  height: 28px;
}

#game.ui-text-large .inventory-item-info {
  min-width: 0;
}

/* ─── Reduced Motion (Accessibility) ─── */

.reduced-motion #sandstorm-layer,
.reduced-motion #thunderstorm-layer,
.reduced-motion #rain-layer,
.reduced-motion #sand-gust-layer { content-visibility: hidden; }

.reduced-motion .dust-devil-pixel,
.reduced-motion .ambient-dust-pixel { content-visibility: hidden; }

.reduced-motion .storm-shake,
.reduced-motion .gust-shake { animation: none !important; }

.reduced-motion .damage-number { animation-duration: 0.01ms !important; }
.reduced-motion .projectile { animation-duration: 0.01ms !important; }

.reduced-motion #zone-banner.zone-banner-visible,
.reduced-motion #levelup-display.levelup-visible { animation-duration: 0.01ms !important; }
.reduced-motion .achievement-alert { transition-duration: 0.01ms !important; }

.reduced-motion .ember-particle,
.reduced-motion .explosion-particle,
.reduced-motion .dice-particle,
.reduced-motion .vaporize-particle,
.reduced-motion .crush-particle { animation: none !important; content-visibility: hidden; }

.reduced-motion .aoe-effect { animation: none !important; }

.reduced-motion .weather-indicator.thunder { animation: none; }
.reduced-motion .action-slot.new-ability,
.reduced-motion .action-slot.new-ability > .new-glow { animation: none; }
.reduced-motion .effect-cd-fill { animation: none !important; stroke-dashoffset: 0 !important; }

/* Decorative actor animations — suppress continuous motion, preserve functional ones.
   Walk/run use composite animations (e.g. sheet-walk-cycle, walk-bob). Override to
   keep the sprite cycle but drop walk-bob/shadow-bounce (decorative bob/bounce).
   :not() exclusions match actors.css — jump, dash, knockback, sit all have their
   own functional animations that must not be clobbered. */
.reduced-motion .actor.moving:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy):not(.sitting-down):not(.sitting):not(.standing-up) .sprite,
.reduced-motion .actor.moving:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy):not(.sitting-down):not(.sitting):not(.standing-up) .sprite-hair,
.reduced-motion .actor.moving:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy):not(.sitting-down):not(.sitting):not(.standing-up) .equip-head,
.reduced-motion .actor.moving:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy):not(.sitting-down):not(.sitting):not(.standing-up) .equip-chest,
.reduced-motion .actor.moving:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy):not(.sitting-down):not(.sitting):not(.standing-up) .equip-weapon { animation-name: sheet-walk-cycle !important; }
.reduced-motion .actor.moving.sprinting:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy) .sprite,
.reduced-motion .actor.moving.sprinting:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy) .sprite-hair,
.reduced-motion .actor.moving.sprinting:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy) .equip-head,
.reduced-motion .actor.moving.sprinting:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy) .equip-chest,
.reduced-motion .actor.moving.sprinting:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy) .equip-weapon { animation-name: sheet-run-cycle !important; }
.reduced-motion .character.moving:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy):not(.sitting-down):not(.sitting):not(.standing-up) .shadow,
.reduced-motion .network-player.moving:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy):not(.sitting-down):not(.sitting):not(.standing-up) .shadow { animation-name: sheet-walk-cycle !important; }
.reduced-motion .character.moving.sprinting:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy) .shadow,
.reduced-motion .network-player.moving.sprinting:not(.jumping):not(.dashing):not(.vehicle-knockback):not(.vehicle-knockback-heavy) .shadow { animation-name: sheet-run-cycle !important; }
.reduced-motion .actor.moving:not(.character):not(.network-player) .shadow { animation: none !important; }
.reduced-motion #select-ring.active.combat-active { animation: none !important; }
.reduced-motion .telegraph-zone { animation: none !important; }
.reduced-motion .ground-effect { animation: none !important; }
.reduced-motion .character.ghost,
.reduced-motion .network-player.ghost { animation: none !important; opacity: 0.5; }
.reduced-motion .character.downed { animation: none !important; opacity: 0.5; }
.reduced-motion .character.immune { animation: none !important; filter: brightness(1.4) saturate(1.2); }
.reduced-motion .enemy.enraged { animation: none !important; filter: brightness(1.1) saturate(1.15); }
.reduced-motion .nameplate-quest { animation: none !important; }
.reduced-motion .nameplate .nameplate-quest { animation: none !important; }

/* Additional in-game toggle coverage for animations in other stylesheets */
.reduced-motion .cooldown-overlay { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
.reduced-motion .toast { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
.reduced-motion .comms-wave span { animation: none !important; }
.reduced-motion .worldmap-waypoint-dot { animation: none !important; }
.reduced-motion .ability-tile.new-tile { animation: none !important; }
.reduced-motion .ability-tile.assigning { animation: none !important; }
.reduced-motion .poof-effect { animation: none !important; }
.reduced-motion .aoe-pulse { animation: none !important; }

/* ─── Chat tab filtering ─── */

.chat-messages.filter-party .chat-message:not([data-chat-channel="party"]):not([data-chat-channel="system"]) { display: none; }
.chat-messages.filter-system .chat-message:not([data-chat-channel="system"]) { display: none; }

/* ============================================
   BOTTOM UI
   Main container for portraits and abilities rows
   
   POINTER-EVENTS HIERARCHY:
   - #bottom-ui: none (click-through container)
     - #interact-prompt: none (visual only)
     - #toast-container: none (visual only)
     - .bottom-dock-row: none (click-through)
       - .portrait-dock-zone: none (click-through)
         - .frame-wrapper: none (click-through)
           - .unit-frame: auto (interactive)
           - .frame-status-container: none
             - .effect-box: auto (hoverable)
             - .ability-box.on-cooldown: auto (hoverable)
       - #action-block: auto (interactive)
   ============================================ */
#bottom-ui {
  position: fixed;
  bottom: var(--gui-margin);
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gui-margin);
  z-index: 10;
  pointer-events: none;
}

/* Bottom dock rows - interactive areas */
.bottom-dock-row {
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: var(--gui-margin);
  pointer-events: none; /* Container click-through, children opt-in */
}

/* Combat HUD dock - shared width for portrait + abilities rows */
#combat-hud-dock {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: fit-content;
  gap: var(--gui-margin);
  pointer-events: none;
}

/* Portrait Row - fixed left and right dock zones */
#portrait-row {
  display: flex;
  justify-content: space-between;
  width: 100%;
  z-index: 2; /* Above abilities row */
  pointer-events: none; /* Don't block world clicks - children re-enable */
}

/* Fixed dock zones - maintain position even when empty */
.portrait-dock-zone {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  gap: var(--gui-margin);
  min-width: 240px;
  pointer-events: none; /* Don't block clicks when empty - children re-enable */
}

#portrait-dock-left {
  align-items: flex-start;
}

#portrait-dock-right {
  align-items: flex-end;
}

/* Abilities Row - centered */
#abilities-row {
  justify-content: center;
  /* Width determined by content */
  width: fit-content;
  z-index: 1; /* Below portrait row */
  /* Maintain dock zone even when action-block is undocked */
  min-height: 40px;
}

/* ============================================
   ACTION BLOCK
   Draggable action bar container
   ============================================ */
#action-block {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--gui-margin-sm);
  /* GPU layer */
  backface-visibility: hidden;
  transform: translate3d(0, 0, 0);
  cursor: grab;
  pointer-events: auto; /* Interactive UI element */
}

#action-block:active {
  cursor: grabbing;
}

/* Only the action slot buttons should be clickable, not draggable */
#action-block .action-slot {
  cursor: pointer;
}

/* Undocked state */
#action-block.undocked {
  position: fixed;
  z-index: 30;
}

#action-block.dragging {
  cursor: grabbing;
  z-index: 40;
  box-shadow: var(--shadow-xl);
}

#action-block.near-dock .redock-indicator {
  opacity: 1;
}

/* ============================================
   UNIT FRAMES (Player & Target)
   Inside portrait row when docked
   ============================================ */
.unit-frame {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--bg-panel-alpha);
  min-width: 240px;
  /* GPU layer */
  backface-visibility: hidden;
  transform: translate3d(0, 0, 0);
  z-index: 10;
  cursor: grab;
  pointer-events: auto; /* Re-enable clicks (parent dock zone has none) */
}

.unit-frame:active {
  cursor: grabbing;
}

/* Unit frame content row (portrait + info) */
.unit-frame-content {
  display: flex;
  align-items: center;
  gap: var(--gui-gap);
  padding: var(--gui-padding);
}

/* Resize handles inherit from .gui-panel resize handles */
.unit-frame .resize-handle-se,
.unit-frame .resize-handle-sw,
.unit-frame .resize-handle-ne,
.unit-frame .resize-handle-nw,
.unit-frame .resize-handle-n,
.unit-frame .resize-handle-s,
.unit-frame .resize-handle-e,
.unit-frame .resize-handle-w {
  position: absolute;
  z-index: 10;
  opacity: 0;
}

/* Show resize handles on hover (unit-frame only) or while actively dragging */
.unit-frame:hover .resize-handle-se,
.unit-frame:hover .resize-handle-sw,
.unit-frame:hover .resize-handle-ne,
.unit-frame:hover .resize-handle-nw,
.unit-frame:hover .resize-handle-n,
.unit-frame:hover .resize-handle-s,
.unit-frame:hover .resize-handle-e,
.unit-frame:hover .resize-handle-w,
.frame-wrapper.dragging .unit-frame .resize-handle-se,
.frame-wrapper.dragging .unit-frame .resize-handle-sw,
.frame-wrapper.dragging .unit-frame .resize-handle-ne,
.frame-wrapper.dragging .unit-frame .resize-handle-nw,
.frame-wrapper.dragging .unit-frame .resize-handle-n,
.frame-wrapper.dragging .unit-frame .resize-handle-s,
.frame-wrapper.dragging .unit-frame .resize-handle-e,
.frame-wrapper.dragging .unit-frame .resize-handle-w {
  opacity: 1;
}

/* Dock button for unit frames */
.unit-frame .dock-btn {
  position: absolute;
  top: var(--gui-padding-sm);
  right: var(--gui-padding-sm);
  opacity: 0;
  z-index: 10;
}

/* Show dock button when undocked (but not actively dragging) */
.frame-wrapper.undocked:not(.dragging) .unit-frame .dock-btn {
  opacity: 0.6;
}

.unit-frame .dock-btn:hover {
  opacity: 1;
}

.unit-frame.resizing {
  cursor: nwse-resize;
}

/* Frame wrapper undocked states (position/z-index handled by .gui-panel) */
.frame-wrapper.undocked .unit-frame {
  box-shadow: var(--shadow-md);
}

.frame-wrapper.dragging .unit-frame {
  box-shadow: var(--shadow-xl);
}

/* Legacy: unit-frame without wrapper (backwards compatibility) */
.unit-frame.undocked {
  position: fixed;
  z-index: 30;
  pointer-events: auto;
  box-shadow: var(--shadow-md);
}

.unit-frame.dragging {
  cursor: grabbing;
  z-index: 40;
  box-shadow: var(--shadow-xl);
}

.unit-frame.near-dock .redock-indicator {
  opacity: 1;
}

/* When docked to left/right columns, adjust styling */
.frame-wrapper.column-docked {
  width: 100%;
}

.frame-wrapper.column-docked .unit-frame {
  min-width: unset;
}

#player-frame {
  /* In portrait row: sits on left */
}

#target-frame {
  /* In portrait row: mirrored layout (details left, icon right) to face inward */
}

#target-frame.hidden {
  display: none;
}

/* Portrait wrapper - contains frame-portrait */
.portrait-wrapper {
  width: var(--size-portrait-md);
  height: var(--size-portrait-md);
}

.frame-portrait {
  position: relative;
  width: 100%;
  height: 100%;
  background: var(--frame-inner);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--portrait-icon-size);
  box-sizing: border-box;
}

/* Portrait level badge - small square showing level number */
.portrait-level {
  position: absolute;
  bottom: var(--gui-padding-sm);
  font-family: var(--font-numbers);
  font-size: var(--font-size-sm);
  color: var(--text-primary);
  background: var(--alpha-black-50);
  padding: var(--gui-padding-sm);
  line-height: 1;
  z-index: 5;
}

/* Player portrait: level hidden (shown in XP bar level boxes instead) */
.player-portrait .portrait-level {
  display: none;
}

/* Enemy/target portrait: level at bottom-right */
.enemy-portrait .portrait-level {
  right: var(--gui-padding-sm);
}

/* Swing timer SVG — inside frame-portrait, stretches to fill */
.frame-portrait .swing-timer-border {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--fade-standard) ease;
  transform: translate3d(0, 0, 0);
}

/* Show when autoattacking — class toggled by JS */
#player-frame.autoattacking .swing-timer-border {
  opacity: 1;
}

/* Portrait swing timer stroke styles (same path as cast timer — starts at 12 o'clock) */
.swing-timer-track {
  fill: none;
  stroke: var(--alpha-white-08);
  stroke-width: 2;
  stroke-linecap: square;
  stroke-linejoin: miter;
}

.swing-timer-fill {
  fill: none;
  stroke: var(--swing-color, var(--accent));
  stroke-width: 2.5;
  stroke-linecap: square;
  stroke-linejoin: miter;
  transform: translate3d(0, 0, 0);
}

/* Cooldown state: ring drains as cooldown progresses */
#player-frame.swing-cooldown .swing-timer-fill {
  --swing-color: var(--accent);
}

/* Target frame swing timer — danger color for enemy attacks */
#target-frame.autoattacking .swing-timer-border {
  opacity: 1;
}

#target-frame.swing-cooldown .swing-timer-fill {
  --swing-color: var(--danger);
}


.frame-info {
  display: flex;
  flex-direction: column;
  gap: var(--gui-padding);
  flex: 1;
  min-width: 0; /* Allow scaling with container */
  width: 100%;
}

.frame-name-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}

.frame-name {
  font-family: var(--font-nameplate);
  font-size: var(--frame-name-size);
  font-weight: 600;
  color: var(--text-primary);
}

.frame-family {
  font-family: var(--font-nameplate);
  font-size: 0.65rem;
  font-weight: 400;
  color: var(--text-secondary);
  margin-left: 6px;
}
.frame-family:empty { display: none; }

.frame-level {
  font-family: var(--font-numbers);
  font-size: var(--frame-level-size);
  color: var(--color-rarity-legendary);
}

/* Container for HP/charge bars */
.frame-bars {
  display: flex;
  flex-direction: column;
  gap: var(--gui-padding-sm);
  width: 100%;
}

.frame-bar {
  position: relative;
  width: 100%;
  height: var(--size-bar-lg);
  background: var(--player-hp-bg);
  overflow: hidden;
}

/* Hide text in portrait bars - visual only */
.frame-bar-text {
  display: none;
}

/* Player charge bar - scoped to player-frame */
#player-frame .frame-bar.charge-bar {
  height: var(--size-bar-md);
  background: var(--player-charge-bg);
}

.frame-hp-fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background: var(--player-hp-color);
  /* GPU-accelerated: scale3d instead of width */
  transform: scale3d(calc(var(--hp-pct, 100) / 100), 1, 1);
  transform-origin: left center;
  transition: transform 0.2s ease;
}

/* Charge fill - base styles (mirrors .frame-hp-fill pattern) */
.frame-charge-fill {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background: var(--player-charge-color);
  /* Use scaleX with width:100% instead of scale3d with calc - more reliable */
  transform: scaleX(var(--charge-pct, 1));
  transform-origin: left center;
  transition: transform 0.2s ease;
}

/* Target frame (enemies) - uses enemy colors */
#target-frame .frame-hp-fill {
  background: var(--enemy-hp-color);
}

/* Friendly NPC target - uses NPC colors */
#target-frame.friendly .frame-hp-fill {
  background: var(--npc-hp-color);
}


#target-frame.friendly .frame-level {
  color: var(--success);
}

/* Vehicle target - friendly green (same as NPC) */
#target-frame.frame-vehicle .frame-hp-fill {
  background: var(--npc-hp-color);
}


#target-frame.frame-vehicle .frame-level {
  color: var(--warning);
}

/* ============================================
   CHARGE BAR (for actors)
   ============================================ */
.frame-bar.charge-bar {
  height: var(--size-bar-md);
  background: var(--charge-bg);
}

/* Hide charge bar for objects and vehicles (non-actors) */
#target-frame.frame-object .frame-bar.charge-bar,
#target-frame.frame-vehicle .frame-bar.charge-bar {
  display: none;
}

/* ============================================
   FUEL BAR (for vehicles)
   ============================================ */
.frame-bar.fuel-bar {
  height: var(--size-bar-md);
  background: var(--charge-bg); /* Same base as charge */
  display: none; /* Hidden by default */
}

/* Show fuel bar only for vehicles */
#target-frame.frame-vehicle .frame-bar.fuel-bar {
  display: block;
}

.frame-fuel-fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background: var(--player-charge-color);
  transform: scale3d(calc(var(--fuel-pct, 100) / 100), 1, 1);
  transform-origin: left center;
  transition: transform 0.2s ease;
}


/* Target frame charge fill (enemies by default) */
#target-frame .frame-charge-fill {
  background: var(--enemy-charge-color);
}

/* Friendly NPC target uses NPC charge color */
#target-frame.friendly .frame-charge-fill {
  background: var(--npc-charge-color);
}

/* ============================================
   TARGET-OF-TARGET SUB-FRAME
   Compact row showing who the targeted enemy is attacking
   ============================================ */

.tot-frame {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 2px var(--gui-padding);
  border-top: 1px solid var(--alpha-white-05);
  font-size: var(--font-size-xs);
}

.tot-label {
  color: var(--text-muted);
  flex-shrink: 0;
}

.tot-name {
  color: var(--text-secondary);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.tot-hp-bar {
  flex-shrink: 0;
  width: 40px;
  height: 3px;
  background: var(--player-hp-bg);
  border-radius: 1px;
  overflow: hidden;
}

.tot-hp-fill {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--player-hp-color);
  border-radius: 1px;
  /* scaleX (not width) so HP changes animate on the compositor, not via per-frame
     layout. --hp-scale (0-1) is set by combatUI.js. */
  transform: scaleX(var(--hp-scale, 1));
  transform-origin: left center;
  transition: transform 0.2s ease;
}

/* ============================================
   FRAME WRAPPER (contains effects/abilities + unit-frame)
   Container is click-through, only unit-frame is interactive
   ============================================ */
.frame-wrapper {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--gui-margin-sm);
  width: 100%;
  min-width: 240px;
  pointer-events: none; /* Click-through - unit-frame opts in */
}

.frame-wrapper .unit-frame {
  cursor: grab;
}

.frame-wrapper .unit-frame:active {
  cursor: grabbing;
}

/* ============================================
   FRAME EFFECTS (Buffs/Debuffs Row)
   ============================================ */
/* Container for effects + abilities rows */
.frame-status-container {
  display: flex;
  flex-direction: column-reverse;
  gap: var(--gui-margin-sm);
  min-width: 240px;
  pointer-events: none; /* Click-through - children opt-in */
}

.frame-effects {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--gui-gap-sm);
  min-height: 24px; /* Reserve space even when empty */
}

.frame-buffs,
.frame-debuffs {
  display: flex;
  gap: var(--space-1);
  flex-wrap: wrap;
  flex: 1; /* Each takes half the space */
}

.frame-buffs {
  justify-content: flex-start;
}

.frame-debuffs {
  justify-content: flex-end;
}

/* Individual buff/debuff box */
.effect-box {
  position: relative;
  width: var(--size-icon-md);
  height: var(--size-icon-md);
  background: var(--alpha-black-60);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--effect-icon-size);
  cursor: help;
  pointer-events: auto; /* Hoverable for tooltip */
}

.effect-box:hover .gui-tooltip,
.effect-box:focus-within .gui-tooltip {
  opacity: 1;
  visibility: visible;
}

/* Duration timer text overlay */
.effect-box .effect-timer {
  position: absolute;
  bottom: calc(-1 * var(--gui-padding-sm));
  right: calc(-1 * var(--gui-padding-sm));
  font-size: var(--effect-timer-size);
  font-family: var(--font-numbers);
  color: var(--text-primary);
  background: var(--alpha-black-70);
  padding: var(--gui-padding-sm);
  line-height: 1;
  z-index: 3;
}

.effect-box .stack-count {
  position: absolute;
  bottom: calc(-1 * var(--gui-padding-sm));
  right: calc(-1 * var(--gui-padding-sm));
  font-size: var(--effect-timer-size);
  font-family: var(--font-numbers);
  font-weight: bold;
  color: var(--text-primary);
  background: var(--alpha-black-70);
  padding: var(--gui-padding-sm);
  line-height: 1;
  z-index: 3;
}

/* SVG stroke cooldown indicator for timed effects */
.effect-box .effect-cd-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
}

.effect-cd-track {
  fill: none;
  stroke: var(--alpha-white-08);
  stroke-width: 2;
}

.effect-cd-fill {
  fill: none;
  stroke-width: 2;
  stroke-linecap: square;
}

@keyframes effect-sweep {
  from { stroke-dashoffset: 88; }
  to   { stroke-dashoffset: 0; }
}

/* Dim icon when effect has duration (timed) */
.effect-box:not(.permanent) .effect-icon {
  opacity: 0.5;
}

/* Permanent effects - full brightness, no timer/stroke */
.effect-box.permanent .effect-timer,
.effect-box.permanent .effect-cd-svg {
  display: none;
}

/* ============================================
   FRAME ABILITIES (Cooldown Row)
   ============================================ */
.frame-abilities {
  display: flex;
  justify-content: flex-start;
  gap: var(--gui-gap-sm);
  min-height: 24px; /* Match effect row height */
  pointer-events: none; /* Click-through - children opt-in */
}

/* Mirror alignment for right dock (target frame) */
/* Right-side frames: mirrored layout (persists when undocked) */
.frame-wrapper:has([data-dock-side="right"]) .frame-effects {
  flex-direction: row-reverse;
}

.frame-wrapper:has([data-dock-side="right"]) .frame-buffs {
  justify-content: flex-end;
}

.frame-wrapper:has([data-dock-side="right"]) .frame-debuffs {
  justify-content: flex-start;
}

.frame-wrapper:has([data-dock-side="right"]) .frame-abilities {
  justify-content: flex-end;
}

/* Hide abilities row for non-hostile targets */
.frame-wrapper:has(#target-frame:not(.hostile)) .frame-abilities,
.frame-wrapper:has(#target-frame.hidden) .frame-abilities {
  display: none;
}


/* Individual ability cooldown box */
.ability-box {
  position: relative;
  width: var(--size-icon-md);
  height: var(--size-icon-md);
  background: var(--alpha-black-60);
  border: none;
  display: none; /* Hidden by default - only show when on cooldown */
  align-items: center;
  justify-content: center;
  font-size: var(--ability-icon-size);
  cursor: help;
}

.ability-box::after {
  content: '';
  position: absolute;
  inset: -10px;
  min-height: 44px;
  min-width: 44px;
}

/* Only show ability icons when on cooldown (active) */
.ability-box.on-cooldown {
  display: flex;
  pointer-events: auto; /* Hoverable for tooltip when visible */
}

.ability-box:hover .gui-tooltip,
.ability-box:focus-within .gui-tooltip {
  opacity: 1;
  visibility: visible;
}

/* Cooldown overlay (fills from bottom) */
.ability-box .ability-cd-overlay {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 100%;
  background: var(--alpha-black-70);
  transform: scale3d(1, calc(var(--cd-pct, 0) / 100), 1);
  transform-origin: bottom center;
  pointer-events: none;
  z-index: 1;
}

/* SVG stroke cooldown indicator (like Sprint) */
.ability-box .ability-cd-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
  opacity: 0;
  transition: opacity var(--fade-snappy) ease;
}

.ability-box.on-cooldown .ability-cd-svg {
  opacity: 1;
}

.ability-cd-track {
  fill: none;
  stroke: var(--alpha-white-08);
  stroke-width: 2;
}

.ability-cd-fill {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linecap: square;
}

/* Cooldown timer text */
.ability-box .ability-cd-timer {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--ability-timer-size);
  font-family: var(--font-numbers);
  color: var(--text-primary);
  z-index: 3;
  opacity: 0;
}

.ability-box.on-cooldown .ability-cd-timer {
  opacity: 1;
}

/* Icon dimmed when on cooldown */
.ability-box.on-cooldown .ability-icon {
  opacity: 0.4;
}

.ability-icon {
  position: relative;
  z-index: 0;
  transition: opacity var(--fade-snappy) ease;
}

@media (forced-colors: active) {
  .effect-box,
  .ability-box {
    border: 1px solid CanvasText;
  }
}

/* ============================================
   RESPONSIVE: Side column docking
   ============================================ */
/* When frame is docked to side columns, stack vertically */
.left-column .unit-frame,
.right-column .unit-frame {
  flex-direction: column;
}

/* Side column adjustments - keep left/right alignment */
.left-column .frame-effects,
.right-column .frame-effects {
  flex-wrap: wrap;
}

.left-column .frame-abilities,
.right-column .frame-abilities {
  flex-wrap: wrap;
}

/* Weakness display removed - combat simplification */

/* ============================================
   ACTION BAR
   ============================================ */
#action-bar,
#action-bar-2 {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--gui-padding-sm);
  background: var(--bg-panel-alpha);
  padding: var(--gui-padding);
  z-index: 20;
}

#action-bar-2 {
  display: none;
}

#game.action-bar-2-visible #action-bar-2 {
  display: flex;
}

/* Old weapon section styles removed - replaced with weapon toggle slot */

.action-slot {
  position: relative;
  width: var(--size-slot);
  height: var(--size-slot);
  background: var(--frame-inner);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  /* GPU-friendly transitions */
  transition: opacity var(--fade-snappy) ease, background-color var(--fade-snappy) ease;
  outline: none;
  -webkit-tap-highlight-color: transparent;
  /* Prevent native text selection/drag on emoji icons and labels */
  user-select: none;
  -webkit-user-drag: none;
}

.action-slot.queued {
  box-shadow: inset 0 0 0 2px oklch(1 0 0 / 0.6);
}

.action-slot:hover:not(.on-cooldown):not(.locked-slot):not(.empty-slot) {
  background: var(--alpha-white-05);
}

.action-slot:focus-visible {
  outline: 2px solid var(--alpha-white-40);
  outline-offset: -2px;
}

/* Action slot tooltips now use the fixed-position singleton (.ability-tooltip)
   from abilityBook.js — inline .gui-tooltip is kept as fallback content but hidden.
   The fixed tooltip escapes the bottom-ui stacking context (z-index issue with portrait frames). */
.action-slot > .gui-tooltip {
  display: none;
}

.action-slot.active {
  /* No special styling - swing timer SVG handles visual feedback */
}

/* Disabled state - when targeting friendly NPC */
.action-slot.disabled {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

.action-slot.disabled::after {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    45deg,
    transparent,
    transparent 3px,
    var(--alpha-black-30) 3px,
    var(--alpha-black-30) 6px
  );
}

/* Out of range — WoW-style red tint when target is beyond ability range */
.action-slot.out-of-range {
  filter: saturate(0.3) brightness(0.7);
  opacity: 0.6;
}

.action-slot.out-of-range::before {
  content: '';
  position: absolute;
  inset: 0;
  background: oklch(from var(--danger) l c h / 0.2);
  pointer-events: none;
  z-index: 6;
}

.action-slot.on-cooldown {
  cursor: not-allowed;
}

/* Cooldown overlay — clockwise radial sweep from 12 o'clock.
   Hidden by default to prevent sub-pixel rendering artifacts from the
   conic-gradient within the GPU-composited #action-block layer. */
.cooldown-overlay {
  position: absolute;
  inset: 0;
  background: conic-gradient(
    transparent var(--cooldown-angle, 360deg),
    var(--alpha-black-70) var(--cooldown-angle, 360deg)
  );
  pointer-events: none;
  z-index: 5;
  display: none;
}

.action-slot.on-cooldown .cooldown-overlay {
  display: block;
}

/* Cooldown timer text — centered, large for readability over dark sweep overlay */
.cooldown-timer {
  position: absolute;
  inset: 0;
  align-items: center;
  justify-content: center;
  font-family: var(--font-numbers);
  font-size: 1.1rem;
  font-weight: bold;
  color: var(--text-primary);
  text-shadow: 0 0 3px var(--alpha-black-90), 0 1px 2px var(--alpha-black-70);
  pointer-events: none;
  z-index: 6;
  display: none;
}

.action-slot.on-cooldown .cooldown-timer {
  display: flex;
}

.slot-icon {
  font-size: var(--action-icon-size);
}

/* Labels hidden - icons only */
.slot-label {
  display: none;
  font-size: var(--action-label-size);
}

.slot-key {
  position: absolute;
  bottom: var(--gui-padding-sm);
  right: var(--gui-padding-sm);
  font-family: var(--font-numbers);
  font-size: var(--action-key-size);
  color: var(--text-muted);
  background: var(--alpha-black-50);
  padding: var(--gui-padding-sm);
}

/* Special slot - no unique border styling */
.special-slot {
  /* Uses default frame-border */
}

/* (removed .action-group — 12-slot bar is flat) */

/* Melee and ranged slots - no special styling, use default frame-border */
.melee-slot,
.ranged-slot {
  /* Uses default frame-border */
}

/* Execute-locked: execute-only abilities (Last Word + Skyfall) when target is above 25% HP (hard gate) */
.action-slot.execute-locked {
  filter: saturate(0.15) brightness(0.5);
  opacity: 0.5;
  cursor: not-allowed;
}

.action-slot.execute-locked::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--alpha-black-50);
  pointer-events: none;
  z-index: 6;
}

/* ============================================
   PROC BORDER — WoW-style sweeping glow on empowered abilities
   Compositor-only: the .proc-border wrapper holds a fixed CSS mask
   (hollow border ring) + overflow:hidden. The ::before pseudo-element
   carries the conic gradient and rotates via transform (GPU layer).
   Only transform + opacity are animated — zero repaints.
   ============================================ */

/* Empowered slot: proc-border animation only, no ambient glow */

/* Non-rotating wrapper: mask + clip.
   Base state: no animation (the implicit default). (Note: a paused animation is
   also dormant — measured session 511 — so the old "paused still costs per-frame
   bookkeeping, Chromium bug 40728212" claim was disproven.) */
.proc-border {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 8;
  opacity: 0;
  overflow: hidden;
  transition: opacity var(--fade-standard) ease;
  /* Hollow rectangle: mask creates 2px border ring inside slot edge,
     matching the SVG swingtimer stroke-width for visual consistency. */
  -webkit-mask:
    linear-gradient(oklch(0 0 0) 0 0) content-box,
    linear-gradient(oklch(0 0 0) 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(oklch(0 0 0) 0 0) content-box,
    linear-gradient(oklch(0 0 0) 0 0);
  mask-composite: exclude;
  padding: 2px;
}

/* Rotating gradient layer — oversized so the ring stays filled
   at every rotation angle. Only transform is animated (compositor). */
.proc-border::before {
  content: '';
  position: absolute;
  inset: -50%;
  background: conic-gradient(
    from 0deg,
    transparent 0%,
    var(--proc-glow) 10%,
    transparent 22%,
    transparent 50%,
    var(--proc-glow-dim) 60%,
    transparent 72%
  );
}

/* Show border ring when parent is empowered */
.action-slot.empowered > .proc-border {
  opacity: 1;
}

/* GPU-accelerated spin on the gradient layer only */
.action-slot.empowered > .proc-border::before {
  animation: proc-spin 2s linear infinite;
}

@keyframes proc-spin {
  to { transform: rotate3d(0, 0, 1, 360deg); }
}

/* Trigger flash: scale3d burst on the wrapper when proc first fires.
   Specificity (0,4,0) must beat empowered rule (0,3,0) above. */
.action-slot.empowered > .proc-border.proc-trigger {
  animation: proc-flash 0.35s ease-out;
}

@keyframes proc-flash {
  0% {
    opacity: 0;
    transform: scale3d(1.2, 1.2, 1);
  }
  40% {
    opacity: 1;
    transform: scale3d(1.06, 1.06, 1);
  }
  100% {
    opacity: 1;
    transform: scale3d(1, 1, 1);
  }
}

/* Swing timer styles moved to player portrait section above */

/* ============================================
   NEW ABILITY GLOW — soft gold backlight for freshly unlocked abilities
   Compositor-only: only opacity is animated. Sits behind slot content
   with negative inset to bleed beyond tile edges as a backlight.
   Suppressed when .empowered (proc border takes visual priority).
   ============================================ */
.new-glow {
  position: absolute;
  inset: -6px;
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  background: radial-gradient(
    ellipse at center,
    var(--proc-glow-ambient) 0%,
    transparent 70%
  );
  transition: opacity var(--fade-snappy) ease;
}

.action-slot.new-ability > .new-glow {
  opacity: 1;
  animation: new-ability-glow-div 2s ease-in-out infinite;
}

.action-slot.empowered > .new-glow {
  opacity: 0;
  animation: none;
}

/* Gold breathing pulse on the slot itself (belt-and-suspenders with .new-glow div) */
.action-slot.new-ability {
  animation: new-ability-pulse 2s ease-in-out infinite;
}

.action-slot.new-ability.empowered {
  animation: none;
}

@keyframes new-ability-glow-div {
  0%, 100% { opacity: 0.7; }
  50% { opacity: 0.25; }
}

@keyframes new-ability-pulse {
  0%, 100% { box-shadow: 0 0 10px 3px var(--proc-glow-ambient); }
  50% { box-shadow: 0 0 4px 1px var(--proc-glow-subtle); }
}

/* ============================================
   CAST/CHANNEL TIMER (SVG stroke - GPU accelerated)
   ============================================ */
.cast-slot-wrapper {
  position: relative;
  display: inline-flex;
}

.cast-timer-border {
  position: absolute;
  inset: -1px;
  width: calc(100% + 2px);
  height: calc(100% + 2px);
  pointer-events: none;
  z-index: 10;
  opacity: 0;
  transform: translate3d(0, 0, 0);
  backface-visibility: hidden;
}

/* Show when casting/channeling */
.cast-slot-wrapper.casting .cast-timer-border,
.cast-slot-wrapper.channeling .cast-timer-border {
  opacity: 1;
}

/* Cast/channel get a soft fade; GCD is instant (default transition: none
   on base rule) to prevent the track stroke hairline during opacity change */
.cast-slot-wrapper.casting .cast-timer-border,
.cast-slot-wrapper.channeling .cast-timer-border {
  transition: opacity var(--fade-standard) ease;
}

.cast-timer-track {
  fill: none;
  stroke: var(--alpha-white-08);
  stroke-width: 2;
  stroke-linecap: square;
  stroke-linejoin: miter;
}

.cast-timer-fill {
  fill: none;
  stroke: var(--cast-color, var(--accent));
  stroke-width: 2.5;
  stroke-linecap: square;
  stroke-linejoin: miter;
  transform: translate3d(0, 0, 0);
  /* PERF: Removed drop-shadow filter and will-change */
}

/* Channel state: same player blue as casts (both are positive player wind-ups) */
.cast-slot-wrapper.channeling .cast-timer-fill {
  --cast-color: var(--cast-player);
}

/* Cast state: player color — charged shot */
.cast-slot-wrapper.casting .cast-timer-fill {
  --cast-color: var(--cast-player);
}

/* Charge ability slots - same style as weapon abilities */

/* Locked slot — ability slotted but level not met (WoW-style pre-slotting)
   Compound selector (.action-slot.locked-slot) ensures specificity matches
   .action-slot.disabled / .action-slot.execute-locked so lock styles win
   via source order (this rule appears later in the stylesheet). */
.action-slot.locked-slot {
  cursor: not-allowed;
  opacity: 0.5;
  filter: grayscale(0.6);
}

.action-slot.locked-slot .slot-label {
  font-size: 0.55rem;
  color: var(--text-disabled);
}

.action-slot.locked-slot::after {
  content: '🔒';
  position: absolute;
  top: 2px;
  right: 2px;
  font-size: 0.55rem;
  opacity: 0.6;
  pointer-events: none;
}

/* Empty slot — no ability equipped (valid drop target) */
.empty-slot {
  cursor: default;
  border: 1px dashed var(--alpha-white-10);
  background: var(--alpha-black-20);
}

/* Hide all content in empty slots */
.empty-slot .slot-icon,
.empty-slot .slot-label,
.empty-slot .slot-key,
.empty-slot .cooldown-overlay,
.empty-slot .cooldown-timer {
  visibility: hidden;
}

/* Dragging state — bar slot being picked up */
.action-slot.dragging {
  opacity: 0.3;
  filter: grayscale(0.5);
}

/* Drop hover — valid drop target highlight during drag */
.action-slot.drop-hover {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  background: var(--alpha-white-05);
}

/* Hidden ability slots (MSQ not yet revealed) */
/* Charge abilities are completely hidden until the MSQ reveals them */
#charge-abilities.hidden-abilities {
  display: none !important;
}

/* Utility slots - same style as weapon abilities */

/* ============================================
   SPRINT TIMER (SVG stroke - GPU accelerated)
   ============================================ */
/* (removed .sprint-slot-wrapper — sprint is now a regular slot) */

.sprint-timer-border {
  position: absolute;
  inset: -1px;
  width: calc(100% + 2px);
  height: calc(100% + 2px);
  pointer-events: none;
  z-index: 10;
  opacity: 0;
  transition: opacity var(--fade-standard) ease;
  /* GPU layer via 3D transform */
  transform: translate3d(0, 0, 0);
}

/* Show when sprint buff is active */
.action-slot.sprint-active .sprint-timer-border {
  opacity: 1;
}

/* Sprint duration reuses cooldown overlay/timer — show during buff */
.action-slot.sprint-active .cooldown-overlay {
  display: block;
}

.action-slot.sprint-active .cooldown-timer {
  display: flex;
}

/* Background track (subtle) */
.sprint-timer-track {
  fill: none;
  stroke: var(--alpha-white-08);
  stroke-width: 2;
  stroke-linecap: square;
  stroke-linejoin: miter;
}

/* Progress fill stroke */
.sprint-timer-fill {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2.5;
  stroke-linecap: square;
  stroke-linejoin: miter;
  /* GPU layer for performance */
  transform: translate3d(0, 0, 0);
  /* PERF: Removed drop-shadow filter and will-change */
  /* Transition set dynamically by JS for precise timing */
}

/* Buff active state - uses same style as cooldown */

/* ============================================
   XP ROW (anchored to bottom of screen)
   Level boxes flanking the XP bar with gap
   Width synced to action bar via JS (--xp-row-width)
   ============================================ */
#xp-row {
  display: flex;
  align-items: flex-end; /* Level boxes taller, XP bar aligns to bottom */
  justify-content: center;
  gap: var(--gui-gap); /* Gap between boxes and bar */
  pointer-events: auto;
  /* Reduce gap from abilities row above */
  margin-top: calc(-1.5 * var(--gui-margin));
  /* Extend to bottom edge by compensating for bottom-ui margin */
  margin-bottom: calc(-1 * var(--gui-margin));
}

/* Level boxes (current and next) - outside the bar */
.xp-level-box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  min-width: 24px;
  height: 24px;
  background: var(--bg-panel-alpha);
  font-family: var(--font-numbers);
  font-size: var(--font-size-xs);
  font-weight: 600;
  color: var(--text-primary);
}

/* ============================================
   XP BAR (inside xp-row)
   Width synced to action bar via JS
   ============================================ */
#xp-bar-container {
  position: relative;
  z-index: 25;
  width: var(--xp-row-width, 300px); /* Synced to action bar width via JS */
  min-width: 100px;
}

#xp-bar-track {
  position: relative;
  height: 8px;
  background: var(--bg-panel-alpha);
  overflow: hidden;
}

/* XP bar tooltip */
#xp-bar-container:focus-visible {
  outline: 2px solid var(--alpha-white-40);
  outline-offset: -1px;
}

#xp-bar-container:hover .gui-tooltip,
#xp-bar-container:focus-within .gui-tooltip {
  opacity: 1;
  visibility: visible;
}

#xp-bar-level {
  color: var(--color-rarity-legendary);
  font-weight: 600;
}

#xp-bar-progress {
  color: var(--text-secondary);
}

#xp-bar-fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background: var(--xp-color);
  /* GPU-accelerated: scale3d instead of width */
  transform: scale3d(calc(var(--xp-pct, 0) / 100), 1, 1);
  transform-origin: left center;
  transition: transform 0.4s ease-out;
}

#xp-bar-notches {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.xp-notch {
  position: absolute;
  width: 1px;
  height: 100%;
  background: var(--alpha-white-15);
}

.xp-notch:nth-child(1) { left: 25%; }
.xp-notch:nth-child(2) { left: 50%; }
.xp-notch:nth-child(3) { left: 75%; }

/* XP bar text - inside the bar */
/* XP bar text hidden - using compact bar */

/* Rested XP bonus indicator (optional enhancement) */
#xp-bar-fill.rested::after {
  content: '';
  position: absolute;
  top: 0;
  left: 100%;
  height: 100%;
  width: 20%;
  background: linear-gradient(180deg, var(--xp-rested) 0%, var(--xp-rested-mid) 50%, var(--xp-rested-dark) 100%);
  opacity: 0.6;
}

/* ============================================
   DIALOGUE SHROUD
   Replaces native ::backdrop — show() avoids
   Chrome's expensive top-layer mechanism that
   showModal() triggers (~26ms render spike).
   Matches dialogue backdrop timing pattern.
   ============================================ */
#dialogue-shroud {
  position: fixed;
  inset: 0;
  background: var(--bg-panel-alpha);
  z-index: 199;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  cursor: pointer;
  transition:
    opacity var(--fade-standard) ease-out,
    visibility var(--fade-standard) ease-out;
  transition-delay: 350ms;
}

#dialogue-shroud.visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition-delay: 0ms;
}

/* ============================================
   DIALOGUE PANEL
   Cinematic enter/exit with staggered shroud.
   Uses show()/close() instead of showModal() to
   avoid top-layer promotion and ::backdrop cost.
   ============================================ */
#dialogue-panel {
  position: fixed;
  top: 50%;
  left: 50%;
  margin: 0;
  padding: calc(var(--gui-padding) * 3);
  width: min(90vw, 600px);
  max-height: 80vh;
  overflow-y: auto;
  background: var(--bg-panel-alpha);
  border: var(--border-hairline);
  font-family: var(--font-dialogue);
  pointer-events: auto;
  z-index: 200;
  box-shadow: var(--shadow-lg);
  contain: layout style paint;
  opacity: 0;
  translate: -50% calc(-50% - 40px) 0;
  scale: 0.8;
  transition: 
    opacity 450ms cubic-bezier(0.36, 0, 0.66, -0.56),
    translate 450ms cubic-bezier(0.36, 0, 0.66, -0.56),
    scale 450ms cubic-bezier(0.36, 0, 0.66, -0.56),
    display 450ms allow-discrete;
}

#dialogue-panel[open] {
  opacity: 1;
  translate: -50% -50% 0;
  scale: 1;
  transition: 
    opacity 550ms cubic-bezier(0.34, 1.56, 0.64, 1),
    translate 550ms cubic-bezier(0.34, 1.56, 0.64, 1),
    scale 550ms cubic-bezier(0.34, 1.56, 0.64, 1),
    display 550ms allow-discrete;
  transition-delay: 200ms;
}

#dialogue-panel[open].modal-entering {
  opacity: 0;
  translate: -50% calc(-50% - 40px) 0;
  scale: 0.8;
}

/* Inner wrapper for flex gap (dialog element doesn't support gap) */
#dialogue-inner {
  display: flex;
  flex-direction: column;
  gap: var(--gui-gap-lg);
}

/* Dialogue content wrapper - portrait + text side by side */
#dialogue-content {
  display: flex;
  gap: var(--gui-gap-lg);
}

/* Portrait - 2x the size of target frame portrait */
#dialogue-portrait {
  flex-shrink: 0;
  width: calc(var(--size-portrait-md) * 2);
  height: calc(var(--size-portrait-md) * 2);
  background: var(--frame-inner);
  display: flex;
  align-items: center;
  justify-content: center;
}

#dialogue-portrait .portrait-icon {
  font-size: calc(var(--portrait-icon-size) * 2);
}

/* Body - contains speaker name and text */
#dialogue-body {
  display: flex;
  flex-direction: column;
  gap: var(--gui-gap-lg);
  flex: 1;
  min-width: 0; /* Allow text to wrap */
  padding: var(--gui-padding-sm) 0;
}

#dialogue-speaker {
  padding: 0 var(--gui-padding) 0 0;
  font-size: var(--font-size-md);
  font-weight: 600;
  color: var(--accent);
}

#dialogue-text {
  font-size: var(--font-size-xl);
  line-height: 1.5;
  color: var(--text-primary);
  min-height: calc(3 * 1.5 * var(--font-size-xl)); /* Stabilize height during typewriter */
}

#dialogue-choices {
  display: flex;
  flex-direction: column;
  gap: var(--gui-gap-sm);
  padding: 0;
}

.dialogue-choice {
  background: var(--frame-inner);
  border: none;
  padding: var(--gui-padding);
  text-align: left;
  font-family: inherit;
  font-size: var(--font-size-lg);
  color: var(--text-primary);
  cursor: pointer;
  /* Slow trail fade-out on release */
  transition: background-color 0.6s ease-out, color 0.6s ease-out;
  display: flex;
  align-items: center;
  gap: var(--gui-gap);
}

.dialogue-choice:hover:not([disabled]),
.dialogue-choice.selected:not([disabled]) {
  background: var(--accent-hover);
  color: var(--text-primary);
  outline: none;
  transition: none;
}

.dialogue-choice:focus-visible:not([disabled]) {
  outline: 2px solid var(--alpha-white-40);
  outline-offset: -2px;
}

.dialogue-choice:hover:not([disabled]) .choice-text,
.dialogue-choice.selected:not([disabled]) .choice-text {
  color: var(--text-primary);
}

.dialogue-choice[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

.choice-key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  background: var(--bg-dark);
  border: none;
  font-size: var(--font-size-sm);
  font-weight: bold;
  color: var(--text-primary);
  flex-shrink: 0;
  order: 1;
}

.choice-text {
  flex: 1;
  /* Slow trail fade-out on release */
  transition: color 0.6s ease-out, background-color 0.6s ease-out;
}

.dialogue-choice:hover .choice-text,
.dialogue-choice.selected .choice-text {
  /* Instant snap on hover */
  transition: none;
}

/* Quest icon for quest-related dialogue options */
.choice-quest-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  background: var(--warning);
  color: var(--text-on-fill);
  font-size: var(--font-size-sm);
  font-weight: bold;
  flex-shrink: 0;
  margin-left: auto;
}

/* Back/navigation options in dialogue */
.dialogue-choice.back-option,
.dialogue-choice.goodbye-option {
  margin-top: var(--gui-gap-md);
}

/* Back option - muted yellow on hover */
.dialogue-choice.back-option:hover,
.dialogue-choice.back-option.selected {
  background: var(--warning-subtle);
}

/* Goodbye option - red on hover */
.dialogue-choice.goodbye-option:hover,
.dialogue-choice.goodbye-option.selected {
  background: var(--danger-subtle);
}

/* ============================================
   INVENTORY PANEL
   ============================================ */
#inventory-panel {
  position: relative;
  /* Wider than other column panels: a grid of slot cells needs the room. */
  min-width: 300px;
  background: var(--bg-panel-alpha);
  font-family: var(--font-display);
}

#inventory-panel.hidden {
  display: none;
}

/* When undocked, use fixed positioning */
#inventory-panel.undocked {
  position: fixed;
}

#inventory-list {
  max-height: 200px;
  overflow-y: auto;
  padding: var(--gui-padding);
}

.inventory-item {
  display: flex;
  align-items: center;
  gap: var(--gui-gap);
  padding: var(--gui-padding);
  cursor: pointer;
}

.inventory-item:hover,
.inventory-item:focus-visible {
  background: var(--alpha-white-05);
}

.inventory-item-icon {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-size-sm);
  font-weight: bold;
}

.inventory-item-icon.green { background: var(--color-rarity-uncommon); }
.inventory-item-icon.blue { background: var(--color-rarity-rare); }
.inventory-item-icon.gold { background: var(--color-rarity-legendary); }
.inventory-item-icon.common { background: var(--color-rarity-common); }
.inventory-item-icon.uncommon { background: var(--color-rarity-uncommon); }
.inventory-item-icon.rare { background: var(--color-rarity-rare); }
.inventory-item-icon.epic { background: var(--color-rarity-epic); }
.inventory-item-icon.legendary { background: var(--color-rarity-legendary); }

.inventory-item-info { flex: 1; }
.inventory-item-name { font-size: var(--font-size-md); font-weight: 600; }
.inventory-item-rarity { font-size: var(--font-size-xs); color: var(--text-secondary); }
.inventory-item-desc { font-size: var(--font-size-xs); color: var(--text-muted); }
.inventory-item-qty { font-size: var(--font-size-sm); color: var(--text-secondary); }
.inventory-use-btn {
  padding: 2px var(--gui-padding);
  font-size: var(--font-size-xs);
  background: var(--alpha-white-10);
  border: 1px solid var(--frame-border);
  color: var(--text-primary);
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.inventory-use-btn:hover { background: var(--alpha-white-15); }

/* Bag (roadmap 2.2) — functional grid. Visual polish deferred to Phase 5. Static
   layout only (no animated/transitioned properties), so no render-perf concern. */
.bag-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gui-gap-sm);
  padding: var(--gui-padding-sm) var(--gui-padding);
  border-bottom: 1px solid var(--frame-border);
}
.bag-tabs.hidden { display: none; }
.bag-tab {
  padding: 2px var(--gui-padding);
  font-size: var(--font-size-xs);
  font-family: var(--font-display);
  background: var(--alpha-white-05);
  border: 1px solid transparent;
  color: var(--text-secondary);
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.bag-tab:hover { background: var(--alpha-white-10); }
.bag-tab.active {
  background: var(--alpha-white-10);
  border-color: var(--frame-border);
  color: var(--text-primary);
}

#inventory-list.bag-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, var(--size-slot));
  gap: var(--gui-gap);
  justify-content: start;
  align-content: start;
}

.bag-cell {
  position: relative;
  width: var(--size-slot);
  height: var(--size-slot);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: var(--alpha-white-05);
  border: 1px solid var(--frame-border);
}
.bag-cell-actionable { cursor: pointer; }
.bag-cell-busy { opacity: 0.5; pointer-events: none; }
.bag-cell-icon { width: 36px; height: 36px; }
.bag-cell-qty {
  position: absolute;
  right: 2px;
  bottom: 1px;
  font-size: var(--font-size-xs);
  color: var(--text-primary);
  background: var(--bg-panel-alpha);
  padding: 0 2px;
}
.bag-empty {
  grid-column: 1 / -1;
  text-align: center;
  color: var(--text-muted);
  padding: var(--gui-padding);
}

/* Slotted-bag interaction states (roadmap 2.2 cutover). Static styles only — no
   animated layout / box-shadow / filter, so the render-perf lint stays clean. */
.bag-cell-empty { border-style: dashed; }
.bag-cell-grabbed {
  border-color: var(--accent);
  background: var(--alpha-white-10);
}
.bag-cell-drop-target { border-color: var(--accent); }
/* Worn / broken gear markers: a small corner dot. */
.bag-cell-worn::after,
.bag-cell-broken::after {
  content: '';
  position: absolute;
  left: 2px;
  bottom: 2px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
}
.bag-cell-worn::after { background: var(--color-rarity-uncommon); }
.bag-cell-broken::after { background: var(--color-rarity-legendary); }
/* Drag ghost (body-appended): follows the cursor while dragging a bag item. */
.bag-drag-ghost {
  position: fixed;
  z-index: 10001;
  pointer-events: none;
  transform: translate(-50%, -50%);
  width: var(--size-slot-sm);
  height: var(--size-slot-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-panel-alpha);
  border: 1px solid var(--accent);
  font-size: var(--font-size-md);
  color: var(--text-primary);
}

.bag-capacity {
  padding: var(--gui-padding-sm) var(--gui-padding);
  border-top: 1px solid var(--frame-border);
  font-size: var(--font-size-xs);
  color: var(--text-secondary);
  text-align: right;
}
.bag-capacity-full { color: var(--color-rarity-legendary); }

.bag-tooltip {
  position: fixed;
  z-index: 10000;
  pointer-events: none;
  max-width: 240px;
  padding: var(--gui-padding);
  background: var(--bg-panel-alpha);
  border: 1px solid var(--frame-border);
  font-family: var(--font-display);
  font-size: var(--font-size-xs);
}
.bag-tooltip[hidden] { display: none; }
.bag-tooltip-name { font-size: var(--font-size-sm); font-weight: 600; }
.bag-tooltip-name.green, .bag-tooltip-name.uncommon { color: var(--color-rarity-uncommon); }
.bag-tooltip-name.blue, .bag-tooltip-name.rare { color: var(--color-rarity-rare); }
.bag-tooltip-name.epic { color: var(--color-rarity-epic); }
.bag-tooltip-name.gold, .bag-tooltip-name.legendary { color: var(--color-rarity-legendary); }
.bag-tooltip-name.common { color: var(--color-rarity-common); }
.bag-tooltip-sub { color: var(--text-muted); margin-bottom: 2px; }
.bag-tooltip-stat { color: var(--text-secondary); }
.inventory-use-btn:disabled { opacity: 0.4; cursor: default; }

/* ============================================
   SHOP PANEL
   Float-only vendor interaction panel
   ============================================ */

#shop-panel {
  position: fixed;
  z-index: 60;
  background: var(--bg-panel);
  border: var(--frame-border-width) solid var(--frame-border);
  box-shadow: var(--shadow-lg);
  font-family: var(--font-display);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  user-select: none;
  contain: layout style;
}

#shop-panel.hidden { display: none; }

#shop-panel:not(.hidden) { pointer-events: auto; }

#shop-buy-section,
#shop-sell-section,
#shop-repair-section {
  flex: 1;
  overflow-y: auto;
  padding: 0;
  min-height: 80px;
}

#shop-buy-list,
#shop-sell-list,
#shop-repair-list {
  padding: var(--gui-padding);
}

.shop-section-label {
  padding: var(--gui-padding);
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border-bottom: 1px solid var(--frame-border);
  background: var(--alpha-white-03);
}

.shop-item {
  display: flex;
  align-items: center;
  gap: var(--gui-gap);
  padding: var(--gui-padding);
}

.shop-item:hover {
  background: var(--alpha-white-05);
}

.shop-price {
  font-size: var(--font-size-sm);
  color: var(--color-gold);
  white-space: nowrap;
  min-width: 36px;
  text-align: right;
}

.shop-price-sell {
  color: var(--color-jade);
}

.shop-buy-btn,
.shop-sell-btn {
  padding: var(--gui-padding-sm) var(--gui-padding);
  min-height: 24px;
  font-size: var(--font-size-xs);
  background: var(--alpha-white-10);
  border: 1px solid var(--frame-border);
  color: var(--text-primary);
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.shop-buy-btn:hover,
.shop-sell-btn:hover { background: var(--alpha-white-15); }

.shop-buy-btn:disabled,
.shop-sell-btn:disabled { opacity: 0.4; cursor: default; }

.shop-close-btn {
  opacity: 0.6;
  font-size: var(--font-size-lg);
  width: 24px;
  height: 24px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-muted);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.shop-close-btn:hover {
  opacity: 1;
  background: var(--alpha-white-10);
}

#shop-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--gui-gap);
}

#shop-currency::before {
  content: '⬡ ';
  opacity: 0.6;
}

/* ============================================
   NOTIFICATIONS (Toasts & Prompts)
   Unified feedback system with color-coded left bars
   ============================================ */

/* Base notification styles */
.notification {
  background: var(--bg-panel);
  border-left: 3px solid var(--text-muted);
  padding: var(--gui-padding);
  font-family: var(--font-display);
  font-size: var(--font-size-md);
  color: var(--text-primary);
  pointer-events: none; /* Click-through - notifications are visual only */
}

/* Semantic color types */
.notification.info    { border-left-color: var(--info); }
.notification.success { border-left-color: var(--success); }
.notification.warning { border-left-color: var(--warning); }
.notification.error   { border-left-color: var(--danger); }
.notification.accent  { border-left-color: var(--accent); }

/* Game-specific types */
.notification.xp      { border-left-color: var(--xp-color); }
.notification.item    { border-left-color: var(--success); }
.notification.quest    { border-left-color: var(--warning); }
.notification.currency { border-left-color: var(--color-gold); }

/* --- Interact Prompt --- 
   Quick fade in/out animation. Override global .hidden to allow transition. */
#interact-prompt {
  display: flex !important;
  align-items: center;
  gap: var(--gui-gap);
  pointer-events: none;
  opacity: 1;
  visibility: visible;
  transition: opacity var(--fade-snappy) ease-out, visibility 0s linear 0s;
}

#interact-prompt.hidden {
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--fade-snappy) ease-out, visibility 0s linear var(--fade-snappy);
}

#interact-prompt:empty { display: none !important; }

#interact-prompt kbd {
  background: var(--frame-inner);
  padding: var(--gui-padding-sm) var(--gui-padding);
  font-family: var(--font-numbers);
  font-size: var(--font-size-sm);
}

/* --- Comms Card (NPC phone calls) --- */
#comms-card {
  display: flex;
  align-items: flex-start;
  gap: var(--gui-gap-lg);
  background: var(--bg-panel-alpha);
  padding: calc(var(--gui-padding) * 2);
  max-width: 360px;
  pointer-events: auto;
  cursor: pointer;
}

#comms-card.hidden {
  display: none;
}

/* Enter animation */
#comms-card.comms-enter {
  animation: comms-in 0.3s ease forwards;
}

/* Exit animation */
#comms-card.comms-exit {
  animation: comms-out 0.3s ease forwards;
}

@keyframes comms-in {
  from {
    opacity: 0;
    transform: translate3d(0, 20px, 0);
  }
  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}

@keyframes comms-out {
  from {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
  to {
    opacity: 0;
    transform: translate3d(0, -10px, 0);
  }
}

/* Portrait */
#comms-portrait {
  position: relative;
  flex-shrink: 0;
  width: var(--size-portrait-md);
  height: var(--size-portrait-md);
  background: var(--frame-inner);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--portrait-icon-size);
}

/* Stroke timer SVG - shows countdown before dismiss */
.comms-timer-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--fade-standard) ease;
}

#comms-card.countdown .comms-timer-svg {
  opacity: 1;
}

.comms-timer-track {
  fill: none;
  stroke: var(--alpha-white-08);
  stroke-width: 2;
}

.comms-timer-fill {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  /* Perimeter of 46x46 rect = 2*(46+46) = 184 */
  stroke-dasharray: 184;
  stroke-dashoffset: 0;
}

/* Content area */
#comms-content {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--gui-gap-lg);
  padding: var(--gui-padding-sm) 0;
}

/* Speaker row - name + wave animation */
#comms-speaker-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gui-gap);
}

#comms-speaker {
  color: var(--accent);
  font-family: var(--font-dialogue);
  font-size: var(--font-size-md);
  font-weight: 600;
  text-transform: capitalize;
}

/* Sound wave animation */
#comms-wave {
  display: flex;
  align-items: center;
  gap: 2px;
  height: 12px;
  opacity: 0;
  transition: opacity var(--fade-standard) ease-out;
}

#comms-card.typing #comms-wave {
  opacity: 1;
  transition: opacity var(--fade-snappy) ease-in;
}

#comms-wave span {
  display: block;
  width: 2px;
  height: 12px; /* Fixed max height - animation uses scaleY */
  background: var(--warning);
  border-radius: 1px;
  transform-origin: center center;
}

/* PERF: Each bar uses scaleY instead of height (GPU-accelerated) */
#comms-wave span:nth-child(1) {
  animation: comms-wave-1 0.42s ease-in-out infinite;
}
#comms-wave span:nth-child(2) {
  animation: comms-wave-2 0.55s ease-in-out infinite;
  animation-delay: 0.1s;
}
#comms-wave span:nth-child(3) {
  animation: comms-wave-3 0.38s ease-in-out infinite;
  animation-delay: 0.05s;
}
#comms-wave span:nth-child(4) {
  animation: comms-wave-4 0.48s ease-in-out infinite;
  animation-delay: 0.15s;
}

@keyframes comms-wave-1 {
  0%, 100% { transform: scale3d(1, 0.25, 1); }
  50% { transform: scale3d(1, 0.83, 1); }
}

@keyframes comms-wave-2 {
  0%, 100% { transform: scale3d(1, 0.42, 1); }
  35% { transform: scale3d(1, 1, 1); }
  70% { transform: scale3d(1, 0.5, 1); }
}

@keyframes comms-wave-3 {
  0%, 100% { transform: scale3d(1, 0.33, 1); }
  40% { transform: scale3d(1, 0.67, 1); }
  80% { transform: scale3d(1, 0.92, 1); }
}

@keyframes comms-wave-4 {
  0%, 100% { transform: scale3d(1, 0.25, 1); }
  60% { transform: scale3d(1, 0.75, 1); }
}

#comms-text {
  margin: 0;
  color: var(--text-primary);
  font-family: var(--font-dialogue);
  font-size: var(--font-size-xl);
  line-height: 1.4;
  text-wrap: pretty;
}

/* Typewriter word spans - prevent mid-word line breaks (shared by dialogue & comms) */
.tw-word {
  white-space: nowrap;
}

/* --- Toast Container --- */
#toast-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gui-gap-sm);
  pointer-events: none; /* Click-through */
}

#toast-container:empty { display: none; }

/* Toast-specific: animation */
.toast {
  animation: toast-in 0.3s ease, toast-out 0.3s ease 2.7s forwards;
  white-space: nowrap;
}

@keyframes toast-in {
  from { opacity: 0; transform: translate3d(0, 10px, 0); }
  to { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes toast-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

/* --- Persistent Toasts (no auto-dismiss) --- */
.toast.persistent {
  animation: toast-in 0.3s ease forwards;
  box-shadow: 0 2px 8px var(--alpha-black-40);
  display: flex;
  align-items: center;
  gap: var(--gui-gap);
  pointer-events: auto;
}

.toast-dismiss {
  flex-shrink: 0;
  background: none;
  border: none;
  color: inherit;
  font-size: 1.1em;
  cursor: pointer;
  opacity: 0.6;
  padding: 2px 4px;
  line-height: 1;
}

.toast-dismiss:hover,
.toast-dismiss:focus-visible {
  opacity: 1;
}

.toast.persistent.fade-out {
  animation: toast-out 0.2s ease forwards;
}

/* Error persistent toast - red border accent with subtle pulse */
.toast.persistent.error {
  border-left-color: var(--danger);
  animation: toast-in 0.3s ease, persistent-pulse 2s ease-in-out 0.3s infinite;
}

@keyframes persistent-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.8; }
}

/* --- Debug Panel (toggle via window.__vmShowToastDebug()) --- */
#toast-debug-panel {
  position: fixed;
  top: var(--gui-margin);
  right: var(--gui-margin);
  background: var(--bg-panel-alpha);
  border: var(--frame-border-width) solid var(--frame-border);
  padding: var(--gui-padding);
  z-index: 450;
  display: none;
  flex-direction: column;
  gap: var(--gui-gap-sm);
  max-width: 280px;
  pointer-events: auto; /* Interactive when visible */
}

#toast-debug-panel.visible {
  display: flex;
}

#toast-debug-panel .debug-title {
  font-family: var(--font-display);
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding-bottom: var(--gui-padding-sm);
  border-bottom: 1px solid var(--alpha-white-05);
}

#toast-debug-panel .toast {
  animation: none;
  position: relative;
}

#toast-debug-panel .toast-type-label {
  position: absolute;
  top: 50%;
  right: var(--gui-padding);
  transform: translateY(-50%);
  font-size: var(--font-size-2xs);
  font-family: var(--font-numbers);
  color: var(--text-muted);
  background: var(--alpha-black-50);
  padding: 2px 4px;
}

/* ============================================
   SETTINGS MENU
   ============================================ */

/* Settings shroud — replaces ::backdrop to avoid showModal top-layer cost.
   Matches #dialogue-shroud pattern. */
#settings-shroud {
  position: fixed;
  inset: 0;
  background: var(--bg-panel-alpha);
  z-index: 199;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  cursor: pointer;
  transition:
    opacity var(--fade-standard) ease-out,
    visibility var(--fade-standard) ease-out;
  transition-delay: 350ms;
}

#settings-shroud.visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition-delay: 0ms;
}

/* Settings modal — uses show()/close() to avoid top-layer promotion cost */
#settings-menu {
  position: fixed;
  top: 50%;
  left: 50%;
  margin: 0;
  translate: -50% calc(-50% - 40px) 0;
  pointer-events: auto;
  border: var(--border-hairline);
  padding: 0;
  width: 640px;
  max-width: 90vw;
  height: 85vh;
  background: var(--bg-panel-alpha);
  font-family: var(--font-display);
  color: inherit;
  box-shadow: var(--shadow-lg);
  contain: layout style paint;
  z-index: 200;
  opacity: 0;
  scale: 0.8;
  transition:
    opacity 450ms cubic-bezier(0.36, 0, 0.66, -0.56),
    scale 450ms cubic-bezier(0.36, 0, 0.66, -0.56),
    translate 450ms cubic-bezier(0.36, 0, 0.66, -0.56),
    display 450ms allow-discrete;
}

#settings-menu[open] {
  display: flex;
  flex-direction: column;
  opacity: 1;
  scale: 1;
  translate: -50% -50% 0;
  transition:
    opacity 550ms cubic-bezier(0.34, 1.56, 0.64, 1),
    scale 550ms cubic-bezier(0.34, 1.56, 0.64, 1),
    translate 550ms cubic-bezier(0.34, 1.56, 0.64, 1),
    display 550ms allow-discrete;
  transition-delay: 200ms;
}

#settings-menu[open].modal-entering {
  opacity: 0;
  scale: 0.8;
  translate: -50% calc(-50% - 40px) 0;
}

/* ---- Header ---- */
.settings-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--gui-padding);
  border-bottom: var(--border-hairline);
  background: var(--alpha-white-02);
  flex-shrink: 0;
}

.settings-header h2 {
  font-size: var(--font-size-lg);
  font-weight: 600;
  color: var(--text-primary);
}

.settings-close {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: var(--font-size-2xl);
  cursor: pointer;
  padding: 0;
  min-width: 24px;
  min-height: 24px;
  line-height: 1;
  transition: color 0.15s ease;
}

.settings-close:hover,
.settings-close:focus-visible {
  color: var(--text-primary);
}

/* ---- Body: sidebar + content ---- */
.settings-body {
  display: flex;
  flex: 1;
  min-height: 0; /* Allow flex children to shrink */
  /* max-height removed: parent #settings-menu has explicit height: 85vh;
     capping the body lower would leave an empty band at the dialog bottom
     in Chromium. Refactor 8 / visual-state-refactor.md §3.2. */
}

/* ---- Sidebar tab navigation ---- */
.settings-tabs {
  display: flex;
  flex-direction: column;
  width: 140px;
  flex-shrink: 0;
  background: var(--bg-dark);
  border-right: var(--border-hairline);
  padding: var(--gui-gap-sm) 0;
}

.settings-tab {
  display: block;
  width: 100%;
  padding: 0.5rem var(--gui-padding);
  background: none;
  border: none;
  border-left: 2px solid transparent;
  font-family: var(--font-display);
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-align: left;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}

.settings-tab:hover,
.settings-tab:focus-visible {
  color: var(--text-secondary);
  background: var(--alpha-white-02);
}

.settings-tab.active {
  color: var(--text-primary);
  border-left-color: var(--accent);
  background: var(--alpha-white-03);
}

/* ---- Content area ---- */
.settings-content {
  flex: 1;
  padding: var(--gui-padding);
  overflow-y: auto;
  min-width: 0; /* Prevent flex blowout */
  scrollbar-width: thin;
  scrollbar-color: var(--alpha-white-08) transparent;
}

/* Tab panes: hidden by default, shown when active */
.settings-pane {
  display: none;
}

.settings-pane.active {
  display: block;
}

/* ---- Sections within panes ---- */
.settings-section {
  margin-bottom: 1rem;
}

.settings-section:last-child {
  margin-bottom: 0;
}

.settings-fieldset {
  border: none;
  margin: 0;
  padding: 0;
}
.settings-fieldset > legend {
  padding: 0;
}

.settings-section h3 {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-bottom: 0.5rem;
  padding-bottom: 0.25rem;
  border-bottom: 1px solid var(--alpha-white-05);
}

/* ---- Nameplate settings groups ---- */
.settings-group {
  margin-bottom: 0.625rem;
}

.settings-group:last-child {
  margin-bottom: 0;
}

.settings-label {
  display: block;
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  margin-bottom: 0.25rem;
}

/* ---- Radio groups (segmented control) ---- */
.settings-radio-group {
  display: flex;
  gap: 2px;
  background: var(--frame-inner);
  border: 1px solid var(--frame-border);
  padding: 2px;
}

.settings-radio {
  flex: 1;
  display: flex;
  cursor: pointer;
}

.settings-radio input[type="radio"] {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.settings-radio input[type="radio"]:focus-visible + span {
  outline: 2px solid var(--alpha-white-40);
  outline-offset: -2px;
}

.settings-radio span {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 0.3rem 0.4rem;
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  text-align: center;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.settings-radio input[type="radio"]:checked + span {
  background: var(--accent);
  color: var(--text-on-fill);
}

.settings-radio:hover span {
  color: var(--text-primary);
}

.settings-radio input[type="radio"]:checked + span:hover {
  color: var(--text-on-fill);
}

/* ---- Toggle checkboxes ---- */
.settings-toggle {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.settings-toggle + .settings-toggle {
  margin-top: var(--gui-margin-sm);
}

.settings-toggle label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  font-size: var(--font-size-sm);
  color: var(--text-primary);
}

.settings-toggle input[type="checkbox"] {
  width: 14px;
  height: 14px;
  accent-color: var(--accent);
  cursor: pointer;
}

/* ---- Hints ---- */
.settings-hint {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  line-height: 1.3;
  margin-left: var(--space-6);
}

/* Standalone hint (direct child of section, not under a toggle) */
.settings-section > .settings-hint {
  margin-left: 0;
  margin-bottom: 0.5rem;
}

/* (controls-list and settings-future-note removed — controls tab is now dynamic) */

/* ---- Slider control (range input) ---- */
.settings-slider-row {
  display: flex;
  align-items: center;
  gap: var(--gui-gap);
}

.settings-slider {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 24px;
  background: transparent;
  outline: none;
}
.settings-slider::-webkit-slider-runnable-track {
  height: 4px;
  background: var(--frame-inner);
  border: 1px solid var(--frame-border);
}
.settings-slider::-moz-range-track {
  height: 4px;
  background: var(--frame-inner);
  border: 1px solid var(--frame-border);
}

.settings-slider:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.settings-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 24px;
  height: 24px;
  background: var(--accent);
  border: none;
  border-radius: 2px;
  cursor: pointer;
}

.settings-slider::-moz-range-thumb {
  width: 24px;
  height: 24px;
  background: var(--accent);
  border: none;
  border-radius: 2px;
  cursor: pointer;
}

.settings-slider-value {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  font-family: var(--font-numbers);
  min-width: 2.5em;
  text-align: right;
}

/* ---- Disabled / stubbed settings ---- */
.settings-disabled {
  opacity: 0.35;
  pointer-events: none;
}

/* ---- Coming Soon badge ---- */
.settings-coming-soon {
  display: inline-block;
  font-size: var(--font-size-2xs);
  color: var(--text-muted);
  border: 1px solid var(--alpha-white-08);
  padding: 1px 6px;
  margin-left: var(--gui-gap-sm);
  vertical-align: middle;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* ---- Version label ---- */
.settings-version {
  margin-top: 1.5rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--alpha-white-05);
  font-size: var(--font-size-2xs);
  color: var(--text-muted);
  text-align: center;
  letter-spacing: 0.05em;
}

/* ---- Graphics / browser info ---- */
.graphics-info {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
}

.browser-note {
  margin-bottom: 0.5rem;
  line-height: 1.4;
}

.browser-ok {
  color: var(--success);
}

.graphics-details {
  background: var(--frame-inner);
  border: var(--frame-border-width) solid var(--frame-border);
  padding: var(--gui-padding);
  margin-top: var(--gui-gap);
}

.graphics-details summary {
  cursor: pointer;
  font-weight: 500;
  color: var(--text-primary);
  font-size: var(--font-size-xs);
}

.graphics-details[open] summary {
  margin-bottom: 0.5rem;
}

.graphics-steps {
  margin: 0.5rem 0 0.5rem 1.2rem;
  padding: 0;
  font-size: var(--font-size-xs);
  line-height: 1.6;
}

.graphics-steps li {
  margin-bottom: 0.25rem;
}

.terminal-note {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  margin: 0.5rem 0 0.25rem;
}

.terminal-cmd {
  display: block;
  background: var(--terminal-cmd-bg);
  border: var(--frame-border-width) solid var(--frame-border);
  padding: 0.4rem 0.5rem;
  font-family: var(--font-numbers);
  font-size: var(--font-size-2xs);
  color: var(--punch-cyan);
  word-break: break-all;
  user-select: all;
}

/* ---- Keybind remapping UI ---- */
.keybind-row {
  display: flex;
  align-items: center;
  gap: var(--gui-gap-sm);
  padding: 0.25rem 0;
}

.keybind-label {
  flex: 1;
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.keybind-key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 3rem;
  padding: 0.2rem 0.5rem;
  background: var(--frame-inner);
  border: 1px solid var(--alpha-white-08);
  font-family: var(--font-numbers);
  font-size: var(--font-size-xs);
  color: var(--text-primary);
  text-align: center;
  cursor: pointer;
  transition: border-color 0.15s ease, background-color 0.15s ease;
  white-space: nowrap;
}

.keybind-key:hover,
.keybind-key:focus-visible {
  border-color: var(--accent);
  background: var(--alpha-white-03);
}

.keybind-key-empty {
  color: var(--text-muted);
  border-style: dashed;
}

.keybind-key-locked {
  cursor: default;
  opacity: 0.5;
  pointer-events: none;
}

.keybind-listening {
  border-color: var(--accent);
  background: var(--alpha-white-05);
  animation: keybind-pulse 1s ease-in-out infinite;
  color: var(--accent);
}

@keyframes keybind-pulse {
  0%, 100% { border-color: var(--accent); }
  50% { border-color: transparent; }
}

.keybind-conflict {
  border-color: var(--warning, var(--accent));
  color: var(--warning, var(--accent));
  font-size: var(--font-size-2xs);
}

.keybind-reset {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: var(--font-size-sm);
  cursor: pointer;
  padding: 0.1rem 0.3rem;
  min-width: 24px;
  min-height: 24px;
  line-height: 1;
  transition: color 0.15s ease;
}

.keybind-reset:hover,
.keybind-reset:focus-visible {
  color: var(--text-primary);
}

.keybind-fixed .keybind-label {
  color: var(--text-muted);
}

.keybind-actions {
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: var(--border-hairline);
}

.settings-btn-secondary {
  background: var(--frame-inner);
  border: 1px solid var(--alpha-white-08);
  color: var(--text-secondary);
  font-family: var(--font-display);
  font-size: var(--font-size-xs);
  padding: 0.4rem 0.8rem;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.settings-btn-secondary:hover,
.settings-btn-secondary:focus-visible {
  background: var(--alpha-white-05);
  color: var(--text-primary);
}

.settings-btn-primary {
  background: var(--accent);
  border: 1px solid var(--accent-bright);
  color: var(--text-on-fill);
  font-family: var(--font-display);
  font-size: var(--font-size-xs);
  padding: 0.4rem 0.8rem;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.settings-btn-primary:hover,
.settings-btn-primary:focus-visible {
  background: var(--accent-bright);
}

.settings-btn-primary:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* ============================================
   GUI MODAL — Reusable <dialog> modal system
   Native <dialog> provides focus trap, backdrop,
   and top-layer stacking. Use with showModal().
   Cinematic enter/exit with staggered backdrop.
   ============================================ */
.gui-modal {
  position: fixed;
  top: 50%;
  left: 50%;
  background: var(--bg-panel);
  border: var(--frame-border-width) solid var(--frame-border);
  padding: 0;
  max-width: 420px;
  width: 90vw;
  font-family: var(--font-display);
  pointer-events: auto;
  z-index: 200;
  box-shadow: var(--shadow-lg);
  contain: layout style paint;
  /* Closed state — above and small (behind) */
  opacity: 0;
  translate: -50% calc(-50% - 40px) 0;
  scale: 0.8;
  /* Exit transition — anticipation easing (inverse of overshoot) */
  transition:
    opacity 450ms cubic-bezier(0.36, 0, 0.66, -0.56),
    translate 450ms cubic-bezier(0.36, 0, 0.66, -0.56),
    scale 450ms cubic-bezier(0.36, 0, 0.66, -0.56),
    display 450ms allow-discrete,
    overlay 450ms allow-discrete;
}

/* Open state — fully visible and centered */
.gui-modal[open] {
  opacity: 1;
  translate: -50% -50% 0;
  scale: 1;
  /* Enter transition — overshoot easing for the arc */
  transition:
    opacity 550ms cubic-bezier(0.34, 1.56, 0.64, 1),
    translate 550ms cubic-bezier(0.34, 1.56, 0.64, 1),
    scale 550ms cubic-bezier(0.34, 1.56, 0.64, 1),
    display 550ms allow-discrete,
    overlay 550ms allow-discrete;
  transition-delay: 200ms;
}

.gui-modal[open].modal-entering {
  opacity: 0;
  translate: -50% calc(-50% - 40px) 0;
  scale: 0.8;
}

.gui-modal::backdrop {
  background: var(--alpha-black-70);
  opacity: 0;
  cursor: pointer;
  transition:
    opacity var(--fade-standard) ease-out,
    overlay var(--fade-standard) ease-out allow-discrete,
    display var(--fade-standard) ease-out allow-discrete;
  transition-delay: 350ms;
}

.gui-modal[open]::backdrop {
  opacity: 1;
  transition-delay: 0ms;
}

.gui-modal[open].modal-entering::backdrop {
  opacity: 0;
}

.gui-modal-body {
  padding: calc(var(--gui-padding) * 3);
}

.gui-modal h2 {
  font-size: var(--font-size-xl);
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 0.75rem;
}

.gui-modal p {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  line-height: 1.5;
  margin-bottom: 0.75rem;
}

.gui-modal .graphics-details {
  margin-bottom: 1rem;
}

.modal-note {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
  font-style: italic;
  margin-bottom: 1rem;
}

.modal-btn {
  display: block;
  width: 100%;
  padding: var(--gui-padding);
  background: var(--punch-cyan);
  border: none;
  color: var(--text-on-fill);
  font-family: var(--font-display);
  font-size: var(--font-size-md);
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--fade-snappy) ease;
}

.modal-btn:hover,
.modal-btn:focus-visible {
  background: var(--modal-hover);
}

/* ============================================
   ONBOARDING WAYPOINT
   ============================================ */
.onboarding-waypoint {
  position: fixed;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  pointer-events: none;
  z-index: 150;
}

.onboarding-waypoint::after {
  content: '';
  position: absolute;
  top: -12px;
  left: -6px;
  width: 0;
  height: 0;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-bottom: 12px solid var(--accent);
  transform: rotate3d(0, 0, 1, -90deg);
  animation: waypoint-pulse 1.5s ease-in-out infinite;
}

@keyframes waypoint-pulse {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 1; }
}

/* ============================================
   RESIZE OVERLAY
   ============================================ */
#resize-overlay {
  position: fixed;
  inset: 0;
  z-index: 900; /* Above everything except during active use */
  background: var(--overlay-bg-warm);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--fade-snappy) ease-out, visibility var(--fade-snappy) ease-out;
  pointer-events: none;
}

#resize-overlay.visible {
  opacity: 1;
  visibility: visible;
}

.resize-overlay-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  color: var(--text-secondary);
  font-family: var(--font-display);
}

.resize-icon {
  font-size: var(--font-size-4xl);
  animation: resize-spin 1.5s linear infinite;
}

.resize-text {
  font-size: var(--font-size-lg);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

@keyframes resize-spin {
  from { transform: rotate3d(0, 0, 1, 0deg); }
  to { transform: rotate3d(0, 0, 1, 360deg); }
}

/* Matches #resize-overlay baseline; below #gui-layer (100) so disconnect/settings stay above */
#tab-resume-overlay {
  position: fixed;
  inset: 0;
  z-index: 99;
  background: var(--overlay-bg-warm);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--fade-snappy) ease-out, visibility var(--fade-snappy) ease-out;
  pointer-events: none;
}

#tab-resume-overlay.visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

/* Instant opaque show (no fade-in) — removed before fade-out so exit transition runs */
#tab-resume-overlay.tab-resume-instant {
  transition: none;
}

/* ============================================
   DISCONNECT OVERLAY
   ============================================ */
@keyframes disconnect-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

#disconnect-overlay {
  position: fixed;
  inset: 0;
  z-index: 10000;
  pointer-events: all;
  background: oklch(0.15 0 0 / 0.85);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--gui-gap);
  animation: disconnect-fade-in var(--fade-quick) ease-out;
}

#disconnect-heading {
  font-family: var(--font-sans);
  font-size: 1.5rem;
  font-weight: 600;
  color: oklch(0.95 0 0);
  margin: 0;
}

#disconnect-status {
  font-family: var(--font-sans);
  font-size: 0.875rem;
  color: oklch(0.7 0 0);
  margin: 0;
}

#disconnect-return {
  margin-top: var(--gui-padding);
  padding: 0.5rem 1.5rem;
  font-family: var(--font-sans);
  font-size: 0.875rem;
  font-weight: 500;
  color: oklch(0.95 0 0);
  background: oklch(0.3 0 0);
  border: 1px solid oklch(0.45 0 0);
  border-radius: 4px;
  cursor: pointer;
  transition: background var(--fade-snappy);
}

#disconnect-return:hover {
  background: oklch(0.38 0 0);
}

#disconnect-return:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ── LOGOUT TIMER OVERLAY ─────────────────────────────────── */

#logout-overlay {
  position: fixed;
  inset: 0;
  z-index: 9998;
  pointer-events: all;
  background: oklch(0.12 0 0 / 0.7);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--gui-gap);
  animation: disconnect-fade-in var(--fade-quick) ease-out;
}

#logout-overlay h2 {
  font-family: var(--font-sans);
  font-size: 1.25rem;
  font-weight: 600;
  color: oklch(0.9 0 0);
  margin: 0;
}

#logout-countdown {
  font-family: var(--font-mono);
  font-size: 2.5rem;
  font-weight: 700;
  color: oklch(0.95 0.05 55);
  margin: 0;
}

#logout-cancel {
  margin-top: var(--gui-padding);
  padding: 0.5rem 1.5rem;
  font-family: var(--font-sans);
  font-size: 0.875rem;
  font-weight: 500;
  color: oklch(0.95 0 0);
  background: oklch(0.3 0 0);
  border: 1px solid oklch(0.45 0 0);
  border-radius: 4px;
  cursor: pointer;
  transition: background var(--fade-snappy);
}

#logout-cancel:hover {
  background: oklch(0.38 0 0);
}

/* ============================================
   RESPONSIVE
   ============================================ */
@media (max-width: 900px) {
  .unit-frame {
    min-width: 160px;
  }
}

@media (max-width: 768px) {
  :root {
    --tile-size: 20px;
  }

  /* Remove panel min-width for mobile and constrain to column width */
  .gui-panel:not(.frame-wrapper),
  #quest-tracker,
  #combat-log-container,
  #inventory-panel,
  #party-frames {
    min-width: 0;
    max-width: 100%;
  }

  /* Docked panels fill column width */
  #left-panel-column > .gui-panel,
  #right-panel-column > .gui-panel {
    width: 100%;
  }

  /* Remove min-width from portrait children */
  .frame-wrapper,
  .frame-status-container,
  .unit-frame {
    min-width: 0;
  }

  /* Prevent columns from overlapping */
  #left-panel-column {
    top: 0.5rem;
    left: 0.5rem;
    bottom: 0.5rem;
    max-width: calc(50% - 1rem);
  }

  #right-panel-column {
    top: 0.5rem;
    right: 0.5rem;
    max-width: calc(50% - 1rem);
  }

  #minimap-container {
    min-width: 0;
    /* Keep square aspect ratio */
    aspect-ratio: 1 / 1;
  }

  #quest-tracker {
    max-width: 100%;
  }

  #bottom-ui {
    bottom: 0.5rem;
    width: 100%;
    padding: 0 0.5rem;
  }

  #combat-hud-dock {
    width: 100%;
  }

  #portrait-row {
    min-width: auto;
    max-width: none;
    width: 100%;
  }

  .action-slot {
    width: 40px;
    height: 40px;
  }

  #weapon-display {
    display: none;
  }

  .unit-frame {
    padding: 0.25rem;
  }

  .portrait-wrapper { display: none; }
  #dialogue-portrait { display: none; }
  
  /* Settings: collapse sidebar to horizontal tab strip on narrow viewports */
  .settings-body {
    flex-direction: column;
  }
  
  .settings-tabs {
    flex-direction: row;
    width: 100%;
    border-right: none;
    border-bottom: var(--border-hairline);
    padding: var(--gui-gap-sm) var(--gui-gap-sm);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    gap: 2px;
    position: relative;
  }

  .settings-tabs::before,
  .settings-tabs::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    width: 20px;
    pointer-events: none;
    z-index: 1;
    opacity: 0;
    transition: opacity 200ms ease;
  }

  .settings-tabs::before {
    left: 0;
    background: linear-gradient(to right, var(--bg-panel), transparent);
  }

  .settings-tabs::after {
    right: 0;
    background: linear-gradient(to left, var(--bg-panel), transparent);
  }

  .settings-tabs.can-scroll-left::before { opacity: 1; }
  .settings-tabs.can-scroll-right::after { opacity: 1; }
  
  .settings-tab {
    border-left: none;
    border-bottom: 2px solid transparent;
    padding: 0.4rem 0.6rem;
    white-space: nowrap;
    text-align: center;
  }
  
  .settings-tab.active {
    border-left-color: transparent;
    border-bottom-color: var(--accent);
  }

  #xp-bar-track {
    height: 6px;
  }

  .xp-level-box {
    width: 20px;
    min-width: 20px;
    height: 20px;
  }

  /* XP row: small gap from ability bar, flush with bottom */
  #xp-row {
    margin-top: calc(-1.5 * var(--gui-margin));
    margin-bottom: calc(-0.5 * var(--gui-margin));
  }
}

/* ============================================
   MOBILE (≤512px)
   Full-width panels and action bar
   ============================================ */
@media (max-width: 512px) {
  /* Portrait containers take 50% minus gap */
  .portrait-dock-zone {
    min-width: calc(50% - var(--gui-margin) / 2);
  }

  /* Ability/XP bar parent goes full width */
  #abilities-row {
    width: 100%;
  }

  #action-block {
    width: 100%;
    /* Pull ability bar down to sit in XP bar footprint */
    margin-bottom: calc(-1.5 * var(--gui-margin));
  }

  /* XP row: pull up to close gap with ability bar */
  #xp-row {
    margin-top: calc(-0.5 * var(--gui-margin));
    margin-bottom: calc(-0.5 * var(--gui-margin));
  }

  #action-bar,
  #action-bar-2 {
    justify-content: center;
    background: var(--alpha-black-00);
  }

  /* All panels fill their parent column */
  #left-panel-column > .gui-panel,
  #right-panel-column > .gui-panel {
    width: 100%;
  }
}

/* ============================================
   CENTER-SCREEN ANNOUNCEMENTS
   Three systems: Zone Banner, Level-Up Display, Achievement Alert
   ============================================ */

.announcement-layer {
  position: fixed;
  pointer-events: none;
  z-index: 1000;
}

/* --- Zone Banner (WoW ZoneTextFrame) --- */
#zone-banner {
  top: 18%;
  left: 50%;
  transform: translate3d(-50%, 0, 0);
  text-align: center;
  opacity: 0;
  transition: none;
}

#zone-banner.zone-banner-visible {
  animation: zone-banner-show 4s ease forwards;
}

.zone-banner-prefix {
  font-size: var(--font-size-xs);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--zone-banner-color, var(--text-primary));
  margin-bottom: 0.25rem;
}

.zone-banner-title {
  font-size: 1.6rem;
  font-weight: 700;
  color: var(--zone-banner-color, var(--text-primary));
  text-shadow: 0 2px 12px var(--alpha-black-60), 0 0 4px var(--alpha-black-40);
  letter-spacing: 0.04em;
}

.zone-banner-zone {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  text-shadow: 0 1px 6px var(--alpha-black-60);
  margin-top: 0.15rem;
}

.zone-banner-level {
  font-size: var(--font-size-xs);
  color: var(--zone-banner-color, var(--text-muted));
  text-shadow: 0 1px 4px var(--alpha-black-60);
  margin-top: 0.1rem;
}

@keyframes zone-banner-show {
  0%   { opacity: 0; transform: translate3d(-50%, 4px, 0); }
  12%  { opacity: 1; transform: translate3d(-50%, 0, 0); }
  50%  { opacity: 1; transform: translate3d(-50%, 0, 0); }
  100% { opacity: 0; transform: translate3d(-50%, -6px, 0); }
}

/* --- Level-Up Display (WoW LevelUpDisplay) --- */
#levelup-display {
  top: 30%;
  left: 50%;
  transform: translate3d(-50%, 0, 0);
  text-align: center;
  opacity: 0;
  transition: none;
}

#levelup-display.levelup-visible {
  animation: levelup-show 4.5s ease forwards;
}

#levelup-display.levelup-ability-mode.levelup-visible {
  animation: levelup-show 3.4s ease forwards;
}

.levelup-title {
  font-size: 2rem;
  font-weight: 800;
  color: var(--xp-color);
  text-shadow: 0 2px 16px var(--alpha-black-60), 0 0 30px var(--celebration-glow);
  letter-spacing: 0.06em;
}

.levelup-ability-mode .levelup-title {
  font-size: 1.5rem;
  color: var(--success);
  text-shadow: 0 2px 12px var(--alpha-black-60);
}

.levelup-stats {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  text-shadow: 0 1px 6px var(--alpha-black-60);
  margin-top: 0.3rem;
  letter-spacing: 0.08em;
}

@keyframes levelup-show {
  0%   { opacity: 0; transform: translate3d(-50%, 0, 0) scale3d(0.92, 0.92, 1); }
  11%  { opacity: 1; transform: translate3d(-50%, 0, 0) scale3d(1, 1, 1); }
  56%  { opacity: 1; transform: translate3d(-50%, 0, 0) scale3d(1, 1, 1); }
  100% { opacity: 0; transform: translate3d(-50%, -8px, 0) scale3d(1, 1, 1); }
}

/* --- Achievement Alert (WoW AlertFrame) --- */
#achievement-container {
  top: 12%;
  right: var(--gui-margin);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: flex-end;
}

.achievement-alert {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 1rem;
  background: var(--bg-panel);
  border: 1px solid var(--alpha-white-10);
  border-left: 3px solid var(--xp-color);
  opacity: 0;
  transform: translate3d(20px, 0, 0);
  transition: opacity 0.4s ease, transform 0.4s ease;
  box-shadow: 0 4px 16px var(--alpha-black-40);
}

.achievement-alert.achievement-visible {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

.achievement-alert.achievement-out {
  opacity: 0;
  transform: translate3d(20px, 0, 0);
  transition: opacity 1.5s ease, transform 1.5s ease;
}

.achievement-icon {
  font-size: 1.3rem;
  color: var(--xp-color);
  flex-shrink: 0;
}

.achievement-title {
  font-size: var(--font-size-sm);
  font-weight: 700;
  color: var(--xp-color);
}

.achievement-desc {
  font-size: var(--font-size-xs);
  color: var(--text-muted);
}
