You have successfully edited this setting

System
Label Value Edit
Version 2.7.6
Language English (English)
Support Discord | Github | Blog
Donate Paypal
Appearance
Label Value Edit
Background Image - not set -
Trianglify No
Trianglify Random Seed heimdall
Treat Tags As: Folders
Miscellaneous
Label Value Edit
Homepage Search No
Default Search Provider - not set -
Link opens in Open in the same tab
Advanced
Label Value Edit
Custom CSS
/* ============================================================
   HEIMDALL — COMMAND CENTER THEME
   Drop in: storage/app/public/custom.css
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;800;900&family=Rajdhani:wght@300;400;500;600;700&family=Share+Tech+Mono&display=swap');

/* ─── CSS VARIABLES ─────────────────────────────────────────── */
:root {
  --teal:        #00f5c8;
  --teal-dim:    #00c49e;
  --teal-glow:   rgba(0, 245, 200, 0.18);
  --amber:       #ffb800;
  --amber-dim:   #cc9200;
  --amber-glow:  rgba(255, 184, 0, 0.18);
  --red-alert:   #ff3a5c;
  --bg-void:     #030508;
  --bg-deep:     #060c14;
  --bg-surface:  #0a1520;
  --bg-elevated: #0f1e2d;
  --border:      rgba(0, 245, 200, 0.12);
  --border-hot:  rgba(0, 245, 200, 0.45);
  --text-primary:   #e8f4f8;
  --text-secondary: #7aaabb;
  --text-dim:       #3d6070;
  --font-display: 'Orbitron', monospace;
  --font-body:    'Rajdhani', sans-serif;
  --font-mono:    'Share Tech Mono', monospace;
  --radius:       4px;
  --radius-lg:    8px;
}

/* ─── RESET + BASE ───────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  cursor: none;
}

body {
  font-family: var(--font-body);
  font-size: 15px;
  background: var(--bg-void);
  color: var(--text-primary);
  min-height: 100vh;
  overflow-x: hidden;
  letter-spacing: 0.02em;
}

/* ─── CUSTOM CURSOR ──────────────────────────────────────────── */
#cursor-dot {
  position: fixed;
  width: 6px; height: 6px;
  background: var(--teal);
  border-radius: 50%;
  pointer-events: none;
  z-index: 99999;
  transition: transform 0.1s ease;
  box-shadow: 0 0 10px var(--teal), 0 0 20px var(--teal);
}
#cursor-ring {
  position: fixed;
  width: 28px; height: 28px;
  border: 1px solid var(--teal);
  border-radius: 50%;
  pointer-events: none;
  z-index: 99998;
  transition: transform 0.18s ease, width 0.2s, height 0.2s, border-color 0.2s;
  opacity: 0.6;
}
body:hover #cursor-ring { opacity: 1; }

/* ─── PARTICLE CANVAS ────────────────────────────────────────── */
#heimdall-canvas {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

/* ─── HEX GRID OVERLAY ───────────────────────────────────────── */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 1;
  background-image:
    repeating-linear-gradient(
      60deg,
      transparent,
      transparent 28px,
      rgba(0, 245, 200, 0.022) 28px,
      rgba(0, 245, 200, 0.022) 29px
    ),
    repeating-linear-gradient(
      -60deg,
      transparent,
      transparent 28px,
      rgba(0, 245, 200, 0.022) 28px,
      rgba(0, 245, 200, 0.022) 29px
    ),
    repeating-linear-gradient(
      0deg,
      transparent,
      transparent 48px,
      rgba(0, 245, 200, 0.015) 48px,
      rgba(0, 245, 200, 0.015) 49px
    );
  pointer-events: none;
}

/* ─── SCANLINES ──────────────────────────────────────────────── */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 2;
  background: repeating-linear-gradient(
    to bottom,
    transparent,
    transparent 2px,
    rgba(0, 0, 0, 0.08) 2px,
    rgba(0, 0, 0, 0.08) 4px
  );
  pointer-events: none;
  animation: scanPulse 8s ease-in-out infinite;
}
@keyframes scanPulse {
  0%, 100% { opacity: 0.4; }
  50%       { opacity: 0.7; }
}

/* ─── MAIN WRAPPER ───────────────────────────────────────────── */
.wrapper,
#wrapper,
.container-fluid,
main {
  position: relative;
  z-index: 10;
}

/* ─── HEADER / NAV ───────────────────────────────────────────── */
header,
.navbar,
nav.navbar {
  background: rgba(3, 5, 8, 0.92) !important;
  backdrop-filter: blur(24px) saturate(1.5);
  border-bottom: 1px solid var(--border-hot) !important;
  box-shadow: 0 1px 0 rgba(0, 245, 200, 0.08), 0 4px 40px rgba(0, 0, 0, 0.6);
  position: sticky;
  top: 0;
  z-index: 1000;
}

/* NAV brand / title */
.navbar-brand,
.navbar-brand span,
header h1,
header .title {
  font-family: var(--font-display) !important;
  font-weight: 800 !important;
  font-size: 1.1rem !important;
  letter-spacing: 0.22em !important;
  text-transform: uppercase !important;
  color: var(--teal) !important;
  text-shadow: 0 0 12px var(--teal), 0 0 30px rgba(0, 245, 200, 0.4);
  animation: glitch 6s infinite;
}
@keyframes glitch {
  0%, 94%, 100% { text-shadow: 0 0 12px var(--teal), 0 0 30px rgba(0,245,200,0.4); transform: none; }
  95%  { text-shadow: -2px 0 var(--amber), 2px 0 var(--red-alert); transform: skewX(-1deg); }
  96%  { text-shadow: 2px 0 var(--teal), -2px 0 var(--amber); transform: skewX(1deg); }
  97%  { text-shadow: 0 0 12px var(--teal); transform: none; }
}

/* NAV links */
.navbar a,
nav a {
  font-family: var(--font-mono) !important;
  font-size: 0.75rem !important;
  letter-spacing: 0.12em !important;
  color: var(--text-secondary) !important;
  text-transform: uppercase;
  transition: color 0.2s, text-shadow 0.2s;
}
.navbar a:hover,
nav a:hover {
  color: var(--teal) !important;
  text-shadow: 0 0 8px var(--teal);
}

/* ─── SEARCH BAR ─────────────────────────────────────────────── */
.search-wrapper,
#search,
input[type="search"],
input[type="text"].search,
.search-input {
  background: rgba(10, 21, 32, 0.8) !important;
  border: 1px solid var(--border) !important;
  border-radius: var(--radius) !important;
  color: var(--text-primary) !important;
  font-family: var(--font-mono) !important;
  font-size: 0.85rem !important;
  letter-spacing: 0.08em !important;
  padding: 10px 18px 10px 42px !important;
  outline: none !important;
  box-shadow: inset 0 0 0 1px transparent;
  transition: all 0.3s ease;
}
.search-wrapper:focus-within,
input[type="search"]:focus,
input[type="text"].search:focus {
  border-color: var(--teal) !important;
  box-shadow: 0 0 0 1px var(--teal), 0 0 24px var(--teal-glow), inset 0 0 12px rgba(0,245,200,0.04) !important;
  background: rgba(0, 245, 200, 0.03) !important;
}
input::placeholder { color: var(--text-dim) !important; }

/* ═══════════════════════════════════════════════════════════════
   HEIMDALL APP CARDS  —  real selectors from Heimdall's DOM
   ═══════════════════════════════════════════════════════════════ */

/* ─── Main grid ──────────────────────────────────────────────── */
#sortable {
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: flex-start !important;
  gap: 18px !important;
  padding: 24px !important;
}

/* ─── Tag group container ────────────────────────────────────── */
.tags-container-parent {
  background: rgba(6, 12, 20, 0.7) !important;
  border: 1px solid var(--border) !important;
  border-radius: var(--radius-lg) !important;
  backdrop-filter: blur(16px) !important;
  box-shadow:
    0 4px 24px rgba(0,0,0,0.4),
    inset 0 1px 0 rgba(0,245,200,0.04) !important;
  overflow: hidden;
  position: relative;
}
/* teal top bar on tag group */
.tags-container-parent::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--teal), transparent);
  opacity: 0.5;
}

/* ─── Tag group title ────────────────────────────────────────── */
.tags-title {
  font-family: var(--font-display) !important;
  font-size: 0.7rem !important;
  font-weight: 700 !important;
  letter-spacing: 0.28em !important;
  text-transform: uppercase !important;
  color: var(--teal) !important;
  text-shadow: 0 0 10px rgba(0,245,200,0.35) !important;
  padding: 14px 18px 10px !important;
  margin: 0 !important;
  border-bottom: 1px solid var(--border) !important;
  display: flex !important;
  align-items: center !important;
  gap: 10px;
}
.tags-title::before {
  content: '//';
  color: rgba(0,245,200,0.35);
  font-size: 0.65rem;
  letter-spacing: 0.1em;
}

/* ─── Tag grid inside group ──────────────────────────────────── */
.tags-container {
  display: flex !important;
  flex-wrap: wrap !important;
  gap: 0 !important;
  padding: 12px !important;
}

/* ─── Individual app card (.item) ───────────────────────────── */
.item {
  position: relative !important;
  display: flex !important;
  align-items: center !important;
  width: 280px !important;
  height: 88px !important;
  padding: 0 70px 0 0 !important;
  margin: 6px !important;
  border-radius: var(--radius-lg) !important;
  background: var(--bg-surface) !important;
  border: 1px solid var(--border) !important;
  box-shadow:
    0 2px 8px rgba(0,0,0,0.4),
    inset 0 1px 0 rgba(255,255,255,0.02) !important;
  overflow: hidden !important;
  transition:
    transform 0.28s cubic-bezier(0.23,1,0.32,1),
    box-shadow 0.28s cubic-bezier(0.23,1,0.32,1),
    border-color 0.28s ease,
    background 0.28s ease !important;
  cursor: pointer;
  backdrop-filter: blur(8px) !important;
}

/* Top shimmer bar */
.item::before {
  content: '' !important;
  position: absolute !important;
  top: 0; left: 0; right: 0 !important;
  height: 1px !important;
  background: linear-gradient(90deg, transparent, var(--teal), transparent) !important;
  opacity: 0 !important;
  transition: opacity 0.3s ease !important;
  z-index: 2 !important;
}

/* Right-side color swatch — override with teal gradient panel */
.item:after {
  content: '' !important;
  position: absolute !important;
  top: 0 !important;
  right: 0 !important;
  width: 64px !important;
  height: 100% !important;
  background: linear-gradient(
    135deg,
    rgba(0,245,200,0.08) 0%,
    rgba(0,245,200,0.14) 100%
  ) !important;
  border-left: 1px solid rgba(0,245,200,0.1) !important;
  opacity: 1 !important;
  transition: background 0.28s ease !important;
  z-index: 0 !important;
}

.item:hover {
  transform: translateY(-4px) scale(1.02) !important;
  background: var(--bg-elevated) !important;
  border-color: var(--border-hot) !important;
  box-shadow:
    0 0 0 1px rgba(0,245,200,0.2),
    0 12px 40px rgba(0,0,0,0.6),
    0 0 28px var(--teal-glow) !important;
}
.item:hover::before { opacity: 1 !important; }
.item:hover:after {
  background: linear-gradient(
    135deg,
    rgba(0,245,200,0.14) 0%,
    rgba(0,245,200,0.22) 100%
  ) !important;
}

/* ─── App icon wrapper ───────────────────────────────────────── */
.app-icon {
  position: relative !important;
  z-index: 1 !important;
  flex-shrink: 0 !important;
  width: 52px !important;
  height: 52px !important;
  margin-left: 14px !important;
  margin-right: 0 !important;
  filter:
    saturate(0.9)
    brightness(1.0)
    drop-shadow(0 0 6px rgba(0,245,200,0.15)) !important;
  transition:
    filter 0.3s ease,
    transform 0.3s cubic-bezier(0.23,1,0.32,1) !important;
  border-radius: var(--radius) !important;
}
.item:hover .app-icon {
  filter:
    saturate(1.1)
    brightness(1.1)
    drop-shadow(0 0 12px rgba(0,245,200,0.35)) !important;
  transform: scale(1.1) !important;
}

