@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');

:root {
  --hud-green: #39ff8f;
  --hud-green-dim: #1c8a52;
  --hud-orange: #ff9130;
  --hud-red: #ff4655;
  --bg-deep: #050b10;
  --bg-panel: rgba(12, 26, 22, 0.92);
  --panel-border: rgba(57, 255, 143, 0.35);
  --text-main: #d9fbe8;
  --text-dim: #7fa695;
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

* { box-sizing: border-box; }
html, body { margin: 0; }

body {
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  color: var(--text-main);
  background: radial-gradient(circle at 50% 0%, #0e2a22, var(--bg-deep) 65%);
  min-height: 100vh;
  overflow-x: hidden;
}

/* ---- moving space backdrop ---- */
.starfield {
  position: fixed;
  inset: -400px;
  z-index: 0;
  pointer-events: none;
  background-image:
    radial-gradient(1.5px 1.5px at 10% 20%, #fff 50%, transparent 51%),
    radial-gradient(1px 1px at 30% 70%, #fff 50%, transparent 51%),
    radial-gradient(2px 2px at 50% 40%, #fff 50%, transparent 51%),
    radial-gradient(1px 1px at 70% 12%, #fff 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 85% 55%, #fff 50%, transparent 51%),
    radial-gradient(1px 1px at 15% 85%, #fff 50%, transparent 51%),
    radial-gradient(1px 1px at 60% 90%, #fff 50%, transparent 51%),
    radial-gradient(2px 2px at 92% 25%, #fff 50%, transparent 51%),
    radial-gradient(1px 1px at 45% 12%, #fff 50%, transparent 51%),
    radial-gradient(1px 1px at 5% 55%, #fff 50%, transparent 51%);
  background-repeat: repeat;
  background-size: 340px 340px;
  opacity: 0.8;
  will-change: transform;
  animation: starfield-fly 22s linear infinite;
}
/* transform-based (not background-position) so this animates on the compositor
   instead of repainting the full oversized layer every frame */
@keyframes starfield-fly {
  from { transform: translate(0, 0); }
  to   { transform: translate(-340px, 340px); }
}

.starfox-horizon {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.asteroid {
  position: absolute;
  left: -80px;
  width: var(--size, 40px);
  height: var(--size, 40px);
  opacity: var(--opacity, 0.4);
  animation: asteroid-drift var(--duration, 30s) linear infinite;
  animation-delay: var(--delay, 0s);
}
.asteroid-spin {
  width: 100%;
  height: 100%;
  animation: asteroid-tumble var(--spin, 12s) linear infinite;
  animation-delay: var(--delay, 0s);
}
.asteroid-spin svg { display: block; width: 100%; height: 100%; }
.asteroid-spin polygon {
  fill: rgba(12, 26, 22, 0.6);
  stroke: var(--hud-green-dim);
  stroke-width: 1.4;
}
@keyframes asteroid-drift {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(100vw + 160px)); }
}
@keyframes asteroid-tumble {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

.scanlines {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(57, 255, 143, 0.03),
    rgba(57, 255, 143, 0.03) 1px,
    transparent 2px,
    transparent 3px
  );
  mix-blend-mode: overlay;
}

/* ---- page layout ---- */
.page-wrap {
  position: relative;
  z-index: 2;
  min-height: 100vh;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 40px 20px 60px;
}

.hud-panel {
  position: relative;
  width: 100%;
  max-width: 460px;
  background: var(--bg-panel);
  border: 1px solid var(--panel-border);
  padding: 36px 32px;
  box-shadow: 0 0 40px rgba(57, 255, 143, 0.08), inset 0 0 60px rgba(0,0,0,0.4);
}
.hud-panel.wide { max-width: 860px; }
.hud-panel.xwide { max-width: 1040px; }

.corner { position: absolute; width: 18px; height: 18px; border: 2px solid var(--hud-green); }
.corner.tl { top: -1px; left: -1px; border-right: none; border-bottom: none; }
.corner.tr { top: -1px; right: -1px; border-left: none; border-bottom: none; }
.corner.bl { bottom: -1px; left: -1px; border-right: none; border-top: none; }
.corner.br { bottom: -1px; right: -1px; border-left: none; border-top: none; }

.callsign-row { display: flex; align-items: center; gap: 14px; margin-bottom: 6px; }
.toad-avatar-wrap { position: relative; flex-shrink: 0; width: 46px; height: 46px; }
.toad-avatar { filter: drop-shadow(0 0 6px rgba(57, 255, 143, 0.5)); }
.lock-reticle {
  position: absolute;
  inset: -6px;
  border: 1px dashed rgba(57, 255, 143, 0.5);
  border-radius: 50%;
  animation: reticle-spin 6s linear infinite;
}
.lock-reticle::before, .lock-reticle::after {
  content: ""; position: absolute; width: 7px; height: 7px; border: 1px solid var(--hud-green);
}
.lock-reticle::before { top: -3px; left: -3px; border-right: none; border-bottom: none; }
.lock-reticle::after { bottom: -3px; right: -3px; border-left: none; border-top: none; }
@keyframes reticle-spin { to { transform: rotate(360deg); } }

.callsign {
  font-family: "Press Start 2P", "Consolas", monospace;
  font-size: 9px;
  letter-spacing: 0.1em;
  line-height: 1.6;
  color: var(--hud-orange);
  text-transform: uppercase;
  flex: 1;
}

.nav-links { display: flex; gap: 8px; flex-shrink: 0; }
.logout-link {
  font-size: 0.65rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-dim);
  text-decoration: none;
  border: 1px solid var(--panel-border);
  padding: 5px 10px;
  flex-shrink: 0;
}
.logout-link:hover { color: var(--hud-green); border-color: var(--hud-green); }

h1 {
  font-family: "Press Start 2P", "Consolas", monospace;
  font-size: 1.15rem;
  line-height: 1.6;
  margin: 10px 0 8px;
  letter-spacing: 0.02em;
  color: var(--hud-green);
  text-shadow: 0 0 12px rgba(57, 255, 143, 0.45);
}

.subtitle {
  color: var(--text-dim);
  font-size: 0.85rem;
  margin: 0 0 22px;
  letter-spacing: 0.03em;
}

/* ---- filter tabs ---- */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 20px;
  padding-bottom: 18px;
  border-bottom: 1px dashed var(--panel-border);
}
.hud-tab {
  font-family: inherit;
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-dim);
  background: rgba(0,0,0,0.3);
  border: 1px solid var(--panel-border);
  padding: 6px 12px;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.hud-tab:hover { color: var(--hud-green); border-color: var(--hud-green-dim); }
.hud-tab.active {
  color: var(--hud-green);
  border-color: var(--hud-green);
  background: rgba(57, 255, 143, 0.12);
  box-shadow: 0 0 10px rgba(57,255,143,0.15);
}

/* ---- console grid / cards ---- */
.console-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 16px;
  contain: content;
}
.console-card {
  border: 1px solid var(--panel-border);
  background: rgba(0, 0, 0, 0.25);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow: hidden; /* clips the screenshot's negative margin and hover zoom */
}
.console-card.hidden { display: none; }

/* ---- screenshot banner (bleeds to the card edges) ---- */
.card-shot {
  display: block;
  margin: -16px -16px 0;
  aspect-ratio: 16 / 9;
  position: relative;
  overflow: hidden;
  background: var(--bg-deep); /* matches the letterbox bars baked into the shots */
  border-bottom: 1px solid var(--panel-border);
}
.card-shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.25s ease;
}
/* keep the CRT feel of the rest of the page over the captured frames */
.card-shot::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom, rgba(0, 0, 0, 0.18) 0 1px, transparent 1px 3px);
}
.console-card:hover .card-shot img { transform: scale(1.04); }
@media (prefers-reduced-motion: reduce) {
  .card-shot img { transition: none; }
  .console-card:hover .card-shot img { transform: none; }
}
.console-card-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  border-bottom: 1px dashed var(--panel-border);
  padding-bottom: 8px;
}
.console-name-wrap { display: flex; align-items: center; gap: 8px; min-width: 0; }
.console-icon { font-size: 1.1rem; flex-shrink: 0; }
.console-name {
  font-weight: bold;
  letter-spacing: 0.02em;
  color: var(--hud-green);
  font-size: 0.92rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tag {
  display: inline-block;
  padding: 2px 8px;
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border: 1px solid currentColor;
  flex-shrink: 0;
  color: var(--hud-green-dim);
}
.card-blurb { margin: 0; font-size: 0.82rem; line-height: 1.45; color: var(--text-main); flex-grow: 1; }
a.dl {
  align-self: flex-start;
  color: var(--hud-green);
  text-decoration: none;
  border: 1px solid var(--hud-green-dim);
  padding: 5px 12px;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
a.dl:hover { background: rgba(57, 255, 143, 0.14); }

/* ---- comm-link transmission window ---- */
.comm-window {
  margin-top: 28px;
  display: flex;
  align-items: stretch;
  border: 1px solid var(--panel-border);
  background: rgba(0, 0, 0, 0.35);
  position: relative;
  overflow: hidden;
}
.comm-portrait {
  flex-shrink: 0;
  width: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(57, 255, 143, 0.06);
  border-right: 1px solid var(--panel-border);
}
.comm-portrait svg { filter: drop-shadow(0 0 6px rgba(57, 255, 143, 0.5)); }
.comm-body { padding: 10px 12px; flex: 1; min-width: 0; }
.comm-label {
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--hud-orange);
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 5px;
}
.comm-label .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--hud-red); flex-shrink: 0;
  animation: comm-blink 1s steps(1) infinite;
}
@keyframes comm-blink { 50% { opacity: 0; } }
.comm-body p { margin: 0; font-size: 0.78rem; font-style: italic; color: var(--text-main); line-height: 1.4; }

/* ---- back button ---- */
.hud-btn {
  display: block;
  width: 100%;
  margin-top: 24px;
  padding: 14px 12px;
  background: linear-gradient(180deg, rgba(57,255,143,0.18), rgba(57,255,143,0.06));
  border: 1px solid var(--hud-green);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.15), inset 0 -3px 0 rgba(0,0,0,0.35);
  color: var(--hud-green);
  font-family: "Press Start 2P", "Consolas", monospace;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  font-size: 0.62rem;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s, transform 0.05s;
}
.hud-btn:hover { background: rgba(57, 255, 143, 0.28); }
.hud-btn:active { transform: translateY(2px); }

@media (max-width: 480px) {
  .page-wrap { padding: 24px 14px 40px; }
  .hud-panel { padding: 26px 18px; }
}

/* ---- tool page components ---- */
.tool-note { font-size: 0.72rem; color: var(--text-dim); margin: 0 0 18px; line-height: 1.5; }

.tool-field-row { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.tool-field-label {
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.tool-textarea {
  width: 100%;
  min-height: 160px;
  resize: vertical;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  color: var(--text-main);
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 0.85rem;
  line-height: 1.5;
  padding: 12px;
  box-sizing: border-box;
}
.tool-textarea:focus { outline: none; border-color: var(--hud-green); }

.tool-text-input {
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  color: var(--text-main);
  font-family: inherit;
  font-size: 0.85rem;
  padding: 10px 12px;
  box-sizing: border-box;
  width: 100%;
}
.tool-text-input:focus { outline: none; border-color: var(--hud-green); }

.tool-output {
  width: 100%;
  min-height: 90px;
  max-height: 420px;
  overflow: auto;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  color: var(--hud-green);
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 0.82rem;
  line-height: 1.5;
  padding: 12px;
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
  box-sizing: border-box;
}
.tool-output.error-text { color: var(--hud-red); }

.tool-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 14px 0; }

.tool-btn {
  font-family: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--hud-green);
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid var(--hud-green-dim);
  padding: 9px 16px;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.tool-btn:hover { background: rgba(57, 255, 143, 0.14); border-color: var(--hud-green); }
.tool-btn:active { transform: translateY(1px); }
.tool-btn.ghost { color: var(--text-dim); border-color: var(--panel-border); }
.tool-btn.ghost:hover { color: var(--hud-green); border-color: var(--hud-green-dim); }

.tool-checks { display: flex; flex-wrap: wrap; gap: 16px; margin: 4px 0 16px; }
.tool-check { display: flex; align-items: center; gap: 7px; font-size: 0.78rem; color: var(--text-main); }
.tool-check input { accent-color: var(--hud-green); width: 15px; height: 15px; }

.tool-slider-row { display: flex; align-items: center; gap: 12px; }
.tool-slider-row input[type="range"] { flex: 1; accent-color: var(--hud-green); }
.tool-slider-value {
  font-family: "Press Start 2P", monospace;
  font-size: 0.8rem;
  color: var(--hud-green);
  min-width: 34px;
  text-align: right;
}

.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; margin: 16px 0; }
.stat-tile { border: 1px solid var(--panel-border); background: rgba(0, 0, 0, 0.25); padding: 12px; text-align: center; }
.stat-tile .stat-value { font-family: "Press Start 2P", monospace; font-size: 0.95rem; color: var(--hud-green); display: block; margin-bottom: 8px; }
.stat-tile .stat-label { font-size: 0.6rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-dim); }

