/* ip2geo v4 — modern brutalist utility reskin
   Source of truth: DESIGN.md
   Round 3-A approved mockup: ~/.gstack/projects/febrile42-ip2geo/designs/v4reskin-20260426/round3/variant-A.png
   Single-file consolidation: every app rule lives here. ip2geo-app.css and the
   html5up Hyperspace template (main.css, noscript.css, jquery + main.js + util.js)
   were retired during the v4 reskin — see git history for the cleanup commit. */

/* ============================================================
   1. TOKENS
   ============================================================ */
:root {
  --bg: #0A0612;
  --surface: #15102B;
  --surface-2: #221940;
  --text: #F5F1FA;
  --text-muted: #9B92AD;
  --accent-purple: #A78BFA;
  --button-purple: #5E42A6;
  --button-purple-hover: #6B4EB8;
  --magenta: #F472B6;
  --magenta-hover: #DC4D9A;
  --border: rgba(255,255,255,0.08);
  --heritage: linear-gradient(to right, #5E42A6 0%, #B74E91 100%);

  --font-sans: 'Geist', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --font-mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --content-max: 1200px;
  --prose-max: 880px;
  --lead-max: 520px;

  --r-sm: 4px;
  --r-md: 6px;
  --r-lg: 8px;
  --r-pill: 9999px;

  /* Verdict palette — drives .asn-verdict, .asn-category, .threat-cta-box, .cat-* chip
     accents, and CTA button fills. Single source so the report's color language stays
     consistent across pill / row text / border / fill contexts. */
  --verdict-high: #e06c9f;
  --verdict-moderate: #e0a85a;
  --verdict-low: #6cb87a;
  --verdict-cloud: #8ab4d4;
  --verdict-unknown: #aaa;

  /* Processing-overlay gradient (heritage hues, theme-aware lightness).
     Dark theme: dimmed near-bg pair so the overlay reads as the room dimming
     rather than a spotlight switching on. Light theme override below restores
     the saturated heritage stops, which read as a clear "stop, processing"
     state against the near-white bg. */
  --overlay-from: rgba(26, 18, 64, 0.96);
  --overlay-to:   rgba(61, 31, 63, 0.96);
}

[data-theme="light"] {
  --bg: #FBF7FF;
  --surface: #FFFFFF;
  --surface-2: #F2EBFB;
  --text: #1A1330;
  --text-muted: #5B5275;
  --accent-purple: #5E42A6;
  --button-purple: #5E42A6;
  --button-purple-hover: #4D3690;
  --magenta: #B74E91;
  --magenta-hover: #9C3F7B;
  --border: rgba(26,19,48,0.10);

  --overlay-from: rgba(94, 66, 166, 0.96);
  --overlay-to:   rgba(183, 78, 145, 0.96);
}

/* Default-link underline visibility tuning, light theme only.
   Dark theme uses var(--border) at rgba(255,255,255,0.08) which reads
   correctly on the dark surface. Light theme's var(--border) at
   rgba(26,19,48,0.10) is too faint on white and links lose their
   affordance. Bump to a 35%-alpha near-black so links read as links;
   hover continues to light up to var(--accent-purple). */
[data-theme="light"] a { text-decoration-color: rgba(26,19,48,0.35); }
[data-theme="light"] footer#footer a { text-decoration-color: rgba(26,19,48,0.35); }

/* ============================================================
   2. RESET + BASE
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; scroll-padding-top: 72px; }

/* Honor the HTML5 [hidden] attribute everywhere. The UA stylesheet's
   `[hidden] { display: none }` is the lowest-specificity rule possible, so
   any class-based `display: flex` or `display: inline-flex` we set later
   silently defeats it. JS that does `el.hidden = true` then becomes a no-op
   for those elements (button.small show-all toggle, block-rules panels).
   The !important is the canonical fix here — it's how Bootstrap, Tailwind,
   and modern resets handle the same UA specificity foot-gun. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.55;
  font-feature-settings: "ss01", "cv11";
  transition: background-color 200ms ease-in-out, color 200ms ease-in-out;
}

@media (prefers-reduced-motion: reduce) {
  body { transition: none; }
}

::selection { background: var(--button-purple); color: #fff; }

/* Default link: restrained — used for nav, wordmark, utility links. */
a {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--border);
  text-underline-offset: 5px;
  transition: text-decoration-color 100ms ease-out, color 100ms ease-out;
}
a:hover { text-decoration-color: var(--accent-purple); color: var(--accent-purple); }
a:focus-visible { outline: 2px solid var(--accent-purple); outline-offset: 2px; border-radius: 2px; }

/* Content link: inline links inside body prose. Accent-purple text + visible
   1.5px underline. Hover thickens to 2.5px. */
.lead a,
.block-body a,
.about-grid p a,
.about-prose a,
.report-inner .prose a,
.field-hint a,
footer a {
  color: var(--accent-purple);
  text-decoration: underline;
  text-decoration-color: var(--accent-purple);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 5px;
}
.lead a:hover,
.block-body a:hover,
.about-grid p a:hover,
.about-prose a:hover,
.report-inner .prose a:hover,
.field-hint a:hover,
footer a:hover {
  color: var(--accent-purple);
  text-decoration-thickness: 2.5px;
}

/* ============================================================
   3. TOP NAV — sticky, 56px, heritage gradient HR
   ============================================================ */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  height: 56px;
  background: var(--bg);
  border-bottom: 1.5px solid transparent;
  background-image:
    linear-gradient(var(--bg), var(--bg)),
    var(--heritage);
  background-origin: border-box;
  background-clip: padding-box, border-box;
}

.nav-inner {
  max-width: var(--content-max);
  height: 100%;
  margin: 0 auto;
  padding: 0 32px;
  display: flex;
  align-items: center;
  gap: 32px;
}

.wordmark {
  font-family: var(--font-sans);
  font-weight: 900;
  font-size: 22px;
  letter-spacing: -0.02em;
  color: var(--text);
  text-decoration: none;
}
.wordmark:hover { color: var(--text); text-decoration: none; }

.nav-links {
  display: flex;
  gap: 24px;
  margin-left: auto;
  align-items: center;
}
.nav-links a {
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  color: var(--text-muted);
  transition: color 100ms ease-out;
}
.nav-links a:hover { color: var(--text); text-decoration: none; }

.theme-toggle {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--text-muted);
  cursor: pointer;
  transition: color 100ms ease-out, border-color 100ms ease-out;
}
.theme-toggle:hover { color: var(--text); border-color: var(--text-muted); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent-purple); outline-offset: 2px; }
.theme-toggle svg { width: 16px; height: 16px; }
[data-theme="dark"] .theme-toggle .icon-sun,
[data-theme="light"] .theme-toggle .icon-moon { display: none; }

/* ============================================================
   4. LAYOUT SHELL
   ============================================================ */
main {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 0 32px;
}

/* ============================================================
   5. SECTION HEAD PATTERN (the editorial flourish)
   H2 left + 0X / LABEL mono tag right + 4px purple rule above the tag
   ============================================================ */
.section-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 24px;
  margin-bottom: 20px;
}

