/* Theme tokens. Dark is the default look; the light palette is applied both
   by OS preference and by the explicit [data-theme] the toggle writes. */
:root {
  --bg: #0b0f17;
  --bg-elev: #121826;
  --bg-inset: #0e131f;
  --border: #1f2937;
  --border-soft: #172032;
  --fg: #e8edf6;
  --fg-dim: #9aa7bd;
  --fg-faint: #64748b;
  --accent: #4f9dff;
  --accent-soft: rgba(79, 157, 255, 0.14);
  --v6: #34d399;
  --v6-soft: rgba(52, 211, 153, 0.14);
  --danger: #f87171;
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.28);
  --radius: 14px;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

:root[data-theme="light"] {
  --bg: #f6f8fc;
  --bg-elev: #ffffff;
  --bg-inset: #f1f4fa;
  --border: #e2e8f0;
  --border-soft: #edf1f7;
  --fg: #0f172a;
  --fg-dim: #52627a;
  --fg-faint: #8593a8;
  --accent: #1d6fe0;
  --accent-soft: rgba(29, 111, 224, 0.10);
  --v6: #0d9668;
  --v6-soft: rgba(13, 150, 104, 0.10);
  --danger: #dc2626;
  --shadow: 0 1px 2px rgba(15,23,42,.06), 0 8px 24px rgba(15,23,42,.06);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg: #f6f8fc;
    --bg-elev: #ffffff;
    --bg-inset: #f1f4fa;
    --border: #e2e8f0;
    --border-soft: #edf1f7;
    --fg: #0f172a;
    --fg-dim: #52627a;
    --fg-faint: #8593a8;
    --accent: #1d6fe0;
    --accent-soft: rgba(29, 111, 224, 0.10);
    --v6: #0d9668;
    --v6-soft: rgba(13, 150, 104, 0.10);
    --danger: #dc2626;
    --shadow: 0 1px 2px rgba(15,23,42,.06), 0 8px 24px rgba(15,23,42,.06);
  }
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  /* A faint wash behind the fold keeps the dark theme from reading flat. */
  background-image: radial-gradient(900px 420px at 50% -180px, var(--accent-soft), transparent 70%);
  background-repeat: no-repeat;
}

.wrap { width: 100%; max-width: 1040px; margin: 0 auto; padding: 0 20px; }

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

/* ── Top bar ─────────────────────────────────────────────────────────── */

.topbar { border-bottom: 1px solid var(--border-soft); }

.topbar-inner {
  display: flex; align-items: center; justify-content: space-between;
  height: 60px;
}

.brand {
  display: inline-flex; align-items: center; gap: 9px;
  color: var(--fg); text-decoration: none;
  font-size: 1.05rem; letter-spacing: -0.01em;
}
.brand strong { color: var(--accent); font-weight: 700; }

.brand-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--v6);
  box-shadow: 0 0 0 3px var(--v6-soft);
}

.ghost-btn {
  appearance: none;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--fg-dim);
  border-radius: 9px;
  padding: 7px 12px;
  font: inherit;
  font-size: .875rem;
  cursor: pointer;
  transition: border-color .15s, color .15s, background .15s;
}
.ghost-btn:hover { border-color: var(--accent); color: var(--fg); }

.theme-icon::before { content: "☀︎"; font-size: 1rem; }
:root[data-theme="light"] .theme-icon::before { content: "☾"; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .theme-icon::before { content: "☾"; }
  :root[data-theme="dark"] .theme-icon::before { content: "☀︎"; }
}

/* ── Hero ────────────────────────────────────────────────────────────── */

.hero { padding: 40px 0 12px; }

.hero h1 {
  margin: 0 0 20px;
  font-size: clamp(1.5rem, 4vw, 2rem);
  letter-spacing: -0.02em;
  font-weight: 650;
}

.ip-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px;
}

.ip-card {
  position: relative;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px 20px 20px;
  overflow: hidden;
}