.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
@media (max-width: 720px) { .two-col { grid-template-columns: 1fr; } }

.md-preview {
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  padding: 14px;
  min-height: 160px;
  max-height: 420px;
  overflow: auto;
  font-size: 0.85rem;
  line-height: 1.55;
  box-sizing: border-box;
}
.md-preview h1, .md-preview h2, .md-preview h3 { color: var(--hud-green); font-family: inherit; text-shadow: none; margin: 0.6em 0 0.3em; }
.md-preview h1:first-child, .md-preview h2:first-child, .md-preview h3:first-child { margin-top: 0; }
.md-preview code { background: rgba(57, 255, 143, 0.1); padding: 1px 5px; font-size: 0.9em; }
.md-preview pre { background: rgba(0, 0, 0, 0.4); padding: 10px; overflow-x: auto; border: 1px solid var(--panel-border); }
.md-preview pre code { background: none; padding: 0; }
.md-preview a { color: var(--hud-orange); }
.md-preview blockquote { border-left: 2px solid var(--hud-green-dim); margin: 0.5em 0; padding: 2px 12px; color: var(--text-dim); }
.md-preview ul, .md-preview ol { padding-left: 1.4em; }
.md-preview hr { border: none; border-top: 1px dashed var(--panel-border); margin: 1em 0; }
.md-preview p { margin: 0.6em 0; }

.password-display { display: flex; gap: 8px; margin-bottom: 16px; }
.password-display input {
  flex: 1;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  color: var(--hud-green);
  font-family: "Consolas", monospace;
  font-size: 1rem;
  letter-spacing: 0.04em;
  padding: 11px 12px;
  min-width: 0;
}

.strength-bar { height: 6px; background: rgba(0, 0, 0, 0.4); border: 1px solid var(--panel-border); margin-bottom: 6px; overflow: hidden; }
.strength-fill { height: 100%; width: 0%; background: var(--hud-red); transition: width 0.2s, background 0.2s; }
.strength-label { font-size: 0.7rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 18px; }