.section-head h1,
.section-head h2,
.section-head h3 {
  font-family: var(--font-sans);
  font-weight: 900;
  letter-spacing: -0.025em;
  margin: 0;
  line-height: 1.05;
}
.section-head h1 { font-size: 40px; }
.section-head h2 { font-size: 34px; }
.section-head h3 { font-size: 28px; }

.section-tag {
  position: relative;
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  padding-top: 12px;
  flex-shrink: 0;
}
.section-tag::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  width: 120px;
  height: 4px;
  background: var(--accent-purple);
}

/* ============================================================
   6. HERO
   ============================================================ */
.hero { padding: 80px 0 56px; }

.lead {
  font-size: 16px;
  line-height: 1.6;
  color: var(--text-muted);
  max-width: var(--prose-max);
  margin: 0 0 32px;
}
.lead strong { color: var(--text); font-weight: 500; }
.lead code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  color: var(--text);
  background: var(--surface);
  padding: 1px 6px;
  border-radius: var(--r-sm);
}

/* ============================================================
   7. LOOKUP FORM
   Desktop: textarea left, filter + button stacked right.
   ≤ 768px: collapse to single column (textarea / filter / button).
   ============================================================ */
.lookup-form { max-width: var(--content-max); }

.form-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: 24px;
  align-items: start;
}

.form-side {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 24px;
  min-height: 100%;
}

.ip-textarea {
  width: 100%;
  min-height: 200px;
  padding: 16px 18px;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.6;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  resize: vertical;
  transition: border-color 100ms ease-out;
}
.ip-textarea:focus {
  outline: none;
  border-color: var(--accent-purple);
}
.ip-textarea::placeholder { color: var(--text-muted); opacity: 0.7; }

.field label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 6px;
}
.field input[type="text"],
.field input[type="email"] {
  width: 100%;
  padding: 10px 12px;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 13px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
}
.field input[type="text"]:focus,
.field input[type="email"]:focus { outline: none; border-color: var(--accent-purple); }
.field input[type="text"]::placeholder,
.field input[type="email"]::placeholder { color: var(--text-muted); opacity: 1; transition: opacity 80ms ease-out; }
.field input[type="text"]:focus::placeholder,
.field input[type="email"]:focus::placeholder { opacity: 0; }
.field-hint { font-size: 12px; color: var(--text-muted); margin-top: 4px; }

.actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: flex-start;
}

/* Processing overlay — full-viewport scrim shown while the bulk-IP lookup
   AJAX round-trip is in flight. Heritage gradient at theme-aware lightness
   (see --overlay-from / --overlay-to in §1) so dark theme doesn't flash-bomb
   visitors mid-scroll. Built dynamically by the submit handler in index.php. */
.processing-overlay {
  position: fixed;
  inset: 0;
  background: linear-gradient(to right, var(--overlay-from), var(--overlay-to));
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2147483647;
}
.processing-overlay__msg {
  font-family: var(--font-mono);
  font-size: 1.1em;
  color: #fff;
  letter-spacing: 0.05em;
  opacity: 0.9;
}
.processing-overlay__dots {
  display: inline-block;
  width: 1.8em;
  text-align: left;
}

/* ============================================================
   8. BUTTONS
   ============================================================ */
.button {
  appearance: none;
  -webkit-appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 20px;
  background: var(--button-purple);
  color: #fff;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 15px;
  border: none;
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background-color 100ms ease-out;
  text-decoration: none;
}
.button:hover { background: var(--button-purple-hover); text-decoration: none; color: #fff; }
.button:focus-visible { outline: 2px solid var(--accent-purple); outline-offset: 2px; }

.button.alt {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border);
}
.button.alt:hover { background: var(--surface); border-color: var(--text-muted); color: var(--text); }

.button.magenta { background: var(--magenta); color: #fff; }
.button.magenta:hover { background: var(--magenta-hover); color: #fff; }

.button.small { padding: 8px 14px; font-size: 13px; }

/* ============================================================
   9. OPT-IN CHECKBOX (recent-lookups)
   ============================================================ */
.opt-in {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text-muted);
  cursor: pointer;
  user-select: none;
}
.opt-in input { accent-color: var(--accent-purple); }
.opt-in .muted-tag { color: var(--text-muted); opacity: 0.7; }

/* Wrapper row for the recent-lookups opt-in checkbox: sits directly below the
   submit button in the .actions column. Fades on hover so the row stays
   discoverable without competing with the primary CTA. */
.opt-in-toggle {
  margin-top: 0.6em;
  font-size: 0.75em;
  opacity: 0.7;
  transition: opacity 0.15s;
}
.opt-in-toggle:hover,
.opt-in-toggle:focus-within {
  opacity: 1;
}
.opt-in-toggle label {
  cursor: pointer;
}

/* ============================================================
   10. GENERIC SECTIONS
   Hairline divider + asymmetric padding (72/42).
   ============================================================ */
section.block { padding: 72px 0 42px; border-top: 1px solid var(--border); }

.block-body { max-width: var(--prose-max); }
.block-body p { margin: 0 0 16px; color: var(--text-muted); }
.block-body p strong { color: var(--text); font-weight: 500; }
.block-body p:last-child { margin-bottom: 0; }

/* ============================================================
   11. TWO-COLUMN GRID (Reports: Free / Full)
   ============================================================ */
.two-col {
  display: grid;
  grid-template-columns: 1fr 1.25fr;
  gap: 48px;
  max-width: 1100px;
}

/* Feature list with terminal-flavored arrow markers in accent-purple. */
.feature-list { list-style: none; padding: 0; margin: 0 0 24px; }
.feature-list li {
  position: relative;
  padding: 6px 0 6px 20px;
  color: var(--text-muted);
  font-size: 15px;
  line-height: 1.55;
}
.feature-list li::before {
  content: "→";
  position: absolute;
  left: 0;
  top: 6px;
  font-family: var(--font-mono);
  font-weight: 500;
  color: var(--accent-purple);
  line-height: 1.55;
}
.feature-list strong { color: var(--text); font-weight: 500; }

.price {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  margin-bottom: 12px;
}
.price .amount { font-family: var(--font-mono); font-weight: 500; color: var(--text); font-size: 22px; }
.price .label { font-size: 13px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.06em; }

h3.subhead {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.015em;
  margin: 0 0 12px;
  color: var(--text);
}

/* ============================================================
   12. INTEL CARD (Community Block List summary)
   ============================================================ */
.intel-card {
  margin-top: 24px;
  padding: 20px 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}
.intel-meta {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.intel-meta strong { color: var(--accent-purple); font-weight: 500; }

/* ============================================================
   13. ABOUT (long-form prose)
   ============================================================ */
.about-prose { max-width: var(--prose-max); }
.about-prose h3 {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.015em;
  margin: 32px 0 12px;
  color: var(--text);
  line-height: 1.25;
}
.about-prose h3:first-child { margin-top: 0; }
.about-prose p {
  margin: 0 0 16px;
  color: var(--text-muted);
  line-height: 1.7;
  font-size: 16px;
}
.about-prose p:last-child { margin-bottom: 0; }
.about-prose strong { color: var(--text); font-weight: 500; }
.about-prose code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  color: var(--text);
  background: var(--surface);
  padding: 1px 6px;
  border-radius: var(--r-sm);
}

/* ============================================================
   14. CONTACT GRID (Social / Donate)
   ============================================================ */
.about-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px 64px;
  max-width: var(--prose-max);
}
.about-grid h3 {
  font-size: 12px;
  font-weight: 500;
  margin: 0 0 12px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-family: var(--font-mono);
}
.about-grid p { margin: 0; color: var(--text-muted); line-height: 1.9; }

