/* ─────────────────────────────────────────────────────────────────────────────
   asn.dev design system
   ─────────────────────────────────────────────────────────────────────────────

   Deliberately NOT the ipinfo house theme (near-black #080c10, cyan #00d4ff,
   JetBrains Mono, dot grid, CRT scanlines). asn.dev is a sibling product, not a
   sub-page of that suite, so it needs to read as its own thing at a glance.

   The reference is drafted survey documents and nautical charts rather than a
   terminal: ink on paper, hairline rules, near-square corners, mono labels in
   tracked small caps, and a single burnt-orange survey-marker accent. Depth
   comes from whitespace and rule weight, never from glow or shadow.

   Light-first with a dark counterpart. Both are first-class; the toggle in the
   masthead writes to localStorage and the inline bootstrap in layout.js applies
   it before first paint.

   Accent contrast: --accent is the text-safe tone (5.1:1 on paper, 8.8:1 on
   ink) and --accent-strong is the more saturated tone reserved for non-text use
   (rules, fills, focus rings). Do not swap them without re-checking contrast.
   ───────────────────────────────────────────────────────────────────────────── */

/* ── Tokens ────────────────────────────────────────────────────────────────── */

:root {
  --paper:        #faf8f4;
  --surface:      #ffffff;
  --surface-sunk: #f3f0ea;

  --ink:    #1a1d21;
  --ink-2:  #4a5158;
  --ink-3:  #7c858e;

  --rule:       #dfdad1;
  --rule-heavy: #c6bfb2;

  --accent:        #a24e00;
  --accent-strong: #c25e00;
  --accent-soft:   #fdf0e4;

  --ok:    #1e7a4b;
  --warn:  #8a5c00;
  --bad:   #b3261e;
  --info:  #20618f;

  --ok-soft:   #e6f4ec;
  --warn-soft: #fbf1dc;
  --bad-soft:  #fbeae9;
  --info-soft: #e7f0f8;

  --sans: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;

  /* Near-square corners keep the drafted feel; 2px only softens the pixel edge. */
  --radius: 2px;

  --wrap: 74rem;
}

:root[data-theme='dark'] {
  --paper:        #14161a;
  --surface:      #1b1e23;
  --surface-sunk: #101215;

  --ink:    #e8e6e1;
  --ink-2:  #a8aeb6;
  --ink-3:  #6e767f;

  --rule:       #2a2f36;
  --rule-heavy: #3d444d;

  --accent:        #ff9a54;
  --accent-strong: #ff9040;
  --accent-soft:   #2a1b0f;

  --ok:    #4cc98a;
  --warn:  #e0a93b;
  --bad:   #f2685e;
  --info:  #6ba8dc;

  --ok-soft:   #12271c;
  --warn-soft: #2a2211;
  --bad-soft:  #2d1614;
  --info-soft: #14212c;
}

/* ── Base ──────────────────────────────────────────────────────────────────── */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  /* Anchor targets clear the sticky masthead instead of hiding under it. */
  scroll-padding-top: 5rem;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  margin: 0 0 0.5em;
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.011em;
}

h1 { font-size: clamp(1.9rem, 1.4rem + 1.8vw, 2.7rem); }
h2 { font-size: 1.4rem; }
h3 { font-size: 1.1rem; }

p { margin: 0 0 1rem; }

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

a:hover { text-decoration-thickness: 2px; }

code, kbd, samp, .mono {
  font-family: var(--mono);
  font-size: 0.92em;
}

:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: 2px;
}

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: 1.5rem;
}

/* Screen-reader-only, but still focusable — used for form labels. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  z-index: 100;
  padding: 0.6rem 1rem;
  background: var(--surface);
  border: 1px solid var(--rule-heavy);
}

.skip-link:focus {
  left: 0.5rem;
  top: 0.5rem;
}

/* ── Masthead ──────────────────────────────────────────────────────────────── */

.masthead {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--rule);
}

.masthead-inner {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  min-height: 4rem;
  padding-block: 0.75rem;
}

.wordmark {
  flex: none;
  font-family: var(--mono);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
}

.wordmark-dot { color: var(--accent-strong); }
.wordmark-tld { color: var(--ink-3); }

.search {
  flex: 1 1 auto;
  display: flex;
  gap: 0.5rem;
  min-width: 0;
}