/* Decorative FA icon on right panel */
.item .svg-inline--fa {
  position: absolute !important;
  right: 0 !important;
  top: 50% !important;
  transform: translateY(-50%) !important;
  width: 52px !important;
  height: 52px !important;
  color: rgba(0,245,200,0.22) !important;
  z-index: 1 !important;
  transition: color 0.3s ease !important;
}
.item:hover .svg-inline--fa {
  color: rgba(0,245,200,0.38) !important;
}

/* ─── App text details ───────────────────────────────────────── */
.details {
  position: relative !important;
  z-index: 1 !important;
  padding: 0 10px 0 14px !important;
  flex: 1 !important;
  min-width: 0 !important;
  display: flex !important;
  flex-direction: column !important;
  justify-content: center !important;
  gap: 4px !important;
}

.details * { color: var(--text-primary) !important; }

.details > .title {
  font-family: var(--font-display) !important;
  font-size: 0.72rem !important;
  font-weight: 700 !important;
  letter-spacing: 0.16em !important;
  text-transform: uppercase !important;
  color: var(--text-primary) !important;
  text-shadow: none !important;
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  transition: color 0.2s ease, text-shadow 0.2s ease !important;
  margin: 0 !important;
  line-height: 1.2 !important;
}
.item:hover .details > .title {
  color: var(--teal) !important;
  text-shadow: 0 0 10px rgba(0,245,200,0.45) !important;
}

/* App description / URL subtitle */
.details .description,
.details .url,
.details p {
  font-family: var(--font-mono) !important;
  font-size: 0.6rem !important;
  letter-spacing: 0.06em !important;
  color: var(--text-dim) !important;
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  margin: 0 !important;
}

/* ─── Live stats (enhanced apps) ────────────────────────────── */
.livestats-container {
  margin-top: 3px !important;
}
.livestats-container .livestats {
  display: flex !important;
  flex-wrap: wrap !important;
  gap: 4px 10px !important;
  list-style: none !important;
  padding: 0 !important;
  margin: 0 !important;
}
.livestats-container .livestats li {
  font-family: var(--font-mono) !important;
  font-size: 0.58rem !important;
  letter-spacing: 0.06em !important;
  color: var(--text-dim) !important;
  padding: 0 !important;
}
.livestats-container .livestats strong {
  color: var(--amber) !important;
  font-weight: 500 !important;
}
.livestats-container .livestats .title {
  font-family: var(--font-mono) !important;
  font-size: 0.55rem !important;
  letter-spacing: 0.1em !important;
  text-transform: uppercase !important;
  color: var(--text-dim) !important;
  margin-bottom: 1px !important;
}

/* ─── Config / settings sidebar buttons ─────────────────────── */
#config-buttons {
  position: fixed !important;
  right: 0 !important;
  bottom: 50% !important;
  transform: translateY(50%) !important;
  display: flex !important;
  flex-direction: column !important;
  background: rgba(6, 12, 20, 0.92) !important;
  border: 1px solid var(--border) !important;
  border-right: none !important;
  border-radius: 8px 0 0 8px !important;
  backdrop-filter: blur(20px) !important;
  box-shadow:
    -4px 0 24px rgba(0,0,0,0.4),
    inset 1px 0 0 rgba(0,245,200,0.04) !important;
  z-index: 500 !important;
  overflow: hidden !important;
}

#config-buttons a {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: 46px !important;
  height: 46px !important;
  background: transparent !important;
  border-bottom: 1px solid var(--border) !important;
  transition: background 0.2s ease !important;
}
#config-buttons a:last-child { border-bottom: none !important; }
#config-buttons a:hover {
  background: rgba(0,245,200,0.08) !important;
}
#config-buttons a svg {
  color: rgba(0,245,200,0.45) !important;
  width: 16px !important;
  height: 16px !important;
  transition: color 0.2s ease, filter 0.2s ease !important;
}
#config-buttons a:hover svg {
  color: var(--teal) !important;
  filter: drop-shadow(0 0 6px rgba(0,245,200,0.5)) !important;
  transform: none !important;
}

/* ─── Search bar ─────────────────────────────────────────────── */
#search-wrapper,
.search-container,
#search {
  background: rgba(6,12,20,0.85) !important;
  border: 1px solid var(--border) !important;
  border-radius: var(--radius) !important;
  backdrop-filter: blur(16px) !important;
  transition: all 0.3s ease !important;
}
#search-wrapper:focus-within,
.search-container:focus-within {
  border-color: var(--teal) !important;
  box-shadow: 0 0 0 1px var(--teal), 0 0 20px var(--teal-glow) !important;
}

/* ─── Item container tooltip ─────────────────────────────────── */
.item-container .tooltip {
  font-family: var(--font-mono) !important;
  font-size: 0.65rem !important;
  letter-spacing: 0.1em !important;
  background: var(--bg-elevated) !important;
  border: 1px solid var(--border-hot) !important;
  color: var(--text-primary) !important;
  border-radius: var(--radius) !important;
  box-shadow: 0 4px 20px rgba(0,0,0,0.5), 0 0 12px var(--teal-glow) !important;
}

/* ─── Card stagger entry animation ──────────────────────────── */
.item {
  animation: cardEntry 0.45s cubic-bezier(0.23,1,0.32,1) both;
}
.item:nth-child(1)  { animation-delay: 0.04s; }
.item:nth-child(2)  { animation-delay: 0.08s; }
.item:nth-child(3)  { animation-delay: 0.12s; }
.item:nth-child(4)  { animation-delay: 0.16s; }
.item:nth-child(5)  { animation-delay: 0.20s; }
.item:nth-child(6)  { animation-delay: 0.24s; }
.item:nth-child(7)  { animation-delay: 0.28s; }
.item:nth-child(8)  { animation-delay: 0.32s; }
.item:nth-child(n+9){ animation-delay: 0.36s; }

@keyframes cardEntry {
  0%   { opacity: 0; transform: translateY(14px) scale(0.97); }
  100% { opacity: 1; transform: translateY(0)    scale(1); }
}

/* ─── .black text override for Heimdall color classes ───────── */
.black { color: var(--text-primary) !important; }
.white { color: var(--text-primary) !important; }

/* ─── TAGS / STATUS PILLS ────────────────────────────────────── */
.tag,
.badge,
.status-badge,
.label {
  font-family: var(--font-mono) !important;
  font-size: 0.62rem !important;
  letter-spacing: 0.14em !important;
  text-transform: uppercase !important;
  border-radius: 2px !important;
  padding: 2px 8px !important;
  background: rgba(0, 245, 200, 0.08) !important;
  border: 1px solid rgba(0, 245, 200, 0.2) !important;
  color: var(--teal) !important;
}

/* ─── BUTTONS ────────────────────────────────────────────────── */
.btn,
button:not([class*="navbar"]) {
  font-family: var(--font-display) !important;
  font-size: 0.7rem !important;
  font-weight: 600 !important;
  letter-spacing: 0.2em !important;
  text-transform: uppercase !important;
  border-radius: var(--radius) !important;
  border: 1px solid var(--border) !important;
  background: rgba(0,245,200,0.06) !important;
  color: var(--teal) !important;
  padding: 8px 20px !important;
  cursor: none;
  transition: all 0.2s ease !important;
  position: relative;
  overflow: hidden;
}
.btn::before,
button::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(0,245,200,0.1), transparent);
  transform: translateX(-100%);
  transition: transform 0.4s ease;
}
.btn:hover,
button:hover {
  background: rgba(0,245,200,0.12) !important;
  border-color: var(--teal) !important;
  box-shadow: 0 0 16px var(--teal-glow) !important;
}
.btn:hover::before,
button:hover::before { transform: translateX(100%); }

.btn-primary {
  background: linear-gradient(135deg, rgba(0,245,200,0.15), rgba(0,196,158,0.08)) !important;
  border-color: var(--teal) !important;
  box-shadow: 0 0 10px var(--teal-glow) !important;
}

/* ─── SIDEBAR ────────────────────────────────────────────────── */
.sidebar,
aside,
#sidebar {
  background: rgba(3, 5, 8, 0.95) !important;
  border-right: 1px solid var(--border) !important;
  backdrop-filter: blur(20px);
}

.sidebar a,
aside a {
  font-family: var(--font-body) !important;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--text-secondary) !important;
  padding: 9px 16px !important;
  border-left: 2px solid transparent !important;
  transition: all 0.2s ease !important;
  display: block;
  font-size: 0.88rem;
}
.sidebar a:hover,
aside a:hover,
.sidebar a.active,
aside a.active {
  color: var(--teal) !important;
  border-left-color: var(--teal) !important;
  background: rgba(0,245,200,0.05) !important;
  text-shadow: 0 0 8px rgba(0,245,200,0.3);
  padding-left: 22px !important;
}

/* ─── PAGE TITLE / SECTION HEADERS ──────────────────────────── */
h1, h2, h3, h4, h5, h6,
.page-title,
.section-title {
  font-family: var(--font-display) !important;
  color: var(--text-primary) !important;
  letter-spacing: 0.12em !important;
  text-transform: uppercase !important;
}

h1, .page-title {
  font-size: 1.6rem !important;
  font-weight: 900 !important;
  color: var(--teal) !important;
  text-shadow: 0 0 20px rgba(0,245,200,0.3);
}

h2 {
  font-size: 1.1rem !important;
  font-weight: 600 !important;
  color: var(--amber) !important;
  text-shadow: 0 0 12px rgba(255,184,0,0.25);
}

h3 { font-size: 0.9rem !important; color: var(--text-secondary) !important; }

/* ─── MODALS / DIALOGS ───────────────────────────────────────── */
.modal-content,
.dialog,
[role="dialog"] {
  background: var(--bg-deep) !important;
  border: 1px solid var(--border-hot) !important;
  border-radius: var(--radius-lg) !important;
  box-shadow:
    0 0 0 1px rgba(0,245,200,0.1),
    0 24px 80px rgba(0,0,0,0.9),
    0 0 60px var(--teal-glow) !important;
  color: var(--text-primary) !important;
}

.modal-header,
.dialog-header {
  border-bottom: 1px solid var(--border) !important;
  background: rgba(0,245,200,0.03) !important;
}

.modal-title {
  font-family: var(--font-display) !important;
  font-size: 0.85rem !important;
  letter-spacing: 0.2em !important;
  text-transform: uppercase !important;
  color: var(--teal) !important;
}

.modal-footer,
.dialog-footer {
  border-top: 1px solid var(--border) !important;
  background: rgba(0,0,0,0.2) !important;
}

/* ─── FORM ELEMENTS ──────────────────────────────────────────── */
input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]),
textarea,
select {
  background: rgba(6, 12, 20, 0.8) !important;
  border: 1px solid var(--border) !important;
  border-radius: var(--radius) !important;
  color: var(--text-primary) !important;
  font-family: var(--font-body) !important;
  font-size: 0.9rem !important;
  padding: 9px 14px !important;
  transition: all 0.25s ease !important;
  outline: none !important;
}
input:focus,
textarea:focus,
select:focus {
  border-color: var(--teal) !important;
  box-shadow: 0 0 0 2px var(--teal-glow), 0 0 14px var(--teal-glow) !important;
}

label {
  font-family: var(--font-mono) !important;
  font-size: 0.72rem !important;
  letter-spacing: 0.14em !important;
  text-transform: uppercase !important;
  color: var(--text-secondary) !important;
  margin-bottom: 4px !important;
  display: block;
}

/* ─── TABLES ─────────────────────────────────────────────────── */
table { border-collapse: collapse; width: 100%; }
thead th {
  font-family: var(--font-mono) !important;
  font-size: 0.68rem !important;
  letter-spacing: 0.18em !important;
  text-transform: uppercase !important;
  color: var(--teal) !important;
  border-bottom: 1px solid var(--border-hot) !important;
  padding: 10px 14px !important;
  background: rgba(0,245,200,0.04) !important;
}
tbody tr {
  border-bottom: 1px solid rgba(0,245,200,0.06) !important;
  transition: background 0.15s ease !important;
}
tbody tr:hover { background: rgba(0,245,200,0.04) !important; }
tbody td {
  padding: 9px 14px !important;
  color: var(--text-secondary) !important;
  font-family: var(--font-body) !important;
  font-size: 0.9rem;
}