/* ============================================================
   15. FOOTER
   Targets includes/footer.php — the v4 reskin renamed the html5up
   `wrapper style1-alt` / `.inner` / `.menu` classes to `#footer` /
   `.footer-inner` / `.footer-menu` so the markup is self-documenting.
   ============================================================ */
footer#footer {
  padding: 48px 0 64px;
  margin-top: 32px;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 13px;
  background: var(--bg);
}
footer#footer .footer-inner {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 0 32px;
}
footer#footer ul.footer-menu {
  list-style: none;
  padding: 0;
  margin: 0 0 8px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 24px;
  font-size: 13px;
}
footer#footer ul.footer-menu:last-child { margin-bottom: 0; }
footer#footer ul.footer-menu li { color: var(--text-muted); }
footer#footer a {
  color: var(--text-muted);
  text-decoration: underline;
  text-decoration-color: var(--border);
  text-underline-offset: 5px;
}
footer#footer a:hover {
  color: var(--accent-purple);
  text-decoration-color: var(--accent-purple);
}

/* ============================================================
   16. RESULTS SECTION (server-rendered after submit / view-token)
   ============================================================ */

/* ---------- 16a. Verdict + ASN category palette ----------
   Used by the report verdict bar, the threat-CTA box, the results-table
   ASN category column, and the filter-chip color accents. The palette is
   tokenised in §1 so every consumer reads from one place. */
.asn-verdict {
    font-family: monospace;
    font-size: 1.4em;
    font-weight: bold;
    text-transform: uppercase;
    letter-spacing: 0.15em;
    padding-left: 0.75em;
    margin-bottom: 0.25em;
}
.asn-verdict--high     { color: var(--verdict-high);     border-left: 3px solid var(--verdict-high); }
.asn-verdict--moderate { color: var(--verdict-moderate); border-left: 3px solid var(--verdict-moderate); }
.asn-verdict--low      { color: var(--verdict-low);      border-left: 3px solid var(--verdict-low); }

/* ASN category labels in #results-table. Pill variant lives in §18 under
   .report-inner — it inherits the same color via currentColor. */
.asn-category {
    font-family: monospace;
    font-size: 0.85em;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.asn-category--scanning    { color: var(--verdict-high); }
.asn-category--cloud       { color: var(--verdict-cloud); }
.asn-category--vpn         { color: var(--verdict-moderate); }
.asn-category--residential { color: var(--verdict-low); }
.asn-category--unknown     { color: #888; }

section#results.block { padding-top: 56px; }
section#results .section-head { margin-bottom: 16px; }

/* ---------- 16b. Results table ----------
   Density via 13px Geist Sans body, 11px mono uppercase headers.
   IP / ASN / CC columns swap to mono so digits align. JS-driven .row-stripe
   handles alternation post-filter; the nth-child reset guards against the
   theme's stripe rule resurrecting after rows hide. */
section#results .table-wrapper {
  margin: 20px 0 16px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow-x: auto;
}

#results-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-sans);
  font-size: 13px;
  margin: 0;
}

#results-table thead th {
  text-align: left;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  white-space: nowrap;
}
#results-table tbody td {
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
  /* No default color — cells inherit body --text. This is critical because
     .asn-category--scanning/cloud/vpn/etc. set their own color, and a
     specific selector here would override them. */
}
#results-table tbody tr:last-child td { border-bottom: 0; }

/* IP, CC, ASN columns -> mono so digits align across rows */
#results-table tbody td:first-child,
#results-table tbody td:nth-child(2),
#results-table tbody td:nth-child(5) {
  font-family: var(--font-mono);
  font-size: 12px;
  font-feature-settings: "tnum" 1;
}
#results-table tbody td:nth-child(2) { color: var(--text-muted); }

/* abbr tooltips inside results table */
#results-table abbr[title] {
    text-decoration: underline dotted;
    text-decoration-color: var(--text-muted);
    cursor: help;
}

/* No row hover: the table is for scanning and reading, not interaction.
   A row-bg change reads as "this row is selectable/clickable" but rows
   aren't actionable, so the affordance lies. */

/* JS-driven stripe (ip2geo-app.js toggles .row-stripe on visible rows,
   .row-hidden on filtered rows). The nth-child reset stops the theme's
   default odd-row stripe from leaking back in once rows hide. */
#results-table tbody tr:nth-child(2n + 1) { background-color: transparent; }
#results-table tbody tr.row-stripe        { background-color: rgba(255,255,255,0.03); }
#results-table tbody tr.row-hidden        { display: none; }
[data-theme="light"] #results-table tbody tr.row-stripe { background-color: rgba(26,19,48,0.03); }

/* Column overflow absorption — ASN Org is the prime overflow culprit; State and
   City are secondary. Truncate at a fixed em cap, expose full text via the
   markup's title attribute on hover. */
#results-table .cell-asn-org {
    max-width: 14em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
#results-table .cell-region,
#results-table .cell-city {
    max-width: 10em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Report table mirror — same density + truncation as the public results table
   (used in report.php contexts that don't sit under #results-table). */
.report-table { font-size: 0.85em; }
.report-table .cell-asn-org {
    max-width: 14em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Empty filter message — center align inside the table card. */
#empty-filter-msg {
  color: var(--text-muted);
  font-size: 13px;
}

/* ---------- 16c. Filter & Export panel ---------- */
#filter-export {
  margin: 24px 0 0;
  padding: 14px 20px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}

/* Accordion summary: chevron + mono uppercase label. */
#filter-details > summary,
#report-filter-details > summary {
  cursor: pointer;
  padding: 0.4em 0;
  list-style: none;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
#filter-details > summary::-webkit-details-marker,
#report-filter-details > summary::-webkit-details-marker { display: none; }
#filter-details > summary::before,
#report-filter-details > summary::before {
    content: '▸ ';
    font-size: 0.85em;
}
#filter-details[open] > summary::before,
#report-filter-details[open] > summary::before { content: '▾ '; }

#filter-summary #filter-count,
#filter-summary #filter-total { color: var(--text); }

/* Two-column filter layout: action buttons + firewall-rules left, chips right. */
#filter-layout {
    display: flex;
    gap: 2.5em;
    padding: 0.6em 0 0.5em;
    flex-wrap: wrap;
    align-items: flex-start;
}

/* Left: action buttons + firewall rule output */
#filter-left {
    flex: 1 1 45%;
    min-width: 220px;
    display: flex;
    flex-direction: column;
    gap: 0.5em;
}

#action-buttons-primary,
#export-buttons {
    display: flex;
    gap: 0.4em;
    flex-wrap: wrap;
    align-items: center;
}

/* Right: filter chips */
#filter-right {
    flex: 0 0 auto;
    display: flex;
    gap: 1.5em;
    align-items: flex-start;
}