/* A hairline in the stack's colour ties each card to its badge. */
.ip-card::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--accent);
}
#card-v6.ip-card::before { background: var(--v6); }
.ip-card[data-state="missing"]::before,
.ip-card[data-state="error"]::before { background: var(--border); }

.ip-card-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 10px;
}

.badge {
  font: 600 .72rem/1 var(--mono);
  letter-spacing: .08em;
  padding: 5px 8px;
  border-radius: 6px;
  background: var(--accent-soft);
  color: var(--accent);
}
.badge-v6 { background: var(--v6-soft); color: var(--v6); }

.ip-status { font-size: .78rem; color: var(--fg-faint); }

.ip-value {
  font-family: var(--mono);
  font-size: clamp(1.05rem, 3.4vw, 1.55rem);
  font-weight: 600;
  letter-spacing: -0.01em;
  /* IPv6 is long; wrapping mid-address beats a horizontal scrollbar. */
  word-break: break-all;
  min-height: 1.6em;
  user-select: all;
}

.ip-card[data-state="missing"] .ip-value,
.ip-card[data-state="error"] .ip-value {
  font-size: 1rem;
  font-weight: 400;
  font-family: var(--sans);
  color: var(--fg-faint);
  user-select: auto;
}

.copy-btn {
  margin-top: 12px;
  appearance: none;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  color: var(--fg-dim);
  border-radius: 8px;
  padding: 6px 12px;
  font: inherit; font-size: .8rem;
  cursor: pointer;
  transition: border-color .15s, color .15s;
}
.copy-btn:hover { border-color: var(--accent); color: var(--fg); }
.copy-btn[data-copied="true"] { border-color: var(--v6); color: var(--v6); }

/* Widths approximate a real address so the card does not resize on load.
   Kept in CSS rather than a style attribute so the page needs no
   'unsafe-inline' in its Content-Security-Policy. */
.skeleton-v4 { width: 11ch; }
.skeleton-v6 { width: 18ch; }

.skeleton {
  display: inline-block; height: 1.1em; vertical-align: middle;
  border-radius: 5px;
  background: linear-gradient(90deg, var(--bg-inset), var(--border-soft), var(--bg-inset));
  background-size: 200% 100%;
  animation: shimmer 1.3s ease-in-out infinite;
}
@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; }
}

.hero-note {
  margin: 18px 0 0;
  padding: 11px 14px;
  border-radius: 10px;
  background: var(--bg-inset);
  border: 1px solid var(--border-soft);
  color: var(--fg-dim);
  font-size: .875rem;
}

/* Marks that the panels below describe a looked-up address rather than the
   visitor's own connection. */
.lookup-banner {
  margin: 14px 0 0;
  padding: 11px 14px;
  border-radius: 10px;
  background: var(--accent-soft);
  border: 1px solid transparent;
  color: var(--accent);
  font-size: .875rem;
  font-weight: 500;
}

/* ── Panels ──────────────────────────────────────────────────────────── */

/* Vertical rhythm lives on the container, not on the panels. Sibling margins
   would also match panels sitting side by side inside .split, pushing the
   second one down by the margin and shrinking it by the same amount. */
main.wrap {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 16px;
}

.panel {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px 20px 20px;
  /* Column layout so the fact list can absorb the height the grid row gets
     from its tallest panel, instead of leaving a pool of dead space. */
  display: flex;
  flex-direction: column;
}

.panel-title {
  margin: 0 0 14px;
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  display: flex; align-items: center; gap: 8px;
}
.panel-icon { font-size: 1rem; }

/* The map stretches to whatever height the row settles on, so it always ends
   flush with the facts panel beside it instead of leaving dead space. */
.panel-map {
  padding: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.panel-map[hidden] { display: none; }

#map {
  width: 100%;
  flex: 1 1 auto;
  min-height: 320px;
  background: var(--bg-inset);
}