mark.regex-match { background: rgba(57, 255, 143, 0.3); color: var(--hud-green); padding: 0 1px; border-radius: 1px; }

.match-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.match-list li { border: 1px solid var(--panel-border); background: rgba(0, 0, 0, 0.25); padding: 8px 10px; font-size: 0.78rem; }
.match-list .match-index { color: var(--hud-orange); margin-right: 8px; }

.copy-toast { font-size: 0.68rem; color: var(--hud-green); margin-left: 2px; opacity: 0; }
.copy-toast.show { opacity: 1; }

.tool-file-input {
  color: var(--text-main);
  font-family: inherit;
  font-size: 0.8rem;
}
.tool-file-input::file-selector-button {
  font-family: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--hud-green);
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid var(--hud-green-dim);
  padding: 9px 16px;
  cursor: pointer;
  margin-right: 12px;
  transition: background 0.15s, border-color 0.15s;
}
.tool-file-input::file-selector-button:hover { background: rgba(57, 255, 143, 0.14); border-color: var(--hud-green); }

.tool-select {
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  color: var(--text-main);
  font-family: inherit;
  font-size: 0.82rem;
  padding: 9px 10px;
}
.tool-select:focus { outline: none; border-color: var(--hud-green); }

.tool-dim-row { display: flex; gap: 12px; }
.tool-dim-row > div { flex: 1; }

.canvas-frame {
  border: 1px solid var(--panel-border);
  background: repeating-conic-gradient(rgba(255,255,255,0.04) 0% 25%, transparent 0% 50%) 50% / 16px 16px;
  padding: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 120px;
  overflow: auto;
}
.canvas-frame canvas { max-width: 100%; height: auto; display: block; }
.canvas-frame img { max-width: 100%; display: block; }

.tool-video-preview {
  width: 100%;
  max-height: 340px;
  border: 1px solid var(--panel-border);
  background: rgba(0, 0, 0, 0.35);
  display: block;
}

.progress-bar { height: 8px; background: rgba(0, 0, 0, 0.4); border: 1px solid var(--panel-border); overflow: hidden; margin: 4px 0 10px; }
.progress-fill { height: 100%; width: 0%; background: var(--hud-green); transition: width 0.15s; }

/* ---- Slippy TV ---- */
.tv-frame {
  background: linear-gradient(160deg, #10241c, #060e0b);
  border: 1px solid var(--panel-border);
  border-radius: 10px;
  padding: 16px;
  box-shadow: inset 0 0 30px rgba(0, 0, 0, 0.6), 0 0 24px rgba(57, 255, 143, 0.06);
}
.tv-screen {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #000;
  border: 2px solid var(--hud-green-dim);
  border-radius: 4px;
  overflow: hidden;
  box-shadow: inset 0 0 40px rgba(0, 0, 0, 0.8);
}
.tv-screen video, .tv-screen #yt-player-wrap { width: 100%; height: 100%; display: block; position: relative; z-index: 1; background: #000; }
.tv-screen video { border: 0; }
.tv-screen #yt-player-wrap iframe { width: 100%; height: 100%; display: block; border: 0; }

.tv-off-msg {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 10px;
  background: #000;
  color: var(--hud-green-dim);
  font-family: "Press Start 2P", monospace;
  font-size: 0.68rem;
  letter-spacing: 0.05em;
  text-align: center;
  padding: 20px;
  opacity: 0;
  pointer-events: none;
}
.tv-screen.tv-off .tv-off-msg { opacity: 1; }
.tv-screen.tv-off iframe, .tv-screen.tv-off video { visibility: hidden; }

.tv-loading-msg {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: rgba(0, 0, 0, 0.55);
  color: var(--hud-green);
  font-family: "Press Start 2P", monospace;
  font-size: 0.65rem;
  letter-spacing: 0.05em;
  text-shadow: 0 0 8px rgba(57, 255, 143, 0.5);
  opacity: 0;
  pointer-events: none;
}
.tv-screen.buffering .tv-loading-msg { opacity: 1; }
.tv-loading-msg .tv-loading-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--hud-green);
  animation: comm-blink 0.9s steps(1) infinite;
}

.tv-static-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  background:
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.12) 0px, rgba(255, 255, 255, 0.12) 1px, transparent 1px, transparent 3px),
    repeating-linear-gradient(90deg, rgba(57, 255, 143, 0.06) 0px, transparent 2px);
}
.tv-screen.flicker .tv-static-overlay { animation: tv-flicker-anim 0.35s steps(6) forwards; }
@keyframes tv-flicker-anim {
  0% { opacity: 0.9; } 25% { opacity: 0.25; } 50% { opacity: 0.75; } 75% { opacity: 0.15; } 100% { opacity: 0; }
}

.tv-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 18px; }

.tv-power-btn {
  padding: 9px 14px;
  border: 1px solid var(--panel-border);
  background: rgba(0, 0, 0, 0.3);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 7px;
  transition: background 0.15s, box-shadow 0.15s, border-color 0.15s, color 0.15s;
  flex-shrink: 0;
}
.tv-power-btn:hover { border-color: var(--hud-green-dim); color: var(--hud-green); }
.tv-power-btn.on {
  background: rgba(57, 255, 143, 0.16);
  border-color: var(--hud-green);
  color: var(--hud-green);
  box-shadow: 0 0 10px rgba(57, 255, 143, 0.3);
}

.channel-readout {
  font-family: "Press Start 2P", monospace;
  font-size: 0.8rem;
  color: var(--hud-green);
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid var(--panel-border);
  padding: 10px 14px;
  text-shadow: 0 0 8px rgba(57, 255, 143, 0.5);
  min-width: 140px;
  text-align: center;
  flex-shrink: 0;
}

.tv-nav-btn {
  width: 40px;
  height: 40px;
  border: 1px solid var(--hud-green-dim);
  background: rgba(0, 0, 0, 0.3);
  color: var(--hud-green);
  font-size: 1rem;
  cursor: pointer;
  flex-shrink: 0;
}
.tv-nav-btn:hover { background: rgba(57, 255, 143, 0.14); border-color: var(--hud-green); }

.volume-row { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 180px; }
.volume-row input[type="range"] { flex: 1; accent-color: var(--hud-green); }
.volume-row .tool-slider-value { min-width: 40px; }

.mute-btn {
  width: 36px;
  height: 36px;
  border: 1px solid var(--panel-border);
  background: rgba(0, 0, 0, 0.3);
  color: var(--text-main);
  font-size: 1rem;
  cursor: pointer;
  flex-shrink: 0;
}
.mute-btn:hover { border-color: var(--hud-green); }

.channel-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; margin-top: 16px; }
.channel-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--panel-border);
  background: rgba(0, 0, 0, 0.25);
  color: var(--text-main);
  padding: 10px 12px;
  font-family: inherit;
  font-size: 0.78rem;
  cursor: pointer;
  text-align: left;
}
.channel-btn:hover { border-color: var(--hud-green-dim); }
.channel-btn.active {
  border-color: var(--hud-green);
  background: rgba(57, 255, 143, 0.1);
  color: var(--hud-green);
  box-shadow: 0 0 10px rgba(57, 255, 143, 0.12);
}
.channel-btn .ch-num {
  font-family: "Press Start 2P", monospace;
  font-size: 0.58rem;
  color: var(--hud-orange);
  flex-shrink: 0;
}

/* ---- calculators (Simple Calculator, Tip Calculator) ---- */
/* Numeric displays use a plain monospace font, never "Press Start 2P" —
   that pixel font draws 8 as S and 0 as O at small sizes. */