/* Section headers above chip columns */
#filter-countries > strong,
#filter-categories > strong,
#report-filter-countries > strong,
#report-filter-categories > strong {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-family: var(--font-mono);
    font-size: 0.65em;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    opacity: 0.9;
    margin-bottom: 0.5em;
}

.chip-hint {
    font-weight: normal;
    text-transform: none;
    letter-spacing: normal;
    font-style: italic;
}

/* Scrollable chip container for countries.
   9.8em lands mid-chip (~5.5 rows), so a partial chip peeks out when
   there are 6+ countries — natural scroll affordance, no extra markup. */
#filter-countries .filter-chips {
    max-height: 9.8em;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.3em;
}

#filter-categories {
    display: flex;
    flex-direction: column;
    gap: 0.3em;
}

/* Toggle chip labels — inactive state. font-mono so "(N)" counts align. */
#filter-countries label,
#filter-categories label,
#report-filter-countries label,
#report-filter-categories label {
    font-family: var(--font-mono);
    font-size: 0.7em;
    font-weight: normal;
    letter-spacing: 0.04em;
    display: block;
    padding: 0.3em 0.9em;
    border: 1px solid var(--border);
    border-radius: 2em;
    cursor: pointer;
    opacity: 0.4;
    transition: opacity 0.12s ease, border-color 0.12s ease, background 0.12s ease;
    user-select: none;
    white-space: nowrap;
    margin: 0;
    line-height: 1.5;
}

/* Active (checked) state */
#filter-countries label:has(input:checked),
#filter-categories label:has(input:checked),
#report-filter-countries label:has(input:checked),
#report-filter-categories label:has(input:checked) {
    opacity: 1;
    border-color: var(--text-muted);
    background: var(--surface-2);
}

/* ASN category chip accent colors */
#filter-categories label.cat-scanning,
#report-filter-categories label.cat-scanning    { color: var(--verdict-high); }
#filter-categories label.cat-cloud,
#report-filter-categories label.cat-cloud       { color: var(--verdict-cloud); }
#filter-categories label.cat-vpn,
#report-filter-categories label.cat-vpn         { color: var(--verdict-moderate); }
#filter-categories label.cat-residential,
#report-filter-categories label.cat-residential { color: var(--verdict-low); }
#filter-categories label.cat-unknown,
#report-filter-categories label.cat-unknown     { color: var(--verdict-unknown); }

/* Active category chip: border color matches accent */
#filter-categories label.cat-scanning:has(input:checked),
#report-filter-categories label.cat-scanning:has(input:checked)    { border-color: rgba(224,108,159,0.6); }
#filter-categories label.cat-cloud:has(input:checked),
#report-filter-categories label.cat-cloud:has(input:checked)       { border-color: rgba(138,180,212,0.6); }
#filter-categories label.cat-vpn:has(input:checked),
#report-filter-categories label.cat-vpn:has(input:checked)         { border-color: rgba(224,168,90,0.6);  }
#filter-categories label.cat-residential:has(input:checked),
#report-filter-categories label.cat-residential:has(input:checked) { border-color: rgba(108,184,122,0.6); }
#filter-categories label.cat-unknown:has(input:checked),
#report-filter-categories label.cat-unknown:has(input:checked)     { border-color: rgba(170,170,170,0.4); }

/* Zero-count chip: heavily dimmed (JS toggles .chip--empty when count is 0). */
#filter-countries label.chip--empty,
#filter-categories label.chip--empty,
#report-filter-countries label.chip--empty,
#report-filter-categories label.chip--empty {
    opacity: 0.15;
}

/* Hide native checkbox; keep in tab order for a11y. */
#filter-countries input[type="checkbox"],
#filter-categories input[type="checkbox"],
#report-filter-countries input[type="checkbox"],
#report-filter-categories input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    pointer-events: none;
}

/* ---------- 16d. Action buttons row (CSV / unresolved / firewall rules) ----
   Lower emphasis than the primary lookup button. Transparent fill, hairline
   border, mono uppercase label. */
.button.small,
button.button.small {
  min-height: 36px;
  line-height: 1.2;
  padding: 6px 12px;
  font-size: 12px;
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-weight: 500;
}
.button.small:hover,
button.button.small:hover {
  background: var(--surface);
  border-color: var(--text-muted);
  color: var(--text);
}
.button.small.alt {
  /* Same baseline as .button.small — already low-emphasis. */
  background: transparent;
}

/* Touch-target a11y: bump min-height on small viewports without breaking flex. */
@media (max-width: 767px) {
  .button.small,
  button.button.small {
    min-height: 44px;
    padding: 8px 14px;
  }
}

/* ---------- 16e. Firewall rules output (.rules-block) ---------- */
.rules-block {
    position: relative;
    margin-top: 0.25em;
}
.rules-block pre {
    background: rgba(255,255,255,0.05);
    border-radius: 4px;
    padding: 1em;
    font-family: monospace;
    font-size: 0.5em;
    overflow-x: auto;
    white-space: pre;
    max-height: 300px;
    overflow-y: auto;
    margin-top: 0;
}
.rules-block .copy-rules {
    position: absolute;
    top: 0.4em;
    right: 0.4em;
    z-index: 1;
}

/* ---------- 16f. Stats summary table ---------- */
#stats-table {
  margin-top: 20px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  border-collapse: collapse;
}
#stats-table td {
  padding: 2px 12px 2px 0;
  vertical-align: top;
}
#stats-table td:first-child {
  font-weight: 500;
  color: var(--text);
  text-align: right;
  font-feature-settings: "tnum" 1;
  min-width: 4em;
  white-space: nowrap;
}

/* ---------- 16g. Cancel notice (Stripe redirect-back banner) ---------- */
#cancel-notice {
    background: rgba(255,255,255,0.07);
    border-left: 3px solid var(--verdict-moderate);
    padding: 0.6em 1em;
    margin-bottom: 1em;
    font-size: 0.9em;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
#cancel-notice button {
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    font-size: 1.1em;
    opacity: 0.6;
    padding: 0 0.25em;
}

/* ---------- 16h. Threat CTA box ----------
   Verdict-color border + tinted background; bottom band houses the CTA button.
   Per-classification color drives both the inset border and the button fill,
   with a darkening :hover effect for the !important verdict fills. */
.threat-cta-box {
    display: flex;
    flex-direction: column;
    border: 1px solid rgba(255,255,255,0.1);
    border-left-width: 4px;
    border-radius: var(--r-md);
    margin: 2em 0;
    overflow: hidden;
}
.threat-cta-box--high     { border-left-color: var(--verdict-high);     border-color: rgba(224,108,159,0.25); background: rgba(224,108,159,0.06); }
.threat-cta-box--moderate { border-left-color: var(--verdict-moderate); border-color: rgba(224,168,90,0.25);  background: rgba(224,168,90,0.06); }
.threat-cta-box--low      { border-left-color: var(--verdict-low);      border-color: rgba(108,184,122,0.25); background: rgba(108,184,122,0.06); }

.threat-cta-box form {
    display: contents;
}

.threat-cta-top {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2em;
    padding: 1.4em 1.6em;
}

.threat-cta-left {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.4em;
    padding: 1.4em 1.6em;
}
.threat-cta-left .asn-verdict {
    margin: 0;
}
.threat-cta-reason {
    font-size: 1em;
    color: var(--text-muted);
    margin: 0;
}
.threat-cta-stats {
    font-size: 0.9em;
    color: var(--text-muted);
    margin: 0;
}