.map-caption {
  margin: 0;
  padding: 10px 16px;
  font-size: .78rem;
  color: var(--fg-faint);
  border-top: 1px solid var(--border-soft);
}

/* ── Fact lists ──────────────────────────────────────────────────────── */

/* Rows stay sized to their content. Stretching them to fill the panel makes
   every row match the tallest one — and the user-agent row is five lines. */
.facts {
  margin: 0;
  display: grid;
  gap: 1px;
  background: var(--border-soft);
  border-radius: 10px;
  overflow: hidden;
}
.facts:empty { background: none; }

.facts > div {
  display: grid;
  grid-template-columns: minmax(96px, 34%) 1fr;
  gap: 12px;
  padding: 10px 12px;
  background: var(--bg-elev);
  align-items: baseline;
}

.facts dt { color: var(--fg-dim); font-size: .82rem; }
.facts dd {
  margin: 0;
  font-size: .9rem;
  word-break: break-word;
  overflow-wrap: anywhere;
}
.facts dd.mono { font-family: var(--mono); font-size: .84rem; }
.facts dd.empty { color: var(--fg-faint); }

.flag { font-size: 1.05em; margin-right: .35em; }

/* ── Lookup ──────────────────────────────────────────────────────────── */

.lookup { display: flex; flex-wrap: wrap; gap: 10px; }

.lookup input {
  flex: 1 1 240px;
  min-width: 0;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--fg);
  font: inherit;
  font-family: var(--mono);
  font-size: .9rem;
  padding: 9px 12px;
}
.lookup input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; }

.primary-btn {
  appearance: none; border: 0; cursor: pointer;
  background: var(--accent);
  color: #fff;
  border-radius: 9px;
  padding: 9px 18px;
  font: inherit; font-size: .9rem; font-weight: 550;
  transition: filter .15s;
}
.primary-btn:hover { filter: brightness(1.08); }

.lookup-error { margin: 12px 0 0; color: var(--danger); font-size: .86rem; }

/* ── API block ───────────────────────────────────────────────────────── */

.api-lead { margin: 0 0 12px; color: var(--fg-dim); font-size: .88rem; }

.code {
  margin: 0;
  padding: 14px 16px;
  background: var(--bg-inset);
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  font-family: var(--mono);
  font-size: .82rem;
  line-height: 1.7;
  color: var(--fg-dim);
  /* Long commands scroll inside the block instead of widening the page. */
  overflow-x: auto;
}

/* ── Footer ──────────────────────────────────────────────────────────── */

.footer {
  margin: 36px auto 40px;
  padding-top: 20px;
  border-top: 1px solid var(--border-soft);
  color: var(--fg-faint);
  font-size: .8rem;
}
.footer p { margin: 0 0 6px; }
.footer a { color: var(--fg-dim); }
.footer-dim { color: var(--fg-faint); opacity: .85; }

/* Leaflet's own chrome has to follow the theme, not its light defaults. */
.leaflet-container { background: var(--bg-inset); font-family: var(--sans); }
.leaflet-control-attribution {
  background: var(--bg-elev) !important;
  color: var(--fg-faint) !important;
  font-size: .68rem !important;
}
.leaflet-control-attribution a { color: var(--fg-dim) !important; }
.leaflet-bar a {
  background: var(--bg-elev) !important;
  color: var(--fg) !important;
  border-bottom-color: var(--border) !important;
}
.leaflet-bar a:hover { background: var(--bg-inset) !important; }

/* OSM tiles are drawn for light UIs; dimming them keeps the dark theme
   coherent without hosting a second tile set. */
:root:not([data-theme="light"]) .leaflet-tile-pane { filter: brightness(.58) saturate(.7) contrast(1.08); }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .leaflet-tile-pane { filter: none; }
}
:root[data-theme="dark"] .leaflet-tile-pane { filter: brightness(.58) saturate(.7) contrast(1.08); }
