/* visitormap dashboard styles.
   Hand-written, no framework, no build step.

   Spacing rule: layout containers own ALL vertical rhythm via `gap`. No element
   sets its own margin-bottom. That is what keeps every gap on the page
   identical no matter which mix of cards, grids and tables a page happens to
   use — the previous version spread spacing across three mechanisms and they
   disagreed with each other. */

:root {
  --gap: 18px;
  --radius: 14px;
  --radius-sm: 9px;

  /* Dark (default) */
  --bg: #14131c;
  --bg-tint: #191826;
  --surface: #1d1b28;
  --surface-2: #262333;
  --line: #322e42;
  --line-soft: #272433;
  --ink: #f3f1f8;
  --ink-dim: #aaa3c0;
  --ink-faint: #7b7391;
  --accent: #a78bfa;
  --accent-hi: #c4b5fd;
  --accent-ink: #191228;
  --accent-wash: rgba(167, 139, 250, .14);
  --danger: #f87171;
  --danger-wash: rgba(248, 113, 113, .12);
  --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 8px 24px -12px rgba(0, 0, 0, .5);
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #f6f5fa;
    --bg-tint: #ffffff;
    --surface: #ffffff;
    --surface-2: #f2f0f7;
    --line: #e2dfec;
    --line-soft: #ece9f3;
    --ink: #1c1926;
    --ink-dim: #5d5673;
    --ink-faint: #8b849f;
    --accent: #7c5cf5;
    --accent-hi: #6944f0;
    --accent-ink: #ffffff;
    --accent-wash: rgba(124, 92, 245, .1);
    --danger: #dc2626;
    --danger-wash: rgba(220, 38, 38, .07);
    --shadow: 0 1px 2px rgba(28, 25, 38, .05), 0 8px 24px -14px rgba(28, 25, 38, .18);
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent-hi); text-decoration: none; }
a:hover { text-decoration: underline; }

h1 { font-size: 1.45rem; margin: 0; letter-spacing: -.02em; font-weight: 650; }
h2 {
  font-size: .72rem; margin: 0; color: var(--ink-faint);
  text-transform: uppercase; letter-spacing: .09em; font-weight: 650;
}

code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: var(--surface-2); padding: .12em .4em;
  border-radius: 5px; font-size: .9em;
}

.muted { color: var(--ink-faint); }

/* --- nav ----------------------------------------------------------------- */

.nav {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 1rem;
  padding: .7rem 1.4rem;
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg) 85%, transparent);
  backdrop-filter: blur(10px);
}
.nav .brand {
  font-weight: 700; letter-spacing: -.02em; color: var(--ink); font-size: .95rem;
}
.nav .spacer { flex: 1; }
.nav .who { color: var(--ink-faint); font-size: .82rem; }
.inline { display: inline; margin: 0; }
.linkish {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--ink-dim); font: inherit; font-size: .82rem;
}
.linkish:hover { color: var(--ink); text-decoration: underline; }

/* The single source of vertical rhythm for every page. */
.wrap {
  max-width: 1120px; margin: 0 auto; padding: var(--gap) 1.4rem 4rem;
  display: grid; gap: var(--gap); align-content: start;
}

/* --- cards --------------------------------------------------------------- */

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.15rem 1.25rem;
  display: grid; gap: .85rem; align-content: start;
  min-width: 0;
}
.panel.narrow { max-width: 480px; }
.panel.danger { border-color: color-mix(in srgb, var(--danger) 35%, var(--line)); }
.panel.flush { padding: 0; overflow: hidden; }
.panel.flush > h2 { padding: 1.15rem 1.25rem 0; }

.empty { color: var(--ink-faint); margin: 0; font-size: .9rem; }
.hint { color: var(--ink-faint); font-size: .82rem; margin: 0; }
.alt { color: var(--ink-faint); font-size: .85rem; margin: 0; }

/* --- page header --------------------------------------------------------- */

.page-head {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
}
.page-head .titles { display: grid; gap: .15rem; min-width: 0; }
.page-head .sub { color: var(--ink-faint); font-size: .85rem; }
.page-head .back { font-size: .82rem; color: var(--ink-faint); }
.page-head .back:hover { color: var(--ink); }
.head-actions { margin-left: auto; display: flex; gap: .5rem; }