.threat-cta-right {
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.threat-cta-features {
    list-style: none;
    padding: 14px 0 0;
    margin: 0;
    font-size: 0.9em;
    color: var(--text);
}
.threat-cta-features li {
    padding: 0.18em 0;
    color: var(--text-muted);
}
.threat-cta-features li::before {
    content: '✓  ';
    opacity: 0.55;
}

/* Bottom band: button + fine print side by side */
.threat-cta-bottom {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 1.4em;
    padding: 0.85em 1.6em;
    border-top: 1px solid var(--border);
    background: var(--surface-2);
}

/* Prominent CTA button — verdict-color fill */
#cta-button {
    flex-shrink: 0;
    font-weight: bold;
    letter-spacing: 0.04em;
    border-color: transparent !important;
    color: #111 !important;
    margin: 0;
    transition: filter 100ms ease-out, transform 100ms ease-out;
}
.threat-cta-box--high     #cta-button { background-color: var(--verdict-high)     !important; }
.threat-cta-box--moderate #cta-button { background-color: var(--verdict-moderate) !important; }
.threat-cta-box--low      #cta-button { background-color: var(--verdict-low)      !important; }

/* brightness(1.15) lifts each verdict color by ~15% — a clear interaction
   signal that works for all three verdict variants without per-color rules. */
.threat-cta-box #cta-button:hover { filter: brightness(1.15); }
.threat-cta-box #cta-button:active { transform: translateY(1px); }

.threat-cta-fine {
    font-size: 0.75em;
    color: var(--text-muted);
    opacity: 0.8;
    margin: 0;
    line-height: 1.55;
}

@media (max-width: 767px) {
    .threat-cta-top {
        grid-template-columns: 1fr;
        gap: 1.2em;
    }
    .threat-cta-bottom {
        flex-direction: column-reverse;
        align-items: flex-start;
        gap: 0.6em;
    }
}

/* ---------- 16i. Recent lookups widget (opt-in localStorage) ----------
   Pill-chip aesthetic. Each lookup is a compact rounded chip with count +
   relative time; the IP preview moves to a title-attribute tooltip so chips
   stay scannable. The widget only renders inside .hero, so no scoping is
   needed in the selectors here. */
#recent-lookups {
    margin: 1.25em 0 0;
    padding: 0;
    border: none;
    background: transparent;
}
#recent-lookups-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75em;
    margin-bottom: 12px;
}
#recent-lookups-header h3 {
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 500;
    line-height: 1.3;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin: 0;
}
#recent-lookups-header h3 small {
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    margin-left: 8px;
    color: var(--text-muted);
    opacity: 0.7;
}
#recent-lookups-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
#recent-lookups-list li {
    margin: 0;
    padding: 0;
}
#recent-lookups-list .recent-lookup-item {
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    height: auto;
    line-height: 1.4;
    padding: 6px 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--text);
    font: inherit;
    font-family: var(--font-sans);
    font-size: 13px;
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
    cursor: pointer;
    transition: border-color 0.12s, background 0.12s;
}
#recent-lookups-list .recent-lookup-item:hover,
#recent-lookups-list .recent-lookup-item:focus {
    background: var(--surface-2);
    border-color: var(--accent-purple);
    color: var(--text);
    outline: none;
}
.recent-lookup-count {
    font-family: var(--font-mono);
    font-feature-settings: "tnum" 1;
    font-weight: 600;
    color: var(--text);
}
.recent-lookup-dot {
    opacity: 0.3;
}
.recent-lookup-time {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-muted);
}

/* ---------- 16j. Toast with undo (privacy-action confirm) ---------- */
#rl-toast {
    position: fixed;
    left: 50%;
    bottom: 1.5em;
    transform: translate(-50%, calc(100% + 2em));
    display: flex;
    align-items: center;
    gap: 0.85em;
    padding: 0.7em 1em 0.7em 1.1em;
    background: rgba(28, 28, 32, 0.96);
    color: #f4f4f6;
    border: 1px solid rgba(255,255,255,0.14);
    border-radius: 6px;
    box-shadow: 0 6px 24px rgba(0,0,0,0.35);
    font-size: 0.9em;
    z-index: 2147483646;
    transition: transform 0.22s ease;
    max-width: calc(100vw - 2em);
}
#rl-toast.rl-toast-visible {
    transform: translate(-50%, 0);
}
#rl-toast-msg {
    line-height: 1.3;
}
#rl-toast #rl-toast-undo {
    background: transparent;
    border: 1px solid rgba(255,255,255,0.25);
    color: inherit;
    font: inherit;
    font-weight: 600;
    height: auto;
    padding: 0.35em 0.85em;
    border-radius: 3px;
    text-transform: none;
    letter-spacing: normal;
    line-height: 1.3;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}
#rl-toast #rl-toast-undo:hover,
#rl-toast #rl-toast-undo:focus {
    background: rgba(255,255,255,0.08);
    border-color: rgba(255,255,255,0.45);
    outline: none;
}

/* ---------- 16k. Filter mobile responsive ---------- */
@media (max-width: 767px) {
    #filter-details:not([open]) #filter-layout { display: none; }
    #filter-layout {
        flex-direction: column;
        gap: 1em;
    }
    #filter-right {
        flex-wrap: wrap;
        gap: 1em;
    }
    #report-filter-layout {
        flex-direction: column;
        gap: 1em;
    }
}

/* ============================================================
   17. RESPONSIVE — GLOBAL
   ============================================================ */
@media (max-width: 768px) {
  .nav-inner { padding: 0 20px; gap: 16px; }
  .nav-links { gap: 16px; }
  .nav-links a { font-size: 13px; }
  main { padding: 0 20px; }
  footer#footer .footer-inner { padding: 0 20px; }

  .section-head { gap: 16px; }
  .section-head h1 { font-size: 30px; }
  .section-head h2 { font-size: 26px; }
  .section-tag { font-size: 12px; padding-top: 10px; }
  .section-tag::before { width: 80px; }

  .hero { padding: 48px 0 40px; }
  .lead { font-size: 17px; }
  section.block { padding: 56px 0 24px; }

  /* Form collapse: textarea / filter / button stack. */
  .form-grid { grid-template-columns: 1fr; gap: 16px; }
  .form-side { min-height: 0; }
  .ip-textarea { min-height: 152px; }

  .two-col { grid-template-columns: 1fr; gap: 32px; max-width: 100%; }
  .about-grid { grid-template-columns: 1fr; gap: 32px; }
}

@media (max-width: 480px) {
  /* Compact nav: keep wordmark + first 2 links + theme toggle. */
  .nav-links a:nth-child(n+3) { display: none; }
}

@media print {
  .nav, .theme-toggle, .actions { display: none; }
}

/* ============================================================
   18. REPORT PAGE (report.php)
   Reuses the #results-table / palette tokens above and adds report-only
   structure: range groups, block-rules tabs, format previews, hosting
   callouts, the report-filter mirror, and the marketing CTAs.
   ============================================================ */