/* ─── SCROLLBAR ──────────────────────────────────────────────── */
::-webkit-scrollbar { width: 4px; height: 4px; }
::-webkit-scrollbar-track { background: var(--bg-void); }
::-webkit-scrollbar-thumb {
  background: rgba(0,245,200,0.3);
  border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover { background: var(--teal); }

/* ─── NOTIFICATIONS / ALERTS ─────────────────────────────────── */
.alert,
.notification,
.toast {
  background: var(--bg-elevated) !important;
  border-radius: var(--radius) !important;
  border-left: 3px solid var(--teal) !important;
  font-family: var(--font-body) !important;
  color: var(--text-primary) !important;
  box-shadow: 0 4px 20px rgba(0,0,0,0.5), 4px 0 0 var(--teal-glow) !important;
}
.alert-warning { border-left-color: var(--amber) !important; }
.alert-danger   { border-left-color: var(--red-alert) !important; }
.alert-success  { border-left-color: var(--teal) !important; }

/* ─── LINKS ──────────────────────────────────────────────────── */
a {
  color: var(--teal-dim) !important;
  text-decoration: none !important;
  transition: color 0.2s ease, text-shadow 0.2s ease !important;
}
a:hover {
  color: var(--teal) !important;
  text-shadow: 0 0 8px rgba(0,245,200,0.4);
}

/* ─── SECTION DIVIDERS ───────────────────────────────────────── */
hr {
  border: none !important;
  height: 1px !important;
  background: linear-gradient(90deg, transparent, var(--teal-dim), transparent) !important;
  opacity: 0.3 !important;
  margin: 28px 0 !important;
}

/* ─── LOADING / SPINNER ──────────────────────────────────────── */
.loading,
.spinner,
[class*="loader"] {
  border-color: rgba(0,245,200,0.15) !important;
  border-top-color: var(--teal) !important;
  filter: drop-shadow(0 0 6px var(--teal));
}

/* ─── STATUS INDICATORS ──────────────────────────────────────── */
.status-online,
.online,
[class*="status-up"] {
  color: var(--teal) !important;
  text-shadow: 0 0 6px var(--teal);
}
.status-offline,
.offline,
[class*="status-down"] {
  color: var(--red-alert) !important;
  text-shadow: 0 0 6px var(--red-alert);
}

/* ─── CARD GRID STAGGER ANIMATION ────────────────────────────── */
.app-card,
.card,
.application-card {
  animation: cardEntry 0.5s cubic-bezier(0.23, 1, 0.32, 1) both;
}
.app-card:nth-child(1),  .card:nth-child(1)  { animation-delay: 0.04s; }
.app-card:nth-child(2),  .card:nth-child(2)  { animation-delay: 0.08s; }
.app-card:nth-child(3),  .card:nth-child(3)  { animation-delay: 0.12s; }
.app-card:nth-child(4),  .card:nth-child(4)  { animation-delay: 0.16s; }
.app-card:nth-child(5),  .card:nth-child(5)  { animation-delay: 0.20s; }
.app-card:nth-child(6),  .card:nth-child(6)  { animation-delay: 0.24s; }
.app-card:nth-child(7),  .card:nth-child(7)  { animation-delay: 0.28s; }
.app-card:nth-child(8),  .card:nth-child(8)  { animation-delay: 0.32s; }
.app-card:nth-child(n+9), .card:nth-child(n+9) { animation-delay: 0.36s; }

@keyframes cardEntry {
  0%   { opacity: 0; transform: translateY(18px) scale(0.96); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* ─── HUD CORNER BRACKETS ────────────────────────────────────── */
.app-card,
.card,
.application-card {
  --b: 12px;
}
.app-card .corner-bracket,
.card .corner-bracket {
  position: absolute;
  width: var(--b); height: var(--b);
  border-color: var(--teal);
  border-style: solid;
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}
.app-card:hover .corner-bracket,
.card:hover .corner-bracket { opacity: 1; }

/* ─── HUD STATUS BAR — compact single row ────────────────────── */
.heimdall-hud-bar {
  display: flex;
  align-items: center;
  gap: 0;
  padding: 0 20px;
  height: 36px;
  background: rgba(3, 8, 14, 0.95);
  border-bottom: 1px solid var(--border-hot);
  box-shadow: 0 2px 16px rgba(0,0,0,0.5);
  position: relative;
  z-index: 999;
  overflow: hidden;
}

/* Left: uptime block */
.hud-left {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
.hud-uptime-label {
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.18em;
  color: var(--text-dim);
  text-transform: uppercase;
}
.hud-uptime-value {
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--teal);
  letter-spacing: 0.06em;
  line-height: 1;
  text-shadow: 0 0 10px rgba(0,245,200,0.4);
}
.hud-session-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-left: 12px;
  border-left: 1px solid var(--border);
}
.hud-session-label {
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  color: var(--text-dim);
  text-transform: uppercase;
}
.hud-session-id {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  color: rgba(0,245,200,0.55);
  letter-spacing: 0.08em;
}
.hud-ping-dot {
  width: 5px; height: 5px;
  background: var(--teal);
  border-radius: 50%;
  animation: pingPulse 1.4s ease-in-out infinite;
  box-shadow: 0 0 5px var(--teal);
  flex-shrink: 0;
}
@keyframes pingPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%       { opacity: 0.3; transform: scale(0.55); }
}

/* Center: clock — takes remaining space, centered */
.hud-center {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
}
.hud-clock {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 900;
  letter-spacing: 0.1em;
  color: var(--teal);
  line-height: 1;
  text-shadow: 0 0 12px rgba(0,245,200,0.45);
}
.hud-date {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  color: var(--text-secondary);
  text-transform: uppercase;
}
.hud-sys-tag {
  font-family: var(--font-mono);
  font-size: 0.55rem;
  letter-spacing: 0.2em;
  color: rgba(0,245,200,0.28);
  text-transform: uppercase;
}

/* Right: stats + terminal button */
.hud-right {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-shrink: 0;
}
.hud-stat-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.hud-stat-label {
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  color: var(--text-dim);
  text-transform: uppercase;
}
.hud-stat-value {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--teal);
}
.hud-stat-value.amber {
  color: var(--amber);
}
.hud-terminal-btn {
  font-family: var(--font-display);
  font-size: 0.55rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 3px 12px;
  border: 1px solid rgba(0,245,200,0.3);
  border-radius: 2px;
  background: rgba(0,245,200,0.05);
  color: var(--teal);
  cursor: none;
  transition: all 0.2s ease;
  white-space: nowrap;
}
.hud-terminal-btn:hover {
  background: rgba(0,245,200,0.12);
  border-color: var(--teal);
  box-shadow: 0 0 8px rgba(0,245,200,0.15);
}

/* ─── FOOTER ─────────────────────────────────────────────────── */
footer {
  background: transparent !important;
  border-top: 1px solid var(--border) !important;
  font-family: var(--font-mono) !important;
  font-size: 0.65rem !important;
  letter-spacing: 0.14em !important;
  color: var(--text-dim) !important;
  text-transform: uppercase;
  padding: 16px 24px !important;
}

/* ─── MOBILE ADAPTIVE ────────────────────────────────────────── */
@media (max-width: 768px) {
  :root { font-size: 13px; }
  body::before { display: none; }
  .navbar-brand { font-size: 0.85rem !important; }
}

/* ─── SPECIAL: AMBER ACCENT FOR PINNED ITEMS ─────────────────── */
.app-card.pinned,
.card.pinned,
.application-card.pinned {
  border-color: rgba(255, 184, 0, 0.22) !important;
}
.app-card.pinned::before,
.card.pinned::before {
  background: linear-gradient(90deg, transparent, var(--amber), transparent) !important;
  opacity: 1;
}
.app-card.pinned:hover {
  box-shadow:
    0 0 0 1px rgba(255,184,0,0.3),
    0 12px 40px rgba(0,0,0,0.7),
    0 0 30px var(--amber-glow) !important;
}

/* ─── SELECTION ──────────────────────────────────────────────── */
::selection {
  background: rgba(0,245,200,0.2);
  color: var(--teal);
}

/* ═══════════════════════════════════════════════════════════════
   WAWTOR TERMINAL WIDGET
   ═══════════════════════════════════════════════════════════════ */

/* ─── Floating window ───────────────────────────────────────────── */
#wt-window {
  position: fixed;
  bottom: 28px;
  right: 28px;
  width: 820px;
  height: 480px;
  min-width: 420px;
  min-height: 240px;
  display: flex;
  flex-direction: column;
  background: #0b0d0f;
  border: 1px solid rgba(0,245,200,0.35);
  border-radius: 8px;
  box-shadow:
    0 0 0 1px rgba(0,245,200,0.1),
    0 24px 80px rgba(0,0,0,0.9),
    0 0 40px rgba(0,245,200,0.08);
  z-index: 8000;
  overflow: hidden;
  resize: both;
  font-family: 'Share Tech Mono', monospace;
  transition: box-shadow 0.2s ease;
}
#wt-window.minimized { height: 36px !important; resize: none; }
#wt-window.maximized {
  inset: 0 !important;
  width: 100vw !important;
  height: 100vh !important;
  border-radius: 0;
  resize: none;
}
#wt-window.hidden { display: none !important; }

/* ─── Title bar ─────────────────────────────────────────────────── */
#wt-titlebar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 0;
  height: 36px;
  background: #141820;
  border-bottom: 1px solid rgba(0,245,200,0.15);
  user-select: none;
  cursor: move;
  padding: 0 10px;
}
.wt-traffic {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-right: 12px;
}
.wt-dot {
  width: 11px; height: 11px;
  border-radius: 50%;
  cursor: none;
  transition: filter 0.15s ease;
}
.wt-dot:hover { filter: brightness(1.4); }
.wt-dot.close  { background: #ff5f57; }
.wt-dot.min    { background: #ffbd2e; }
.wt-dot.max    { background: #28c840; }

.wt-title {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  color: rgba(0,245,200,0.6);
  text-transform: uppercase;
  flex: 1;
}
#wt-conn-status {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  padding: 2px 10px;
  border-radius: 2px;
  margin-right: 8px;
}
#wt-conn-status.connected    { color: #00f5c8; background: rgba(0,245,200,0.08); border: 1px solid rgba(0,245,200,0.25); }
#wt-conn-status.disconnected { color: #ff3a5c; background: rgba(255,58,92,0.08); border: 1px solid rgba(255,58,92,0.25); }
#wt-conn-status.connecting   { color: #ffb800; background: rgba(255,184,0,0.08);  border: 1px solid rgba(255,184,0,0.25); }

.wt-btn {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 3px 12px;
  border-radius: 2px;
  border: 1px solid rgba(0,245,200,0.2);
  background: rgba(0,245,200,0.04);
  color: rgba(0,245,200,0.7);
  cursor: none;
  margin-left: 6px;
  transition: all 0.15s ease;
  white-space: nowrap;
}
.wt-btn:hover {
  background: rgba(0,245,200,0.12);
  border-color: rgba(0,245,200,0.5);
  color: #00f5c8;
}
.wt-btn.active {
  background: rgba(0,245,200,0.15);
  border-color: #00f5c8;
  color: #00f5c8;
  box-shadow: 0 0 8px rgba(0,245,200,0.2);
}

/* ─── Body (terminal + macro panel) ────────────────────────────── */
#wt-body {
  flex: 1;
  display: flex;
  overflow: hidden;
  min-height: 0;
}

/* ─── xterm container ───────────────────────────────────────────── */
#wt-xterm {
  flex: 1;
  min-width: 0;
  padding: 6px 4px;
  background: #0b0d0f;
  /* CRITICAL: xterm must receive pointer events for focus/selection */
  pointer-events: auto !important;
  cursor: text !important;
}
#wt-xterm * {
  /* Override the global cursor:none from custom cursor module */
  pointer-events: auto !important;
}
#wt-xterm .xterm {
  height: 100%;
  cursor: text !important;
}
#wt-xterm .xterm-screen {
  cursor: text !important;
}
#wt-xterm .xterm canvas {
  cursor: text !important;
  pointer-events: auto !important;
}
#wt-xterm .xterm-viewport {
  scrollbar-width: thin;
  scrollbar-color: rgba(0,245,200,0.25) transparent;
}