.calc-display {
  width: 100%;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  color: var(--hud-green);
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 2.1rem;
  text-align: right;
  padding: 20px 16px 14px;
  margin-bottom: 4px;
  overflow-x: auto;
  white-space: nowrap;
  box-sizing: border-box;
}
.calc-subdisplay {
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 0.78rem;
  color: var(--text-dim);
  text-align: right;
  min-height: 1.1em;
  padding: 0 16px;
  margin-bottom: 16px;
}

.calc-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 18px; }
.calc-key {
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 1.15rem;
  color: var(--text-main);
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid var(--panel-border);
  padding: 16px 0;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.calc-key:hover { background: rgba(57, 255, 143, 0.14); border-color: var(--hud-green); }
.calc-key:active { transform: translateY(1px); }
.calc-key.calc-op { color: var(--hud-orange); border-color: rgba(255, 145, 48, 0.35); }
.calc-key.calc-op:hover { background: rgba(255, 145, 48, 0.14); border-color: var(--hud-orange); }
.calc-key.calc-op.active { background: rgba(255, 145, 48, 0.22); border-color: var(--hud-orange); }
.calc-key.calc-equals { color: var(--hud-green); border-color: var(--hud-green-dim); grid-column: span 2; }
.calc-key.calc-clear, .calc-key.calc-back { color: var(--hud-red); border-color: rgba(255, 70, 85, 0.35); }
.calc-key.calc-clear:hover, .calc-key.calc-back:hover { background: rgba(255, 70, 85, 0.14); border-color: var(--hud-red); }
.calc-key.calc-zero { grid-column: span 2; }

.calc-result-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin: 16px 0; }
.calc-result-tile { border: 1px solid var(--panel-border); background: rgba(0, 0, 0, 0.25); padding: 14px 12px; text-align: center; }
.calc-result-tile .calc-result-value {
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 1.25rem;
  color: var(--hud-green);
  display: block;
  margin-bottom: 8px;
}
.calc-result-tile .calc-result-label { font-size: 0.6rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-dim); }
.calc-result-tile.highlight { border-color: var(--hud-green-dim); background: rgba(57, 255, 143, 0.06); }
.calc-result-tile.highlight .calc-result-value { font-size: 1.55rem; }

.calc-slider-value {
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 0.9rem;
  color: var(--hud-green);
  min-width: 44px;
  text-align: right;
}