.search input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.55rem 0.75rem;
  font-family: var(--mono);
  font-size: 0.9rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--rule-heavy);
  border-radius: var(--radius);
}

.search input::placeholder {
  color: var(--ink-3);
  /* The placeholder is a syntax hint, not a prompt — keep it quiet. */
  opacity: 1;
}

.search input:focus {
  outline: none;
  border-color: var(--accent-strong);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.search button,
.btn {
  flex: none;
  padding: 0.55rem 1rem;
  font-family: var(--sans);
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--paper);
  background: var(--ink);
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  cursor: pointer;
}

.search button:hover,
.btn:hover {
  background: var(--accent);
  border-color: var(--accent);
}

.theme-toggle {
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  font-size: 1rem;
  color: var(--ink-2);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  cursor: pointer;
}

.theme-toggle:hover {
  color: var(--accent);
  border-color: var(--rule-heavy);
}

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

.hero {
  padding-block: clamp(3rem, 2rem + 5vw, 5.5rem) 2.5rem;
  border-bottom: 1px solid var(--rule);
}

.hero-eyebrow,
.eyebrow {
  margin: 0 0 0.9rem;
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

.hero-lede {
  max-width: 46rem;
  font-size: 1.12rem;
  color: var(--ink-2);
}

/* Sample-query strip under the hero lede. */
.examples {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
  margin: 1.75rem 0 0;
  padding: 0;
  list-style: none;
}

.examples li {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

.examples a {
  font-size: 0.9rem;
  font-weight: 500;
}

.examples span {
  font-size: 0.8rem;
  color: var(--ink-3);
}

/* ── Sections ──────────────────────────────────────────────────────────────── */

.section { padding-block: 2.5rem; }

.section > h1 { margin-bottom: 1rem; }

/* Body copy inside a section shouldn't run the full grid width. */
.section > p { max-width: 46rem; }

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

.panel {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 1.5rem;
}

/* Stacking margin for panels laid out in normal flow. */
.panel + .panel { margin-top: 1.25rem; }

/* Grid gap already handles spacing between cards. Without this reset the
   sibling margin above pushes every panel after the first down by 1.25rem, so a
   row of cards lands with staggered tops instead of a flush edge. */
.grid > .panel + .panel { margin-top: 0; }

.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--rule);
}

.panel-head h2,
.panel-head h3 { margin: 0; }

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

/* ── Stat tiles ────────────────────────────────────────────────────────────── */

.stat {
  padding: 1rem 1.25rem;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-left: 2px solid var(--accent-strong);
  border-radius: var(--radius);
}