/* --- embed strip --------------------------------------------------------- */

.embed { display: grid; gap: .6rem; grid-template-columns: 1fr auto; align-items: center; }
.embed > h2 { grid-column: 1 / -1; }
.snippet {
  width: 100%; min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .76rem; line-height: 1.5; color: var(--ink-dim);
  background: var(--surface-2); border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm); padding: .6rem .7rem; resize: none;
  white-space: pre; overflow-x: auto;
}

/* --- hero (landing) ------------------------------------------------------ */

.hero { display: grid; gap: .8rem; padding: 2.5rem 0 1rem; justify-items: start; }
.hero h1 { font-size: clamp(1.9rem, 5vw, 2.6rem); }
.lede { color: var(--ink-dim); font-size: 1.05rem; max-width: 34rem; margin: 0; }
.hero-cta { display: flex; gap: .6rem; flex-wrap: wrap; }
.steps { margin: 0; padding-left: 1.15rem; color: var(--ink-dim); display: grid; gap: .3rem; }

/* --- forms --------------------------------------------------------------- */

.stack { display: grid; gap: .75rem; justify-items: stretch; }
.stack label, .colors label {
  display: grid; gap: .3rem; font-size: .8rem; color: var(--ink-dim); min-width: 0;
}

input, textarea, button, select {
  font: inherit; color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm); padding: .5rem .65rem;
}
input:focus-visible, textarea:focus-visible, button:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}

button, .cta, .cta-alt {
  border-radius: var(--radius-sm); font-weight: 600; font-size: .875rem;
  cursor: pointer; padding: .5rem .95rem; border: 1px solid transparent;
  transition: background .12s ease, border-color .12s ease;
}
button, .cta { background: var(--accent); color: var(--accent-ink); border: 0; }
button:hover, .cta:hover { background: var(--accent-hi); text-decoration: none; }
.stack > button, .btn-row > button { justify-self: start; }

.btn-ghost, .cta-alt {
  background: transparent; color: var(--ink); border: 1px solid var(--line);
}
.btn-ghost:hover, .cta-alt:hover {
  background: var(--surface-2); border-color: var(--accent); text-decoration: none;
}
.danger-btn { background: var(--danger); color: #fff; }
.danger-btn:hover { background: var(--danger); filter: brightness(1.1); }

.colors { display: grid; gap: .6rem; grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr)); }

/* --- notices ------------------------------------------------------------- */

.notice {
  padding: .55rem .75rem; border-radius: var(--radius-sm);
  margin: 0; font-size: .875rem;
}
.notice-error {
  background: var(--danger-wash); color: var(--danger);
  border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent);
}
.notice-ok {
  background: rgba(52, 211, 153, .12); color: #34d399;
  border: 1px solid rgba(52, 211, 153, .3);
}

/* --- site list ----------------------------------------------------------- */

.site-list { list-style: none; margin: 0; padding: 0; display: grid; }
.site-list li {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  padding: .7rem .25rem; border-bottom: 1px solid var(--line-soft);
}
.site-list li:last-child { border-bottom: 0; }
.site-name { font-weight: 600; }
.site-domain { color: var(--ink-faint); font-size: .82rem; }
.site-hits {
  margin-left: auto; color: var(--ink-dim); font-size: .78rem;
  font-variant-numeric: tabular-nums; background: var(--surface-2);
  padding: .2rem .5rem; border-radius: 999px;
}

/* --- stats --------------------------------------------------------------- */

.stats {
  display: grid; gap: var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}
.stat {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: .95rem 1.1rem; display: grid; gap: .1rem; align-content: start;
}
.stat-label {
  color: var(--ink-faint); font-size: .7rem; font-weight: 650;
  text-transform: uppercase; letter-spacing: .08em; order: -1;
}
.stat-value {
  font-size: 1.85rem; font-weight: 680; line-height: 1.15;
  font-variant-numeric: tabular-nums; letter-spacing: -.03em;
}
.stat-sub { color: var(--ink-faint); font-size: .78rem; }

/* --- layout grids -------------------------------------------------------- */