/* ─── Connect screen (shown when no WS) ────────────────────────── */
#wt-connect-screen {
  display: none;
  flex: 1;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 18px;
  padding: 32px;
  background: #0b0d0f;
}
#wt-connect-screen.visible { display: flex; }

.wt-connect-title {
  font-family: 'Orbitron', monospace;
  font-size: 0.8rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: #00f5c8;
  text-shadow: 0 0 12px rgba(0,245,200,0.4);
}
.wt-connect-desc {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: #7aaabb;
  text-align: center;
  max-width: 420px;
  line-height: 1.8;
}
.wt-connect-desc code {
  background: rgba(0,245,200,0.08);
  border: 1px solid rgba(0,245,200,0.2);
  border-radius: 3px;
  padding: 2px 8px;
  color: #00f5c8;
  font-size: 0.68rem;
}
.wt-connect-row {
  display: flex;
  gap: 8px;
  width: 100%;
  max-width: 440px;
}
.wt-connect-row input {
  flex: 1;
  background: rgba(10,21,32,0.9) !important;
  border: 1px solid rgba(0,245,200,0.2) !important;
  border-radius: 3px !important;
  color: #e8f4f8 !important;
  font-family: 'Share Tech Mono', monospace !important;
  font-size: 0.78rem !important;
  padding: 8px 14px !important;
}
.wt-connect-row input:focus {
  border-color: #00f5c8 !important;
  box-shadow: 0 0 0 1px rgba(0,245,200,0.3) !important;
  outline: none !important;
}
.wt-connect-btn {
  padding: 8px 20px;
  font-family: 'Orbitron', monospace;
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  border: 1px solid rgba(0,245,200,0.4);
  border-radius: 3px;
  background: rgba(0,245,200,0.08);
  color: #00f5c8;
  cursor: none;
  transition: all 0.2s ease;
  white-space: nowrap;
}
.wt-connect-btn:hover {
  background: rgba(0,245,200,0.16);
  box-shadow: 0 0 12px rgba(0,245,200,0.2);
}

/* ─── Macro panel ───────────────────────────────────────────────── */
#wt-macro-panel {
  width: 0;
  overflow: hidden;
  background: #0e1318;
  border-left: 0px solid rgba(0,245,200,0.15);
  display: flex;
  flex-direction: column;
  transition: width 0.28s cubic-bezier(0.23,1,0.32,1), border-width 0.28s ease;
  flex-shrink: 0;
}
#wt-macro-panel.open {
  width: 260px;
  border-left-width: 1px;
}

.wt-macro-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid rgba(0,245,200,0.12);
  flex-shrink: 0;
}
.wt-macro-title {
  font-family: 'Orbitron', monospace;
  font-size: 0.62rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #00f5c8;
  white-space: nowrap;
}
.wt-macro-edit-btn {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 2px 9px;
  border: 1px solid rgba(0,245,200,0.2);
  border-radius: 2px;
  background: transparent;
  color: rgba(0,245,200,0.5);
  cursor: none;
  transition: all 0.15s ease;
  white-space: nowrap;
}
.wt-macro-edit-btn:hover, .wt-macro-edit-btn.active {
  background: rgba(0,245,200,0.1);
  border-color: rgba(0,245,200,0.5);
  color: #00f5c8;
}

.wt-macro-list {
  flex: 1;
  overflow-y: auto;
  padding: 8px 0;
  scrollbar-width: thin;
  scrollbar-color: rgba(0,245,200,0.2) transparent;
}

/* Macro item — display mode */
.wt-macro-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0;
  margin: 2px 8px;
  border-radius: 4px;
  border: 1px solid transparent;
  overflow: hidden;
  transition: all 0.15s ease;
  min-height: 46px;
}
.wt-macro-item:hover {
  background: rgba(0,245,200,0.04);
  border-color: rgba(0,245,200,0.12);
}

.wt-macro-run {
  flex-shrink: 0;
  width: 34px; height: 100%;
  min-height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0,245,200,0.06);
  border-right: 1px solid rgba(0,245,200,0.1);
  cursor: none;
  transition: background 0.15s ease;
  font-size: 0.75rem;
  color: #00f5c8;
}
.wt-macro-run:hover {
  background: rgba(0,245,200,0.18);
  color: #fff;
}
.wt-macro-run.running { color: #ffb800; animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.wt-macro-info {
  flex: 1;
  padding: 6px 10px;
  min-width: 0;
}
.wt-macro-name {
  font-family: 'Orbitron', monospace;
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #e8f4f8;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wt-macro-cmd {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.58rem;
  color: rgba(0,245,200,0.45);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 2px;
}

.wt-macro-del {
  flex-shrink: 0;
  width: 28px; height: 100%;
  min-height: 46px;
  display: none;
  align-items: center;
  justify-content: center;
  background: transparent;
  border-left: 1px solid rgba(255,58,92,0.1);
  cursor: none;
  color: rgba(255,58,92,0.4);
  font-size: 0.72rem;
  transition: all 0.15s ease;
}
.wt-macro-del:hover { background: rgba(255,58,92,0.1); color: #ff3a5c; }
.edit-mode .wt-macro-del { display: flex; }

/* Edit inputs inside macro items */
.wt-macro-item.editing {
  flex-direction: column;
  align-items: stretch;
  padding: 8px 10px;
  background: rgba(0,245,200,0.04);
  border-color: rgba(0,245,200,0.2);
  gap: 5px;
}
.wt-macro-input {
  width: 100%;
  background: rgba(6,12,20,0.8) !important;
  border: 1px solid rgba(0,245,200,0.2) !important;
  border-radius: 2px !important;
  color: #e8f4f8 !important;
  font-family: 'Share Tech Mono', monospace !important;
  font-size: 0.7rem !important;
  padding: 4px 8px !important;
  outline: none !important;
}
.wt-macro-input:focus { border-color: rgba(0,245,200,0.5) !important; }
.wt-macro-input.name-input {
  font-family: 'Orbitron', monospace !important;
  font-size: 0.62rem !important;
  letter-spacing: 0.08em !important;
  text-transform: uppercase !important;
  color: #e8f4f8 !important;
}
.wt-macro-save-row {
  display: flex;
  gap: 5px;
  justify-content: flex-end;
  margin-top: 2px;
}
.wt-macro-save, .wt-macro-cancel {
  font-family: 'Orbitron', monospace;
  font-size: 0.55rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 3px 10px;
  border-radius: 2px;
  cursor: none;
  transition: all 0.15s ease;
}
.wt-macro-save {
  border: 1px solid rgba(0,245,200,0.35);
  background: rgba(0,245,200,0.08);
  color: #00f5c8;
}
.wt-macro-save:hover { background: rgba(0,245,200,0.18); }
.wt-macro-cancel {
  border: 1px solid rgba(255,255,255,0.08);
  background: transparent;
  color: #7aaabb;
}
.wt-macro-cancel:hover { background: rgba(255,255,255,0.05); }

/* Add macro button */
.wt-macro-add-btn {
  margin: 8px;
  padding: 8px;
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.65rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(0,245,200,0.5);
  border: 1px dashed rgba(0,245,200,0.2);
  border-radius: 4px;
  background: transparent;
  cursor: none;
  transition: all 0.2s ease;
  text-align: center;
  display: none;
}
.wt-macro-add-btn:hover {
  color: #00f5c8;
  border-color: rgba(0,245,200,0.5);
  background: rgba(0,245,200,0.04);
}
.edit-mode .wt-macro-add-btn { display: block; }

/* ─── Settings panel (inside macro panel bottom) ────────────────── */
.wt-macro-settings {
  flex-shrink: 0;
  border-top: 1px solid rgba(0,245,200,0.1);
  padding: 10px 12px;
}
.wt-settings-label {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.58rem;
  letter-spacing: 0.14em;
  color: #3d6070;
  text-transform: uppercase;
  margin-bottom: 5px;
}
.wt-settings-input {
  width: 100%;
  background: rgba(6,12,20,0.8) !important;
  border: 1px solid rgba(0,245,200,0.15) !important;
  border-radius: 2px !important;
  color: rgba(0,245,200,0.7) !important;
  font-family: 'Share Tech Mono', monospace !important;
  font-size: 0.65rem !important;
  padding: 5px 8px !important;
  outline: none !important;
}
.wt-settings-input:focus { border-color: rgba(0,245,200,0.4) !important; }

/* ─── Resize handle indicator ────────────────────────────────────── */
#wt-window::after {
  content: '';
  position: absolute;
  bottom: 3px; right: 4px;
  width: 10px; height: 10px;
  border-right: 2px solid rgba(0,245,200,0.25);
  border-bottom: 2px solid rgba(0,245,200,0.25);
  pointer-events: none;
}

/* ─── Toggle button (always visible) ────────────────────────────── */
#wt-toggle {
  position: fixed;
  bottom: 28px;
  right: 28px;
  z-index: 7999;
  font-family: 'Orbitron', monospace;
  font-size: 0.62rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  padding: 10px 18px;
  border: 1px solid rgba(0,245,200,0.4);
  border-radius: 4px;
  background: rgba(3,8,14,0.95);
  color: #00f5c8;
  cursor: none;
  transition: all 0.2s ease;
  box-shadow: 0 4px 20px rgba(0,0,0,0.5), 0 0 12px rgba(0,245,200,0.1);
  display: none;
}
#wt-toggle:hover {
  background: rgba(0,245,200,0.12);
  box-shadow: 0 4px 20px rgba(0,0,0,0.5), 0 0 20px rgba(0,245,200,0.2);
}
Custom JavaScript
/* ============================================================
   HEIMDALL — COMMAND CENTER THEME  |  custom.js
   Drop in: storage/app/public/custom.js
   ============================================================ */