.tip-quick-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 16px; }
.tip-quick-btn {
  font-family: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.03em;
  color: var(--text-main);
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid var(--panel-border);
  padding: 8px 14px;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.tip-quick-btn:hover { background: rgba(57, 255, 143, 0.14); border-color: var(--hud-green); }
.tip-quick-btn.active { color: var(--hud-green); border-color: var(--hud-green); background: rgba(57, 255, 143, 0.14); }

.tool-number-input {
  width: 100%;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  color: var(--hud-green);
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 1rem;
  padding: 11px 12px;
  box-sizing: border-box;
}
.tool-number-input:focus { outline: none; border-color: var(--hud-green); }

/* ---- World Internet Radio ---- */
.radio-now-playing {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  padding: 16px;
  border: 1px solid var(--panel-border);
  background: rgba(0, 0, 0, 0.3);
  margin: 20px 0;
}
.radio-now-playing-info { display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1 1 220px; }
.radio-now-playing-info .console-name { max-width: 220px; }

/* Station names run longer than typical project-card titles — wrap instead
   of ellipsizing, so the full name is always readable. Some tags (country/
   network labels) are also long, so name and tag are stacked in separate
   rows here rather than sharing the homepage cards' single side-by-side
   row — no flex-basis/shrink combination keeps two long, independently-
   wrapping strings from colliding when they share one line. */
.station-card .console-name { white-space: normal; overflow: visible; text-overflow: clip; }
.station-card .console-card-head { flex-direction: column; align-items: flex-start; gap: 4px; }

.radio-transport { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.radio-play-btn {
  width: 42px;
  height: 42px;
  font-size: 1.1rem;
  color: var(--hud-green);
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid var(--hud-green-dim);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
}
.radio-play-btn:hover { background: rgba(57, 255, 143, 0.14); border-color: var(--hud-green); }
.radio-play-btn.playing {
  background: rgba(57, 255, 143, 0.16);
  border-color: var(--hud-green);
  box-shadow: 0 0 10px rgba(57, 255, 143, 0.3);
}

.radio-status {
  font-family: inherit;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.72rem;
  color: var(--text-dim);
}
.radio-status.tuning { color: var(--hud-orange); }
.radio-status.on-air { color: var(--hud-green); text-shadow: 0 0 8px rgba(57, 255, 143, 0.5); }
.radio-status.paused { color: var(--text-dim); }
.radio-status.error { color: var(--hud-red); }

.radio-volume { flex: 1 1 200px; min-width: 160px; }

.region-heading {
  font-family: inherit;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.78rem;
  color: var(--hud-orange);
  border-bottom: 1px dashed var(--panel-border);
  padding-bottom: 6px;
  margin: 28px 0 12px;
}
.region-heading:first-of-type { margin-top: 8px; }

.station-card.playing {
  border-color: var(--hud-green);
  background: rgba(57, 255, 143, 0.04);
  box-shadow: 0 0 10px rgba(57, 255, 143, 0.12);
}

.station-tune-btn {
  align-self: flex-start;
  color: var(--hud-green);
  background: none;
  border: 1px solid var(--hud-green-dim);
  padding: 5px 12px;
  font-family: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.station-tune-btn:hover { background: rgba(57, 255, 143, 0.14); }
.station-tune-btn.playing { background: rgba(57, 255, 143, 0.22); border-color: var(--hud-green); color: var(--hud-green); }

/* ---- search bar (project archive) ---- */
.search-bar { position: relative; margin-bottom: 18px; }
.search-icon {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.8rem;
  opacity: 0.5;
  pointer-events: none;
}
.search-input { padding-left: 34px; }
.search-clear-btn {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 0.9rem;
  cursor: pointer;
  padding: 4px 6px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s, color 0.15s;
}
.search-bar.has-query .search-clear-btn { opacity: 1; pointer-events: auto; }
.search-clear-btn:hover { color: var(--hud-green); }
.search-empty-msg {
  display: none;
  color: var(--text-dim);
  font-size: 0.82rem;
  padding: 18px 4px;
  text-align: center;
}
.search-empty-msg.show { display: block; }

/* ---- color palette generator ---- */
.palette-grid { display: flex; gap: 10px; margin: 18px 0; }
.swatch {
  flex: 1;
  min-width: 0;
  aspect-ratio: 3 / 4;
  border: 1px solid var(--panel-border);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  cursor: pointer;
  position: relative;
  transition: transform 0.1s;
}
.swatch:hover { transform: translateY(-3px); }
.swatch-info { background: rgba(0, 0, 0, 0.55); padding: 7px 4px; text-align: center; }
.swatch-hex {
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 0.68rem;
  color: var(--text-main);
  display: block;
}
.swatch-lock {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 24px;
  height: 24px;
  border: 1px solid var(--panel-border);
  background: rgba(0, 0, 0, 0.5);
  color: var(--text-dim);
  font-size: 0.78rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.swatch-lock:hover { color: var(--hud-green); }
.swatch-lock.locked { color: var(--hud-green); border-color: var(--hud-green); background: rgba(57, 255, 143, 0.14); }
@media (max-width: 560px) {
  .palette-grid { flex-wrap: wrap; }
  .swatch { flex: 1 1 calc(33.33% - 8px); aspect-ratio: 1 / 1; }
}

/* ---- text diff checker ---- */
.diff-output {
  width: 100%;
  max-height: 420px;
  overflow: auto;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 0.8rem;
  line-height: 1.55;
}
.diff-line { padding: 1px 10px; white-space: pre-wrap; word-break: break-word; }
.diff-line .diff-marker { display: inline-block; width: 1.4em; opacity: 0.7; }
.diff-line.added { background: rgba(57, 255, 143, 0.12); color: var(--hud-green); }
.diff-line.removed { background: rgba(255, 70, 85, 0.12); color: var(--hud-red); }
.diff-line.same { color: var(--text-dim); }

/* ---- generic show/hide utility (mode tabs, etc.) ---- */
.hidden { display: none; }

/* ---- stopwatch / timer ---- */
/* Uses a color/background keyframe, not `transition: opacity` — anything
   under .hud-panel (backdrop-filter: blur) gets stuck mid-fade with an
   opacity transition in this Chromium version, so alerts flash color instead. */
.timer-alert { animation: timer-flash 0.5s steps(2) 6; }
@keyframes timer-flash {
  50% { background: rgba(255, 70, 85, 0.28); color: var(--hud-red); }
}

/* ---- image to ASCII art ---- */
/* Deliberately not .tool-output: that wraps long lines, which shears the
   picture in half. ASCII art needs `pre` and a line-height of exactly 1. */
.ascii-output {
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid var(--panel-border);
  color: var(--hud-green);
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 7px;
  line-height: 1;
  letter-spacing: 0;
  white-space: pre;
  overflow: auto;
  max-height: 560px;
  padding: 10px;
  margin: 0 0 16px;
  box-sizing: border-box;
}

/* ---- audio spectrum analyzer ---- */
/* A canvas with no intrinsic ratio needs an explicit CSS height, otherwise it
   collapses to the default 150px and the drawing buffer resizes every frame. */
.viz-canvas {
  display: block;
  width: 100%;
  height: 240px;
  background: #050b10;
  border: 1px solid var(--panel-border);
  box-sizing: border-box;
}

/* ---- contrast checker ---- */
.colour-row { display: flex; gap: 8px; align-items: center; }
.colour-row .tool-text-input { flex: 1; min-width: 0; }
/* The preview sets its own colours inline — that is the entire point of it,
   so nothing here may specify a colour or background. */
.wcag-preview {
  border: 1px solid var(--panel-border);
  padding: 18px 16px;
  line-height: 1.5;
}
.wcag-preview p { margin: 0 0 10px; }
.wcag-preview p:last-child { margin-bottom: 0; }
.wcag-small { font-size: 16px; }
.wcag-bold { font-size: 18.66px; font-weight: 700; }
.wcag-large { font-size: 24px; }

/* ---- CSS playground ---- */
.css-preview {
  border: 1px solid var(--panel-border);
  min-height: 220px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: repeating-conic-gradient(rgba(255,255,255,0.04) 0% 25%, transparent 0% 50%) 50% / 16px 16px;
  padding: 26px;
  box-sizing: border-box;
}
.css-swatch { width: 100%; height: 200px; }
.css-shadow-box {
  width: 190px;
  height: 130px;
  background: var(--text-main);
  border-radius: 8px;
}
.stop-row { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.stop-row .tool-text-input { flex: 1; min-width: 0; }
.stop-row input[type="range"] { flex: 2; accent-color: var(--hud-green); }
.stop-remove {
  background: rgba(0,0,0,0.3);
  border: 1px solid var(--panel-border);
  color: var(--text-dim);
  cursor: pointer;
  font-family: inherit;
  padding: 6px 10px;
}
.stop-remove:hover { color: var(--hud-red); border-color: var(--hud-red); }

/* ---- regex NFA visualizer ---- */
.nfa-canvas {
  display: block;
  width: 100%;
  height: 380px;
  background: #050b10;
  border: 1px solid var(--panel-border);
  box-sizing: border-box;
}
.tape { display: flex; flex-wrap: wrap; gap: 4px; margin: 12px 0; }
.tape-cell {
  border: 1px solid var(--panel-border);
  padding: 6px 9px;
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 0.9rem;
  color: var(--text-dim);
  min-width: 12px;
  text-align: center;
}
.tape-cell.done { color: var(--hud-green); border-color: var(--hud-green-dim); }
.tape-cell.current { color: var(--bg-deep); background: var(--hud-green); border-color: var(--hud-green); }

/* ---- favicon generator ---- */
.icon-previews { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-end; margin: 16px 0; }
.icon-preview { text-align: center; }
.icon-preview canvas {
  display: block;
  border: 1px solid var(--panel-border);
  background: repeating-conic-gradient(rgba(255,255,255,0.06) 0% 25%, transparent 0% 50%) 50% / 8px 8px;
  image-rendering: pixelated;
}
.icon-preview span {
  display: block;
  margin-top: 5px;
  font-size: 0.6rem;
  letter-spacing: 0.05em;
  color: var(--text-dim);
}

/* ---- path tracer ---- */
.trace-canvas {
  display: block;
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  border: 1px solid var(--panel-border);
  background: #050b10;
  image-rendering: auto;
}

/* ---- colour swatch input (meme generator) ---- */
.tool-color-input {
  width: 46px;
  height: 34px;
  padding: 2px;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  cursor: pointer;
}
.tool-color-input:focus { outline: none; border-color: var(--hud-green); }

/* ---- phone-sized touch targets + small-screen layout (2026-08-13) ----
   These controls were laid out for a mouse and land between 15px and 37px
   tall, well under the ~44px a thumb reliably hits. Everything sizing-related
   here is scoped to the phone breakpoint, so the desktop layout is untouched.
   This block is identical across every tool subdomain — keep it in sync. */
.tool-btn, .hud-tab, .logout-link, .home-link, .tool-select, .tool-file-input,
.tip-quick-btn, .station-tune-btn, .mute-btn, .swatch-lock, .stop-remove,
.dl, .login-btn, .hud-btn, .search-clear-btn, .tv-power-btn {
  touch-action: manipulation;
}
/* A grid track floors at its content's min-content width unless told
   otherwise, which is how one wide canvas drags the whole page sideways. */
.two-col > * { min-width: 0; }

@media (max-width: 560px) {
  .tool-btn,
  .tool-select,
  .tool-file-input,
  .tool-color-input,
  .tool-text-input,
  .tip-quick-btn,
  .station-tune-btn,
  .mute-btn { min-height: 44px; }

  .tool-btn { padding: 12px 18px; }
  /* Square icon button — it needs the width as much as the height. */
  .mute-btn { min-width: 44px; }

  .hud-tab {
    min-height: 44px;
    padding: 10px 12px;
    flex: 1 1 30%;
    text-align: center;
  }

  .nav-links .logout-link,
  .nav-links .home-link,
  .callsign-row .home-link {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  input[type="range"] { height: 44px; }

  .tool-check { min-height: 44px; }
  .tool-check input { width: 20px; height: 20px; }

  .swatch-lock { width: 40px; height: 40px; }
  .stop-remove { min-height: 44px; min-width: 44px; }
  .search-clear-btn { min-height: 44px; min-width: 44px; }
  .hud-btn { min-height: 44px; }
  .tv-power-btn { min-height: 44px; }

  /* Hub card actions and the login chip — the primary tap on those pages. */
  a.dl,
  .login-btn {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  /* Three selects side by side cannot fit a phone — stack them instead of
     letting the row push the page wider than the viewport. */
  .tool-dim-row { flex-wrap: wrap; }
  .tool-dim-row > div { flex: 1 1 100%; min-width: 0; }
}

/* ---- perf-lite -------------------------------------------------------------
   Toggled on <html> by the inline perf-lite snippet (low-power devices) or by
   the user's "reduce effects" preference. The starfield itself stays: it is a
   compositor transform now and costs essentially nothing. What this drops are
   the two effects that force full-viewport work every frame -- mix-blend-mode
   compositing and backdrop-filter blur. */
.perf-lite { --bg-panel: rgba(12, 26, 22, 0.95); }
.perf-lite .scanlines { mix-blend-mode: normal; opacity: 0.4; }
.perf-lite .starfield,
.perf-lite .asteroid,
.perf-lite .asteroid-spin { animation: none; }
.perf-lite *,
.perf-lite *::before,
.perf-lite *::after {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}

/* ---- loan-calculator ------------------------------------------------------
   Input grid, the principal/interest split bar, and the two canvas charts.
   Every figure on this page is a number, so nothing here may use "Press Start
   2P" — that face renders 8 as S and 0 as O, which on a mortgage total would
   be genuinely misleading. */

/* ---- shared tool components (used by several of the 2026-08-21 batch) -----
   Readout tiles, scrolling result tables and the error variant of .tool-note.
   Every value shown through these is a number, an address or a hex string, so
   nothing here may use "Press Start 2P" — that face renders 8 as S and 0 as O. */

.net-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 12px;
  margin: 16px 0;
}
.net-grid > * { min-width: 0; }

.net-tile {
  border: 1px solid var(--panel-border);
  background: rgba(0, 0, 0, 0.25);
  padding: 10px 12px;
}
.net-tile-label {
  font-size: 0.6rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 6px;
}
.net-tile-value {
  font-size: 0.85rem;
  color: var(--hud-green);
  line-height: 1.45;
  /* Addresses and 39-digit counts must wrap rather than widen the grid. */
  overflow-wrap: anywhere;
}
.net-tile-value.mono {
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
}

.net-table-wrap {
  /* Four columns of IPv6 will not fit a phone; the table scrolls inside its
     own box rather than dragging the page sideways. */
  overflow-x: auto;
  margin: 12px 0 20px;
  border: 1px solid var(--panel-border);
}
.net-table {
  width: 100%;
  border-collapse: collapse;
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 0.75rem;
  white-space: nowrap;
}
.net-table th {
  text-align: left;
  padding: 8px 12px;
  background: rgba(57, 255, 143, 0.08);
  color: var(--text-dim);
  font-size: 0.6rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--panel-border);
}
.net-table td {
  padding: 7px 12px;
  color: var(--text-main);
  border-bottom: 1px solid rgba(57, 255, 143, 0.12);
}
.net-table tr:last-child td { border-bottom: none; }
.net-table td.yes { color: var(--hud-green); }
.net-table td.no { color: var(--hud-red); }

.cert-section-label {
  font-size: 0.6rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin: 16px 0 8px;
}

/* Errors reuse .tool-note but need to read as a problem, not a footnote. */
.tool-note[role="alert"] {
  color: var(--hud-red);
  white-space: pre-line;
  display: none;
  margin-bottom: 12px;
}

@media (max-width: 560px) {
  .net-table { font-size: 0.68rem; }
  .net-table th, .net-table td { padding: 6px 8px; }
}


/* ---- finding cards (shared by unicode-inspector and exif-viewer) ----------
   A coloured left edge carries the severity; there is no transition on
   opacity anywhere, because anything under .hud-panel gets stuck at its
   starting opacity in this Chromium. */

.finding {
  border: 1px solid var(--panel-border);
  border-left-width: 3px;
  background: rgba(0, 0, 0, 0.22);
  padding: 12px 14px;
  margin: 0 0 12px;
}
.finding.bad { border-left-color: var(--hud-red); }
.finding.warn { border-left-color: var(--hud-orange); }
.finding.info { border-left-color: var(--text-dim); }
.finding.good { border-left-color: var(--hud-green); }

.finding-title {
  font-size: 0.8rem;
  margin-bottom: 6px;
  color: var(--hud-green);
}
.finding.bad .finding-title { color: var(--hud-red); }
.finding.warn .finding-title { color: var(--hud-orange); }

.finding-detail {
  margin: 0;
  font-size: 0.72rem;
  line-height: 1.55;
  color: var(--text-dim);
}
.finding-list {
  margin: 8px 0 0;
  padding-left: 18px;
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 0.7rem;
  line-height: 1.6;
  color: var(--text-main);
}

@media (max-width: 560px) {
  .finding-list { padding-left: 14px; }
}


.field-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px;
  margin-bottom: 18px;
}
.field-grid > * { min-width: 0; margin-bottom: 0; }

.net-tile.highlight {
  border-color: var(--hud-green);
  background: rgba(57, 255, 143, 0.08);
}
.net-tile.highlight .net-tile-value { font-size: 1.05rem; }

.split-bar {
  display: flex;
  height: 34px;
  border: 1px solid var(--panel-border);
  margin: 8px 0 12px;
  overflow: hidden;
}
.split-part {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "Consolas", "SFMono-Regular", Menlo, Monaco, "Courier New", monospace;
  font-size: 0.68rem;
  white-space: nowrap;
  overflow: hidden;
}
.split-part.principal {
  background: rgba(57, 255, 143, 0.22);
  color: var(--hud-green);
}
.split-part.interest {
  background: rgba(255, 145, 48, 0.22);
  color: var(--hud-orange);
}

.chart-frame {
  border: 1px solid var(--panel-border);
  background: rgba(0, 0, 0, 0.28);
  padding: 8px;
  margin-bottom: 12px;
}
.chart-frame canvas {
  /* The canvas has a fixed drawing buffer; CSS scales it to the panel. Without
     an explicit height it would collapse to the default 150px. */
  display: block;
  width: 100%;
  height: auto;
  max-height: 300px;
}

.net-table td.interest-cell { color: var(--hud-orange); }

@media (max-width: 560px) {
  .field-grid { grid-template-columns: 1fr; gap: 10px; }
  .split-part { font-size: 0.6rem; }
  .chart-frame { padding: 4px; }
}

/* ---- calendar ---------------------------------------------------------------
   Every grid track here carries `min-width: 0`. A CSS grid `1fr` track floors
   at its content's min-content width, so a long event title in one day cell
   would otherwise drag the whole page sideways on a phone — the same overflow
   bug image-to-vector hit in the 2026-08-13 touch pass.
   ---------------------------------------------------------------------------- */

.cal-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.cal-nav { display: flex; gap: 6px; flex: 0 0 auto; }
.cal-arrow { padding: 9px 13px; }
.cal-period {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-size: 0.95rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--hud-green);
  text-align: center;
}
.cal-actions { flex: 0 0 auto; }
.tool-btn.primary { color: var(--bg-deep); background: var(--hud-green); border-color: var(--hud-green); }
.tool-btn.primary:hover { background: #6bffb0; }
.tool-btn.danger { color: var(--hud-red); border-color: rgba(255, 70, 85, 0.5); }
.tool-btn.danger:hover { background: rgba(255, 70, 85, 0.14); border-color: var(--hud-red); }

.cal-weekdays {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 2px;
  margin-bottom: 2px;
}
.weekday-cell {
  min-width: 0;
  padding: 6px 4px;
  font-size: 0.64rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  text-align: center;
  color: var(--text-dim);
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--panel-border);
}
/* The week/day headers gain a gutter column to line up with the hour labels. */
.cal-weekdays.week-head { grid-template-columns: 52px repeat(auto-fit, minmax(0, 1fr)); }
.time-gutter-head { border: 1px solid transparent; }
.day-head-cell {
  font-family: inherit;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 2px;
  align-items: center;
}
.day-head-cell .dh-num { font-size: 0.95rem; color: var(--text-main); }
.day-head-cell.is-today { border-color: var(--hud-green); color: var(--hud-green); }
.day-head-cell.is-today .dh-num { color: var(--hud-green); }

.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  grid-auto-rows: minmax(92px, auto);
  gap: 2px;
  margin-bottom: 20px;
}
.day-cell {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 3px;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--panel-border);
  overflow: hidden;
}
.day-cell.other-month { opacity: 0.42; }
.day-cell.is-today { border-color: var(--hud-green); background: rgba(57, 255, 143, 0.07); }
.day-num {
  align-self: flex-start;
  font-family: inherit;
  font-size: 0.72rem;
  color: var(--text-dim);
  background: none;
  border: 1px solid transparent;
  padding: 2px 6px;
  cursor: pointer;
  flex: 0 0 auto;
}
.day-num:hover { color: var(--hud-green); border-color: var(--hud-green-dim); }
.day-cell.is-today .day-num { color: var(--hud-green); }
.day-events { display: flex; flex-direction: column; gap: 2px; min-width: 0; overflow: hidden; }

.ev-chip {
  display: flex;
  gap: 5px;
  align-items: baseline;
  min-width: 0;
  width: 100%;
  font-family: inherit;
  font-size: 0.66rem;
  text-align: left;
  padding: 3px 5px;
  cursor: pointer;
  border: 1px solid;
  background: rgba(0, 0, 0, 0.4);
}
.ev-chip-time { flex: 0 0 auto; opacity: 0.75; font-size: 0.6rem; }
.ev-chip-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.day-more {
  font-family: inherit;
  font-size: 0.6rem;
  text-align: left;
  color: var(--text-dim);
  background: none;
  border: none;
  padding: 2px 5px;
  cursor: pointer;
}
.day-more:hover { color: var(--hud-green); }

/* Event colours. Each is a border + a tinted background, so a chip stays
   legible against the panel in both the normal and perf-lite themes. */
.c-green  { border-color: var(--hud-green-dim); color: var(--hud-green); background: rgba(57, 255, 143, 0.13); }
.c-orange { border-color: #a55e18; color: var(--hud-orange); background: rgba(255, 145, 48, 0.13); }
.c-cyan   { border-color: #1b7d8f; color: #4fe6ff; background: rgba(79, 230, 255, 0.13); }
.c-violet { border-color: #6c4bb8; color: #c3a6ff; background: rgba(195, 166, 255, 0.13); }
.c-red    { border-color: #a52833; color: var(--hud-red); background: rgba(255, 70, 85, 0.13); }

/* ---- extra calendars (generated overlay days) ----
   These sit BESIDE your own events and must read as clearly secondary: no
   filled background, a dashed leading edge, and dimmed text. They keep the
   plain .ev-chip / .ev-block base class on purpose -- that is what the phone
   rule further down (`.cal-grid .ev-chip { pointer-events: none }`) selects
   on to hand a tap through to the day cell underneath. */
.ev-chip.is-overlay,
.ev-block.is-overlay {
  background: rgba(0, 0, 0, 0.28);
  border-style: dashed;
  border-left-width: 3px;
  border-left-style: solid;
  opacity: 0.86;
}
.ev-chip.is-overlay:hover,
.ev-block.is-overlay:hover { opacity: 1; }
.ev-chip-glyph {
  flex: 0 0 auto;
  font-size: 0.62rem;
  line-height: 1;
  opacity: 0.9;
}
.ev-chip.k-launch .ev-chip-glyph,
.ev-block.k-launch .ev-chip-glyph { color: #4fe6ff; }

/* The read-only detail sheet */
.info-when {
  margin: 0 0 10px;
  font-size: 0.8rem;
  color: var(--hud-green);
  letter-spacing: 0.04em;
}
.info-note {
  margin: 0 0 12px;
  font-size: 0.76rem;
  line-height: 1.55;
  color: var(--text-dim);
}
.info-meta {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 14px;
  margin: 0 0 14px;
  font-size: 0.74rem;
}
.info-meta dt { color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.66rem; }
.info-meta dd { margin: 0; color: var(--text-main); }
a.tool-btn.info-link { display: inline-flex; align-items: center; text-decoration: none; }

/* Birthdays: the list reuses .up-item, plus a trailing Remove button that
   must not stretch the row. */
.bday-del { flex: 0 0 auto; align-self: center; font-size: 0.66rem; padding: 5px 10px; }
.up-item .bday-del { margin-left: auto; }
/* .tool-text-input is width:100%, which is right in the editor's grid and
   wrong in a flex row -- both fields would each claim the whole line. */
.bday-name { flex: 1 1 170px; width: auto; max-width: 260px; min-width: 0; }
.bday-date { flex: 0 1 185px; width: auto; min-width: 0; }
.ev-chip .ev-chip-glyph + .ev-chip-title { min-width: 0; }

/* Layer switches */
.layer-group {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 18px;
  margin-bottom: 6px;
}
.layer-label {
  flex: 0 0 auto;
  min-width: 118px;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--text-dim);
}
.layer-group .tool-checks { margin: 0; flex: 1 1 260px; }
.cal-help.fine { font-size: 0.7rem; opacity: 0.8; }

/* ---- week / day time grid ---- */
.allday-strip {
  display: grid;
  grid-template-columns: 52px repeat(auto-fit, minmax(0, 1fr));
  gap: 2px;
  margin-bottom: 2px;
}
.allday-strip.empty { display: none; }
.allday-label {
  font-size: 0.58rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: 4px;
  align-self: center;
}
.allday-col {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 2px;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--panel-border);
  min-height: 26px;
}

.time-scroll {
  max-height: 560px;
  overflow: auto;
  border: 1px solid var(--panel-border);
  margin-bottom: 20px;
}
/* Everything that has to stay column-aligned lives in here, so one horizontal
   scroll moves the header, the all-day strip and the hour grid together. */
.time-inner { min-width: 100%; }
.time-inner .cal-weekdays.week-head,
.time-inner .allday-strip { margin: 0; }
/* Keep the day names in view while scrolling down through the hours. Needs an
   opaque background or the hour grid shows through it. */
.time-inner .cal-weekdays.week-head {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--bg-deep);
}
.time-grid {
  display: grid;
  grid-template-columns: 52px repeat(7, minmax(0, 1fr));
  min-height: 1200px;
}
.time-grid.day-mode { grid-template-columns: 52px minmax(0, 1fr); }
.time-gutter { display: grid; grid-template-rows: repeat(24, 1fr); min-width: 0; }
.hour-label {
  font-size: 0.58rem;
  color: var(--text-dim);
  text-align: right;
  padding-right: 6px;
  border-right: 1px solid var(--panel-border);
  position: relative;
}
/* Sit the label on the line it names rather than centred in the hour block. */
.hour-label span { position: absolute; top: -0.4em; right: 6px; }
.time-col {
  position: relative;
  min-width: 0;
  display: grid;
  grid-template-rows: repeat(24, 1fr);
  border-left: 1px solid rgba(57, 255, 143, 0.14);
}
.time-col.is-today { background: rgba(57, 255, 143, 0.045); }
.hour-slot {
  border: none;
  border-top: 1px solid rgba(57, 255, 143, 0.11);
  background: none;
  cursor: pointer;
  padding: 0;
  min-width: 0;
}
.hour-slot:hover { background: rgba(57, 255, 143, 0.08); }
.ev-block {
  position: absolute;
  display: flex;
  flex-direction: column;
  gap: 1px;
  overflow: hidden;
  min-width: 0;
  font-family: inherit;
  font-size: 0.64rem;
  text-align: left;
  padding: 2px 4px;
  cursor: pointer;
  border: 1px solid;
  background: rgba(0, 0, 0, 0.55);
}
.ev-block-time { font-size: 0.58rem; opacity: 0.8; }
.ev-block-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.now-line {
  position: absolute;
  left: 0;
  right: 0;
  height: 0;
  border-top: 1px solid var(--hud-red);
  pointer-events: none;
  z-index: 2;
}

/* ---- upcoming list ---- */
.cal-section-title {
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--hud-orange);
  margin: 22px 0 10px;
}
.up-item { display: flex; gap: 12px; align-items: baseline; }
.up-when { flex: 0 0 auto; min-width: 84px; }
.up-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.up-title {
  font-family: inherit;
  font-size: 0.82rem;
  text-align: left;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
.up-title:hover { text-decoration: underline; }
.up-meta { font-size: 0.68rem; color: var(--text-dim); }
.cal-empty, .cal-help { font-size: 0.74rem; color: var(--text-dim); line-height: 1.6; }

/* ---- import / export row ---- */
.cal-io-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 12px 0; }
.io-label { margin: 0; flex: 0 0 auto; }
.cal-status {
  font-size: 0.72rem;
  color: var(--hud-green);
  border-left: 2px solid var(--hud-green-dim);
  padding: 6px 10px;
  background: rgba(57, 255, 143, 0.06);
}
.cal-status.error { color: var(--hud-red); border-left-color: var(--hud-red); background: rgba(255, 70, 85, 0.07); }
.cal-error {
  font-size: 0.74rem;
  color: var(--hud-red);
  border-left: 2px solid var(--hud-red);
  padding: 6px 10px;
  margin: 0 0 12px;
}

/* ---- editor dialog ----
   No `transition: opacity` anywhere in here: the dialog is a descendant of
   .hud-panel, whose backdrop-filter permanently freezes an opacity transition
   at its starting value in this Chromium. Show/hide is instant on purpose. */
.cal-modal {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 24px 12px;
  overflow-y: auto;
  background: rgba(2, 6, 9, 0.82);
}
/* The sitewide `.hidden { display: none }` utility is declared ~700 lines
   above this, so at equal specificity the `display: flex` on .cal-modal wins
   and a "hidden" dialog stays laid out -- a fixed, inset:0 sheet that eats
   every click on the page underneath. Restate it with both classes so the
   source order stops mattering. */
.cal-modal.hidden { display: none; }

.cal-dialog {
  width: 100%;
  max-width: 620px;
  background: var(--bg-panel);
  border: 1px solid var(--hud-green-dim);
  padding: 20px;
  box-shadow: 0 0 26px rgba(0, 0, 0, 0.7);
}
.cal-dialog.narrow { max-width: 440px; }
.cal-dialog h3 {
  margin: 0 0 16px;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--hud-green);
}
.cal-dialog .field-grid { margin-bottom: 12px; }
.cal-dialog .tool-field-row.full { grid-column: 1 / -1; }
.cal-dialog-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 6px; }
.scope-text { font-size: 0.78rem; line-height: 1.6; margin: 0 0 16px; }
.rrule-summary {
  font-size: 0.7rem;
  color: var(--hud-orange);
  margin: 0;
  line-height: 1.5;
}
.byday-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.byday-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.68rem;
  color: var(--text-main);
  border: 1px solid var(--panel-border);
  padding: 6px 8px;
  cursor: pointer;
  min-height: 34px;
}
.byday-chip input { accent-color: var(--hud-green); width: 14px; height: 14px; }
.byday-chip:has(input:checked) { border-color: var(--hud-green); color: var(--hud-green); }

