/* ---------------------------------------------------------------------------
   KumoDNS website — the "d2" dark design.
   Build version 3.13.0
   ---------------------------------------------------------------------------

   ⚠️ THIS IS /web2 ONLY. /web keeps the original light stylesheet and is not
   touched by anything here. The two directories are independent copies so that
   reverting is a matter of pointing the docroot back at /web.

   ── WHY IT RESTYLES THE OLD CLASS NAMES RATHER THAN INVENTING NEW ONES ──────

   The site is 26 pages plus 42 wiki articles and 10 blog posts, and every one
   of them is markup written against this stylesheet's class names — .wrap,
   .card, .btn, .section-head, .wiki-body and about a hundred more. Rewriting
   the markup of 78 pages to suit a new stylesheet would have been the slow way
   to redesign and the fast way to lose content.

   So the CLASS CONTRACT IS THE COMPONENT API and this file is a second
   implementation of it. Every class the old stylesheet defined is defined here,
   in the dark palette, so every existing page renders correctly under the new
   design with its markup untouched. New d2-specific components (the
   announcement bar, the hero panel, the plan cards) are additive and live at
   the bottom.

   ⚠️ A CONSEQUENCE WORTH KNOWING: a page that looks wrong in /web2 is usually a
   class this file has not implemented, not a broken page. Check against the
   contract before editing markup.

   ── THE FONT IS STILL SELF-HOSTED ──────────────────────────────────────────

   The supplied design used Arial to work offline. This keeps Inter, served from
   this folder, because includes/seo_check.php FAILS any page that fetches a
   resource from a third party — a font CDN is a request outside our control and
   every visitor's IP address disclosed to whoever serves it. Not a performance
   opinion: the Privacy Policy names its subprocessors and a font CDN nobody
   declared is a gap in a published document.
   --------------------------------------------------------------------------- */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url(../fonts/inter-var-latin-v20.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- tokens ----------

   From the supplied design. The neutrals carry a slight violet bias so they sit
   with the accent rather than beside it; a pure grey against this purple reads
   as two unrelated decisions.

   --ink and --ink-soft exist because a dark page needs TWO text weights far
   more than a light one does: pure white on near-black at body size vibrates,
   so running text is --ink-soft and only headings take --ink. */
:root {
  color-scheme: dark;

  --bg:         #161719;   /* page ground */
  --surface:    #202124;   /* cards, panels */
  --surface-2:  #26272b;   /* raised inside a card */
  --line:       #36373e;   /* hairline */
  --line-soft:  #2b2c31;   /* quieter hairline, code wells */

  --ink:        #fafaff;   /* headings, emphasis */
  --ink-soft:   #c9cad2;   /* running text */
  --muted:      #a7a9b3;   /* secondary */
  --faint:      #83858f;   /* captions, meta */

  --purple:     #8176ff;
  --purple-dim: #6e64ff;
  /* ⚠️ THIS READ `--purple-lit: var(--purple-lit)` UNTIL 6.637.0 — a custom
     property referencing itself, which the spec makes invalid at computed-value
     time. The token resolved to nothing, so every use of it in the DEFAULT
     theme fell back to the guaranteed-invalid value and, `color` being
     inherited, simply took their parent's colour. Links, plan ticks and the
     feature symbols were rendering as body text and had been since the d2
     promotion, on production too. (No count here on purpose — a number baked
     into a comment beside the thing it counts goes stale on the next edit.)
     
     #a79bff is not a new pick: it is the literal `.feature-symbol` already
     carried before it was tokenised, and it is LIGHTER than --purple, which is
     what "lit" means on a dark ground (the light theme inverts that, see the
     note there). 7.50:1 on the page, 6.73:1 on a card. */
  --purple-lit: #a79bff;
  --purple-wash:#8176ff1f;

  /* ⚠️ SAMPLED FROM THE LOGO, NOT PICKED BY EYE. #fc5b27 is the most common
     solid warm pixel in kumodns-logo-d2.png — the "DNS" in the wordmark — so
     the masthead pill and the lockup cannot drift apart. */
  --orange:     #fc5b27;
  --orange-lit: #ff7345;

  --good:       #4ec98a;
  --warn:       #e0a33c;
  --bad:        #ef6b5c;


  /* Surfaces the d2 block needs that the contract layer did not have. */
  --bg-deep:    #131416;   /* footer and the deep decorative panels */
  --surface-alt:#1a1b1e;   /* the alternating section band */
  --line-strong:#4a4b55;   /* a border that has to be seen, not felt */

  /* ⚠️ THE OUTER SHELL WIDTH, IN ONE PLACE. The hero card, the trust strip, the
     announcement bar and the back-to-top rail all have to share a right edge —
     that is the whole reason the theme switch and the button line up — and it
     was written out four times. A token cannot drift. */
  --shell:      min(1400px, 95%);

  /* ⚠️ AND THE INNER ONE. .wrap is what the masthead sits in, so anything that
     has to line up with the "Check our free plan" pill measures against this,
     not --shell. Two containers, two tokens, and neither written out twice. */
  --wrap:       min(1180px, 92%);

  --radius:     16px;
  --radius-sm:  11px;
  --shadow:     0 18px 46px rgba(0,0,0,.42);
  --shadow-sm:  0 6px 18px rgba(0,0,0,.28);
}

/* ---------- the light theme ----------

   ⚠️ DARK IS THE DEFAULT AND LIGHT IS THE OVERRIDE, deliberately. The bare
   :root above carries the dark palette, so a browser that runs no JavaScript,
   or one that runs it before localStorage is readable, gets the design as
   drawn rather than a half-applied light theme.

   ⚠️ NOTHING HERE READS prefers-color-scheme. The choice is the visitor's and it
   is remembered; an OS preference silently overriding a button somebody pressed
   is worse than not offering the button. If that is ever wanted it belongs in
   the inline script as the INITIAL value, not as a media query that fights the
   stored one.

   Most of this is a token swap — the stylesheet was converted to tokens at
   6.617.0 precisely so that it could be. The rules after the tokens are the
   ones that could not be: fixed panels, decorative gradients, and the handful
   of places where a colour is not simply "ink on surface". */
:root[data-theme="light"] {
  color-scheme: light;

  --bg:         #fbfaf8;
  --bg-deep:    #f4f2ee;
  --surface:    #ffffff;
  --surface-2:  #f6f5f2;
  --surface-alt:#f5f3ef;
  --line:       #e6e2da;
  --line-soft:  #f0ede7;
  --line-strong:#cfc9bf;

  --ink:        #1b2330;
  --ink-soft:   #3d4654;
  --muted:      #5c6570;
  /* ⚠️ #69727e, NOT #78818d. The lighter value was 3.78:1 on this page ground,
     which clears AA only for large text — and --faint is the caption and meta
     colour, which is the smallest text on the site. 4.67:1. The dark theme's
     #83858f is already 4.88:1 and needs no change. */
  --faint:      #69727e;

  /* ⚠️ --purple-lit IS DARKER THAN --purple HERE, WHICH IS THE OPPOSITE OF DARK
     MODE. It is the link and accent colour; on a dark ground it has to be light
     to be read, on a light ground it has to be dark. Inverting the palette
     naively is how a light theme ends up with pale lilac links nobody can see. */
  --purple:     #6e64ff;
  --purple-dim: #5a50e8;
  --purple-lit: #4f45d6;
  --purple-wash:#6e64ff16;

  --good:       #1f8f5f;
  --warn:       #9a6b12;
  --bad:        #c0392b;

  --shadow:     0 18px 46px rgba(27,35,48,.10);
  --shadow-sm:  0 6px 18px rgba(27,35,48,.07);
}

/* The rules that are not a token swap. */
:root[data-theme="light"] body { background: var(--bg); }
:root[data-theme="light"] header.site { background: #fbfaf8e6; }
:root[data-theme="light"] .announce { background: var(--surface-alt); }

/* A near-white pill is invisible on a near-white page, so the primary button
   inverts: dark pill, light label. */
:root[data-theme="light"] .btn-primary { background: var(--ink); color: #fff; }
:root[data-theme="light"] .btn-primary:hover { background: var(--purple-dim); color: #fff; }
:root[data-theme="light"] .btn-ghost:hover { background: var(--surface-2); border-color: var(--line-strong); }
:root[data-theme="light"] .tip-bubble { background: #fff; color: var(--ink); }
:root[data-theme="light"] .wiki-search input[type=search]:focus { background-color: #fff; }
:root[data-theme="light"] .review-note { border-color: #e8d8a8; background: #fdf6e6; }

/* The decorative panels. Same composition, light materials — a wash of the
   accent rather than a glow out of the dark. */
:root[data-theme="light"] .hero-card {
  border-color: var(--line);
  background:
    radial-gradient(95% 78% at 72% 46%, #e9e7ff 0%, #f3f1fb 34%, transparent 72%),
    radial-gradient(60% 60% at 8% 0%, #f2f0ea 0%, transparent 70%),
    #ffffff;
}
:root[data-theme="light"] .network,
:root[data-theme="light"] .final-cta {
  background:
    radial-gradient(70% 90% at 18% 110%, #e7e5ff 0%, transparent 62%),
    radial-gradient(70% 90% at 84% 108%, #eceaff 0%, transparent 62%),
    #f7f6f2;
  border-color: var(--line);
}
:root[data-theme="light"] .dns-panel {
  background: linear-gradient(160deg, #ffffff 0%, #f7f6f2 60%);
  border-color: var(--line);
}
:root[data-theme="light"] .float-label,
:root[data-theme="light"] .float-history { background: #fff; border-color: var(--line); }
:root[data-theme="light"] .orbit { border-color: #00000010; }
:root[data-theme="light"] .orbit-two { border-color: #0000000a; }
:root[data-theme="light"] .panel-top .tiny-icon { background: var(--purple-wash); color: var(--purple-dim); }
:root[data-theme="light"] .record b { background: var(--purple-wash); color: var(--purple-dim); }
:root[data-theme="light"] .plan.featured {
  background: linear-gradient(180deg, #f0eeff 0%, #faf9ff 46%, #ffffff 100%);
  border-color: var(--purple);
}
:root[data-theme="light"] .timeline-item .current { background: var(--purple-wash); color: var(--purple-dim); }
:root[data-theme="light"] .nameservers div { background: #ffffffb0; border-color: var(--line); }
:root[data-theme="light"] footer.site { background: var(--bg-deep); }
:root[data-theme="light"] .spf-node.spf-fail { background: #c0392b0f; }
:root[data-theme="light"] .spf-node.spf-warn { background: #9a6b120f; }

/* ---------- base ---------- */
* { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: 100px; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink-soft);
  font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Arial, sans-serif;
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; height: auto; }
a { color: var(--purple-lit); text-decoration: none; }
a:hover { color: var(--ink); }
button { font: inherit; }
a, button, summary { -webkit-tap-highlight-color: transparent; }

/* A visible focus ring is not optional. It is how the site is usable without a
   mouse, and the dark ground needs a light ring to register at all. */
a:focus-visible, button:focus-visible, summary:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 3px solid #a7a0ff;
  outline-offset: 3px;
  border-radius: 4px;
}

h1, h2, h3, h4 { color: var(--ink); line-height: 1.16; margin: 0 0 .5em; text-wrap: balance; letter-spacing: -.02em; }
h1 { font-size: clamp(34px, 5vw, 56px); font-weight: 780; letter-spacing: -.035em; }
h2 { font-size: clamp(27px, 3.3vw, 40px); font-weight: 750; letter-spacing: -.03em; }
h3 { font-size: 19px; font-weight: 700; }
h4 { font-size: 15px; font-weight: 700; }
p  { margin: 0 0 1em; }

hr { border: 0; border-top: 1px solid var(--line); margin: 34px 0; }

::selection { background: var(--purple); color: var(--ink); }

.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;
}

/* ---------- layout primitives ---------- */
.wrap { width: var(--wrap); margin: 0 auto; }

/* A band is a full-bleed tinted strip. On the light design it was a warm wash;
   here it is a lift OUT of the page ground, because on a dark page the only
   direction a surface can move is up. */
.band { background: var(--surface); border-block: 1px solid var(--line); padding: 62px 0; }

.section-head { max-width: 62ch; margin-bottom: 34px; }
.section-head p { color: var(--muted); margin-top: 12px; font-size: 16.5px; }

.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 11.5px; font-weight: 800; letter-spacing: .18em; text-transform: uppercase;
  color: var(--purple-lit);
}
.eyebrow .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--purple); flex: none; }

.lead { font-size: 19px; line-height: 1.62; color: var(--muted); max-width: 62ch; }
.hint { font-size: 13.5px; color: var(--faint); }
.note { font-size: 13.5px; color: var(--faint); }

.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; }

.grid   { display: grid; gap: 18px; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid > * { min-width: 0; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  border: 1px solid transparent; border-radius: 999px;
  padding: 12px 22px; font-size: 14.5px; font-weight: 650; white-space: nowrap;
  cursor: pointer; transition: transform .18s ease, background .18s ease, border-color .18s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn-primary { background: #f8f8fc; color: #202126; }
.btn-primary:hover { background: var(--purple-lit); color: #151515; }
.btn-navy { background: var(--purple-dim); color: var(--ink); }
.btn-navy:hover { background: var(--purple); color: var(--ink); }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line-strong); }
.btn-ghost:hover { background: var(--surface-2); color: var(--ink); border-color: #6a6a78; }
.btn-lg { padding: 15px 28px; font-size: 15.5px; }

/* ---------- header ---------- */
header.site {
  position: sticky; top: 0; z-index: 40;
  background: #161719e6; backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
header.site .bar { display: flex; align-items: center; gap: 28px; padding: 15px 0; }
/* .brand is defined once, in the d2 block below. */

nav.main { margin-left: auto; display: flex; align-items: center; gap: 26px; font-size: 14px; font-weight: 600; }
nav.main a { color: var(--ink-soft); }
nav.main a:hover { color: var(--ink); }
nav.main a[aria-current="page"] { color: var(--purple-lit); }
nav.main .btn { margin-left: 6px; }

.menu-toggle {
  display: none; margin-left: auto;
  background: transparent; color: var(--ink); border: 1px solid var(--line);
  border-radius: 999px; padding: 8px 16px; font-size: 13.5px; font-weight: 650; cursor: pointer;
}

/* ---------- hero ---------- */
.hero { padding: 66px 0 10px; }
.hero h1 { margin-bottom: 18px; }
.hero .lead { font-size: 19.5px; }
.hero-split { display: flex; align-items: center; gap: 40px; justify-content: space-between; }
.hero-split .section-head { margin-bottom: 0; }
/* ⚠️ THE MASCOTS HAVE NO WHITE BODY — THEY HAVE NO BODY AT ALL.
   
   Sampled from mascot-help.png: the forehead, the cheeks, the chest and the
   raised hand are all rgb(255,255,255) at alpha 127, which is FULLY
   TRANSPARENT. Only the navy outline, the blue trim, the desk and the laptop
   carry ink. The artwork was drawn for a cream page and lets it show through as
   the body — so on #161719 the character reads as a dark silhouette with blue
   linework, which is exactly what was reported.
   
   It cannot be repaired from the file. A flood fill from the border reaches the
   body, so the outline is open somewhere: with any pixel carrying ink treated
   as a wall, the enclosed area comes to 966px against a body of roughly 20,000.
   There is no region to fill.
   
   So the page supplies the light ground the artwork expects. A background on
   the <img> itself shows through its transparent areas, which is precisely the
   behaviour wanted — no wrapper element, and it fixes all ten mascots at once.
   Slightly off-white rather than #fff so it sits with the palette instead of
   glaring, and generously padded so the character is not cropped by the radius. */
/* ⚠️ NO PANEL BEHIND THE MASCOTS, and the story is worth keeping.
   
   6.609.0 put a light panel behind every mascot on the grounds that the artwork
   had no body and relied on a white page. That was true of exactly ONE of the
   ten — mascot-help.png, the contact page's — and I generalised from that single
   sample. Measured across all ten: nine have an opaque white body already
   (58-89% white through the upper torso, 0% transparent); only help was 1% white
   and 68% transparent.
   
   So nine of them never needed anything, help was re-cut from source artwork at
   6.610.0, and the panel is gone. */
.hero-mascot { width: 170px; flex: none; }
.mascot { width: 150px; }
.cta-row { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 24px; }
.cta-band { background: var(--surface); border-block: 1px solid var(--line); padding: 62px 0; text-align: center; }
.cta-band .cta-row { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 22px; justify-content: center; }
.cta-band p { color: var(--muted); max-width: 62ch; margin-inline: auto; }

/* ---------- cards ---------- */
.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 24px; transition: border-color .18s ease, transform .18s ease;
}
.card h3 { margin-bottom: .4em; }
.card p:last-child { margin-bottom: 0; }
a.card:hover { border-color: var(--line-strong); transform: translateY(-2px); }

.ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: 12px; margin-bottom: 14px;
  background: var(--purple-wash); color: var(--purple-lit); font-size: 19px;
}
.ico svg { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 1.7; }
.tint { background: var(--surface-2); }

.chip, .pill {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 11.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  padding: 4px 11px; border-radius: 999px;
  background: var(--line-soft); color: var(--muted);
}

.tick, .yes { color: var(--good); }
.no  { color: var(--faint); }
.inf { color: var(--purple-lit); font-size: 17px; line-height: 1; }

/* ---------- forms ---------- */
.form { display: block; }
.field-row { margin-bottom: 16px; }
.field-row > label, .field-label {
  display: block; font-size: 13px; font-weight: 700; color: var(--muted);
  margin-bottom: 7px; letter-spacing: .01em;
}
.form input[type=text], .form input[type=email], .form input[type=url],
.form select, .form textarea {
  width: 100%; background: var(--bg); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 12px 14px; font: inherit; font-size: 15px;
  transition: border-color .15s ease;
}
.form input:hover, .form select:hover, .form textarea:hover { border-color: var(--line-strong); }
.form input:focus, .form select:focus, .form textarea:focus { border-color: var(--purple); }
.form input.invalid, .form select.invalid, .form textarea.invalid { border-color: var(--bad); }
.form textarea { min-height: 150px; resize: vertical; }

/* THE NATIVE DROPDOWN ARROW IS REPLACED, because a dark <select> keeps the
   platform's light arrow on several browsers and it reads as a rendering
   fault. The SVG is inline so it costs no request. */
.form select {
  appearance: none; -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23a7a9b3' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; background-size: 12px;
  padding-right: 38px;
}

.err { display: block; margin-top: 6px; font-size: 13px; color: var(--bad); font-weight: 600; }

/* The honeypot. Off-screen rather than display:none, which some bots skip. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ⚠️ WHAT IS OURS AND WHAT IS CLOUDFLARE'S.
   
   `.cf-turnstile` is OUR div; the widget inside it is a cross-origin iframe
   Cloudflare renders, and nothing in this stylesheet can reach inside it. So
   the border below is a frame we draw AROUND the widget, in the same dark grey
   as every other border on the site (--line). Cloudflare's own panel chrome
   comes from data-theme="dark" on the nine placeholders and has no colour
   option — there is no setting for its border.
   
   overflow:hidden with a radius clips the widget's corners into ours, so the
   two read as one control rather than a box inside a box. line-height:0 kills
   the inline descender gap under the iframe, which would otherwise show as a
   pale sliver along the bottom edge. */
/* ⚠️ NO FRAME. 6.606.0 drew a dark grey border around the widget and 6.607.0
   made it black; both were reported as ugly, and bare is what was asked for.
   
   Nothing is left here but the gap above it and `line-height: 0`. That one
   property is not decoration: the iframe is an inline element, so without it
   the line box reserves room for a descender and leaves a few pixels of card
   showing under the widget — which reads as a misaligned edge and is exactly
   the sort of thing a frame gets added to hide.
   
   The widget's own panel and its corners are Cloudflare's. data-theme is the
   only lever the API gives us — there is no border-colour option — and since
   6.636.0 the nine placeholders pass turnstile_theme() rather than a fixed
   "dark". ⚠️ THAT IS WHAT MAKES THE WIDGET STOP LOOKING FRAMED. Our own frame
   went at 6.608.0; what was still read as a border afterwards was a dark
   Cloudflare panel sitting on a light card. Matching the theme is the fix, and
   it is the last one available from this side. */
.cf-turnstile { margin-top: 4px; line-height: 0; }
.cf-turnstile iframe { display: block; }

/* ---------- notices ---------- */
.notice { border: 1px solid var(--line); border-left-width: 4px; border-radius: var(--radius-sm); padding: 15px 17px; background: var(--surface); margin-bottom: 18px; }
.notice b { display: block; color: var(--ink); font-size: 15px; }
.notice p { margin: 6px 0 0; font-size: 14px; color: var(--muted); }
.notice-ok  { border-left-color: var(--good); }
.notice-ok b { color: var(--good); }
.notice-bad { border-left-color: var(--bad); }
.notice-bad b { color: var(--bad); }

/* ---------- tables ---------- */
.table-scroll { display: block; width: 100%; max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 11px 13px; border-bottom: 1px solid var(--line); font-size: 14.5px; }
th { color: var(--muted); font-size: 12px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; }
tr:last-child td { border-bottom: 0; }

.preview-wrap { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--surface); }
.preview-top { background: var(--surface-2); padding: 10px 14px; font-size: 12.5px; color: var(--muted); border-bottom: 1px solid var(--line); }
.preview { width: 100%; }
.preview td, .preview th { border-bottom: 1px solid var(--line-soft); }
.preview tr:last-child td { border-bottom: 0; }

.rtype {
  display: inline-block; min-width: 46px; text-align: center;
  font-size: 11px; font-weight: 800; border-radius: 6px; padding: 3px 7px;
  background: var(--line-soft); color: var(--ink-soft);
}
.rtype.o { background: var(--purple-wash); color: var(--purple-lit); }

/* ---------- FAQ ---------- */
.faq { display: grid; gap: 10px; }
.faq details { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm); }
.faq summary {
  cursor: pointer; list-style: none; padding: 16px 48px 16px 18px; position: relative;
  font-weight: 650; color: var(--ink); font-size: 15.5px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: '+'; position: absolute; right: 18px; top: 50%; transform: translateY(-50%);
  font-size: 20px; color: var(--purple-lit); line-height: 1;
}
.faq details[open] summary::after { content: '\2212'; }
.faq p { margin: 0 18px 16px; color: var(--muted); font-size: 15px; }
.faq-legend { font-size: 13.5px; color: var(--faint); margin-top: 14px; }
.faq-legend b { color: var(--ink-soft); }

/* ---------- footer ---------- */
footer.site { border-top: 1px solid var(--line); background: var(--bg-deep); margin-top: 70px; padding: 54px 0 26px; }
.foot-grid { display: grid; grid-template-columns: 1.4fr repeat(4, 1fr); gap: 30px; }
.foot-brand p { color: var(--faint); font-size: 14px; margin-top: 12px; max-width: 30ch; }
.foot-col { display: flex; flex-direction: column; gap: 9px; font-size: 14px; }
.foot-col b { color: var(--ink); font-size: 13px; font-weight: 750; letter-spacing: .04em; margin-bottom: 4px; }
.foot-col a { color: var(--muted); }
.foot-col a:hover { color: var(--ink); }
.foot-rule { border: 0; border-top: 1px solid var(--line); margin: 14px 0 10px; }
.foot-base {
  display: flex; flex-wrap: wrap; gap: 14px; justify-content: space-between;
  border-top: 1px solid var(--line); margin-top: 40px; padding-top: 20px;
  font-size: 13px; color: var(--faint);
}
.foot-base a { color: var(--faint); }
.foot-base a:hover { color: var(--ink-soft); }

/* The rail that puts the control on the same right edge as the theme switch —
   see the note in includes/back_to_top.php for why it is a container and not an
   offset. */
.to-top-rail {
  /* ⚠️ --wrap, NOT --shell. This was asked to sit at the same end as the theme
     switch, so when the switch moved back to the masthead's container at
     6.630.0 this had to move with it — otherwise the instruction that put them
     together silently stops being true. */
  position: fixed; left: 0; right: 0; bottom: 24px; z-index: 30;
  width: var(--wrap); margin-inline: auto;
  display: flex; justify-content: flex-end;
  pointer-events: none;
}
.to-top {
  pointer-events: auto;
  width: 42px; height: 42px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink);
  box-shadow: var(--shadow-sm);
}
.to-top:hover { border-color: var(--purple); color: var(--purple-lit); }
.to-top svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* The word is for width, not for reading — the arrow carries the meaning and
   aria-label carries it for anyone who cannot see either. */
.to-top span { display: none; }

/* ⚠️ THE SCRIPT ADDS THIS CLASS; CSS SHOWS THE CONTROL BY DEFAULT. A blocked or
   slow script therefore leaves a working button that is occasionally redundant,
   rather than a long page with no way back up. Without the rule the class does
   nothing and the button is simply always visible — still the safe direction. */
.to-top.is-hidden { opacity: 0; visibility: hidden; transform: translateY(6px); pointer-events: none; }
@media (max-width: 760px) {
  /* Back to a plain corner offset on a phone: the rail is 95% of a narrow
     screen, so aligning to it would put the button almost at the edge anyway,
     and the extra margin keeps it clear of a thumb resting on the bezel. */
  .to-top-rail { width: auto; left: auto; right: 16px; bottom: 16px; }
}
.to-top { transition: opacity .18s ease, visibility .18s ease, transform .18s ease, border-color .15s ease, color .15s ease; }

/* ---------- legal pages ---------- */
.legal { max-width: 78ch; }
.legal h2 { margin-top: 1.6em; font-size: 24px; }
.legal h3 { margin-top: 1.4em; }
.legal li { margin-bottom: .5em; }
.legal-nav { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 26px; }
.legal-nav a { font-size: 13.5px; padding: 7px 14px; border-radius: 999px; border: 1px solid var(--line); color: var(--muted); }
.legal-nav a:hover { border-color: var(--purple); color: var(--ink); }
.legal-nav a[aria-current="page"] { background: var(--purple-wash); border-color: var(--purple); color: var(--ink); }
.updated { font-size: 13.5px; color: var(--faint); }
.prose { max-width: 70ch; }
.prose h2 { margin-top: 1.5em; }

/* ---------- tooltips ---------- */
/* ⚠️ A CIRCLED QUESTION MARK, NOT AN UNDERLINED ONE. My first version gave .tip
   a dotted underline, which rendered the trigger as a bare "?" pressed against
   the end of the sentence — "400 records per zone?" reads as a typo, not as a
   control. The original is a 15px circle set off by a margin, and that is what
   makes it legible as something to hover.

   position:relative is what the bubble anchors to; remove it and the bubble
   anchors to the page. */
.tip { position: relative; display: inline-flex; align-items: center; justify-content: center;
       width: 15px; height: 15px; margin-left: 5px; border: 1px solid currentColor;
       border-radius: 50%; font-size: 9.5px; font-weight: 700; line-height: 1;
       opacity: .6; cursor: help; vertical-align: middle; flex: none; }
.tip:hover, .tip:focus-visible { opacity: 1; }

/* ⚠️ THE Z-INDEX IS ON .plan .tip, NOT ON .tip GENERALLY. It makes the trigger a
   stacking context so the bubble is not clipped by the card's own overflow —
   and doing it globally would trap the bubble inside inline text elsewhere. */
.plan .tip { z-index: 2; }

.tip-bubble {
  position: absolute; left: 50%; transform: translateX(-50%); bottom: calc(100% + 8px); z-index: 20;
  background: #0e0f11; color: var(--ink); border: 1px solid var(--line);
  border-radius: 9px; padding: 9px 11px; font-size: 12.5px; width: max-content; max-width: 260px;
  box-shadow: var(--shadow-sm); opacity: 0; visibility: hidden; transition: opacity .12s ease;
}
.tip:hover .tip-bubble, .tip:focus-within .tip-bubble, .tip:focus-visible .tip-bubble { opacity: 1; visibility: visible; }
/* The list items are flex since 6.600.0, so a trigger appended to a bullet would
   otherwise stretch and centre with the row rather than sit on the text. */
.tip-jump { font-size: 12px; color: var(--purple-lit); }

/* ---------- plan cards ---------- */
.plans { display: grid; grid-template-columns: repeat(5, 1fr); gap: 14px; align-items: start; }
.plan {
  position: relative; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 24px 20px; display: flex; flex-direction: column; gap: 12px;
}
/* The featured plan lifts rather than shouts: a border in the accent and a
   faint wash, not a different size. A card that is physically bigger than its
   neighbours makes the comparison harder, which is the opposite of the job. */
.plan.featured { border-color: var(--purple); background: linear-gradient(180deg, var(--purple-wash), transparent 220px), var(--surface); }
.plan .promo-label, .plan .popular-label {
  position: absolute; top: -11px; left: 20px;
  background: var(--purple); color: var(--ink); font-size: 10.5px; font-weight: 800;
  letter-spacing: .12em; text-transform: uppercase; padding: 4px 11px; border-radius: 999px;
}
.plan h3 { font-size: 17px; margin: 0; }
.plan .promo-blurb, .plan > p { color: var(--muted); font-size: 14px; margin: 0; }
.plan .promo-price, .plan .price {
  display: flex; align-items: baseline; gap: 4px;
  font-size: 40px; font-weight: 780; color: var(--ink); letter-spacing: -.04em; line-height: 1;
}
.plan .promo-price span, .plan .price span { font-size: 17px; font-weight: 700; }
.plan .promo-per, .plan .price small { font-size: 13px; font-weight: 600; color: var(--faint); letter-spacing: 0; }
.plan ul { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 8px; }
/* ⚠️ NO ::before HERE EITHER. There were TWO of these — this one in the
   contract layer and another in the d2 block — and removing only the d2 one
   left the doubled tick exactly as it was. The page draws its own
   <span class="tick">; the stylesheet colours it and does not add a second. */
.plan li { position: relative; font-size: 14px; color: var(--ink-soft); }
.plan .trial { font-size: 12.5px; color: var(--faint); }
.plan .btn { width: 100%; }

/* ---------- promotions ---------- */
/* ⚠️ TWO COLUMNS, as the original has. Mine was a single-column grid, so
   offers.php stacked the offer copy above its code panel instead of setting
   them side by side. position:relative because the original carries it and a
   future absolutely-positioned child would otherwise anchor to the page. */
.promo { position: relative; display: grid; grid-template-columns: 1fr 300px; gap: 32px;
         padding: 30px 32px; border: 1px solid var(--line); border-radius: 20px;
         background: var(--surface); }
.promo.is-featured { border-color: var(--purple); }
@media (max-width: 760px) { .promo { grid-template-columns: 1fr; gap: 20px; padding: 22px 20px; } }
.promo-copy h3 { margin-bottom: .3em; }
.promo-flag { display: inline-flex; align-items: center; gap: 7px; font-size: 11.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--purple-lit); }
/* ⚠️ UNSCOPED. My only .promo-label rule was written as `.plan .promo-label`,
   which never matches on offers.php — the label above the coupon code was
   rendering with no styling at all. Two components share the name; both need a
   rule. */
.promo-label { display: block; font-size: 11.5px; font-weight: 800; letter-spacing: .09em;
               text-transform: uppercase; color: var(--faint); margin-bottom: 8px; }
.promo-code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; background: var(--line-soft); border: 1px dashed var(--line); border-radius: 9px; padding: 8px 12px; color: var(--ink); display: inline-block; letter-spacing: .06em; }
.promo-was { text-decoration: line-through; color: var(--faint); }
.promo-now { color: var(--ink); font-weight: 750; }
.promo-saving { color: var(--good); font-weight: 700; font-size: 13.5px; }
.promo-plan { font-size: 13.5px; color: var(--muted); }
.promo-list { display: grid; gap: 14px; }
.promo-side { display: grid; gap: 10px; align-content: start; }
.promo-cta { display: flex; gap: 12px; flex-wrap: wrap; }
.promo-hint, .promo-terms, .promo-foot { font-size: 13px; color: var(--faint); }

/* ---------- status page ---------- */
.status-banner { border: 1px solid var(--line); border-left-width: 4px; border-radius: var(--radius); padding: 20px 22px; background: var(--surface); }
.status-banner.status-ok { border-left-color: var(--good); }
.status-banner.status-critical { border-left-color: var(--bad); }
.status-banner.status-planned { border-left-color: var(--purple); }
.status-head { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; }
.status-dot { width: 11px; height: 11px; border-radius: 50%; background: var(--good); flex: none; }
.status-critical .status-dot { background: var(--bad); }
.status-planned .status-dot { background: var(--purple); }
.status-list { display: grid; gap: 14px; margin-top: 22px; }
.status-incident { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; }
.status-meta { font-size: 13px; color: var(--faint); display: flex; gap: 12px; flex-wrap: wrap; }
.status-cat { font-size: 12px; color: var(--muted); }
.status-timeline { display: grid; gap: 12px; margin-top: 14px; border-left: 2px solid var(--line); padding-left: 16px; }
.status-tl-head { font-size: 13px; color: var(--muted); font-weight: 700; }
.status-tl-body { font-size: 14.5px; }
.status-post { font-size: 14.5px; }
.status-empty { color: var(--faint); padding: 26px 0; }
.status-filter { display: flex; gap: 9px; flex-wrap: wrap; margin-bottom: 18px; }
.status-note { font-size: 13.5px; color: var(--faint); }
.status-back { font-size: 13.5px; }
.status-closed { color: var(--faint); }
.pill-investigating { background: #e0a33c26; color: var(--warn); }
.pill-identified    { background: #e0a33c26; color: var(--warn); }
.pill-monitoring    { background: #8176ff26; color: var(--purple-lit); }
.pill-resolved      { background: #4ec98a26; color: var(--good); }
.pill-completed     { background: #4ec98a26; color: var(--good); }
.pill-scheduled     { background: var(--line-soft); color: var(--muted); }

/* ---------- the free tools ---------- */
.tool-form-wrap { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 24px 26px 20px; }
.tool-row { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-end; }
.tool-row .tool-domain { flex: 1 1 320px; margin-bottom: 0; }
.tool-row .tool-type   { flex: 0 0 170px; margin-bottom: 0; }
.tool-row .field-row   { margin-bottom: 0; }
.tool-challenge { margin-top: 22px; }
.tool-submit { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: 20px; margin-bottom: 0; }
.tool-submit .hint { margin: 0; }
.hint .tool-nudge a { color: var(--purple-lit); text-decoration: underline; text-underline-offset: 2px; font-weight: 700; }
.hint .tool-nudge a:hover { text-decoration: none; }
.tool-results { margin-top: 10px; }
.tool-results:focus { outline: none; }
.tool-results h2 .tool-queried { font-size: .72em; color: var(--purple-lit); }
.tool-table { width: 100%; }
.tool-table thead th { background: var(--surface-2); }
.tool-table tbody th { font-weight: 700; color: var(--ink-soft); text-transform: none; letter-spacing: 0; font-size: 14px; }
.tool-num { font-variant-numeric: tabular-nums; text-align: right; }
.tool-muted { color: var(--faint); }
.tool-answer { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; overflow-wrap: anywhere; }

/* Result cards. ⚠️ COLOUR IS NOT THE ONLY SIGNAL — each card states its verdict
   in words, because roughly one man in twelve cannot separate the red card from
   the green one and a page whose meaning is carried by hue tells them nothing. */
.mail-card { border: 1px solid var(--line); border-left-width: 4px; border-radius: var(--radius-sm); padding: 16px 18px; margin-top: 14px; background: var(--surface); }
.mail-card.mail-ok   { border-left-color: var(--good); }
.mail-card.mail-warn { border-left-color: var(--warn); }
.mail-card.mail-fail { border-left-color: var(--bad); }
.mail-card.mail-info { border-left-color: var(--faint); }
.mail-head { font-weight: 750; font-size: 15.5px; color: var(--ink); display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.mail-flag { font-size: 11px; letter-spacing: .07em; text-transform: uppercase; font-weight: 800; padding: 2px 8px; border-radius: 999px; background: var(--line-soft); color: var(--muted); }
.mail-ok   .mail-flag { background: #4ec98a26; color: var(--good); }
.mail-warn .mail-flag { background: #e0a33c26; color: var(--warn); }
.mail-fail .mail-flag { background: #ef6b5c26; color: var(--bad); }
.mail-detail { margin-top: 7px; font-size: 14.5px; line-height: 1.6; color: var(--muted); }
.mail-record { margin-top: 9px; padding: 8px 10px; border-radius: 8px; background: var(--line-soft); overflow-wrap: anywhere; line-height: 1.5; color: var(--ink-soft); }
.mail-good { color: var(--good); }
.mail-warn { color: var(--warn); }
.mail-bad  { color: var(--bad); }

/* The SPF checker's expanded record. The rail is on the child <ul> so a branch
   gets one continuous line however many terms hang off it. */
.spf-tree { list-style: none; margin: 0; padding: 0; }
.spf-tree .spf-tree { margin: 6px 0 4px; padding-left: 18px; border-left: 2px solid var(--line); }
.spf-node { padding: 7px 0 7px 10px; border-left: 3px solid transparent; margin-bottom: 2px; }
.spf-node.spf-fail { border-left-color: var(--bad); background: #ef6b5c12; }
.spf-node.spf-warn { border-left-color: var(--warn); background: #e0a33c12; }
.spf-term { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; font-weight: 700; overflow-wrap: anywhere; background: var(--line-soft); border-radius: 6px; padding: 2px 7px; color: var(--ink); }
.spf-cost { font-size: 11px; letter-spacing: .05em; text-transform: uppercase; font-weight: 800; padding: 2px 8px; border-radius: 999px; margin-left: 8px; background: #e0a33c26; color: var(--warn); font-variant-numeric: tabular-nums; white-space: nowrap; }
.spf-note { display: block; margin-top: 5px; font-size: 13.5px; line-height: 1.55; color: var(--muted); }

/* ---------- nameservers ---------- */
/* ⚠️ NO COUNT ANYWHERE. The list renders whatever the page passes it and the
   stylesheet never states, implies or reserves space for a number of them. */
.ns-list { display: grid; gap: 10px; }
.ns { display: flex; align-items: center; gap: 12px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 13px 16px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 14px; color: var(--ink); }

/* ---------- contact ---------- */
.contact-grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: 30px; align-items: start; }
.contact-form-wrap { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 26px; }
.contact-side { display: grid; gap: 16px; align-content: start; }

/* ---------- wiki ---------- */
/* ⚠️ CONTENT LEFT, CONTENTS PANEL RIGHT. Mine had the columns the other way
   round, so every one of the 42 articles opened with its table of contents
   where the prose should be. */
.wiki-layout { display: grid; grid-template-columns: minmax(0, 1fr) 268px; gap: 46px; align-items: start; }
.wiki-side { position: sticky; top: 90px; display: grid; gap: 18px; }
/* A bordered panel, as the original is — a bare list floating beside the prose
   reads as part of it. */
.wiki-toc { border: 1px solid var(--line); border-radius: 14px; padding: 18px 20px;
            background: var(--surface); display: grid; gap: 7px; font-size: 14px; }
.wiki-toc a { color: var(--muted); }
.wiki-toc a:hover { color: var(--ink); }
/* ⚠️ .wiki-section IS A CONTAINER, NOT A LABEL. I re-implemented it as a small
   uppercase caption — and wiki.php wraps each whole category in it, heading,
   blurb, grid and all. text-transform is inherited, so every card title and
   every summary on the wiki index rendered in shouting capitals. The original
   is spacing and nothing else.

   The lesson is the same one the .promo-label miss taught: a class name does
   not tell you what the element is. Read the markup. */
.wiki-section { margin-bottom: 46px; }
.wiki-section:last-child { margin-bottom: 0; }
.wiki-section h2 a { color: inherit; }
.wiki-section h2 a:hover { color: var(--purple-lit); }
.wiki-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px; }
.wiki-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; }
.wiki-card h3 { font-size: 16px; }
.wiki-card p { color: var(--muted); font-size: 14px; margin-bottom: 0; }
.wiki-crumb { margin-top: 22px; font-size: 13.5px; color: var(--faint); display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.wiki-crumb a { color: var(--muted); }
.wiki-subhead { color: var(--muted); font-size: 16.5px; }
.wiki-updated { font-size: 13px; color: var(--faint); }
.wiki-tag { font-size: 11.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--purple-lit); background: var(--purple-wash); padding: 3px 9px; border-radius: 999px; }
/* ⚠️ THE INPUT IS type="search" AND THE FORM IS NOT .form, so until now NOTHING
   in this stylesheet matched it — it rendered as a raw browser control, which is
   why the placeholder was clipped and the box was a few characters wide. It
   needed a rule, not a wider one.
   
   A real GET form, so it works with JavaScript off and a result is a URL
   somebody can paste into a ticket. */
.wiki-search { display: flex; gap: 10px; flex-wrap: wrap; align-items: stretch;
               margin: 26px 0 8px; max-width: 620px; }

.wiki-search .field { position: relative; flex: 1 1 320px; min-width: 0; display: flex; }

/* The magnifier is a background image on the input rather than an element, so
   the control stays a single focusable thing and the icon cannot be tabbed to
   or read out. Inline SVG data URI: no request, and it inherits nothing, so the
   colour is set here deliberately. */
.wiki-search input[type=search] {
  width: 100%; background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 15px 20px 15px 50px; font: inherit; font-size: 15.5px;
  transition: border-color .16s ease, background .16s ease;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a7a9b3' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: 18px center; background-size: 18px;
}
.wiki-search input[type=search]::placeholder { color: var(--faint); }
.wiki-search input[type=search]:hover { border-color: var(--line-strong); }
.wiki-search input[type=search]:focus { border-color: var(--purple); background-color: #24252a; }

/* Safari draws its own clear button and a rounded inner shape that fights the
   radius above; both are removed so the control looks the same everywhere. */
.wiki-search input[type=search]::-webkit-search-decoration,
.wiki-search input[type=search]::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.wiki-search input[type=search] { -webkit-appearance: none; appearance: none; }

.wiki-search .btn { flex: none; padding: 15px 30px; }

@media (max-width: 620px) {
  .wiki-search { max-width: none; }
  .wiki-search .btn { width: 100%; }
}
.wiki-results { display: grid; gap: 12px; }
.wiki-result { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 16px 18px; }
.wiki-nextprev { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; border-top: 1px solid var(--line); margin-top: 40px; padding-top: 20px; font-size: 14.5px; }
.wiki-table { width: 100%; margin: 18px 0; }
.wiki-video { width: 100%; border-radius: var(--radius); border: 1px solid var(--line); display: block; }

/* The article body. ⚠️ THIS IS THE ONLY PLACE 52 CONTENT PAGES GET THEIR TYPE,
   so every element the renderer can emit needs a rule here. */
.wiki-body { max-width: 72ch; font-size: 16.5px; }
.wiki-body h2 { margin-top: 1.7em; font-size: 26px; }
.wiki-body h3 { margin-top: 1.5em; font-size: 18.5px; }
.wiki-body p { color: var(--ink-soft); }
.wiki-body ul, .wiki-body ol { padding-left: 22px; }
.wiki-body li { margin-bottom: .45em; }
.wiki-body code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .88em; background: var(--line-soft); border-radius: 5px; padding: 2px 6px; color: var(--ink); }
.wiki-body pre { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 15px 17px; overflow-x: auto; }
.wiki-body pre code { background: none; padding: 0; }
.wiki-body blockquote { border-left: 3px solid var(--purple); margin: 18px 0; padding: 4px 0 4px 16px; color: var(--muted); }
.wiki-body img { border-radius: var(--radius-sm); border: 1px solid var(--line); }
.wiki-body table { margin: 18px 0; }
.wiki-body a { text-decoration: underline; text-underline-offset: 2px; }

/* ---------- blog ---------- */
.blog-art { width: 100%; border-radius: var(--radius); border: 1px solid var(--line); display: block; margin-bottom: 26px; }
.bar { display: flex; align-items: center; }

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
  .btn:hover, a.card:hover { transform: none; }
}

/* ---------- responsive ---------- */
@media (max-width: 1040px) {
  .plans { grid-template-columns: repeat(2, 1fr); }
  .wiki-layout { grid-template-columns: 1fr; }
  .wiki-side { position: static; }
  .foot-grid { grid-template-columns: 1fr 1fr 1fr; }
}
@media (max-width: 900px) {
  .grid-4, .grid-3 { grid-template-columns: repeat(2, 1fr); }
  .contact-grid { grid-template-columns: 1fr; }
  .hero-split { flex-direction: column; align-items: flex-start; gap: 24px; }
  .hero-mascot { width: 140px; align-self: center; }

  /* The masthead collapses to a toggle. nav.main is hidden rather than removed,
     so the links stay in the document for a crawler and for a reader who has
     JavaScript switched off — .open is added by includes/footer.php's script. */
  .menu-toggle { display: inline-flex; }
  nav.main {
    display: none; position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--surface); border-bottom: 1px solid var(--line); padding: 10px 4%;
  }
  nav.main.open { display: flex; }
  nav.main a { padding: 12px 0; border-bottom: 1px solid var(--line-soft); }
  nav.main a:last-child { border-bottom: 0; }
  nav.main .btn { margin: 12px 0 6px; }
  header.site .bar { position: relative; }
}
@media (max-width: 640px) {
  body { font-size: 15.5px; }
  .band, .cta-band { padding: 46px 0; }
  .hero { padding: 44px 0 6px; }
  .grid-2, .grid-3, .grid-4, .plans { grid-template-columns: 1fr; }
  .foot-grid { grid-template-columns: 1fr 1fr; }
  .tool-form-wrap { padding: 18px 16px 14px; }
  .tool-row .tool-type { flex: 1 1 100%; }
  .spf-tree .spf-tree { padding-left: 11px; }
  .spf-cost { margin-left: 0; margin-top: 5px; display: inline-block; }
}
@media (max-width: 480px) {
  .foot-grid { grid-template-columns: 1fr; }
  .foot-base { flex-direction: column; }
}

/* A caution note inside a legal or wiki page. Amber rather than red: it marks
   something to read carefully, not something that has gone wrong. */
.review-note {
  border: 1px solid #5a4a24; background: #e0a33c14; border-radius: 13px;
  padding: 16px 18px; margin: 22px 0 6px; color: var(--ink-soft); font-size: 14.5px;
}
.review-note b { color: var(--warn); }

/* ---------- announcement strip ---------- */
/* Above the masthead and NOT sticky with it: it is a one-time read, and a line
   that follows you down a 40-screen wiki article is a line you resent by the
   third screen. */
.announce {
  background: var(--surface); border-bottom: 1px solid var(--line);
  font-size: 13.5px; color: var(--muted); text-align: center; padding: 10px 0;
}
.announce a { color: var(--ink); font-weight: 600; margin-left: 10px; }
.announce a:hover { color: var(--purple-lit); }
.announce span { margin-left: 5px; }
@media (max-width: 640px) { .announce { font-size: 12.5px; } .announce a { display: block; margin: 4px 0 0; } }

/* ---------- scoped component parts ----------

   ⚠️ THESE ARE NOT ORPHANS. Each is a child class that only means anything
   inside its parent — `.blurb` inside `.plan`, `.cn` inside `table.compare` —
   which is why a coverage check that only reads line-leading selectors reports
   them as unstyled. They are the second half of components defined above. */

.plan .pname  { font-size: 15px; font-weight: 800; letter-spacing: -.01em; color: var(--ink); }
.plan .blurb  { font-size: 13.5px; color: var(--muted); margin: 14px 0 16px; }
.plan .per    { font-size: 12.5px; color: var(--faint); font-weight: 650; margin-top: 5px; }
.plan .flag {
  position: absolute; top: -11px; left: 20px; background: var(--purple); color: #fff;
  font-size: 10.5px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
  padding: 4px 10px; border-radius: 999px;
}

/* The comparison matrix. min-width plus .table-scroll on the wrapper, because a
   19-row feature table cannot honestly compress to a phone — it scrolls. */
table.compare { width: 100%; min-width: 780px; border-collapse: collapse; font-size: 14px; }
table.compare thead th { background: var(--surface-2); border-bottom: 1px solid var(--line); padding: 18px 16px; text-align: center; vertical-align: bottom; }
table.compare th, table.compare td { border-bottom: 1px solid var(--line-soft); }
table.compare tbody td { text-align: center; padding: 13px 16px; }
table.compare tbody th { text-align: left; font-weight: 400; text-transform: none; letter-spacing: 0; font-size: 14px; }
table.compare thead .cn { display: block; font-size: 15px; font-weight: 800; color: var(--ink); }
table.compare thead .cp { display: block; font-size: 13px; color: var(--muted); font-weight: 650; margin-top: 3px; }
table.compare .rl { display: block; font-weight: 700; color: var(--ink); }
table.compare .rn { display: block; font-size: 12px; color: var(--faint); }
table.compare .c  { margin: 0; }

.hero-mascot.square { width: 185px; }
.hero-mascot.small  { width: 125px; }
.section-head.wide  { max-width: none; }
.hero-split.snug { justify-content: flex-start; gap: 198px; }
.hero-split.snug .hero-mascot { margin-left: 0; }
@media (max-width: 900px) { .hero-split.snug { gap: 24px; } }

.legal table .row-note a { color: var(--purple-lit); font-weight: 650; }
.foot-grid p.foot-where { margin-top: 10px; font-size: 12.5px; color: var(--faint); }
.wiki-nextprev a.is-next { text-align: right; }
@media (max-width: 640px) { .wiki-nextprev a.is-next { text-align: left; } }

.promo .promo-main { display: grid; gap: 14px; }
.tool-form { display: block; }
.text-sm { font-size: 13.5px; }

/* ===========================================================================
   THE d2 HOME PAGE — built against p1–p6, not against the supplied index.html
   ===========================================================================

   ⚠️ THE SCREENSHOTS ARE THE SPEC. The HTML that came with the design is a
   sketch of the content; p1–p6 are what it is supposed to look like, and the
   two differ in every structural decision that matters — the hero is an inset
   glowing card rather than a full-bleed section, the feature columns carry no
   card at all, the featured plan wears a ribbon across its top edge rather than
   a floating pill, and the network band is a gradient panel rather than a flat
   one. Built from the pictures. */

/* ---------- the brand mark ---------- */
/* A lilac rounded square holding a lowercase k, then the wordmark with "kumo"
   set bold and "dns" regular. Drawn in CSS rather than shipped as an image so
   it stays sharp at any density and costs no request. */
/* The lockup is an image again, recoloured for this ground — see the note in
   includes/header.php. Sized by width with height:auto from the base img rule,
   so the 520x88 asset renders at 2x. */
/* Sizing and the theme swap both live in the lockup block further down, so that
   there is one rule per concern. `.brand img` used to be here setting
   display:block — see the note there for why that broke the swap. */
.brand { display: inline-flex; align-items: center; flex: none; }

/* ---------- masthead ---------- */
/* Transparent and NOT sticky: it sits above the hero card on the page ground,
   and a sticky bar would slide over the card's rounded top corner. */
/* ⚠️ THE HOME MASTHEAD IS STICKY TOO, on request. It was `position: static`
   from 6.596.0 so that it sat on the page ground above the hero card and could
   not slide over the card's rounded top corner — but that meant it scrolled
   away, which is the behaviour that was reported.
   
   It now uses the same sticky bar as every other page. The card DOES pass under
   it on scroll; the blurred translucent background is what keeps that readable
   rather than looking like a rendering fault, and z-index 40 puts it above the
   card's own stacking context.
   
   THE SCROLL OFFSET MOVES WITH IT. html{scroll-padding-top} in the base block
   clears a sticky header for in-page anchors — the home page's own nav links to
   #features, #plans, #network and #faq, and every one of them would otherwise
   land beneath the bar now that it is always there. It is raised to 100px in
   the same release because the 240px logo makes this masthead 85px tall and
   90px left five pixels of clearance. */
header.site .bar { padding: 22px 0; gap: 34px; }
nav.main { gap: 30px; font-size: 14.5px; font-weight: 600; }
nav.main a { color: var(--ink-soft); }
nav.main a:hover { color: var(--ink); }
nav.main .btn { margin-left: 10px; }

/* ⚠️ `nav.main a` OUT-SPECIFIES `.btn-primary`, WHICH MADE THE PILL UNREADABLE.
   (0,1,2) against (0,1,0): the pill is an <a> inside nav.main, so it took
   #d7d8de and rendered light grey text on a near-white pill — 1.34:1, which is
   invisible rather than merely low. That is what was reported as "similar
   colour for words and background", and it was a cascade collision, not a
   palette choice.
   
   Fixed by matching the specificity rather than reaching for !important, and by
   giving the pill the logo's orange as asked.
   
   ⚠️ WHITE TEXT ON THE ORANGE, CHOSEN DELIBERATELY AND NOT BY OVERSIGHT.
   #ffffff on #fc5b27 is 3.15:1. That clears WCAG AA for large text (3:1) and
   falls short of the 4.5:1 this 14.5px control would need to clear it as body
   text. #202126 would have been 5.10:1 and was what shipped at 6.614.0; white
   was asked for after the trade was put plainly, so this is a decision on the
   record rather than something to "fix" on sight.
   
   If it is ever revisited, there are two ways to keep white AND pass: take the
   orange down to about #c4410f, which breaks the match with the logo; or set
   the label at 18.66px bold, which qualifies it as large text at the 3:1
   threshold. Neither was wanted here. */
nav.main a.btn-primary { background: var(--orange); color: #fff; border-color: transparent; }
nav.main a.btn-primary:hover { background: var(--orange-lit); color: #fff; }

/* ---------- pill buttons ---------- */
/* Every button in the design is a pill with the label and the arrow pushed
   apart, not sitting next to each other. That gap is most of the look. */
.btn { gap: 22px; border-radius: 999px; padding: 15px 26px; font-size: 15px; font-weight: 650; }
.btn .arr { font-size: 17px; line-height: 1; }
.btn-lg { padding: 18px 32px; font-size: 15.5px; }
.btn-primary { background: #f8f8fc; color: #202126; }
.btn-primary:hover { background: #dcd7ff; color: #151515; }
.btn-ghost { background: transparent; border-color: var(--line-strong); color: var(--ink); }
.btn-ghost:hover { background: var(--surface-2); border-color: #5c5c6b; }
.btn-purple { background: var(--purple); color: #fff; border-color: transparent; }
.btn-purple:hover { background: #9289ff; color: #fff; }

/* A text link that behaves like a button but wears no chrome. */
.text-link { display: inline-flex; align-items: center; gap: 12px; font-weight: 650; font-size: 15px; color: var(--ink); }
.text-link:hover { color: var(--purple-lit); }

/* ---------- the hero card ---------- */
/* ⚠️ AN INSET ROUNDED PANEL, NOT A FULL-BLEED SECTION. The page ground shows
   down both sides of it, which is what makes the glow inside read as light in
   a box rather than as a gradient on the page. */
.hero-card {
  position: relative; overflow: hidden;
  margin: 8px auto 0; width: var(--shell);
  border-radius: 30px; border: 1px solid #23242e;
  background:
    radial-gradient(95% 78% at 72% 46%, #2a2d66 0%, #1a1b33 34%, transparent 72%),
    radial-gradient(60% 60% at 8% 0%, #232438 0%, transparent 70%),
    #0e0f15;
  padding: 74px 6% 78px;
}
.hero-card .hero { display: grid; grid-template-columns: 1.02fr .98fr; gap: 40px; align-items: center; padding: 0; }
/* ⚠️ BIGGER, on request — 11.5px to 13.5px — and the tracking eased from .2em to
   .16em so the line grows in size rather than in width. It is the first thing
   read above the headline and it names what the page is.
   
   ⚠️ AND THE COLOUR IS A TOKEN NOW. It was #9a9cb4, a literal, because
   tokenising at 6.617.0 excluded .hero-card and the exclusion matched its
   descendants — the same miss that left the three panel headings white. On the
   dark card it was fine at 7.09:1; on the LIGHT card it was #9a9cb4 on white,
   2.70:1, which fails AA outright. var(--muted) is 8.17:1 dark and 5.91:1
   light. */
.hero-card .eyebrow { color: var(--muted); letter-spacing: .16em; font-weight: 700; font-size: 13.5px; }
.hero-card h1 { font-size: clamp(38px, 5.4vw, 66px); line-height: 1.04; letter-spacing: -.045em; font-weight: 800; margin: 22px 0 22px; color: var(--ink); }
.hero-card .lead { font-size: 17.5px; line-height: 1.75; color: var(--ink-soft); max-width: 46ch; }
.hero-card .cta-row { margin-top: 34px; gap: 28px; align-items: center; }
.hero-card .note { margin-top: 26px; font-size: 12.5px; color: var(--faint); }
.hero-card .note .sep { margin: 0 8px; }

/* ---------- the hero visual ---------- */
/* The record panel is tilted away from the reader, with two faint orbit rings
   behind it and three labels floating at its edges. Decorative throughout:
   aria-hidden in the markup, because a screen reader reading a fake DNS table
   between the headline and the button learns nothing it can act on. */
.hero-visual { position: relative; min-height: 430px; }
.orbit { position: absolute; border: 1px solid #ffffff0f; border-radius: 50%; pointer-events: none; }
.orbit-one { inset: -6% -14% 4% 2%; }
.orbit-two { inset: 12% 4% 20% 18%; border-color: #ffffff0a; }

.dns-panel {
  position: absolute; right: 2%; top: 8%; width: 86%;
  border: 1px solid #ffffff14; border-radius: 18px;
  background: linear-gradient(160deg, #1b1d2e 0%, #15161f 60%);
  padding: 20px 22px 16px;
  transform: perspective(1400px) rotateY(-13deg) rotateX(4deg);
  box-shadow: 0 36px 70px rgba(0,0,0,.45);
}
.panel-top { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
.panel-top .tiny-icon { width: 34px; height: 34px; border-radius: 10px; background: #2b2d45; color: var(--purple-lit); display: inline-flex; align-items: center; justify-content: center; font-size: 16px; flex: none; }
.panel-top .who { display: flex; flex-direction: column; line-height: 1.25; }
.panel-top .who b { color: var(--ink); font-size: 16px; font-weight: 700; }
.panel-top .who small { font-size: 9.5px; letter-spacing: .16em; color: var(--faint); text-transform: uppercase; }
.panel-top .synced { margin-left: auto; font-size: 11.5px; color: var(--faint); white-space: nowrap; }

.record-head, .record { display: grid; grid-template-columns: 74px 66px 1fr; gap: 12px; align-items: center; }
.record-head { font-size: 9.5px; letter-spacing: .15em; color: var(--faint); text-transform: uppercase; padding-bottom: 10px; }
.record { padding: 9px 0; border-top: 1px solid #ffffff0d; font-size: 12.5px; }
.record b { justify-self: start; background: #2a2c42; color: var(--purple-lit); border-radius: 6px; padding: 3px 9px; font-size: 10.5px; font-weight: 700; letter-spacing: .04em; }
.record span { color: var(--faint); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.record code { color: var(--ink-soft); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; overflow-wrap: anywhere; }
.panel-bottom { display: flex; justify-content: space-between; align-items: center; margin-top: 14px; padding-top: 12px; border-top: 1px solid #ffffff0d; font-size: 11px; color: var(--faint); }

.float-label {
  position: absolute; right: 0; top: -4%; z-index: 2;
  display: inline-flex; align-items: center; gap: 14px;
  background: #1e2030; border: 1px solid #ffffff14; border-radius: 12px;
  padding: 11px 15px; font-size: 12.5px; color: var(--ink); box-shadow: var(--shadow-sm);
}
.float-label span { color: var(--muted); font-size: 11.5px; }
.float-history {
  position: absolute; left: -4%; bottom: 8%; z-index: 2;
  display: flex; align-items: center; gap: 13px;
  background: #24263a; border: 1px solid #ffffff14; border-radius: 14px;
  padding: 14px 18px; box-shadow: var(--shadow);
}
.float-history > span { color: var(--purple-lit); font-size: 17px; line-height: 1; }
.float-history strong { display: block; color: var(--ink); font-size: 13.5px; font-weight: 650; }
.float-history small { display: block; color: var(--faint); font-size: 11.5px; }
.visual-note { position: absolute; right: 2%; bottom: -8px; font-size: 11.5px; color: var(--faint); }

/* ---------- trust strip ---------- */
.trust-strip { width: var(--shell); margin: 0 auto; }
.trust-strip .row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; padding: 30px 0 6px; }
.trust-strip div { display: flex; align-items: center; gap: 12px; justify-content: center; font-size: 14px; color: var(--ink-soft); }
.trust-strip span { color: var(--faint); font-size: 16px; line-height: 1; flex: none; }

/* ---------- sections ---------- */
/* Generous vertical air is most of what makes the design feel calm — the
   screenshots give every section roughly a screen of its own. */
.section { padding: 118px 0; }
.section-alt { background: var(--surface-alt); }
.section-heading { text-align: center; max-width: 720px; margin: 0 auto 64px; }
/* The home page's features heading sits in a .hero-split beside the mascot.
   Every other page puts a .section-head in that row, so the existing
   `.hero-split .section-head { margin-bottom: 0 }` does not reach this one.
   
   The 64px is not decoration — it is the gap between the heading and the
   feature grid. Inside a flex row it would make the heading box taller than
   its text and throw off the vertical centring against the mascot, so it moves
   to the wrapper, where it does the same job from outside the row. */
.hero-split .section-heading { margin-bottom: 0; }
.hero-split.heading-row { margin-bottom: 64px; }
@media (max-width: 900px) { .hero-split.heading-row { margin-bottom: 44px; } }
.section-heading .eyebrow { color: var(--faint); letter-spacing: .2em; font-size: 11.5px; font-weight: 700; }
.section-heading h2 { font-size: clamp(30px, 3.9vw, 50px); font-weight: 800; letter-spacing: -.04em; line-height: 1.08; margin: 18px 0 20px; color: var(--ink); }
.section-heading p { color: var(--muted); font-size: 16.5px; line-height: 1.75; margin: 0; }

/* ---------- feature columns ----------
   ⚠️ NO CARD. In p2 these are bare columns on the page ground — no border, no
   panel, no padding box. Wrapping them in .card was the single most visible way
   my first attempt was not this design. */
.feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 56px; }
.feature-grid article > * { max-width: 34ch; }
.feature-symbol { font-size: 28px; color: var(--purple-lit); line-height: 1; margin-bottom: 30px; display: block; }
.feature-grid h3 { font-size: 20px; font-weight: 750; letter-spacing: -.02em; color: var(--ink); margin-bottom: 16px; }
.feature-grid p { color: var(--muted); font-size: 15px; line-height: 1.75; margin-bottom: 30px; }
.feature-grid a { color: var(--purple-lit); font-size: 13.5px; font-weight: 600; }
.feature-grid a:hover { color: var(--purple-lit); }

/* ---------- plan cards ---------- */
.pricing-note { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; font-size: 13px; color: var(--faint); margin-bottom: 22px; }
/* THE TWO ASSURANCES READ AS STATEMENTS, NOT FINE PRINT (6.637.0).
   Both sat at 13px in --faint, the caption colour — 4.88:1 dark and 4.67:1
   light, which passes AA and still looks like a footnote, because contrast is
   not the same thing as prominence. They are the DDoS and availability
   promises, so they now get weight, size and a surface of their own.
   
   ⚠️ A CLASS, NOT :first-child. The sibling in each row is a quieter line that
   must stay quiet, and a positional selector silently moves the emphasis the
   first time either row is reordered. */
.assurance {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 14.5px; font-weight: 600; color: var(--ink-soft);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 999px; padding: 9px 16px;
}
.assurance::before {
  content: ''; flex: none; width: 7px; height: 7px;
  border-radius: 50%; background: var(--purple-lit);
}
.assurance a { color: var(--purple-lit); text-decoration: underline; text-underline-offset: 3px; }
.plans { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; align-items: start; }
/* ⚠️ NO overflow: hidden. It was here so the featured plan's ribbon clipped into
   the card's rounded top corners — and it also clipped the records-per-zone
   tooltip INSIDE the card, which no z-index can defeat: overflow wins over
   stacking order every time.
   
   The ribbon gets its own matching radius instead (14px, the card's 15px less
   its 1px border), which is the same result without trapping everything else. */
/* ⚠️ THE 52px TOP PADDING IS A RESERVED BAND, AND EVERY CARD GETS IT — even
   the four that never paint anything in it. It is what keeps all five plan
   names on one line: the featured card's ribbon is absolutely positioned and
   occupies no flow, so the band is the only thing holding the name clear of
   it, and a band on the featured card alone would drop that one name below its
   neighbours. Change this and the ribbon's own height together, never one. */
.plan {
  position: relative; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line); border-radius: 15px;
  padding: 52px 26px 34px;
}
/* ⚠️ THE RIBBON IS PART OF THE CARD, NOT A BADGE FLOATING ABOVE IT. In p3 it
   is a full-width purple bar filling the card's top edge. It gets no extra
   padding of its own — see the band above — because the plan names were asked
   to line up across the row, which the p3 sketch's taller featured card did
   not do. */
.plan.featured { border-color: #6f63c8; background: linear-gradient(180deg, #2b2650 0%, #1e1d2c 46%, var(--surface) 100%); }
.plan .flag {
  position: absolute; inset: 0 0 auto 0; height: 30px;
  display: flex; align-items: center; justify-content: center;
  background: #a394ff; color: #241f45;
  font-size: 10.5px; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  border-radius: 14px 14px 0 0; padding: 0;
}
.plan .pname { font-size: 21px; font-weight: 750; letter-spacing: -.02em; color: var(--ink); }
.plan .blurb { color: var(--muted); font-size: 14px; line-height: 1.6; margin: 12px 0 30px; min-height: 44px; }
.plan .promo-price, .plan .price { display: flex; align-items: baseline; gap: 5px; font-size: 44px; font-weight: 800; color: var(--ink); letter-spacing: -.045em; line-height: 1; margin-bottom: 26px; }
.plan .promo-price .cur, .plan .price .cur { font-size: 15px; font-weight: 700; align-self: flex-start; margin-top: 5px; }
.plan .per { font-size: 13px; font-weight: 500; color: var(--faint); letter-spacing: 0; margin: 0; }
.plan .btn { width: 100%; justify-content: center; gap: 14px; padding: 14px 18px; font-size: 14.5px; }
.plan .trial { text-align: center; font-size: 12px; color: var(--faint); margin-top: 14px; }
.plan ul { list-style: none; margin: 26px 0 0; padding: 26px 0 0; border-top: 1px solid var(--line); display: grid; gap: 13px; }
/* ⚠️ ONE TICK MECHANISM, NOT TWO. This was a ::before on every .plan li, and
   plans.php already writes its own <span class="tick">&check;</span> into each
   bullet — so every line on that page showed the tick twice. index.php, which I
   wrote, was the only page relying on the pseudo-element.
   
   Resolved towards the markup rather than the stylesheet: a real element is
   what plans.php, offers.php and the comparison table already use, and a
   pseudo-element that silently doubles whatever the page supplies is the kind
   of rule that breaks the next page somebody adds. index.php now emits the same
   span, and this rule is gone. */
/* ⚠️ NO padding-left. It was 24px, left over from when the tick was an
   absolutely-positioned ::before at left:0 and the text needed clearing. The
   tick became a real flex child at 6.600.0 and the padding stayed, so every
   bullet sat 24px further right than the plan name, the price and the button
   above it — the ticks lined up with nothing.

   align-items:baseline, not center: a bullet that wraps to two lines would
   otherwise centre the tick against the whole block and leave it floating
   between the lines instead of sitting on the first one. */
.plan li { font-size: 13.5px; color: var(--ink-soft); display: flex; align-items: baseline; gap: 10px; }
.plan li .tick { color: var(--purple-lit); font-weight: 700; flex: none; }
.compare-row { display: flex; justify-content: space-between; gap: 18px; flex-wrap: wrap; align-items: center; margin-top: 40px; font-size: 13px; color: var(--faint); }

/* ---------- the control / Time Machine section ---------- */
.control { display: grid; grid-template-columns: 1fr 1.05fr; gap: 76px; align-items: center; }
.control-copy .eyebrow { color: var(--faint); letter-spacing: .2em; font-size: 11.5px; font-weight: 700; }
.control-copy h2 { font-size: clamp(30px, 3.7vw, 47px); font-weight: 800; letter-spacing: -.04em; line-height: 1.08; margin: 18px 0 22px; color: var(--ink); }
.control-copy p { color: var(--muted); font-size: 16px; line-height: 1.78; margin-bottom: 34px; max-width: 48ch; }

.history-panel { background: var(--surface); border: 1px solid var(--line); border-radius: 18px; padding: 26px 28px 22px; box-shadow: var(--shadow); }
.history-title { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding-bottom: 18px; border-bottom: 1px solid var(--line); }
.history-title > span:first-child { display: inline-flex; align-items: center; gap: 12px; color: var(--ink); font-weight: 700; font-size: 16px; }
.history-title .ret { color: var(--purple-lit); font-size: 15px; }
.demo-label { font-size: 9.5px; letter-spacing: .16em; color: var(--faint); text-transform: uppercase; }
.timeline-item { display: flex; align-items: center; gap: 15px; padding: 18px 0; border-bottom: 1px solid var(--line); }
.timeline-item i { width: 9px; height: 9px; border-radius: 50%; border: 2px solid #8176ff; flex: none; }
.timeline-item > div { flex: 1; min-width: 0; }
.timeline-item strong { display: block; color: var(--ink); font-size: 14px; font-weight: 650; }
.timeline-item span { display: block; color: var(--faint); font-size: 12.5px; }
.timeline-item .current { flex: none; background: #2f2b55; color: var(--purple-lit); border-radius: 999px; padding: 4px 11px; font-size: 11px; font-weight: 600; }
.timeline-item .ver { flex: none; color: var(--faint); font-size: 11.5px; }
.history-bottom { padding-top: 18px; font-size: 12px; color: var(--faint); }

/* ---------- network band ---------- */
/* A gradient panel rather than a flat band: indigo bleeding in from the lower
   corners, which is what separates this section from the two either side of it
   without a border. */
.network {
  text-align: center;
  background:
    radial-gradient(70% 90% at 18% 110%, #262a5e 0%, transparent 62%),
    radial-gradient(70% 90% at 84% 108%, #232653 0%, transparent 62%),
    #12131c;
  border-block: 1px solid #23242e;
}
.network .eyebrow { color: var(--muted); letter-spacing: .2em; font-size: 11.5px; font-weight: 700; }
.network h2 { font-size: clamp(30px, 4vw, 50px); font-weight: 800; letter-spacing: -.04em; line-height: 1.08; margin: 18px 0 20px; color: var(--ink); }
.network > .wrap > p { color: var(--muted); font-size: 16.5px; line-height: 1.75; max-width: 620px; margin: 0 auto 54px; }
.nameservers { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; max-width: 1120px; margin: 0 auto; }
.nameservers div { background: #ffffff05; border: 1px solid #ffffff12; border-radius: 14px; padding: 22px 16px; }
.nameservers span { display: block; font-size: 11px; letter-spacing: .22em; color: var(--faint); margin-bottom: 10px; }
.nameservers code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 14px; color: var(--ink-soft); }
.network-bottom { display: flex; justify-content: center; gap: 46px; flex-wrap: wrap; margin-top: 44px; font-size: 12.5px; color: var(--faint); }

/* ---------- FAQ ---------- */
/* ⚠️ TWO COLUMNS AND NO CARDS. The heading block sits on the left and the
   questions are hairline-separated rows on the right, each with a + at the far
   end. Boxed <details> was the other thing my first attempt got wrong. */
.faq-split { display: grid; grid-template-columns: .78fr 1.22fr; gap: 80px; align-items: start; }
.faq-split .eyebrow { color: var(--faint); letter-spacing: .2em; font-size: 11.5px; font-weight: 700; }
.faq-split h2 { font-size: clamp(30px, 3.7vw, 47px); font-weight: 800; letter-spacing: -.04em; line-height: 1.08; margin: 18px 0 20px; color: var(--ink); }
.faq-split > div:first-child p { color: var(--muted); margin-bottom: 14px; }
.questions details { border-bottom: 1px solid var(--line); }
.questions summary {
  cursor: pointer; list-style: none; position: relative;
  padding: 26px 44px 26px 0; font-size: 16px; font-weight: 600; color: var(--ink);
}
.questions summary::-webkit-details-marker { display: none; }
.questions summary::after { content: '+'; position: absolute; right: 4px; top: 50%; transform: translateY(-50%); font-size: 21px; font-weight: 400; color: var(--muted); line-height: 1; }
.questions details[open] summary::after { content: '\2212'; }
.questions p { margin: -6px 44px 26px 0; color: var(--muted); font-size: 15px; line-height: 1.75; }

/* ---------- final CTA ---------- */
.final-cta {
  text-align: center; padding: 124px 0;
  background:
    radial-gradient(60% 110% at 20% 100%, #262a5e 0%, transparent 60%),
    radial-gradient(60% 110% at 80% 100%, #232653 0%, transparent 60%),
    #12131c;
  border-top: 1px solid #23242e;
}
.final-cta .eyebrow { color: var(--muted); letter-spacing: .2em; font-size: 11.5px; font-weight: 700; }
.final-cta h2 { font-size: clamp(32px, 4.4vw, 56px); font-weight: 800; letter-spacing: -.04em; line-height: 1.08; margin: 20px auto 20px; max-width: 16ch; color: var(--ink); }
.final-cta p { color: var(--muted); font-size: 16.5px; margin-bottom: 34px; }
.final-cta small { display: block; margin-top: 20px; font-size: 12px; color: var(--faint); }

/* ---------- footer ---------- */
footer.site { background: #161719; padding: 74px 0 34px; }
/* HOME ONLY: the page ends on a full-bleed CTA band, so the footer butts
   straight onto it. An inner page ends on ordinary content and needs the gap. */
body.home footer.site { border-top: 0; margin-top: 0; }
body.inner footer.site { border-top: 1px solid var(--line); margin-top: 78px; }
.foot-grid { grid-template-columns: 1.7fr 1fr 1fr 1fr; gap: 40px; }
.foot-brand p, .foot-grid p.foot-where { color: var(--faint); font-size: 14px; line-height: 1.7; margin-top: 18px; }
.foot-col b { color: var(--ink); font-size: 14.5px; font-weight: 700; margin-bottom: 10px; }
.foot-col a { color: var(--faint); font-size: 14px; }
.foot-col a:hover { color: var(--ink); }

/* ---------- responsive ---------- */
@media (max-width: 1040px) {
  .hero-card .hero { grid-template-columns: 1fr; gap: 64px; }
  .hero-visual { min-height: 380px; }
  .control, .faq-split { grid-template-columns: 1fr; gap: 48px; }
  .feature-grid { grid-template-columns: 1fr; gap: 44px; }
  .feature-grid article > * { max-width: none; }
  .plans { grid-template-columns: repeat(2, 1fr); }
  .nameservers { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 760px) {
  .hero-card { border-radius: 22px; padding: 48px 6% 54px; width: 94%; }
  .hero-card h1 { font-size: clamp(32px, 9vw, 44px); }
  .hero-visual { min-height: 320px; }
  .dns-panel { position: relative; right: auto; top: auto; width: 100%; transform: none; }
  .orbit, .float-label, .float-history, .visual-note { display: none; }
  .section { padding: 74px 0; }
  .section-heading { margin-bottom: 44px; }
  .trust-strip .row { grid-template-columns: 1fr; gap: 14px; }
  .trust-strip div { justify-content: flex-start; }
  .plans, .nameservers { grid-template-columns: 1fr; }
  .network-bottom { gap: 18px; flex-direction: column; }
  .final-cta { padding: 78px 0; }
}

/* The legal links in the footer's bottom bar (p6). A row that wraps rather than
   a grid: four items of very different lengths, and on a phone they should fall
   onto a second line under the copyright rather than compress. */
.foot-legal { display: flex; flex-wrap: wrap; gap: 22px; }
.foot-legal a { color: var(--faint); }
.foot-legal a:hover { color: var(--ink); }
@media (max-width: 480px) { .foot-legal { gap: 14px; } }

/* ===========================================================================
   THE WIKI INDEX, as a knowledge base
   ===========================================================================

   Rebuilt on the HostPapa knowledgebase pattern, on request: a search hero,
   three ways in, then one FULL-WIDTH BLOCK PER CATEGORY rather than a grid of
   equal cards.

   ⚠️ WHY FULL-WIDTH BLOCKS AND NOT A GRID. A grid of 42 equal cards makes every
   article look equally important and gives a reader no way to judge where to
   start. A block per category carries the category's own heading, its blurb and
   its article count, so the shape of the documentation is visible before any
   single article is. It also scales: a category with 12 articles and one with 5
   look different, which they are. */

.kb-hero { text-align: center; padding: 58px 0 44px; }
.kb-hero .eyebrow { justify-content: center; }
.kb-hero h1 { margin: 18px auto 16px; max-width: 18ch; }
.kb-hero .lead { margin: 0 auto 30px; max-width: 58ch; color: var(--muted); }

/* Three ways in, as the reference has. Equal cards, because these three ARE
   equally weighted — unlike the articles below them. */
.kb-ways { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 58px; }
.kb-way { display: block; background: var(--surface); border: 1px solid var(--line); border-radius: 15px; padding: 24px; transition: border-color .18s ease, transform .18s ease; }
.kb-way:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.kb-way .kb-icon { margin-bottom: 14px; }
.kb-way b { display: block; color: var(--ink); font-size: 16.5px; font-weight: 700; margin-bottom: 6px; }
.kb-way p { color: var(--muted); font-size: 14px; margin: 0; }

.kb-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: 12px; flex: none;
  background: var(--purple-wash); color: var(--purple-lit); font-size: 19px; line-height: 1;
}

/* One block per category. */
.kb-cat { border: 1px solid var(--line); border-radius: 16px; background: var(--surface); padding: 26px 28px; margin-bottom: 18px; }
.kb-cat:last-child { margin-bottom: 0; }
.kb-cat-head { display: flex; align-items: flex-start; gap: 18px; }
.kb-cat-head > div:first-of-type { flex: 1; min-width: 0; }
.kb-cat-head h2 { font-size: 21px; font-weight: 750; letter-spacing: -.02em; margin: 0 0 6px; }
.kb-cat-head h2 a { color: var(--ink); }
.kb-cat-head h2 a:hover { color: var(--purple-lit); }
.kb-cat-head p { color: var(--muted); font-size: 14.5px; margin: 0; }
.kb-meta { flex: none; text-align: right; display: grid; gap: 6px; }
.kb-count { font-size: 12.5px; color: var(--faint); white-space: nowrap; }
.kb-viewall { font-size: 13.5px; font-weight: 650; color: var(--purple-lit); white-space: nowrap; }

/* The article list. Two columns on a wide screen because the titles are short
   and a single column of twelve leaves half the block empty. */
.kb-arts { list-style: none; margin: 22px 0 0; padding: 22px 0 0; border-top: 1px solid var(--line);
           display: grid; grid-template-columns: repeat(2, 1fr); gap: 2px 28px; }
.kb-arts li { min-width: 0; }
.kb-arts a { display: block; padding: 9px 0; font-size: 14.5px; color: var(--ink-soft); border-bottom: 1px solid transparent; }
.kb-arts a:hover { color: var(--purple-lit); }
/* ⚠️ BIGGER THAN A CAPTION, on request. At 11.5px it read as metadata attached
   to the article above it rather than as a heading for the group below. Now set
   at the article size and in the body colour, with the tracking eased off —
   uppercase at 15px does not need .09em to read as a label, and keeping it
   would have made the heading wider than some of the titles under it. */
.kb-sub { grid-column: 1 / -1; font-size: 15px; font-weight: 750; letter-spacing: .04em;
          text-transform: uppercase; color: var(--ink); margin: 20px 0 6px; }
.kb-sub:first-child { margin-top: 0; }

@media (max-width: 900px) {
  .kb-ways { grid-template-columns: 1fr; }
  .kb-arts { grid-template-columns: 1fr; }
  .kb-cat-head { flex-wrap: wrap; }
  .kb-meta { text-align: left; }
}
@media (max-width: 640px) {
  .kb-hero { padding: 40px 0 32px; }
  .kb-cat { padding: 20px; }
}

/* ---------- the theme switch ---------- */
/* Absolutely positioned so the announcement text stays optically centred in the
   bar. Its right edge is .wrap's right edge, which is where the masthead's
   "Check our free plan" pill also ends. */
/* ⚠️ THE ANNOUNCE BAR IS BACK TO .wrap's WIDTH, which is the masthead's. It was
   widened to the hero card at 6.618.0 and moved back at 6.630.0, on request —
   the switch now ends where the "Check our free plan" pill ends, and both sit in
   the same container, so that holds at every width rather than at one.
   
   No width override at all now: it inherits .wrap. The message stays centred
   either way. */
.announce .wrap { position: relative; }
.announce-msg { display: inline; }

.theme-toggle {
  position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; gap: 7px;
  background: transparent; color: var(--muted);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 5px 13px 5px 10px; font-size: 12.5px; font-weight: 600;
  cursor: pointer; line-height: 1;
  transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--line-strong); background: var(--surface-2); }

/* The glyph is drawn, so it costs no request and inherits currentColor. A
   crescent in dark mode, a filled disc with a ring in light. */
.theme-ico { width: 13px; height: 13px; border-radius: 50%; flex: none; position: relative;
             box-shadow: inset -4px -1px 0 0 currentColor; }
:root[data-theme="light"] .theme-ico {
  box-shadow: 0 0 0 1.5px currentColor inset, 0 0 0 3px transparent;
  background: currentColor;
}

/* ⚠️ HIDDEN UNTIL THE SCRIPT HAS CORRECTED ITS LABEL, and gone entirely without
   JavaScript. The markup ships the dark-default wording; a visitor whose stored
   preference is light would otherwise see a button reading "Light" on a light
   page for one frame. [hidden]-style suppression rather than visibility so it
   takes no space either. */
.theme-toggle[aria-hidden="true"] { display: none; }

@media (max-width: 760px) {
  /* The bar is one line on a phone and the message wraps; a control overlapping
     wrapped text is worse than no control there, so it goes back into flow. */
  .theme-toggle { position: static; transform: none; margin: 6px auto 0; display: flex; width: max-content; }
  .announce .wrap { display: flex; flex-direction: column; align-items: center; }
}

/* ---------- the theme-swapped lockup ---------- */
/* Dark ships visible because dark is the default; the light variant is hidden
   until [data-theme="light"] is set, which the head script does before paint. */
/* ⚠️ THE HIDE RULES ARE `img.brand-*`, NOT `.brand-*`, AND THAT IS THE WHOLE FIX.
   `.brand img { display: block }` used to sit in the masthead block above:
   (0,1,1) against `.brand-light`'s (0,1,0), so display:block won and BOTH
   lockups rendered side by side in dark mode from 6.620.0 until now.
   
   Two changes, not one. The old `.brand img` rule is gone, so nothing competes;
   and these carry the element as well as the class, so they would still win if
   it came back. Matching specificity rather than reaching for !important — the
   same resolution the masthead pill needed at 6.614.0.
   
   It is also the third duplicate-rule bug in this stylesheet. The width was set
   here AND there. One rule per concern. */
.brand-img { display: block; width: 240px; height: auto; }
.foot-brand .brand-img { width: 196px; }
img.brand-light { display: none; }
:root[data-theme="light"] img.brand-dark { display: none; }
:root[data-theme="light"] img.brand-light { display: block; }

/* ⚠️ The three panel headings above take var(--ink), not #fff. Tokenising at
   6.617.0 excluded .hero-card, .network and .final-cta so their decorative
   gradients would not follow the theme — but the exclusion matched DESCENDANTS
   too, so the headings kept their white and vanished on a light ground. The
   panels stay excluded; their text does not. Fixed in place rather than
   shadowed, so there is one rule per selector. */

/* ---------- behaviours the contract carries that the d2 rewrite dropped ----------

   ⚠️ FOUR RULES THE GUIDE HAS CLAIMS FOR AND THIS STYLESHEET LOST. When the
   150-class contract was re-implemented at 6.594.0 it was re-implemented by
   APPEARANCE — colours, spacing, radius — and these four are behaviour, so they
   were invisible in that reading and survived only as failing claims once /web2
   became /web and guide-check started auditing this file.

   Each is restored with the reasoning from the release that added it, because
   "what it does" is not enough to stop it being dropped again. */

/* A hovered plan card rises above its neighbours.
   ⚠️ THE TOOLTIP IS THE REASON. .plan .tip carries a z-index so its bubble is
   not clipped by the card, and that made the card a stacking context — so the
   bubble was then painted UNDER the next card along instead. The card has to
   win too. focus-within as well as hover: .tip is tabbable and a keyboard user
   has no hover to rely on. */
.plan:hover, .plan:focus-within { z-index: 3; }

/* The whole plan card is clickable, not only the button at its foot.
   The ::after is on the BUTTON and stretches to the card, so the accessible
   name and the focus ring stay on the real control — a card-level <a> would
   have to name itself, and everything inside it becomes link text. */
/* .plan already sets position:relative twice above; the ::after needs it and
   nothing else here does. Three rules for one selector is how this stylesheet
   has gone wrong four times now. */
.plan .btn::after { content: ''; position: absolute; inset: 0; border-radius: inherit; }
/* Anything the reader must still be able to click or select sits above it. */
/* ⚠️ .flag IS NOT IN THIS SELECTOR, AND THAT IS THE WHOLE POINT. It was, and
   `position: relative` here silently overrode the `position: absolute` the flag
   is given above — same specificity, later in the file. The ribbon fell back
   into the card's flow, became a pill the width of the content box, and pushed
   the plan name down by its own height. Nothing about the symptom pointed at a
   z-index rule written five releases earlier for the tooltip.
   The flag needs the stacking order, not the positioning scheme. */
.plan .tip, .plan ul { position: relative; z-index: 2; }
.plan .flag { z-index: 2; }

/* An embedded video reserves its space before it loads, so the article does not
   jump when it arrives. The width/height attributes are the other half and live
   in includes/wiki_render.php. */
.wiki-video video { width: 100%; height: auto; aspect-ratio: 16 / 9; display: block; }

/* The record-type chart is a wiki table rendered OUTSIDE the wiki as well —
   plans.php embeds it — so the table styling cannot be scoped to .wiki-body. */
.wiki-table table { width: 100%; border-collapse: collapse; }
.wiki-table table th, .wiki-table table td { padding: 10px 12px; border-bottom: 1px solid var(--line); font-size: 14px; }
.wiki-table table thead th { background: var(--surface-2); color: var(--muted); font-size: 12px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; }
.wiki-table table tr:last-child td { border-bottom: 0; }