(function () {
  'use strict';

  /* ─── UTILITY ──────────────────────────────────────────────── */
  const qs  = (sel, ctx = document) => ctx.querySelector(sel);
  const qsa = (sel, ctx = document) => [...ctx.querySelectorAll(sel)];
  const on  = (el, ev, fn, opts) => el && el.addEventListener(ev, fn, opts);

  /* =====================================================
     1. PARTICLE CANVAS — deep-space starfield with
        teal constellation lines
     ===================================================== */
  function initParticles() {
    const canvas = document.createElement('canvas');
    canvas.id = 'heimdall-canvas';
    document.body.prepend(canvas);
    const ctx = canvas.getContext('2d');

    const CONFIG = {
      count:       120,
      maxDist:     140,
      speed:       0.22,
      teal:        '0, 245, 200',
      amber:       '255, 184, 0',
      mouseDist:   130,
      mouseRepel:  0.012,
    };

    let W, H, mouse = { x: -9999, y: -9999 };

    function resize() {
      W = canvas.width  = window.innerWidth;
      H = canvas.height = window.innerHeight;
    }
    resize();
    on(window, 'resize', resize);
    on(window, 'mousemove', e => { mouse.x = e.clientX; mouse.y = e.clientY; });

    class Particle {
      constructor() { this.reset(true); }
      reset(init = false) {
        this.x  = Math.random() * W;
        this.y  = init ? Math.random() * H : -4;
        this.vx = (Math.random() - 0.5) * CONFIG.speed;
        this.vy = (Math.random() - 0.5) * CONFIG.speed;
        this.r  = Math.random() * 1.4 + 0.3;
        this.alpha = Math.random() * 0.6 + 0.2;
        // ~5% amber stars
        this.color = Math.random() < 0.05 ? CONFIG.amber : CONFIG.teal;
        this.pulse = Math.random() * Math.PI * 2;
        this.pulseSpeed = 0.015 + Math.random() * 0.02;
      }
      update() {
        // mouse repel
        const dx = this.x - mouse.x;
        const dy = this.y - mouse.y;
        const dist = Math.sqrt(dx * dx + dy * dy);
        if (dist < CONFIG.mouseDist) {
          const force = (CONFIG.mouseDist - dist) / CONFIG.mouseDist;
          this.vx += dx / dist * force * CONFIG.mouseRepel;
          this.vy += dy / dist * force * CONFIG.mouseRepel;
        }

        // dampen velocity
        this.vx *= 0.994;
        this.vy *= 0.994;

        this.x += this.vx;
        this.y += this.vy;
        this.pulse += this.pulseSpeed;

        // wrap edges
        if (this.x < -10) this.x = W + 10;
        if (this.x > W + 10) this.x = -10;
        if (this.y < -10) this.y = H + 10;
        if (this.y > H + 10) this.y = -10;
      }
      draw() {
        const a = this.alpha * (0.75 + 0.25 * Math.sin(this.pulse));
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
        ctx.fillStyle = `rgba(${this.color}, ${a})`;
        ctx.fill();
      }
    }

    const particles = Array.from({ length: CONFIG.count }, () => new Particle());

    function drawLines() {
      for (let i = 0; i < particles.length; i++) {
        for (let j = i + 1; j < particles.length; j++) {
          const a = particles[i], b = particles[j];
          const dx = a.x - b.x, dy = a.y - b.y;
          const d2 = dx * dx + dy * dy;
          if (d2 < CONFIG.maxDist * CONFIG.maxDist) {
            const alpha = (1 - Math.sqrt(d2) / CONFIG.maxDist) * 0.18;
            ctx.beginPath();
            ctx.moveTo(a.x, a.y);
            ctx.lineTo(b.x, b.y);
            ctx.strokeStyle = `rgba(${CONFIG.teal}, ${alpha})`;
            ctx.lineWidth = 0.6;
            ctx.stroke();
          }
        }
      }
    }

    function loop() {
      ctx.clearRect(0, 0, W, H);
      particles.forEach(p => { p.update(); p.draw(); });
      drawLines();
      requestAnimationFrame(loop);
    }
    loop();
  }

  /* =====================================================
     2. CUSTOM CURSOR
     ===================================================== */
  function initCursor() {
    const dot  = document.createElement('div');
    const ring = document.createElement('div');
    dot.id  = 'cursor-dot';
    ring.id = 'cursor-ring';
    document.body.append(dot, ring);

    let rx = 0, ry = 0, mx = 0, my = 0;
    let isHovering = false;

    on(document, 'mousemove', e => {
      mx = e.clientX; my = e.clientY;
      dot.style.left  = mx + 'px';
      dot.style.top   = my + 'px';
      // Hide custom cursor inside xterm so it doesn't interfere
      const inXterm = e.target.closest('#wt-xterm');
      dot.style.opacity  = inXterm ? '0' : '1';
      ring.style.opacity = inXterm ? '0' : '1';
    });

    // Lag ring for smooth trail
    (function ringLoop() {
      rx += (mx - rx) * 0.14;
      ry += (my - ry) * 0.14;
      ring.style.left = (rx - 14) + 'px';
      ring.style.top  = (ry - 14) + 'px';
      requestAnimationFrame(ringLoop);
    })();

    // Expand ring on interactive elements
    const hotSelectors = 'a, button, .btn, .app-card, .card, .application-card, input, select, textarea, [role="button"]';
    on(document, 'mouseover', e => {
      if (e.target.closest(hotSelectors)) {
        ring.style.width  = '44px';
        ring.style.height = '44px';
        ring.style.borderColor = 'rgba(0, 245, 200, 0.9)';
        dot.style.transform = 'scale(2)';
        isHovering = true;
      }
    });
    on(document, 'mouseout', e => {
      if (isHovering && !e.target.closest(hotSelectors)) {
        ring.style.width  = '28px';
        ring.style.height = '28px';
        ring.style.borderColor = 'rgba(0, 245, 200, 0.6)';
        dot.style.transform = 'scale(1)';
        isHovering = false;
      }
    });

    // Click burst
    on(document, 'click', e => {
      const burst = document.createElement('div');
      burst.style.cssText = `
        position:fixed; left:${e.clientX - 20}px; top:${e.clientY - 20}px;
        width:40px; height:40px; border-radius:50%;
        border:2px solid rgba(0,245,200,0.8);
        pointer-events:none; z-index:99997;
        animation:cursorBurst 0.5s ease-out forwards;
      `;
      document.body.append(burst);
      setTimeout(() => burst.remove(), 520);
    });
  }

  /* =====================================================
     3. HUD STATUS BAR — 3-column large metrics
     ===================================================== */
  function initHudBar() {
    const SESSION_ID = Math.random().toString(36).slice(2,9).toUpperCase();

    const bar = document.createElement('div');
    bar.className = 'heimdall-hud-bar';
    bar.innerHTML = `
      <!-- LEFT: uptime + session -->
      <div class="hud-left">
        <span class="hud-uptime-label">Uptime</span>
        <span class="hud-uptime-value" id="hud-uptime">00:00:00</span>
        <div class="hud-session-row">
          <div class="hud-ping-dot"></div>
          <span class="hud-session-label">Online</span>
          <span class="hud-session-id">#${SESSION_ID}</span>
        </div>
      </div>

      <!-- CENTER: clock + date -->
      <div class="hud-center">
        <span class="hud-clock" id="hud-clock">--:--:--</span>
        <span class="hud-date"  id="hud-date">--- -- ----</span>
        <span class="hud-sys-tag">WAWTOR</span>
      </div>

      <!-- RIGHT: stats + terminal button -->
      <div class="hud-right">
        <div class="hud-stat-row">
          <span class="hud-stat-label">Containers</span>
          <span class="hud-stat-value">6</span>
        </div>
        <div class="hud-stat-row">
          <span class="hud-stat-label">Tailscale</span>
          <span class="hud-stat-value">UP</span>
        </div>
        <div class="hud-stat-row">
          <span class="hud-stat-label">Temp</span>
          <span class="hud-stat-value amber">38°C</span>
        </div>
        <button class="hud-terminal-btn" id="hud-term-btn">⌨ Terminal</button>
      </div>
    `;

    const nav = qs('header, nav.navbar, .navbar, #topnav');
    if (nav && nav.parentNode) {
      nav.parentNode.insertBefore(bar, nav.nextSibling);
    } else {
      document.body.prepend(bar);
    }

    // Live clock
    function tick() {
      const now = new Date();
      const hh = String(now.getHours()).padStart(2,'0');
      const mm = String(now.getMinutes()).padStart(2,'0');
      const ss = String(now.getSeconds()).padStart(2,'0');
      const clockEl = qs('#hud-clock');
      if (clockEl) clockEl.textContent = `${hh}:${mm}:${ss}`;

      const dateEl = qs('#hud-date');
      if (dateEl) dateEl.textContent = now.toLocaleDateString('en-US', {
        weekday:'short', month:'short', day:'numeric', year:'numeric'
      }).toUpperCase();
    }
    tick();
    setInterval(tick, 1000);

    // Session uptime counter
    const start = Date.now();
    setInterval(() => {
      const el = qs('#hud-uptime');
      if (!el) return;
      const s = Math.floor((Date.now() - start) / 1000);
      const H = String(Math.floor(s / 3600)).padStart(2,'0');
      const M = String(Math.floor((s % 3600) / 60)).padStart(2,'0');
      const S = String(s % 60).padStart(2,'0');
      el.textContent = `${H}:${M}:${S}`;
    }, 1000);

    // Terminal button wires to the terminal widget
    on(qs('#hud-term-btn'), 'click', () => {
      const win = qs('#wt-window');
      const tog = qs('#wt-toggle');
      if (!win) return;
      if (win.classList.contains('hidden')) {
        win.classList.remove('hidden');
        if (tog) tog.style.display = 'none';
      } else {
        win.classList.add('hidden');
        if (tog) tog.style.display = 'block';
      }
    });
  }

  /* =====================================================
     3b. TERMINAL WIDGET
     ===================================================== */
  function initTerminalWidget() {

    /* ── Default macros ────────────────────────────────── */
    const DEFAULT_MACROS = [
      { id: 'm1', name: 'Restart Nginx',      cmd: 'docker restart nginx-proxy' },
      { id: 'm2', name: 'Restart Portainer',  cmd: 'docker restart portainer' },
      { id: 'm3', name: 'Restart Nextcloud',  cmd: 'docker restart nextcloud' },
      { id: 'm4', name: 'Restart MariaDB',    cmd: 'docker restart mariadb' },
      { id: 'm5', name: 'Restart Redis',      cmd: 'docker restart redis' },
      { id: 'm6', name: 'Docker PS',          cmd: 'docker ps --format "table {{.Names}}\\t{{.Status}}"' },
      { id: 'm7', name: 'System Uptime',      cmd: 'uptime' },
      { id: 'm8', name: 'Disk Usage',         cmd: 'df -h /' },
    ];

    function loadMacros() {
      try {
        const raw = localStorage.getItem('wt_macros');
        return raw ? JSON.parse(raw) : DEFAULT_MACROS;
      } catch { return DEFAULT_MACROS; }
    }
    function saveMacros(list) {
      localStorage.setItem('wt_macros', JSON.stringify(list));
    }
    function loadWsUrl() {
      return localStorage.getItem('wt_ws_url') || 'ws://localhost:7682/ws';
    }
    function saveWsUrl(url) {
      localStorage.setItem('wt_ws_url', url);
    }

    /* ── Load xterm.js + fit addon from CDN ─────────────── */
    function loadScript(src) {
      return new Promise((res, rej) => {
        if (document.querySelector(`script[src="${src}"]`)) { res(); return; }
        const s = document.createElement('script');
        s.src = src; s.onload = res; s.onerror = rej;
        document.head.appendChild(s);
      });
    }
    function loadLink(href) {
      if (document.querySelector(`link[href="${href}"]`)) return;
      const l = document.createElement('link');
      l.rel = 'stylesheet'; l.href = href;
      document.head.appendChild(l);
    }

    /* ── Build DOM ─────────────────────────────────────── */
    const win = document.createElement('div');
    win.id = 'wt-window';
    win.innerHTML = `
      <div id="wt-titlebar">
        <div class="wt-traffic">
          <div class="wt-dot close"  id="wt-close"></div>
          <div class="wt-dot min"    id="wt-min"></div>
          <div class="wt-dot max"    id="wt-max"></div>
        </div>
        <span class="wt-title">dmw@wawtor  —  terminal</span>
        <span id="wt-conn-status" class="disconnected">DISCONNECTED</span>
        <button class="wt-btn" id="wt-macro-toggle">⚡ Macros</button>
        <button class="wt-btn" id="wt-reconnect-btn">Reconnect</button>
      </div>
      <div id="wt-body">
        <!-- xterm mount -->
        <div id="wt-xterm"></div>
        <!-- connect screen -->
        <div id="wt-connect-screen">
          <div class="wt-connect-title">Connect to Backend Terminal</div>
          <div class="wt-connect-desc">
            This widget connects to a WebSocket terminal server.<br>
            Recommended: <code>ttyd</code> running on your wawtor server.<br><br>
            Install: <code>apt install ttyd</code><br>
            Run: <code>ttyd -p 7681 bash</code>
          </div>
          <div class="wt-connect-row">
            <input type="text" id="wt-ws-input" placeholder="ws://wawtor:7682/ws" />
            <button class="wt-connect-btn" id="wt-do-connect">Connect</button>
          </div>
        </div>
        <!-- macro panel -->
        <div id="wt-macro-panel">
          <div class="wt-macro-header">
            <span class="wt-macro-title">⚡ Service Macros</span>
            <button class="wt-macro-edit-btn" id="wt-edit-mode-btn">Edit</button>
          </div>
          <div class="wt-macro-list" id="wt-macro-list"></div>
          <button class="wt-macro-add-btn" id="wt-add-macro">+ Add Macro</button>
          <div class="wt-macro-settings">
            <div class="wt-settings-label">WebSocket URL</div>
            <input class="wt-settings-input" id="wt-ws-setting" type="text"
                   placeholder="ws://wawtor:7681/ws" />
          </div>
        </div>
      </div>
    `;

    document.body.appendChild(win);

    // Toggle button (shows when window is hidden)
    const toggleBtn = document.createElement('button');
    toggleBtn.id = 'wt-toggle';
    toggleBtn.textContent = '⌨ Terminal';
    document.body.appendChild(toggleBtn);
    on(toggleBtn, 'click', () => {
      win.classList.remove('hidden');
      toggleBtn.style.display = 'none';
    });

    /* ── State ──────────────────────────────────────────── */
    let term       = null;
    let fitAddon   = null;
    let ws         = null;
    let macros     = loadMacros();
    let editMode   = false;
    let isMinimized = false;

    const connScreen   = qs('#wt-connect-screen');
    const xtermMount   = qs('#wt-xterm');
    const macroPanel   = qs('#wt-macro-panel');
    const macroList    = qs('#wt-macro-list');
    const connStatus   = qs('#wt-conn-status');
    const wsInput      = qs('#wt-ws-input');
    const wsSetting    = qs('#wt-ws-setting');

    // Pre-fill stored URL
    const stored = loadWsUrl();
    if (wsInput)   wsInput.value   = stored;
    if (wsSetting) wsSetting.value = stored;

    /* ── Load xterm then init ──────────────────────────── */
    loadLink('https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css');

    Promise.all([
      loadScript('https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.min.js'),
      loadScript('https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.min.js'),
    ]).then(() => {
      term = new Terminal({
        theme: {
          background:   '#0b0d0f',
          foreground:   '#e8f4f8',
          cursor:       '#00f5c8',
          cursorAccent: '#0b0d0f',
          selectionBackground: 'rgba(0,245,200,0.25)',
          black:   '#0b0d0f', brightBlack:   '#3d6070',
          red:     '#ff3a5c', brightRed:     '#ff6b84',
          green:   '#00f5c8', brightGreen:   '#00f5c8',
          yellow:  '#ffb800', brightYellow:  '#ffca44',
          blue:    '#4a9eff', brightBlue:    '#7ab8ff',
          magenta: '#cc44ff', brightMagenta: '#dd88ff',
          cyan:    '#00c49e', brightCyan:    '#00f5c8',
          white:   '#7aaabb', brightWhite:   '#e8f4f8',
        },
        fontFamily: "'Share Tech Mono', 'Courier New', monospace",
        fontSize:   13,
        lineHeight: 1.4,
        cursorBlink: true,
        cursorStyle: 'block',
        scrollback:  2000,
        allowTransparency: true,
      });

      fitAddon = new FitAddon.FitAddon();
      term.loadAddon(fitAddon);
      term.open(xtermMount);

      // Register input handler ONCE — references outer ws variable
      term.onData(data => {
        if (ws && ws.readyState === WebSocket.OPEN) {
          ws.send('0' + data);
        }
      });

      // Register resize handler here where term is defined
      term.onResize(() => sendResize());

      // Click anywhere in terminal to focus it
      on(xtermMount, 'click', () => term.focus());

      // Try auto-connect
      attemptConnect(loadWsUrl());

      // Resize observer
      new ResizeObserver(() => {
        if (fitAddon && !isMinimized) {
          try { fitAddon.fit(); } catch(e){}
        }
      }).observe(win);
    });

    /* ── WebSocket connection ───────────────────────────── */
    function setStatus(state) {
      connStatus.className = state;
      const labels = { connected:'CONNECTED', disconnected:'DISCONNECTED', connecting:'CONNECTING…' };
      connStatus.textContent = labels[state] || state.toUpperCase();
    }

    function attemptConnect(url) {
      if (!url || !url.startsWith('ws')) {
        showConnectScreen(true);
        return;
      }
      if (ws) { try { ws.close(); } catch(e){} }
      setStatus('connecting');

      ws = new WebSocket(url, ['tty']);  // 'tty' subprotocol is REQUIRED by ttyd
      ws.binaryType = 'arraybuffer';

      ws.onopen = () => {
        setStatus('connected');
        showConnectScreen(false);
        saveWsUrl(url);
        if (wsSetting) wsSetting.value = url;
        if (wsInput)   wsInput.value   = url;

        // ttyd auth — must include cols/rows in initial message
        const cols = (term && term.cols) || 80;
        const rows = (term && term.rows) || 24;
        ws.send(JSON.stringify({ AuthToken: '', columns: cols, rows: rows }));

        setTimeout(() => {
          if (fitAddon) { try { fitAddon.fit(); } catch(e){} }
          sendResize();
          term && term.focus();
        }, 200);
      };

      ws.onmessage = (e) => {
        if (!term) return;
        if (typeof e.data === 'string') {
          const type    = e.data[0];
          const payload = e.data.slice(1);
          if (type === '0') {
            // OUTPUT — ttyd uses '0' for server→client output
            term.write(payload);
          } else if (type === '1') {
            // Also handle '1' just in case build differs
            term.write(payload);
          } else if (type === '2') {
            try {
              const t = JSON.parse(payload);
              qs('.wt-title').textContent = t.title || 'dmw@wawtor  —  terminal';
            } catch(e) {}
          }
        } else if (e.data instanceof ArrayBuffer) {
          // Binary frame — first byte is opcode, rest is data
          const bytes = new Uint8Array(e.data);
          if (bytes.length > 1) {
            term.write(bytes.slice(1));  // strip the opcode byte
          }
        }
      };

      ws.onerror = () => { setStatus('disconnected'); showConnectScreen(true); };
      ws.onclose = () => { setStatus('disconnected'); };
    }

    function sendResize() {
      if (!ws || ws.readyState !== WebSocket.OPEN || !term) return;
      // ttyd resize opcode is '4', NOT '1'
      ws.send('4' + JSON.stringify({ columns: term.cols, rows: term.rows }));
    }

    function showConnectScreen(show) {
      connScreen.classList.toggle('visible', show);
      xtermMount.style.display = show ? 'none' : 'block';
    }

    /* ── Macro panel ────────────────────────────────────── */
    function renderMacros() {
      macroList.innerHTML = '';
      macros.forEach((m, idx) => {
        const item = document.createElement('div');
        item.className = 'wt-macro-item';
        item.dataset.id = m.id;
        item.innerHTML = `
          <div class="wt-macro-run" title="Run macro">▶</div>
          <div class="wt-macro-info">
            <div class="wt-macro-name">${escHtml(m.name)}</div>
            <div class="wt-macro-cmd">${escHtml(m.cmd)}</div>
          </div>
          <div class="wt-macro-del" title="Delete">✕</div>
        `;

        // Run
        qs('.wt-macro-run', item).onclick = () => runMacro(m, qs('.wt-macro-run', item));

        // Double-click name/cmd to edit
        qs('.wt-macro-info', item).ondblclick = () => enterEditItem(item, m);

        // Delete
        qs('.wt-macro-del', item).onclick = () => {
          macros = macros.filter(x => x.id !== m.id);
          saveMacros(macros);
          renderMacros();
        };

        macroList.appendChild(item);
      });
    }

    function enterEditItem(item, m) {
      item.classList.add('editing');
      item.innerHTML = `
        <input class="wt-macro-input name-input" value="${escHtml(m.name)}" placeholder="Macro name" />
        <input class="wt-macro-input cmd-input"  value="${escHtml(m.cmd)}"  placeholder="Command…" />
        <div class="wt-macro-save-row">
          <button class="wt-macro-cancel">Cancel</button>
          <button class="wt-macro-save">Save</button>
        </div>
      `;
      qs('.wt-macro-save', item).onclick = () => {
        const newName = qs('.name-input', item).value.trim();
        const newCmd  = qs('.cmd-input',  item).value.trim();
        if (!newName || !newCmd) return;
        const idx = macros.findIndex(x => x.id === m.id);
        if (idx !== -1) { macros[idx].name = newName; macros[idx].cmd = newCmd; }
        saveMacros(macros);
        renderMacros();
      };
      qs('.wt-macro-cancel', item).onclick = () => renderMacros();
      qs('.name-input', item).focus();
    }

    function runMacro(m, btn) {
      if (ws && ws.readyState === WebSocket.OPEN && term) {
        // ttyd text protocol: '0' + data
        ws.send('0' + m.cmd + '\r');
        term.focus();
        // Visual feedback
        btn.classList.add('running');
        btn.textContent = '⟳';
        setTimeout(() => { btn.classList.remove('running'); btn.textContent = '▶'; }, 800);
      } else {
        // Fallback: copy to clipboard
        navigator.clipboard.writeText(m.cmd).catch(() => {});
        btn.textContent = '✓';
        setTimeout(() => { btn.textContent = '▶'; }, 1200);
      }
    }

    // Edit mode toggle
    on(qs('#wt-edit-mode-btn'), 'click', () => {
      editMode = !editMode;
      macroPanel.classList.toggle('edit-mode', editMode);
      qs('#wt-edit-mode-btn').classList.toggle('active', editMode);
      qs('#wt-edit-mode-btn').textContent = editMode ? 'Done' : 'Edit';
    });

    // Add new macro
    on(qs('#wt-add-macro'), 'click', () => {
      const newM = { id: 'm' + Date.now(), name: 'New Macro', cmd: 'echo hello' };
      macros.push(newM);
      saveMacros(macros);
      renderMacros();
      // Auto-enter edit on the new item
      const lastItem = macroList.lastElementChild;
      if (lastItem) enterEditItem(lastItem, newM);
    });

    // WS URL setting
    on(wsSetting, 'change', () => {
      const url = wsSetting.value.trim();
      saveWsUrl(url);
      if (wsInput) wsInput.value = url;
    });

    // Connect screen button
    on(qs('#wt-do-connect'), 'click', () => {
      const url = wsInput.value.trim();
      if (url) attemptConnect(url);
    });
    on(wsInput, 'keydown', e => { if (e.key === 'Enter') qs('#wt-do-connect').click(); });

    // Reconnect button
    on(qs('#wt-reconnect-btn'), 'click', () => attemptConnect(loadWsUrl()));

    // Macro panel toggle
    on(qs('#wt-macro-toggle'), 'click', () => {
      macroPanel.classList.toggle('open');
      qs('#wt-macro-toggle').classList.toggle('active', macroPanel.classList.contains('open'));
      setTimeout(() => { if (fitAddon) try { fitAddon.fit(); } catch(e){} }, 300);
    });

    renderMacros();

    /* ── Window controls ────────────────────────────────── */
    on(qs('#wt-close'), 'click', () => {
      win.classList.add('hidden');
      toggleBtn.style.display = 'block';
    });

    on(qs('#wt-min'), 'click', () => {
      isMinimized = !isMinimized;
      win.classList.toggle('minimized', isMinimized);
    });

    on(qs('#wt-max'), 'click', () => {
      win.classList.toggle('maximized');
      setTimeout(() => { if (fitAddon) try { fitAddon.fit(); } catch(e){} }, 100);
    });

    /* ── Drag ───────────────────────────────────────────── */
    const titlebar = qs('#wt-titlebar');
    let dragOffX = 0, dragOffY = 0, dragging = false;

    function savePos() {
      const rect = win.getBoundingClientRect();
      localStorage.setItem('wt_pos', JSON.stringify({ left: rect.left, top: rect.top }));
    }

    function restorePos() {
      try {
        const saved = JSON.parse(localStorage.getItem('wt_pos'));
        if (saved) {
          // Clamp to viewport in case screen size changed
          const maxL = window.innerWidth  - 200;
          const maxT = window.innerHeight - 60;
          const left = Math.max(0, Math.min(saved.left, maxL));
          const top  = Math.max(0, Math.min(saved.top,  maxT));
          win.style.right  = 'auto';
          win.style.bottom = 'auto';
          win.style.left   = left + 'px';
          win.style.top    = top  + 'px';
        }
      } catch(e) {}
    }

    on(titlebar, 'mousedown', e => {
      if (e.target.closest('.wt-dot, .wt-btn')) return;
      if (win.classList.contains('maximized')) return;
      dragging = true;
      const rect = win.getBoundingClientRect();
      dragOffX = e.clientX - rect.left;
      dragOffY = e.clientY - rect.top;
      win.style.transition = 'none';
      win.style.right  = 'auto';
      win.style.bottom = 'auto';
      e.preventDefault();
    });

    on(document, 'mousemove', e => {
      if (!dragging) return;
      win.style.left = (e.clientX - dragOffX) + 'px';
      win.style.top  = (e.clientY - dragOffY) + 'px';
    });

    on(document, 'mouseup', () => {
      if (dragging) { dragging = false; savePos(); }
    });

    // Restore saved position, start hidden
    restorePos();
    win.classList.add('hidden');
    toggleBtn.style.display = 'block';
  }

  function escHtml(s) {
    return String(s)
      .replace(/&/g,'&amp;')
      .replace(/</g,'&lt;')
      .replace(/>/g,'&gt;')
      .replace(/"/g,'&quot;');
  }

  /* =====================================================
     4. HUD CORNER BRACKETS ON CARDS
     ===================================================== */
  function initCornerBrackets() {
    const cards = qsa('.item');
    cards.forEach(card => {
      if (!card.querySelector('.corner-bracket')) {
        const positions = [
          { top:'5px',  left:'5px',  borderWidth:'2px 0 0 2px' },
          { top:'5px',  right:'5px', borderWidth:'2px 2px 0 0' },
          { bottom:'5px', left:'5px',  borderWidth:'0 0 2px 2px' },
          { bottom:'5px', right:'68px', borderWidth:'0 2px 2px 0' },
        ];
        positions.forEach(pos => {
          const b = document.createElement('div');
          b.className = 'corner-bracket';
          b.style.cssText = Object.entries({
            ...pos,
            position:'absolute',
            width:'10px', height:'10px',
            borderColor:'rgba(0,245,200,0.7)',
            borderStyle:'solid',
            opacity:'0',
            transition:'opacity 0.3s ease',
            pointerEvents:'none',
            zIndex:'3',
          }).map(([k,v]) => `${k.replace(/[A-Z]/g,m=>'-'+m.toLowerCase())}:${v}`).join(';');
          card.appendChild(b);
        });
        card.addEventListener('mouseenter', () => {
          card.querySelectorAll('.corner-bracket').forEach(b => b.style.opacity = '1');
        });
        card.addEventListener('mouseleave', () => {
          card.querySelectorAll('.corner-bracket').forEach(b => b.style.opacity = '0');
        });
      }
    });
  }

  function initCardTilt() {
    const cards = qsa('.item');
    cards.forEach(card => {
      on(card, 'mousemove', e => {
        const rect = card.getBoundingClientRect();
        const cx = rect.left + rect.width / 2;
        const cy = rect.top  + rect.height / 2;
        const rx = ((e.clientY - cy) / (rect.height / 2)) * -5;
        const ry = ((e.clientX - cx) / (rect.width  / 2)) *  5;
        card.style.transform = `perspective(600px) rotateX(${rx}deg) rotateY(${ry}deg) translateY(-4px) scale(1.02)`;
      });
      on(card, 'mouseleave', () => {
        card.style.transform = '';
        card.style.transition = 'transform 0.45s cubic-bezier(0.23,1,0.32,1)';
        setTimeout(() => { card.style.transition = ''; }, 460);
      });
    });
  }

  /* =====================================================
     6. RIPPLE EFFECT on interactive elements
     ===================================================== */
  function initRipple() {
    on(document, 'click', e => {
      const target = e.target.closest('.btn, button, .item');
      if (!target) return;

      const rect = target.getBoundingClientRect();
      const ripple = document.createElement('span');
      const size = Math.max(rect.width, rect.height) * 2;

      ripple.style.cssText = `
        position:absolute;
        width:${size}px; height:${size}px;
        left:${e.clientX - rect.left - size/2}px;
        top:${e.clientY - rect.top  - size/2}px;
        background:rgba(0,245,200,0.12);
        border-radius:50%;
        transform:scale(0);
        animation:rippleAnim 0.6s ease-out forwards;
        pointer-events:none; z-index:10;
      `;
      target.style.overflow = 'hidden';
      target.appendChild(ripple);
      setTimeout(() => ripple.remove(), 620);
    });
  }

  /* =====================================================
     7. BOOT SEQUENCE — wawtor server terminal shell
     ===================================================== */
  function initBootSequence() {
    if (sessionStorage.getItem('hd_boot_v2')) return;
    sessionStorage.setItem('hd_boot_v2', '1');

    const HOST   = 'wawtor';
    const USER   = 'dmw';
    const KERNEL = '6.8.0-wawtor-lts';
    const now    = new Date();
    const bootTs = now.toISOString().replace('T', ' ').slice(0, 19);
    const upSeed = (Math.random() * 4 + 0.5).toFixed(2);

    /*  Each entry:
        { cmd: string | null, out: [ { text, color } ] }
        cmd=null → output-only block (kernel banner, etc.)
    */
    const SCRIPT = [
      // ── kernel boot banner (no prompt) ──────────────────────
      { cmd: null, out: [
        { text: `[    0.000000] Linux version ${KERNEL} (gcc 13.2.0)`, color: '#4a7c6e' },
        { text: `[    0.000000] BIOS-provided memory map:`, color: '#4a7c6e' },
        { text: `[    0.000000] ACPI: IRQ0 used by override.`, color: '#4a7c6e' },
        { text: `[    0.418312] pci 0000:00:01.0: [8086:1237] type 00 class 0x060000`, color: '#4a7c6e' },
        { text: `[    1.203441] EXT4-fs (nvme0n1p2): mounted filesystem with ordered data mode`, color: '#4a7c6e' },
        { text: `[    1.887604] systemd[1]: Detected architecture x86-64.`, color: '#4a7c6e' },
        { text: `[    1.887660] systemd[1]: Hostname set to <${HOST}>.`, color: '#00f5c8' },
        { text: ``, color: '' },
        { text: `Ubuntu 24.04.2 LTS ${HOST} ${KERNEL} #1 SMP`, color: '#7aaabb' },
        { text: ``, color: '' },
      ]},

      // ── systemctl check ─────────────────────────────────────
      { cmd: `systemctl is-active --all 2>/dev/null | head -12`, out: [
        { text: `  docker          active`, color: '#00f5c8' },
        { text: `  portainer       active`, color: '#00f5c8' },
        { text: `  nextcloud       active`, color: '#00f5c8' },
        { text: `  tailscaled      active`, color: '#00f5c8' },
        { text: `  nginx           active`, color: '#00f5c8' },
        { text: `  samba           active`, color: '#00f5c8' },
        { text: `  ssh             active`, color: '#00f5c8' },
        { text: `  cron            active`, color: '#00f5c8' },
        { text: `  ufw             active`, color: '#00f5c8' },
      ]},

      // ── disk usage ──────────────────────────────────────────
      { cmd: `df -h --output=target,used,avail,pcent | column -t`, out: [
        { text: `Mounted on         Used    Avail   Use%`, color: '#7aaabb' },
        { text: `/                  14G     198G    7%`, color: '#e8f4f8' },
        { text: `/mnt/storage       2.1T    5.7T    27%`, color: '#e8f4f8' },
        { text: `/mnt/media         890G    3.1T    22%`, color: '#e8f4f8' },
        { text: `/boot/efi          11M     511M    3%`, color: '#e8f4f8' },
      ]},

      // ── docker containers ───────────────────────────────────
      { cmd: `docker ps --format "table {{.Names}}\\t{{.Status}}\\t{{.Ports}}" 2>/dev/null`, out: [
        { text: `NAMES              STATUS              PORTS`, color: '#7aaabb' },
        { text: `portainer          Up 14 days          0.0.0.0:9443->9443/tcp`, color: '#e8f4f8' },
        { text: `nextcloud          Up 14 days          0.0.0.0:8080->80/tcp`, color: '#e8f4f8' },
        { text: `watchtower         Up 14 days          8080/tcp`, color: '#e8f4f8' },
        { text: `nginx-proxy        Up 14 days          0.0.0.0:80->80/tcp, 443->443/tcp`, color: '#e8f4f8' },
        { text: `mariadb            Up 14 days          3306/tcp`, color: '#e8f4f8' },
        { text: `redis              Up 14 days          6379/tcp`, color: '#e8f4f8' },
      ]},

      // ── tailscale status ─────────────────────────────────────
      { cmd: `tailscale status 2>/dev/null`, out: [
        { text: `100.x.x.x  ${HOST}  tagged-devices  active; relay "mia", tx 1.4MiB rx 892KiB`, color: '#00f5c8' },
      ]},

      // ── temp / uptime ────────────────────────────────────────
      { cmd: `uptime && sensors 2>/dev/null | grep -E 'Core|temp'`, out: [
        { text: ` ${bootTs}  up ${upSeed} days,  1 user,  load average: 0.12, 0.18, 0.21`, color: '#e8f4f8' },
        { text: `Core 0:        +38.0°C  (high = +80.0°C, crit = +100.0°C)`, color: '#ffb800' },
        { text: `Core 1:        +37.0°C  (high = +80.0°C, crit = +100.0°C)`, color: '#ffb800' },
        { text: `Core 2:        +39.0°C  (high = +80.0°C, crit = +100.0°C)`, color: '#ffb800' },
        { text: `Core 3:        +38.0°C  (high = +80.0°C, crit = +100.0°C)`, color: '#ffb800' },
      ]},

      // ── final ────────────────────────────────────────────────
      { cmd: `echo "all systems nominal — welcome back, ${USER}"`, out: [
        { text: ``, color: '' },
        { text: `  ██╗    ██╗ █████╗ ██╗    ██╗████████╗ ██████╗ ██████╗ `, color: '#00f5c8' },
        { text: `  ██║    ██║██╔══██╗██║    ██║╚══██╔══╝██╔═══██╗██╔══██╗`, color: '#00f5c8' },
        { text: `  ██║ █╗ ██║███████║██║ █╗ ██║   ██║   ██║   ██║██████╔╝`, color: '#00c49e' },
        { text: `  ██║███╗██║██╔══██║██║███╗██║   ██║   ██║   ██║██╔══██╗`, color: '#00c49e' },
        { text: `  ╚███╔███╔╝██║  ██║╚███╔███╔╝   ██║   ╚██████╔╝██║  ██║`, color: '#009e7e' },
        { text: `   ╚══╝╚══╝ ╚═╝  ╚═╝ ╚══╝╚══╝    ╚═╝    ╚═════╝ ╚═╝  ╚═╝`, color: '#009e7e' },
        { text: ``, color: '' },
        { text: `  all systems nominal — welcome back, ${USER}`, color: '#ffb800' },
        { text: ``, color: '' },
      ]},
    ];

    /* ── Build overlay ──────────────────────────────────────── */
    const overlay = document.createElement('div');
    overlay.id = 'wawtor-boot';
    overlay.style.cssText = `
      position:fixed; inset:0; z-index:99999;
      background:#0b0d0f;
      display:flex; flex-direction:column;
      font-family:'Share Tech Mono',monospace;
      font-size:0.8rem; line-height:1.7;
      overflow:hidden;
    `;

    /* terminal title bar */
    const titleBar = document.createElement('div');
    titleBar.style.cssText = `
      flex-shrink:0; display:flex; align-items:center; gap:8px;
      padding:8px 16px;
      background:#161a1e;
      border-bottom:1px solid rgba(0,245,200,0.12);
    `;
    titleBar.innerHTML = `
      <span style="width:10px;height:10px;border-radius:50%;background:#ff5f57;display:inline-block"></span>
      <span style="width:10px;height:10px;border-radius:50%;background:#ffbd2e;display:inline-block"></span>
      <span style="width:10px;height:10px;border-radius:50%;background:#28c840;display:inline-block"></span>
      <span style="margin-left:12px;color:#3d6070;font-size:0.72rem;letter-spacing:0.14em">
        ${USER}@${HOST}: ~
      </span>
    `;
    overlay.appendChild(titleBar);

    /* scrollable terminal body */
    const body = document.createElement('div');
    body.style.cssText = `
      flex:1; overflow-y:auto; padding:18px 24px 24px;
      scroll-behavior:smooth;
    `;
    /* scanlines inside terminal */
    body.style.backgroundImage = `repeating-linear-gradient(
      to bottom, transparent, transparent 2px,
      rgba(0,0,0,0.15) 2px, rgba(0,0,0,0.15) 4px
    )`;
    overlay.appendChild(body);

    document.body.appendChild(overlay);

    /* ── Rendering helpers ──────────────────────────────────── */
    function appendLine(text, color, extraStyle = '') {
      const el = document.createElement('div');
      el.style.cssText = `color:${color || '#e8f4f8'};white-space:pre;${extraStyle}`;
      el.textContent = text;
      body.appendChild(el);
      body.scrollTop = body.scrollHeight;
      return el;
    }

    function appendPrompt(cmd) {
      const row = document.createElement('div');
      row.style.cssText = `display:flex; align-items:baseline; white-space:pre;`;
      row.innerHTML = `
        <span style="color:#00f5c8">${USER}@${HOST}</span>
        <span style="color:#7aaabb">:</span>
        <span style="color:#4a9eff">~</span>
        <span style="color:#7aaabb">$ </span>
        <span id="cmd-target" style="color:#e8f4f8"></span>
        <span class="blink-cursor" style="
          display:inline-block;width:8px;height:1em;
          background:#00f5c8;margin-left:1px;
          animation:blinkCursor 0.75s step-end infinite;
          vertical-align:text-bottom;
        "></span>
      `;
      body.appendChild(row);
      body.scrollTop = body.scrollHeight;
      return { target: row.querySelector('#cmd-target'), cursor: row.querySelector('.blink-cursor') };
    }

    /* ── Sequencer ──────────────────────────────────────────── */
    let scriptIdx = 0;

    // Generate a plausible-looking MAC address seeded to this browser
    function genMac() {
      const seed = navigator.userAgent + screen.width + screen.height + navigator.language;
      let hash = 0;
      for (let i = 0; i < seed.length; i++) {
        hash = ((hash << 5) - hash) + seed.charCodeAt(i);
        hash |= 0;
      }
      const hex = Math.abs(hash).toString(16).padStart(12, '0');
      // Set locally administered bit on first octet for realism
      const octs = [];
      for (let i = 0; i < 12; i += 2) octs.push(hex.slice(i, i + 2));
      octs[0] = (parseInt(octs[0], 16) | 0x02 & ~0x01).toString(16).padStart(2,'0');
      return octs.join(':').toUpperCase();
    }

    const CLIENT_MAC = genMac();

    function runNext() {
      if (scriptIdx >= SCRIPT.length) {
        // Show MAC warning prompt instead of auto-fading
        showMacPrompt();
        return;
      }

      const block = SCRIPT[scriptIdx++];

      if (block.cmd === null) {
        typeOutputLines(block.out, 0, runNext);
      } else {
        const { target, cursor } = appendPrompt('');
        typeCommand(block.cmd, target, cursor, () => {
          cursor.remove();
          setTimeout(() => typeOutputLines(block.out, 0, runNext), 40);
        });
      }
    }

    function showMacPrompt() {
      appendLine('', '');

      // Warning box
      const warn = document.createElement('div');
      warn.style.cssText = `
        margin:12px 0;
        border:1px solid rgba(255,184,0,0.5);
        border-left:3px solid #ffb800;
        border-radius:4px;
        padding:14px 18px;
        background:rgba(255,184,0,0.05);
        color:#ffb800;
        font-family:'Share Tech Mono',monospace;
        font-size:0.78rem;
        line-height:1.9;
      `;
      warn.innerHTML = `
        <div style="color:#ffb800;font-size:0.7rem;letter-spacing:0.22em;margin-bottom:8px;">
          ⚠  SECURITY NOTICE — WAWTOR ACCESS CONTROL
        </div>
        <div style="color:#e8f4f8;">This terminal session is monitored and logged.</div>
        <div style="color:#e8f4f8;">By continuing you acknowledge that the following</div>
        <div style="color:#e8f4f8;">client identifier has been recorded:</div>
        <div style="margin-top:10px;color:#00f5c8;letter-spacing:0.12em;">
          MAC ADDRESS&nbsp;&nbsp;<span style="color:#ffb800;font-size:0.9rem;">${CLIENT_MAC}</span>
        </div>
        <div style="margin-top:2px;color:#3d6070;font-size:0.65rem;">
          Timestamp: ${new Date().toISOString()}
        </div>
      `;
      body.appendChild(warn);
      body.scrollTop = body.scrollHeight;

      // Prompt row
      appendLine('', '');
      const promptRow = document.createElement('div');
      promptRow.style.cssText = `
        display:flex; align-items:center; gap:14px;
        font-family:'Share Tech Mono',monospace;
        font-size:0.78rem;
      `;
      promptRow.innerHTML = `
        <span style="color:#7aaabb;">Continue to dashboard?</span>
        <button id="boot-accept" style="
          font-family:'Orbitron',monospace; font-size:0.62rem;
          letter-spacing:0.18em; text-transform:uppercase;
          padding:6px 20px; border:1px solid rgba(0,245,200,0.5);
          border-radius:3px; background:rgba(0,245,200,0.08);
          color:#00f5c8; cursor:pointer; transition:all 0.2s ease;
        ">[ ACCEPT & CONTINUE ]</button>
        <button id="boot-decline" style="
          font-family:'Orbitron',monospace; font-size:0.62rem;
          letter-spacing:0.18em; text-transform:uppercase;
          padding:6px 20px; border:1px solid rgba(255,58,92,0.3);
          border-radius:3px; background:rgba(255,58,92,0.05);
          color:#ff3a5c; cursor:pointer; transition:all 0.2s ease;
        ">[ DISCONNECT ]</button>
      `;
      body.appendChild(promptRow);
      body.scrollTop = body.scrollHeight;

      const acceptBtn  = qs('#boot-accept');
      const declineBtn = qs('#boot-decline');

      acceptBtn.onmouseenter  = () => { acceptBtn.style.background  = 'rgba(0,245,200,0.18)'; acceptBtn.style.boxShadow  = '0 0 16px rgba(0,245,200,0.2)'; };
      acceptBtn.onmouseleave  = () => { acceptBtn.style.background  = 'rgba(0,245,200,0.08)'; acceptBtn.style.boxShadow  = 'none'; };
      declineBtn.onmouseenter = () => { declineBtn.style.background = 'rgba(255,58,92,0.12)'; };
      declineBtn.onmouseleave = () => { declineBtn.style.background = 'rgba(255,58,92,0.05)'; };

      acceptBtn.onclick = () => {
        promptRow.innerHTML = `<span style="color:#00f5c8;">Access granted. Loading dashboard...</span>`;
        body.scrollTop = body.scrollHeight;
        setTimeout(() => {
          overlay.style.transition = 'opacity 0.8s ease';
          overlay.style.opacity = '0';
          setTimeout(() => overlay.remove(), 820);
        }, 600);
      };

      declineBtn.onclick = () => {
        promptRow.innerHTML = `<span style="color:#ff3a5c;">Session terminated. Goodbye.</span>`;
        body.scrollTop = body.scrollHeight;
        setTimeout(() => {
          document.body.style.transition = 'opacity 0.5s ease';
          document.body.style.opacity = '0';
        }, 800);
      };
    }

    function typeCommand(cmd, target, cursor, done) {
      let i = 0;
      function step() {
        if (i >= cmd.length) { done(); return; }
        target.textContent += cmd[i++];
        body.scrollTop = body.scrollHeight;
        // Faster: 8-18ms per character instead of 28-66ms
        setTimeout(step, 8 + Math.random() * 10);
      }
      // Shorter initial pause: 60-120ms instead of 180-300ms
      setTimeout(step, 60 + Math.random() * 60);
    }

    function typeOutputLines(lines, idx, done) {
      if (idx >= lines.length) { done(); return; }
      const { text, color } = lines[idx];
      appendLine(text, color);
      // Faster: 8-14ms per line instead of 22-40ms
      const delay = text.trim() === '' ? 8 : 8 + Math.random() * 6;
      setTimeout(() => typeOutputLines(lines, idx + 1, done), delay);
    }

    /* inject blinkCursor keyframe if not present */
    if (!document.querySelector('#wawtor-boot-kf')) {
      const s = document.createElement('style');
      s.id = 'wawtor-boot-kf';
      s.textContent = `
        @keyframes blinkCursor {
          0%,100% { opacity:1; }
          50%      { opacity:0; }
        }
      `;
      document.head.appendChild(s);
    }

    /* kick it off */
    setTimeout(runNext, 120);
  }

  /* =====================================================
     8. AMBIENT GLOW TRAIL
     ===================================================== */
  function initGlowTrail() {
    const trail = [];
    const N = 10;
    for (let i = 0; i < N; i++) {
      const el = document.createElement('div');
      el.style.cssText = `
        position:fixed; width:${6 - i*0.4}px; height:${6 - i*0.4}px;
        background:rgba(0,245,200,${0.28 - i*0.024});
        border-radius:50%;
        pointer-events:none; z-index:99990;
        transition:left ${0.04 + i*0.04}s ease, top ${0.04 + i*0.04}s ease;
        transform:translate(-50%,-50%);
      `;
      document.body.appendChild(el);
      trail.push(el);
    }
    on(document, 'mousemove', e => {
      trail.forEach(el => {
        el.style.left = e.clientX + 'px';
        el.style.top  = e.clientY + 'px';
      });
    });
  }

  /* =====================================================
     9. INJECT REQUIRED KEYFRAMES
     ===================================================== */
  function injectKeyframes() {
    const style = document.createElement('style');
    style.textContent = `
      @keyframes rippleAnim {
        to { transform:scale(1); opacity:0; }
      }
      @keyframes cursorBurst {
        0%   { transform:scale(0.5); opacity:1; }
        100% { transform:scale(2.5); opacity:0; }
      }
    `;
    document.head.appendChild(style);
  }

  /* =====================================================
     10. OBSERVER: re-init on dynamic card injection
     ===================================================== */
  function initObserver() {
    const ob = new MutationObserver(() => {
      initCornerBrackets();
      initCardTilt();
    });
    ob.observe(document.body, { childList: true, subtree: true });
  }

  /* =====================================================
     11. KEYBOARD SHORTCUT OVERLAY  (press ?)
     ===================================================== */
  function initShortcutHelp() {
    const shortcuts = [
      ['?',       'Toggle this overlay'],
      ['Ctrl+K',  'Focus search'],
      ['Escape',  'Close modal / search'],
    ];

    const overlay = document.createElement('div');
    overlay.id = 'hd-shortcuts';
    overlay.style.cssText = `
      display:none; position:fixed; inset:0;
      background:rgba(3,5,8,0.92); z-index:99000;
      justify-content:center; align-items:center;
      backdrop-filter:blur(12px);
    `;

    const box = document.createElement('div');
    box.style.cssText = `
      background:#0a1520; border:1px solid rgba(0,245,200,0.3);
      border-radius:8px; padding:36px 48px; min-width:380px;
      box-shadow:0 0 60px rgba(0,245,200,0.15);
    `;
    box.innerHTML = `
      <div style="font-family:'Orbitron',monospace;font-size:0.7rem;
           letter-spacing:0.24em;color:#00f5c8;margin-bottom:24px;
           text-transform:uppercase;text-shadow:0 0 10px #00f5c8">
        ⌨ KEY BINDINGS
      </div>
      ${shortcuts.map(([k,v]) => `
        <div style="display:flex;justify-content:space-between;
             margin-bottom:14px;font-family:'Share Tech Mono',monospace;
             font-size:0.78rem;">
          <span style="background:rgba(0,245,200,0.1);border:1px solid rgba(0,245,200,0.25);
                border-radius:3px;padding:3px 10px;color:#00f5c8">${k}</span>
          <span style="color:#7aaabb;align-self:center">${v}</span>
        </div>
      `).join('')}
      <div style="margin-top:22px;font-family:'Share Tech Mono',monospace;
           font-size:0.65rem;color:#3d6070;text-transform:uppercase;
           letter-spacing:0.1em">Press ESC or ? to close</div>
    `;
    overlay.appendChild(box);
    document.body.appendChild(overlay);

    let open = false;
    function toggle() {
      open = !open;
      overlay.style.display = open ? 'flex' : 'none';
    }
    on(document, 'keydown', e => {
      if (e.key === '?' && !['INPUT','TEXTAREA','SELECT'].includes(document.activeElement.tagName)) toggle();
      if (e.key === 'Escape' && open) toggle();
    });
    on(overlay, 'click', e => { if (e.target === overlay) toggle(); });
  }

  /* ─── BOOT ORDER ─────────────────────────────────────────────── */
  function init() {
    injectKeyframes();
    initBootSequence();
    initParticles();
    initCursor();
    initHudBar();
    initTerminalWidget();
    initCornerBrackets();
    initCardTilt();
    initRipple();
    initGlowTrail();
    initObserver();
    initShortcutHelp();
  }

  if (document.readyState === 'loading') {
    on(document, 'DOMContentLoaded', init);
  } else {
    init();
  }

})();