/* ---- calendar on a phone ----
   Deliberately the last block in this file. The sitewide 44px block sits
   ~500 lines above, and later rules win at equal specificity, so anything
   here that resizes a control has to restate the 44px floor itself. */
@media (max-width: 620px) {
  .cal-toolbar { gap: 8px; }
  .cal-period { order: -1; flex: 1 0 100%; text-align: left; font-size: 0.85rem; }
  .cal-nav, .cal-actions { flex: 1 1 auto; }
  .cal-actions .tool-btn { width: 100%; }
  .cal-toolbar .tool-btn { min-height: 44px; }

  .cal-nav .tool-btn, .cal-arrow { min-width: 44px; }

  /* Seven columns across a 390px screen is ~50px a day, so nothing inside a
     month cell can be a 44px target without covering its neighbours. Rather
     than inflate hit areas that would overlap, the cell itself becomes one
     large target that opens the day view, and its contents become display
     only. Keyboard activation still works -- pointer-events only redirects
     taps, not Enter on a focused button. */
  .cal-grid { grid-auto-rows: minmax(72px, auto); }
  .day-cell { cursor: pointer; }
  .cal-grid .day-num, .cal-grid .ev-chip, .cal-grid .day-more { pointer-events: none; }
  .weekday-cell { font-size: 0.56rem; padding: 5px 1px; }
  .day-num { min-height: 28px; padding: 4px 7px; }
  .ev-chip { font-size: 0.6rem; padding: 4px; }
  /* Below this width the time is what gets cut, not the title. */
  .ev-chip-time { display: none; }

  /* Same reasoning one level down: a week column is ~50px wide, so its blocks
     are display-only and the day header above opens the day view. A day-view
     column has the full width, so blocks there stay tappable -- the hour rows
     are stretched so a 44px floor is about 35 minutes rather than an hour. */
  /* A 7-column week does not fit 390px at a tappable size, so the whole thing
     scrolls sideways inside .time-scroll at a floor of 56px a column. The page
     body itself still never scrolls horizontally. */
  .week-inner { min-width: 432px; }
  .time-grid.day-mode { min-height: 1800px; }
  .ev-block { min-height: 44px; }
  .allday-col .ev-chip { min-height: 44px; }
  .time-scroll { max-height: 440px; }

  .cal-weekdays.week-head, .allday-strip { grid-template-columns: 40px repeat(auto-fit, minmax(0, 1fr)); }
  .time-grid { grid-template-columns: 40px repeat(7, minmax(0, 1fr)); }
  .time-grid.day-mode { grid-template-columns: 40px minmax(0, 1fr); }
  .hour-label { font-size: 0.52rem; padding-right: 3px; }
  .hour-label span { right: 3px; }
  .time-scroll { max-height: 400px; }

  .up-item { flex-direction: column; gap: 3px; }
  .up-when { min-width: 0; }
  .up-title { min-height: 44px; display: flex; align-items: center; }

  .cal-io-row { flex-direction: column; align-items: stretch; }
  .cal-io-row .tool-btn { min-height: 44px; width: 100%; }
  .cal-io-row .tool-file-input { min-height: 44px; }

  .cal-dialog { padding: 14px; }
  .cal-dialog-actions .tool-btn { flex: 1 1 auto; min-height: 44px; }
  .byday-chip { min-height: 44px; flex: 1 1 28%; justify-content: center; }
}

/* ---- account sync row ----
   Appended after the calendar's own phone block, so anything here that sizes a
   control has to restate the 44px floor itself. */
.sync-toggle {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 44px;
  border: 1px solid var(--panel-border);
  padding: 0 12px;
  cursor: pointer;
}
.sync-toggle:has(input:checked) { border-color: var(--hud-green); color: var(--hud-green); }
.cal-help a { color: var(--hud-green); }
#sync-now-btn[disabled], #sync-toggle[disabled] { opacity: 0.45; cursor: not-allowed; }
.sync-toggle:has(input[disabled]) { opacity: 0.45; cursor: not-allowed; }

@media (max-width: 620px) {
  .sync-toggle { flex: 1 1 100%; }
}