/* Map beside the country ranking: the two things you look at first, on one
   screen instead of stacked. Collapses below 900px. */
.split { display: grid; gap: var(--gap); grid-template-columns: minmax(0, 1.75fr) minmax(0, 1fr); }
.grid { display: grid; gap: var(--gap); grid-template-columns: repeat(auto-fit, minmax(255px, 1fr)); }
.row-2 { display: grid; gap: var(--gap); grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); align-items: start; }

@media (max-width: 900px) { .split { grid-template-columns: 1fr; } }

/* --- breakdown bars ------------------------------------------------------ */

.bars { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.bar-row {
  position: relative; display: flex; align-items: center; gap: .5rem;
  padding: .34rem .5rem; border-radius: 7px; overflow: hidden; font-size: .85rem;
}
.bar-fill {
  position: absolute; inset: 0 auto 0 0;
  background: var(--accent-wash); border-radius: 7px;
}
.bar-label {
  position: relative; flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bar-count {
  position: relative; color: var(--ink-dim);
  font-variant-numeric: tabular-nums; font-size: .78rem;
}
.flag { font-size: .95rem; }

/* --- hits table ---------------------------------------------------------- */

/* Capped so 50 rows scroll inside the card instead of stretching the page. */
.table-scroll { overflow: auto; max-height: 380px; }
.hits { width: 100%; border-collapse: collapse; font-size: .82rem; white-space: nowrap; }
.hits th {
  position: sticky; top: 0; z-index: 1;
  text-align: left; padding: .5rem .75rem; color: var(--ink-faint);
  font-weight: 650; font-size: .68rem; text-transform: uppercase;
  letter-spacing: .06em; background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.hits td { padding: .45rem .75rem; border-bottom: 1px solid var(--line-soft); }
.hits tbody tr:last-child td { border-bottom: 0; }
.hits tbody tr:hover td { background: var(--bg-tint); }
.hits .num { color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.hits .path { color: var(--ink-dim); max-width: 16rem; overflow: hidden; text-overflow: ellipsis; }

/* --- collapsible sections ------------------------------------------------ */

/* Settings and deletion are rare actions; collapsed they cost one line each
   instead of two full cards of scrolling. */
details.panel { gap: 0; }
details.panel > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: .5rem;
  font-size: .72rem; font-weight: 650; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-faint);
}
details.panel > summary::-webkit-details-marker { display: none; }
details.panel > summary::before {
  content: "›"; display: inline-block; font-size: 1.1rem; line-height: 1;
  transition: transform .15s ease; color: var(--ink-faint);
}
details.panel[open] > summary { margin-bottom: .95rem; }
details.panel[open] > summary::before { transform: rotate(90deg); }
details.panel > summary:hover { color: var(--ink); }

/* --- map preview --------------------------------------------------------- */

.map-card { padding: 0; overflow: hidden; gap: 0; }
.map-card svg { display: block; width: 100%; height: auto; }
.map-empty { padding: 1.15rem 1.25rem; }

@media (max-width: 620px) {
  :root { --gap: 14px; }
  .wrap { padding: var(--gap) .9rem 3rem; }
  .stat-value { font-size: 1.5rem; }
  .embed { grid-template-columns: 1fr; }
  .embed button { justify-self: start; }
}

/* ==========================================================================
   THEME TOGGLE CONTROL
   ========================================================================== */

/* The label is CSS-driven so it always matches the theme actually applied —
   no JavaScript keeping button text in sync with reality. It names the theme
   you would switch TO, not the one you are in. */
.theme-toggle {
  background: transparent; border: 1px solid var(--line); color: var(--ink-dim);
  font-size: .74rem; padding: .3rem .6rem; cursor: pointer;
  border-radius: var(--radius-sm); font-weight: 600;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--accent); background: var(--surface-2); }
.theme-toggle::after { content: "hacker mode"; }
:root[data-theme="hacker"] .theme-toggle::after { content: "normal mode"; }

/* ==========================================================================
   RETRO TERMINAL THEME  ("hacker")

   Selector is :root[data-theme="hacker"], which outranks both the :root dark
   default and the prefers-color-scheme:light block on specificity — so it wins
   regardless of the visitor's OS setting or source order.
   ========================================================================== */

:root[data-theme="hacker"] {
  --gap: 16px;
  --radius: 0;
  --radius-sm: 0;

  --bg: #040704;
  --bg-tint: #0a170a;
  --surface: #060d06;
  --surface-2: #0a170a;
  --line: #1c5c1c;
  --line-soft: #113811;
  --ink: #4dff7a;
  --ink-dim: #2ecc55;
  --ink-faint: #17a03a;
  --accent: #00ff41;
  --accent-hi: #9dffb4;
  --accent-ink: #020a02;
  --accent-wash: rgba(0, 255, 65, .16);
  --danger: #ff5f56;
  --danger-wash: rgba(255, 95, 86, .12);
  --shadow: 0 0 0 1px rgba(0, 255, 65, .05), 0 0 22px -8px rgba(0, 255, 65, .35);

  --mono: ui-monospace, "Cascadia Mono", Consolas, "DejaVu Sans Mono",
          "Liberation Mono", "Courier New", monospace;
}

:root[data-theme="hacker"] body {
  font-family: var(--mono);
  font-size: 13.5px;
  letter-spacing: .02em;
  color: var(--ink);
  text-shadow: 0 0 6px rgba(0, 255, 65, .3);
  background-image: radial-gradient(ellipse at 50% -10%, rgba(0, 255, 65, .07), transparent 62%);
}

:root[data-theme="hacker"] ::selection { background: var(--accent); color: #020a02; text-shadow: none; }

/* --- CRT overlays --------------------------------------------------------
   Both are fixed and pointer-events:none, so they sit over the whole page
   without ever intercepting a click. */

:root[data-theme="hacker"] body::before {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 9998;
  background: repeating-linear-gradient(to bottom,
    rgba(0, 0, 0, .26) 0 1px, transparent 1px 3px);
}
:root[data-theme="hacker"] body::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 9997;
  background: radial-gradient(ellipse at center, transparent 52%, rgba(0, 0, 0, .55));
  animation: crt-flicker 7s steps(1) infinite;
}
@keyframes crt-flicker {
  0%, 96%, 100% { opacity: 1; }
  97% { opacity: .82; }
  98% { opacity: 1; }
  99% { opacity: .9; }
}
@keyframes caret-blink { 50% { opacity: 0; } }

/* A flickering screen is a migraine trigger for some people, and this is
   decoration. Anyone who has asked their OS for less motion gets a steady one. */
@media (prefers-reduced-motion: reduce) {
  :root[data-theme="hacker"] body::after { animation: none; }
  :root[data-theme="hacker"] .nav .brand::after { animation: none; }
}

/* --- typography ---------------------------------------------------------- */

:root[data-theme="hacker"] h1 {
  text-transform: uppercase; letter-spacing: .06em; font-weight: 700;
  font-size: 1.2rem; color: var(--accent);
}
:root[data-theme="hacker"] h1::before { content: "> "; opacity: .75; }
:root[data-theme="hacker"] h2 { letter-spacing: .12em; color: var(--ink-faint); }
:root[data-theme="hacker"] h2::before { content: "// "; }
:root[data-theme="hacker"] .hero h1 { font-size: clamp(1.5rem, 4.2vw, 2.1rem); }

/* --- nav ----------------------------------------------------------------- */

:root[data-theme="hacker"] .nav {
  background: #030603; backdrop-filter: none;
  border-bottom: 1px solid var(--line);
}
:root[data-theme="hacker"] .nav .brand {
  color: var(--accent); text-transform: uppercase; letter-spacing: .16em;
}
:root[data-theme="hacker"] .nav .brand::before { content: "root@"; color: var(--ink-faint); }
:root[data-theme="hacker"] .nav .brand::after {
  content: "_"; color: var(--accent); animation: caret-blink 1.1s steps(1) infinite;
}

/* --- surfaces ------------------------------------------------------------ */

:root[data-theme="hacker"] .panel,
:root[data-theme="hacker"] .stat {
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
}
:root[data-theme="hacker"] .stat-value {
  color: var(--accent); font-weight: 700; letter-spacing: 0;
  text-shadow: 0 0 12px rgba(0, 255, 65, .5);
}
:root[data-theme="hacker"] .stat-label { color: var(--ink-faint); }

/* --- controls: drawn as terminal commands -------------------------------- */

:root[data-theme="hacker"] button,
:root[data-theme="hacker"] input,
:root[data-theme="hacker"] textarea { font-family: var(--mono); }

:root[data-theme="hacker"] input,
:root[data-theme="hacker"] textarea {
  background: #020602; border-color: var(--line);
  color: var(--ink); caret-color: var(--accent);
}
:root[data-theme="hacker"] input:focus-visible,
:root[data-theme="hacker"] textarea:focus-visible {
  outline-color: var(--accent); border-color: var(--accent);
}

/* .theme-toggle is excluded from the bracket treatment because it draws its
   own label through ::after; .linkish is plain text by design. */
:root[data-theme="hacker"] button:not(.theme-toggle):not(.linkish),
:root[data-theme="hacker"] .cta,
:root[data-theme="hacker"] .cta-alt {
  text-transform: uppercase; letter-spacing: .1em; font-weight: 700;
}
:root[data-theme="hacker"] button:not(.theme-toggle):not(.linkish)::before,
:root[data-theme="hacker"] .cta::before,
:root[data-theme="hacker"] .cta-alt::before { content: "[ "; }
:root[data-theme="hacker"] button:not(.theme-toggle):not(.linkish)::after,
:root[data-theme="hacker"] .cta::after,
:root[data-theme="hacker"] .cta-alt::after { content: " ]"; }

:root[data-theme="hacker"] button:not(.theme-toggle):not(.linkish),
:root[data-theme="hacker"] .cta {
  background: var(--accent); color: var(--accent-ink); text-shadow: none;
}
:root[data-theme="hacker"] .btn-ghost,
:root[data-theme="hacker"] .cta-alt {
  background: transparent; color: var(--accent); border: 1px solid var(--line);
}
:root[data-theme="hacker"] .danger-btn { background: var(--danger); color: #150303; }
:root[data-theme="hacker"] .linkish { color: var(--ink-dim); }

:root[data-theme="hacker"] .theme-toggle {
  border-color: var(--line); color: var(--ink-faint);
  text-transform: uppercase; letter-spacing: .08em;
}

/* --- lists, bars, tables ------------------------------------------------- */

:root[data-theme="hacker"] .bar-row { border-radius: 0; }
:root[data-theme="hacker"] .bar-fill { border-radius: 0; background: var(--accent-wash); }
:root[data-theme="hacker"] .bar-count { color: var(--accent); }
:root[data-theme="hacker"] .site-hits {
  border-radius: 0; border: 1px solid var(--line-soft); color: var(--accent);
}
:root[data-theme="hacker"] .site-name { color: var(--accent); }

:root[data-theme="hacker"] .hits { font-family: var(--mono); }
:root[data-theme="hacker"] .hits th {
  background: var(--surface); color: var(--ink-faint);
  border-bottom: 1px solid var(--line); letter-spacing: .1em;
}
:root[data-theme="hacker"] .hits tbody tr:hover td { background: rgba(0, 255, 65, .07); }

:root[data-theme="hacker"] .snippet {
  background: #020602; border-color: var(--line-soft); color: var(--accent);
}

/* --- collapsibles -------------------------------------------------------- */

:root[data-theme="hacker"] details.panel > summary { color: var(--ink-faint); }
:root[data-theme="hacker"] details.panel > summary::before { content: "+"; font-size: .95rem; }
:root[data-theme="hacker"] details.panel[open] > summary::before { content: "-"; transform: none; }

/* --- map preview ---------------------------------------------------------
   The SVG carries the site's own colours as inline attributes so the preview
   matches the live widget. Here we deliberately override them to phosphor
   green. The background needs !important because it is an inline style;
   path/circle fills are presentation attributes, which CSS outranks anyway. */

:root[data-theme="hacker"] .map-card svg { background: #030603 !important; }
:root[data-theme="hacker"] .map-card path { fill: #0e3315; }
:root[data-theme="hacker"] .map-card circle {
  fill: var(--accent); fill-opacity: .85;
  filter: drop-shadow(0 0 3px rgba(0, 255, 65, .8));
}