.report-section {
  padding: 56px 0 64px;
}
.report-inner {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 0 32px;
}
@media (max-width: 768px) {
  .report-section { padding: 32px 0 48px; }
  .report-inner { padding: 0 20px; }
}

/* Header rows: H2 + meta + verdict badge. */
.report-inner > h2,
.report-header-row h2 {
  font-family: var(--font-sans);
  font-weight: 900;
  font-size: 34px;
  letter-spacing: -0.025em;
  line-height: 1.05;
  color: var(--text);
  margin: 0;
}
.report-inner h3 {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 20px;
  letter-spacing: -0.015em;
  color: var(--text);
  margin: 32px 0 12px;
}
.report-inner p {
  color: var(--text-muted);
  line-height: 1.6;
  margin: 0 0 12px;
}
.report-inner p strong { color: var(--text); font-weight: 500; }
.report-inner code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  color: var(--text);
  background: var(--surface);
  padding: 1px 6px;
  border-radius: var(--r-sm);
}

/* Stat-pill: surface-2 with hairline. */
.report-inner .stat-pill {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border-radius: var(--r-pill);
  padding: 5px 12px;
  opacity: 1;
  white-space: nowrap;
}

/* Header meta line (123 IPs · April 30, 2026) */
.report-inner .report-header-stats {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  opacity: 1;
}

/* Email notice + community banner: surface card with accent-purple inset bar. */
.report-inner .report-email-notice,
.report-inner .community-intel-banner,
.report-inner #community-consent-banner {
  background: var(--surface) !important;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent-purple) !important;
  border-radius: var(--r-md);
  color: var(--text-muted);
  padding: 14px 18px !important;
  margin-bottom: 20px !important;
  font-size: 14px !important;
}
.report-inner .report-email-notice strong,
.report-inner .community-intel-banner strong { color: var(--text); }

/* Demo banner — same surface treatment, magenta inset to signal "preview". */
.report-inner > div[style*="background:rgba(224,168,90"] {
  background: var(--surface) !important;
  border: 1px solid var(--border);
  border-left: 3px solid var(--magenta) !important;
  border-radius: var(--r-md);
  color: var(--text-muted) !important;
  padding: 14px 18px !important;
}

/* Tables in the report — adopt the #results-table treatment. */
.report-inner table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-sans);
  font-size: 13px;
  margin: 16px 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
}
.report-inner thead th {
  text-align: left;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  white-space: nowrap;
}
.report-inner tbody td {
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.report-inner tbody tr:last-child td { border-bottom: 0; }

/* Section heads inside the report — canonical .section-head pattern (H_ left
   + 0X / LABEL right + 4px purple rule above the tag). */
.report-inner .section-head h3 {
  font-size: 28px;
  font-weight: 900;
  letter-spacing: -0.025em;
  line-height: 1.05;
  margin: 0;
}

/* Generous breathing room between major report subsections. The default
   .section-head margin (20px) is sized for top-level pages; in a long
   report the gap needs to read as a section break, not a paragraph break.
   DESIGN.md spec: 96-128px between sections; 80px is the desktop compromise. */
.report-inner .section-head {
  margin-top: 80px;
  margin-bottom: 24px;
}
@media (max-width: 768px) {
  .report-inner .section-head {
    margin-top: 56px;
    margin-bottom: 16px;
  }
}

/* Filled verdict pills inside Top Threat Sources. The per-classification color
   (.asn-category--scanning etc.) drives both bg + border via currentColor +
   color-mix, so the verdict palette stays the single source of truth. */
.report-inner .asn-category {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  border: 1px solid color-mix(in srgb, currentColor 32%, transparent);
  background: color-mix(in srgb, currentColor 12%, transparent);
}

/* ---------- 18a. Ranges + Block Rules layout ---------- */
.ranges-stack {
    margin-bottom: 2em;
}
.block-rules-fullwidth {
    margin-bottom: 2em;
}

.ranges-rules-grid {
    display: flex !important;
    gap: 2.5em;
    align-items: flex-start;
    margin-bottom: 2em;
}
.ranges-col {
    flex: 2;
    min-width: 0;
    overflow: hidden;
}
.rules-col {
    flex: 1;
    min-width: 0;
    position: sticky;
    top: 2em;
    align-self: flex-start;
}

/* In the right column, stack download buttons vertically full-width. */
.rules-col .block-rules-panel {
    flex-direction: column;
    gap: 0.45em;
}
.rules-col .block-rules-panel .button {
    display: block;
    width: 100%;
    box-sizing: border-box;
    text-align: center;
}

/* Block Rules + Hosting Callout side-by-side at desktop, stacked below.
   Activates ONLY in stack mode (.block-rules-fullwidth parent). */
.report-inner .block-rules-grid > .block-rules-grid-main,
.report-inner .block-rules-grid > .block-rules-grid-rail { min-width: 0; }
@media (min-width: 960px) {
  .report-inner .block-rules-fullwidth > .block-rules-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 32px;
    align-items: start;
  }
}

/* ---------- 18b. ASN range groups + CIDR chips ---------- */
.asn-range-group {
    margin-bottom: 1em;
    padding-bottom: 1em;
    border-bottom: 1px solid rgba(255,255,255,0.07);
}
.asn-range-group:last-child {
    border-bottom: none;
    padding-bottom: 0;
    margin-bottom: 0;
}
.asn-range-header {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.35em;
    margin-bottom: 0.5em;
}
.asn-range-org {
    font-size: 0.88em;
    opacity: 0.65;
}
.asn-range-count {
    font-size: 0.72em;
    opacity: 0.4;
}
.cidr-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35em;
}
.cidr-chip {
    font-family: var(--font-mono);
    font-size: 0.78em;
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 3px;
    padding: 0.2em 0.5em;
    white-space: nowrap;
    line-height: 1.4;
    user-select: all;
}

/* Stack ranges/rules columns on tablet and below */
@media (max-width: 900px) {
    .ranges-rules-grid {
        flex-direction: column;
        gap: 0;
    }
    .rules-col {
        position: static;
        margin-top: 3.5em;
    }
    .rules-col .block-rules-panel {
        flex-direction: row;
        flex-wrap: wrap;
    }
    .rules-col .block-rules-panel .button {
        display: inline-block;
        width: auto;
    }
}

/* ---------- 18c. Block-rules tabs + panel ---------- */
.block-rules-tablist {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--border);
    margin-bottom: 1em;
}
.block-rules-tab {
    cursor: pointer;
    padding: 0.3em 1.2em 0.4em;
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: bold;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
    opacity: 0.45;
    border-bottom: 2px solid transparent;
    border-color: var(--border);
    margin-bottom: -1px;
    user-select: none;
    transition: opacity 0.15s ease, border-color 0.15s ease;
    outline: none;
}
.block-rules-tab.active {
    opacity: 1;
    color: var(--text);
    border-bottom-color: var(--accent-purple);
}
.block-rules-tab:not(.active):not(.brt-disabled):hover {
    opacity: 0.7;
}
.block-rules-tab:focus-visible {
    outline: 2px solid rgba(255,255,255,0.5);
    outline-offset: 2px;
}
.block-rules-tab.brt-disabled {
    opacity: 0.2;
    cursor: not-allowed;
}
.block-rules-panel {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5em;
    padding: 12px 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    margin: 12px 0;
}
.block-rules-panel .button {
    margin: 0;
}
/* (block-rules-panel[hidden] is honored by the global [hidden] rule in §2.) */