.stat-label {
  display: block;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.stat-value {
  display: block;
  margin-top: 0.35rem;
  font-family: var(--mono);
  font-size: 1.5rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* ── Badges ────────────────────────────────────────────────────────────────── */

/* Status is never colour-alone — every badge carries its own text label. */
.badge {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 500;
  border: 1px solid currentColor;
  border-radius: var(--radius);
}

.badge-ok   { color: var(--ok);   background: var(--ok-soft); }
.badge-warn { color: var(--warn); background: var(--warn-soft); }
.badge-bad  { color: var(--bad);  background: var(--bad-soft); }
.badge-info { color: var(--info); background: var(--info-soft); }
.badge-mute { color: var(--ink-3); background: var(--surface-sunk); }

/* ── Tables ────────────────────────────────────────────────────────────────── */

.table-scroll { overflow-x: auto; }

/* Long inventory tables get a bounded viewport instead of extending the page
   indefinitely. AS15169's prefix list alone made the page ~18,000px tall. */
.table-scroll.is-tall {
  max-height: 34rem;
  overflow-y: auto;
}

/* Keep the header visible while scrolling a bounded table. */
.table-scroll.is-tall thead th {
  position: sticky;
  top: 0;
  background: var(--surface);
  z-index: 1;
}

table.data {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: 0.88rem;
}

table.data thead th {
  padding: 0.5rem 0.75rem;
  text-align: left;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  border-bottom: 1px solid var(--rule-heavy);
  white-space: nowrap;
}

table.data td {
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}

table.data tbody tr:hover { background: var(--surface-sunk); }

table.data .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Operator names come from RIPE's AS-name list, where the median is 23
   characters but the tail reaches 203 ("Federal State Budget Institution
   NATIONAL MEDICAL RESEARCH CENTER FOR OBSTETRICS, GYNECOLO..."). Bounding the
   cell keeps the five columns aligned instead of letting 0.5% of networks force
   a horizontal scrollbar; the untruncated value stays on the title attribute.
   34ch sits between p50 (23) and p90 (45). */
table.data .netname {
  display: inline-block;
  max-width: 34ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* inline-block on the cell baseline otherwise drops the row by a pixel. */
  vertical-align: bottom;
}

/* ── Notices ───────────────────────────────────────────────────────────────── */

.notice {
  padding: 1rem 1.25rem;
  background: var(--surface-sunk);
  border: 1px dashed var(--rule-heavy);
  border-radius: var(--radius);
  color: var(--ink-2);
}

.notice h2,
.notice h3 { color: var(--ink); }

.notice p:last-child { margin-bottom: 0; }

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

.footer {
  margin-top: 4rem;
  padding-block: 2.5rem;
  border-top: 1px solid var(--rule);
  background: var(--surface-sunk);
  font-size: 0.9rem;
  color: var(--ink-2);
}

/* Single column since the sibling-tools nav was removed. Still a grid rather
   than plain flow so the spacing between the three lines is set once here
   instead of as three paragraph margins. */
.footer-inner {
  display: grid;
  gap: 0.35rem;
}

.footer-lede {
  max-width: 40rem;
  margin-bottom: 0.6rem;
}

/* Build stamp and credit read as one quiet mono block under the lede. */
.footer-meta,
.footer-built {
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--ink-3);
  margin: 0;
}

/* ── Staging banner ────────────────────────────────────────────────────────── */

/* The banner is position:fixed, so it would otherwise sit on top of the last
   rows of the footer. The script that injects it also sets this class, which
   reserves the space it occupies. */
body.has-dev-banner { padding-bottom: 2.25rem; }

.dev-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 50;
  padding: 0.35rem 1rem;
  text-align: center;
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #fff;
  background: var(--bad);
}

/* ── Responsive ────────────────────────────────────────────────────────────── */

@media (max-width: 48rem) {
  .masthead-inner {
    flex-wrap: wrap;
    row-gap: 0.75rem;
  }

  /* Search drops to its own full-width row below the wordmark and toggle. */
  .search {
    order: 3;
    flex-basis: 100%;
  }

  .theme-toggle { margin-left: auto; }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ── Entity heads ──────────────────────────────────────────────────────────── */

.entity-head {
  padding-block: 2.5rem 1.5rem;
}

.entity-head h1 {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.6em;
}

/* The registry name sits beside the identifier at a smaller weight: the AS
   number is the fact, the name is the label people recognise. */
.entity-name {
  font-family: var(--sans);
  font-size: 0.55em;
  font-weight: 500;
  color: var(--ink-2);
  letter-spacing: 0;
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.75rem 0 0;
}

/* ── Sub-navigation ────────────────────────────────────────────────────────── */

.subnav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--rule);
}

.subnav-item {
  padding: 0.5rem 0.9rem;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink-2);
  text-decoration: none;
  /* Transparent underline reserves the space, so the current item doesn't
     shift the row by 2px when it gains its rule. */
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.subnav-item:hover { color: var(--ink); }

.subnav-item.is-current {
  color: var(--accent);
  border-bottom-color: var(--accent-strong);
}

/* Sections that exist in the information architecture but aren't built yet.
   Shown rather than hidden so the shape of the site is legible. */
.subnav-item.is-pending {
  color: var(--ink-3);
  cursor: default;
}

.subnav-item.is-pending::after {
  content: ' · soon';
  font-size: 0.85em;
}

/* ── Stat row ──────────────────────────────────────────────────────────────── */

.stat-row {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  margin-bottom: 1.5rem;
}

.stat-note {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.78rem;
  color: var(--ink-3);
}

/* ── Panel header aside ────────────────────────────────────────────────────── */

.panel-aside {
  flex: none;
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--ink-3);
}

/* ── Definition lists ──────────────────────────────────────────────────────── */

.deflist {
  display: grid;
  /* Label column sizes to content but never crowds the value column. */
  grid-template-columns: minmax(8rem, max-content) 1fr;
  gap: 0.5rem 1.5rem;
  margin: 0;
}