/* ---------- 18d. Format-block (CIDR / iptables / ufw / nginx preview) ---------- */
.format-entry {
    width: 100%;
    margin-bottom: 0.5em;
}
.format-toggle {
    font-family: var(--mono, var(--font-mono));
    font-size: 0.82em;
    text-align: left;
    width: 100%;
}
.format-block {
    margin-top: 0.4em;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface);
    overflow: hidden;
}
.format-block pre,
.block-rules-panel pre {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text);
    padding: 14px 16px;
    margin: 0;
    overflow-x: auto;
}
.block-script-preview {
    margin: 0;
    padding: 0.75em 1em;
    font-size: 0.78em;
    line-height: 1.55;
    max-height: 280px;
    overflow-y: auto;
    white-space: pre;
}
.format-actions {
    display: flex;
    align-items: center;
    gap: 0.5em;
    padding: 0.5em 0.75em;
    background: rgba(255,255,255,0.04);
    border-bottom: 1px solid rgba(255,255,255,0.08);
}
.format-actions .copy-btn,
.format-actions .button.small {
    flex: 1;
    text-align: center;
    justify-content: center;
}
.copy-btn {
    cursor: pointer;
    color: inherit;
    background: transparent;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.cidr-explainer {
    font-size: 0.82em;
    opacity: 0.7;
    margin: 0 0 0.75em;
    font-style: italic;
}

/* ---------- 18e. AbuseIPDB + hosting callouts ---------- */
.report-inner .abuseipdb-callout {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent-purple);
  border-radius: var(--r-md);
  padding: 14px 18px;
  margin: 16px 0 20px;
  font-size: 14px;
  color: rgba(138,180,212,0.9);
}

.hosting-callout {
    margin-bottom: 1.25em;
    padding: 0.7em 1em;
    font-size: 0.86em;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: rgba(255,255,255,0.04);
    line-height: 1.5;
}
.report-inner .hosting-callout { margin-top: 1.25em; }
.hosting-callout-links {
    margin: 0.4em 0 0;
    padding-left: 1.4em;
}
.hosting-callout-links li { margin-bottom: 0.2em; }
.hosting-note {
    opacity: 0.6;
    font-size: 0.92em;
}
.report-inner .hosting-note { margin: 10px 0 0; }
.report-inner .hosting-prose-fine {
  font-size: 0.9em;
  color: var(--text-muted);
  opacity: 0.85;
  margin-bottom: 8px;
}

/* ---------- 18f. Free-report upgrade CTA ---------- */
.free-report-upgrade {
    margin: 1.5em 0 2em;
    padding: 1.2em 1.4em;
    border: 1px solid rgba(224,168,90,0.25);
    border-left-width: 3px;
    border-left-color: var(--verdict-moderate);
    border-radius: var(--r-md);
    background: rgba(224,168,90,0.07);
}
.free-report-upgrade__headline {
    margin: 0 0 0.5em;
    font-weight: bold;
}
.free-report-upgrade__features {
    list-style: none;
    padding: 0;
    margin: 0 0 1em;
    font-size: 0.88em;
}
.free-report-upgrade__features li {
    padding: 0.2em 0;
}
.free-report-upgrade__features li::before {
    content: '✓  ';
    opacity: 0.45;
}
.free-report-upgrade__fine {
    margin: 0.6em 0 0;
    font-size: 0.82em;
    opacity: 0.55;
}

/* ---------- 18g. Report-page block-script filter (mirror of the home filter) ---------- */
#report-filter {
    margin-bottom: 2em;
}

#report-filter-layout {
    display: flex;
    gap: 1.5em;
    padding: 0.6em 0 0.5em;
    flex-wrap: wrap;
    align-items: flex-start;
}

#report-filter-categories {
    display: flex;
    flex-direction: column;
    gap: 0.3em;
}

#report-filter-countries {
    display: flex;
    flex-direction: column;
    gap: 0.3em;
}

#report-filter-countries .filter-chips {
    max-height: 9.8em;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.3em;
}

/* ---------- 18h. Inline-style sweep — classes backing the styles previously
   hardcoded on the markup in report.php / report_functions.php. ---------- */

/* Free-report top-IPs table */
.report-inner .report-table-wrap { overflow-x: auto; }
.report-inner .report-free-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9em;
}
.report-inner .report-free-table th,
.report-inner .report-free-table td {
  padding: 6px 10px;
  text-align: left;
}
.report-inner .report-free-table th { white-space: nowrap; }
.report-inner .report-free-table .col-num { color: var(--text-muted); opacity: 0.7; }
.report-inner .report-free-table .col-mono { font-family: var(--font-mono); font-feature-settings: "tnum" 1; }

/* Global col-mono — the canonical "monospace digits, aligned" class. Used
   unwrapped in report.php Top Threat Sources (IP, hits) and intel.php (CIDR),
   where there's no per-table wrapper class to scope against. */
.col-mono { font-family: var(--font-mono); font-feature-settings: "tnum" 1; }
.report-inner .report-free-table .col-asn { font-size: 0.85em; }
.report-inner .report-free-table .col-asn .asn-org { opacity: 0.6; margin-left: 4px; }
.report-inner .report-free-table .col-right { text-align: right; }
.report-inner .report-free-table .col-locked { text-align: right; opacity: 0.35; }
.report-inner .report-free-table th.col-locked { opacity: 1; color: var(--text-muted); }

/* Generic dim-dash placeholder (was inline span style="opacity:0.4">—</span>) */
.dim-dash { opacity: 0.4; }

/* Small note above tables */
.report-inner .report-table-note {
  font-size: 0.85em;
  color: var(--text-muted);
  margin: 0 0 8px;
}

/* H3 inline summary span (the "showing X of Y" in Top Threat Sources) */
.report-inner .report-list-summary {
  font-size: 0.6em;
  font-weight: normal;
  color: var(--text-muted);
  opacity: 0.7;
  margin-left: 8px;
  letter-spacing: 0.04em;
}

/* Free-report expiry banner */
.report-inner .free-report-expiry {
  margin: 1.5em 0;
  padding: 12px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--text-muted);
  border-radius: var(--r-md);
  font-size: 14px;
  color: var(--text-muted);
}
.report-inner .free-report-expiry a {
  margin-left: 8px;
  color: var(--accent-purple);
}

/* Free-report share row */
.report-inner .free-report-share { margin: 1.5em 0; }
.report-inner .free-report-share-label {
  margin: 0 0 8px;
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
.report-inner .free-report-share-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.report-inner .free-report-share-input {
  font-family: var(--font-mono);
  font-size: 12px;
  padding: 8px 12px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  flex: 1;
  min-width: 0;
  max-width: 36em;
}

/* Bottom attribution line on the free report */
.report-inner .report-footer-note {
  margin-top: 2em;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  color: var(--text-muted);
  opacity: 0.7;
}
.report-inner .report-footer-note a { color: var(--text-muted); }
.report-inner .report-footer-note a:hover { color: var(--accent-purple); }

/* Report header row — title left, meta right; verdict-row variant. */
.report-inner .report-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 8px;
}
.report-inner .report-header-row h2 { margin: 0; }
.report-inner .report-verdict-row { margin-top: 12px; }
.report-inner .report-verdict-row .asn-verdict { margin: 0; }
.report-inner .report-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}
.report-inner .report-actions .button { white-space: nowrap; }
@media (max-width: 736px) {
  .report-inner .report-header-row { flex-direction: column; align-items: flex-start; gap: 4px; }
  .report-inner .print-report-btn { display: none; }
}

/* "No high-confidence threats" note (LOW verdict) and "no ASN ranges" */
.report-inner .report-quiet-note,
.report-inner .report-no-ranges {
  font-size: 0.9em;
  color: var(--text-muted);
  opacity: 0.85;
  margin: 8px 0;
}

/* Demo banner — reuse for both "Demo Report" and any preview banner. */
.report-inner .demo-banner {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--magenta);
  border-radius: var(--r-md);
  padding: 12px 18px;
  margin-bottom: 1.5em;
  font-size: 14px;
  color: var(--text-muted);
}
.report-inner .demo-banner strong { color: var(--text); }
.report-inner .demo-banner a {
  margin-left: 12px;
  color: var(--accent-purple);
}

/* Community Intel banner consent buttons + collapsed state */
.report-inner .community-banner-prose {
  margin: 6px 0 12px;
}
.report-inner .community-banner-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.report-inner .community-banner-fine {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--text-muted);
  opacity: 0.7;
}
.report-inner .consent-collapsed {
  font-size: 13px;
  color: var(--text-muted);
}
.report-inner .consent-reconsider-link {
  color: var(--accent-purple);
  text-decoration: underline;
  cursor: pointer;
  margin-left: 4px;
}
.report-inner .privacy-link {
  color: var(--text-muted);
  font-size: 0.9em;
  margin-left: 4px;
}
.report-inner .community-banner-prose-tight { margin: 8px 0 5px; opacity: 0.85; }
.report-inner .community-banner-list { margin: 0; padding-left: 24px; }
.report-inner .community-banner-refresh-row { margin: 12px 0 0; }

/* Generic fine print at the bottom of report sections (e.g. data-retention notes) */
.report-inner .report-fine-print {
  font-size: 12px;
  color: var(--text-muted);
  opacity: 0.7;
  margin: 1em 0 0;
}

/* Community-preview table (the locked-tier teaser) */
.report-inner .community-preview-banner {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent-purple);
  border-radius: var(--r-md);
  padding: 12px 18px;
  margin-bottom: 1.5em;
  font-size: 14px;
  color: var(--text-muted);
}
.report-inner .community-preview-banner strong { color: var(--text); }
.report-inner .community-preview-tag {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-left: 6px;
}
.report-inner .community-preview-table {
  width: 100%;
  font-size: 0.85em;
  border-collapse: collapse;
  margin: 8px 0 0;
}
.report-inner .community-preview-table th {
  text-align: left;
  padding: 4px 12px 4px 0;
  font-weight: normal;
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.report-inner .community-preview-table td {
  padding: 3px 12px 3px 0;
  color: var(--text-muted);
}
.report-inner .community-preview-table .ip-mono {
  font-family: var(--font-mono);
  color: var(--text);
  opacity: 0.85;
}

/* Inline link with utility margin (was style="margin-left:0.5em" or "1em") */
.report-inner .inline-after { margin-left: 8px; }
.report-inner .inline-after-lg { margin-left: 16px; }
.report-inner .margin-top-1 { margin-top: 1em; }

/* ============================================================
   19. MARKETING / UTILITY PAGES
   Long-form prose (changelog, legal, privacy), the community block list
   (intel.php), and the resend-email form (send-report-link.php). Scoped
   under .report-inner so they inherit the same content rhythm as the
   report page.
   ============================================================ */

/* Subtitle line directly under a section-head H1 (e.g. intel "Past 7 days") */
.report-inner .section-subtitle {
  margin: -4px 0 24px;
  color: var(--text-muted);
  font-size: 14px;
}

/* Long-form prose: changelog, legal, privacy, etc. */
.report-inner .prose h3 {
  margin: 1.6em 0 0.4em;
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: 0.01em;
}
.report-inner .prose h3:first-child { margin-top: 0; }
.report-inner .prose p {
  margin: 0 0 1em;
  color: var(--text);
  line-height: 1.65;
}
.report-inner .prose ol,
.report-inner .prose ul {
  margin: 0 0 1em 1.4em;
  color: var(--text);
  line-height: 1.65;
}
.report-inner .prose li { margin: 0.2em 0; }
.report-inner .prose code {
  font-family: var(--font-mono);
  font-size: 12.5px;
  padding: 1px 5px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 3px;
  color: var(--text);
}

/* Subtle inline link */
.report-inner .link-muted {
  font-size: 13px;
  color: var(--text-muted);
  text-decoration: underline;
  text-decoration-color: var(--border);
}
.report-inner .link-muted:hover { color: var(--accent-purple); }

/* Horizontal button row with consistent gap + wrap */
.report-inner .button-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 1.5em 0;
}

/* Horizontal-scroll wrapper for tables wider than the inner column */
.report-inner .table-wrapper--scroll { overflow-x: auto; }

/* Community block list table (intel.php) */
.report-inner .intel-table {
  width: 100%;
  border-collapse: collapse;
  margin: 0.5em 0 0;
  font-size: 14px;
}
.report-inner .intel-table th,
.report-inner .intel-table td {
  padding: 10px 14px;
  text-align: left;
  border-bottom: 1px solid var(--border);
}
.report-inner .intel-table th {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  background: var(--surface);
}
.report-inner .intel-table td { color: var(--text); }
.report-inner .intel-table .col-mono {
  font-family: var(--font-mono);
  font-feature-settings: "tnum" 1;
}

/* Hairline separator between body and CTAs */
.report-inner .section-rule {
  height: 1px;
  border: 0;
  background: var(--border);
  margin: 2em 0 1.5em;
}

/* Form-level error message */
.report-inner .form-error {
  color: var(--magenta);
  margin: 0 0 1em;
}

/* Mono-display token */
.report-inner .token-display {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-muted);
  word-break: break-all;
}

/* Resend-link form: constrain width + space the submit button */
.report-inner .resend-form { max-width: 420px; }
.report-inner .resend-form .field { margin-bottom: 1em; }
.report-inner .form-actions { margin-top: 1em; }

/* ============================================================
   20. COMMUNITY BLOCK LIST CALLOUT
   The "No console/SSH access?" link below the iptables/ufw/nginx buttons.
   Inline opacity:0.7 on the wrapper used to dim the link too, killing
   affordance — prose stays muted, link uses accent + underline so it reads
   as a CTA.
   ============================================================ */
.cbl-callout {
  margin: 12px 0 0;
  font-size: 13px;
  color: var(--text-muted);
}
.cbl-link {
  color: var(--accent-purple);
  text-decoration: underline;
  text-decoration-color: var(--accent-purple);
  text-underline-offset: 5px;
  font-weight: 500;
  white-space: nowrap;
}
.cbl-link:hover {
  color: var(--magenta);
  text-decoration-color: var(--magenta);
}