.deflist dt {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-top: 0.15rem;
}

.deflist dd {
  margin: 0;
  word-break: break-word;
}

/* ── Prose (description cards) ─────────────────────────────────────────────── */

.prose { max-width: 46rem; }

.prose h3 {
  margin-top: 1.5rem;
  font-size: 1rem;
}

.prose h4 {
  margin-top: 1.25rem;
  font-size: 0.92rem;
  color: var(--ink-2);
}

.prose ul {
  /* padding-left, not margin: a bullet that wraps then hangs under its own
     first line rather than under the marker. */
  margin: 0 0 1rem;
  padding-left: 1.25rem;
}

.prose li { margin-bottom: 0.35rem; }

.prose code {
  padding: 0.1em 0.35em;
  background: var(--surface-sunk);
  border-radius: var(--radius);
}

/* ── Bar chart ─────────────────────────────────────────────────────────────── */

.bar-chart {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.bar-row {
  display: grid;
  grid-template-columns: 3.5rem 1fr 4.5rem;
  align-items: center;
  gap: 0.75rem;
}

.bar-label {
  font-family: var(--mono);
  font-size: 0.82rem;
  color: var(--ink-2);
  text-align: right;
}

.bar-track {
  width: 100%;
  height: 0.85rem;
  background: var(--surface-sunk);
  border-radius: var(--radius);
  /* The <rect> inside inherits this via fill="currentColor", so each theme
     supplies its own accent instead of one being flipped into the other. */
  color: var(--accent-strong);
  display: block;
}

.bar-value {
  font-family: var(--mono);
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

/* ── Filter row ────────────────────────────────────────────────────────────── */

.filter-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.filter-row input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.5rem 0.7rem;
  font-family: var(--mono);
  font-size: 0.85rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--rule-heavy);
  border-radius: var(--radius);
}

.filter-row input:focus {
  outline: none;
  border-color: var(--accent-strong);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.filter-count {
  flex: none;
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--ink-3);
}

/* ── Link lists ────────────────────────────────────────────────────────────── */

.link-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ── Small print ───────────────────────────────────────────────────────────── */

.fineprint {
  margin: 1rem 0 0;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--ink-3);
}

.fineprint:last-child { margin-bottom: 0; }

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

/* ── Click-out interstitial ────────────────────────────────────────────────── */

/*
 * /out is a full-stop page, so it gets a narrow measure and a lot of air. The
 * hostname is the one thing a visitor actually needs to read, so it is set
 * large and in mono; the full URL sits under it, smaller, for anyone who wants
 * to check the path before committing.
 */
.out {
  max-width: 42rem;
}

.out-host {
  margin: 0.5rem 0 0.25rem;
  font-family: var(--mono);
  font-size: clamp(1.35rem, 1rem + 2vw, 1.9rem);
  font-weight: 500;
  color: var(--ink);
  /* A hostname has no spaces, so a long one would otherwise push the layout
     wider rather than wrap. */
  overflow-wrap: anywhere;
}

.out-url {
  margin: 0 0 1.5rem;
  font-size: 0.85rem;
  color: var(--ink-3);
  overflow-wrap: anywhere;
}

.out-lede {
  max-width: 40rem;
  color: var(--ink-2);
}

.out-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
  margin-top: 1.75rem;
}

/* .btn was written for <button>, so an anchor wearing it still inherits the
   base link colour and underline. Undo both. */
.out-actions .btn {
  display: inline-block;
  text-decoration: none;
  color: var(--paper);
}

/* The escape hatch is deliberately the quieter of the two. Leaving is the
   action the visitor already chose; staying only needs to be findable. */
.out-actions .btn-quiet {
  color: var(--ink-2);
  background: transparent;
  border-color: var(--rule-heavy);
}

.out-actions .btn-quiet:hover {
  color: var(--paper);
  background: var(--ink);
  border-color: var(--ink);
}

/* ── Responsive ────────────────────────────────────────────────────────────── */

@media (max-width: 40rem) {
  /* Stack the definition list: side-by-side columns get unreadably narrow. */
  .deflist { grid-template-columns: 1fr; gap: 0.15rem; }
  .deflist dd { margin-bottom: 0.6rem; }

  .bar-row { grid-template-columns: 3rem 1fr 3.5rem; gap: 0.5rem; }
}
