/* ============================================================================
 * Uptimia — tools-page.css
 * The SHARED layer for the 29 free-tool pages.
 *
 * Created 2026-07-28 as Step 4 (plumbing) of the free-tool CSS refactor
 * described in docs/free-tools-css-refactor-audit.md. It ships EMPTY on
 * purpose: the <link> and the `.tool` root class land first, with zero rules,
 * so that the wiring can be proven byte-for-byte neutral before a single
 * declaration is hoisted into it.
 *
 * ----------------------------------------------------------------------------
 * 1. LOAD ORDER — this is the whole safety model
 * ----------------------------------------------------------------------------
 *
 *     homepage-v30.css  ->  tools.css  ->  tools-page.css  ->  <tool>.css
 *
 * Every tool template emits the four <link>s in exactly that order (three
 * templates substitute for the second slot — see §4). Consequence:
 *
 *   .tool .hero      (here)         0-2-0
 *   .mxc .hero       (mx-checker)   0-2-0   <- same specificity, loads LATER
 *
 * so ANY surviving per-tool rule beats the shared one with no `!important`
 * and no `@layer`. That is why the 29 per-tool scope prefixes are kept: they
 * are the escape hatch, not the problem. Never raise the specificity of a
 * rule in this file above `.tool <selector>` — doing so silently disarms
 * every per-tool override in the fleet.
 *
 * ----------------------------------------------------------------------------
 * 2. THE `.tool` SCOPE CONTRACT
 * ----------------------------------------------------------------------------
 *
 * Each tool page's root element carries BOTH classes:
 *
 *     <div class="tool mxc">   <div class="tool avt-page">   <div class="tool snc">
 *
 * Rules in this file MUST be scoped `.tool …` — never bare. Two reasons:
 *
 *   a) homepage-v30.css defines BARE `.hero` (:169), `.hero h1 em` (:216),
 *      `.mono` (:93) and `.faq` (:975) at 0-1-0, and its reset is scoped
 *      `.hp-content *` (:5), which does NOT cover tool markup. Tool pages sit
 *      outside `.hp-content`, so v30's generic selectors already reach them.
 *      An unscoped rule here would collide with ~30 marketing pages' idea of
 *      what `.hero` means.
 *   b) tools.css is ALSO loaded by templates/website/tools/index.html.twig
 *      (the /tools directory page) and by the v1 templates/website/tools/
 *      sla-calculator.html.twig, neither of which has a `.tool` root. Scoping
 *      is what keeps this file off those two pages.
 *
 * Custom properties live in a single `.tool { … }` block. It is 0-1-0, so a
 * tool file's own `.mxc { … }` block still overrides it token by token.
 *
 * Do NOT edit homepage-v30.css's `:root` (~30 marketing pages depend on it)
 * and do NOT edit tools.css (it is the /tools DIRECTORY sheet; its
 * `.tool-table` :339 and `.tool-form-error` :105 are live on the v1 SLA page).
 *
 * ----------------------------------------------------------------------------
 * 3. MEDIA QUERIES ADD ZERO SPECIFICITY — the ordering rule
 * ----------------------------------------------------------------------------
 *
 * A media query contributes nothing to specificity. So:
 *
 *     tools-page.css   @media (max-width:960px){ .tool .v-answer{font-size:34px} }   0-2-0
 *     traceroute.css   .trc .v-answer{font-size:44px}                                0-2-0, LATER
 *
 * the responsive rule LOSES, at every width, and the page silently keeps its
 * desktop size on a phone. Today it works only because both declarations live
 * in the same file with the media block last.
 *
 * THEREFORE: no @media block may be hoisted into this file until (a) the base
 * rule it overrides has been hoisted here too, and (b) every per-tool
 * full-body copy of that base rule has been deleted. Surviving per-tool
 * overrides must be trimmed to only the diverging declaration — never a
 * copied rule body. Same rule applies to the future
 * `@media (prefers-reduced-motion: reduce)` block.
 *
 * Within this file, put all @media blocks AFTER all base rules, at the end.
 *
 * ----------------------------------------------------------------------------
 * 4. THE FOUR-WAY BREAKPOINT LADDER (documented, not yet unified)
 * ----------------------------------------------------------------------------
 *
 * Four different ladders are in play on a single tool page. They are listed
 * here so that a new rule is written against the right one rather than a
 * fourth invented value:
 *
 *   | sheet                | breakpoints        | what it governs            |
 *   |----------------------|--------------------|----------------------------|
 *   | homepage-v30.css     | 980, 600           | site chrome, marketing hero|
 *   | tools.css            | 780, 640, 480      | the /tools directory grid  |
 *   | <tool>.css (all 29)  | 960, 620           | tool hero + results chrome |
 *   | tools-page.css       | follow 960 / 620   | shared tool chrome         |
 *
 * New shared rules use the tool ladder (960 / 620) because that is what the
 * markup this file styles was authored against. Unifying the ladder itself is
 * out of scope — v30's 980/600 is shared with ~30 marketing pages.
 *
 * ----------------------------------------------------------------------------
 * 5. NAMING
 * ----------------------------------------------------------------------------
 *
 * Shared @keyframes must be named `tool-pulse` / `tool-rot` / `tool-land`.
 * homepage-v30.css already owns a global `@keyframes pulse` (:166, :803), and
 * keyframe names are document-global — redefining `pulse` here would leak onto
 * every page that loads v30. Tool-unique animations keep distinct names
 * (`avt-pulse`, `avt-mk-pulse`, `avt-feedin`, `avt-shimmer`, `whoc-blink`,
 * `wfc-land`) and must never be renamed into the shared set.
 *
 * ----------------------------------------------------------------------------
 * 6. EXCLUSIONS that any future hoist must respect
 * ----------------------------------------------------------------------------
 *
 *   - dns-checker + website-from-country: `.dns-hero`/`.wfc-hero`,
 *     padding:128px 24px 0, `.verdict-zone{margin-top:-64px}`,
 *     `.verdict-in{padding:104px}` are a deliberate nav-blend layout. They are
 *     excluded from the hero and verdict hoists entirely. They also load
 *     dashboard-mockup.css instead of tools.css.
 *   - availability_test: `.avt-page .verdict-in` is a flex two-column layout
 *     with no `.verdict-hero`/`.v-answer`/`.v-side`/`.v-chip` at all. Its
 *     template (templates/website/availability-test-frontpage.html.twig) loads
 *     no tools.css either.
 *   - Semantic colour divergence is NOT drift: `.capture h3 em` and
 *     `.check-banner` are var(--bad) in blacklist / domain / is-it-down / ssl
 *     because those tools banner an actual failure. Collapsing them to the
 *     22-tool majority is a meaning change.
 *   - `.badge-img` has two incompatible shapes (height:20px vs
 *     max-width:100%;height:auto). Neither may be hoisted over the other.
 *   - `.pbar i` transition differs on purpose (.3s dns/wfc, .5s availability,
 *     none in 10 files).
 *   - Badge classes are assembled at RUNTIME through per-tool `BADGE_CLS` maps
 *     and string concatenation. A static grep reporting a selector "unused" is
 *     not proof; check the JS construction site before deleting anything.
 * ========================================================================== */


/* ============================================================================
 * TOKENS — the free-tool fork of homepage-v30.css's :root
 * ----------------------------------------------------------------------------
 * Step 5 of docs/free-tools-css-refactor-audit.md (§2 Tier 1b). These 13 custom
 * properties were declared IDENTICALLY in each tool sheet's own scope block
 * (27 files x 13, minus 3 absentees). Verified before hoisting: every one of the
 * 13 had exactly ONE value variant across all 29 sheets — nothing was collapsed.
 *
 * Five are absent from v30's :root entirely:
 *     --cta  --cta-ink  --bad-bright  --amber  --amber-bright
 * Eight are a deliberate fleet-wide FORK of v30 (v30's value in the comment):
 *     --soft --dark-muted --dark-line --bad-soft --bad-line --warn-soft
 *     --warn-line --mono
 *
 * This block is 0-1-0 and loads BEFORE <tool>.css, so any tool re-declaring a
 * token in its own .mxc{} still wins. Do NOT move these into
 * homepage-v30.css's :root — ~30 marketing pages read that block.
 * ==========================================================================*/
.tool{
  --soft:#98989f;                                    /* v30 :root #74747e */
  --cta:#4ec97e;                                     /* v30 lacks */
  --cta-ink:#2a2c30;                                 /* v30 lacks */
  --dark-muted:rgba(245,247,250,.62);                /* v30 rgba(245,247,250,.6) */
  --dark-line:rgba(255,255,255,.07);                 /* v30 rgba(255,255,255,.05) */
  --bad-soft:#fbf1ef;                                /* v30 #fdecea */
  --bad-line:#efd3cf;                                /* v30 #f3c5bf */
  --bad-bright:#ff7a68;                              /* v30 lacks */
  --warn-soft:#fbf6ea;                               /* v30 #fdf3e1 */
  --warn-line:#ecdfc0;                               /* v30 #ecd4a3 */
  --amber:#e2b93b;                                   /* v30 lacks */
  --amber-bright:#f0cd6d;                            /* v30 lacks */
  --mono:'JetBrains Mono',ui-monospace,'SF Mono',Menlo,monospace;  /* v30 leads with ui-monospace */

  --permalink-w:360px;                               /* Step 7c — see PERMALINK ROW below */
}

/* ==========================================================================
 * SHARED ANIMATIONS (Step 6)
 *
 * Named tool-* on purpose: homepage-v30.css already owns a global
 * @keyframes pulse (:166, :803) and loads FIRST on every tool page. A bare
 * "pulse" here would either be shadowed by it or leak document-wide.
 *
 * Deliberately NOT folded in, and they must keep their distinct names:
 *   avt-pulse   availability_test — rgba(52,211,153) (a stale pre-v3 green)
 *   wfc-land    website-from-country — translateY(-7px), not -6px
 *   avt-mk-pulse / avt-feedin / avt-shimmer / whoc-blink — single-tool
 * ==========================================================================*/
@keyframes tool-pulse{0%,100%{box-shadow:0 0 0 3px rgba(78,201,126,.18)}50%{box-shadow:0 0 0 6px rgba(78,201,126,.07)}}
@keyframes tool-rot{to{transform:rotate(360deg)}}
@keyframes tool-land{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}

/* The three consumer rules that were byte-identical in every tool that had
 * them. 0-2-0 / 0-3-0 here, and <tool>.css still loads later, so any tool
 * needing a divergence keeps a trimmed override (availability_test does, for
 * both dot rules). */
.tool .spin{width:15px;height:15px;border-radius:50%;border:2px solid rgba(255,255,255,.18);border-top-color:var(--accent-bright);animation:tool-rot .8s linear infinite}
.tool .hero-eyebrow .dot{width:6px;height:6px;border-radius:50%;background:var(--accent-bright);box-shadow:0 0 0 3px rgba(78,201,126,.18);animation:tool-pulse 2.2s infinite}
.tool .badge-up .dot{background:var(--accent-bright);animation:tool-pulse 2.2s infinite}
/* ==========================================================================
 * DARK HERO SHELL (Step 7a)
 *
 * Hoisted from 27 tool sheets. `.tool .hero` is 0-2-0 so it beats
 * homepage-v30.css's BARE `.hero` (:169, 0-1-0) while still losing to any
 * surviving per-tool `.mxc .hero` (0-2-0, later file).
 *
 * EXCLUDED ENTIRELY: dns-checker and website-from-country. They renamed the
 * shell to `.dns-hero` / `.wfc-hero` on purpose to escape v30's global
 * `.hero`, and blend into the translucent nav with `margin-top:-64px` +
 * `.hero-in{padding:128px 24px 0}`. Neither template emits `class="hero"`, so
 * nothing here reaches them; their `.hero-in/-sub/-ticks/-eyebrow/-pad`
 * copies were left in full rather than trimmed.
 *
 * Surviving overrides, each trimmed to the diverging declaration only:
 *   availability_test  .hero{margin-top:0;padding:0} (its 2nd copy, kept)
 *                      .hero h1{max-width:820px}  .hero-sub{max-width:600px}
 *                      and it emits no .hero-pad and no .hero-eyebrow at all
 *   .hero-sub width    660px x10, 640px x3, 620px (is-it-down), 600px (avt)
 *   dkim-checker       .hero-ticks{margin:18px auto 0}
 * A `--hero-sub-w` token was considered and rejected: it costs the same one
 * line per divergent tool and adds a name to the token contract.
 *
 * The `@media 960/620` hero-h1 steps deliberately stay in the tool files —
 * media queries add zero specificity, so a hoisted one here would lose to
 * them. They ship in Step 8, after every base rule is shared.
 * ==========================================================================*/
.tool .hero{background:var(--dark);color:var(--dark-ink);
  position:relative;overflow:hidden;}
.tool .hero::before{content:'';position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(ellipse 780px 380px at 50% 118%, rgba(78,201,126,.13), transparent 62%),
    radial-gradient(ellipse 600px 300px at 12% -30%, rgba(78,201,126,.06), transparent 60%);}
.tool .hero-in{max-width:1120px;margin:0 auto;padding:64px 24px 0;position:relative;text-align:center}
.tool .hero-eyebrow{display:inline-flex;align-items:center;gap:8px;
  font-family:var(--mono);font-size:11.5px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;
  color:var(--dark-muted);
  border:1px solid var(--dark-line-2);border-radius:999px;padding:6px 14px;
  background:rgba(255,255,255,.03);}
.tool .hero h1{margin:22px auto 14px;max-width:840px;font-size:52px;line-height:1.08;font-weight:700;letter-spacing:-.028em;color:#fff}
.tool .hero-sub{max-width:680px;margin:0 auto;font-size:16.5px;line-height:1.6;color:var(--dark-muted)}
.tool .hero-ticks{display:flex;justify-content:center;flex-wrap:wrap;gap:10px 26px;
  margin:20px auto 0;
  font-family:var(--mono);font-size:12.5px;color:var(--dark-muted);}
.tool .hero-ticks span{display:inline-flex;align-items:center;gap:7px;white-space:nowrap}
.tool .hero-ticks svg{color:var(--accent-bright)}
.tool .hero-pad{height:56px}
/* ==========================================================================
 * CTA + GHOST BUTTONS (Step 7a, second commit)
 *
 * .btn-cta hoisted from 27 of 29; .act-ghost (+ :hover, + svg) from 28 of 29.
 *
 * Surviving overrides, trimmed to the diverging declarations only:
 *   dns-checker / website-from-country  .btn-cta{padding:9px 15px;font-size:14px}
 *     — the same +1px sizing that goes with their nav-blend hero. Everything
 *       else in the rule was byte-identical, so only those two lines remain.
 *
 * subnet-calculator has no .act-ghost rule and its template and JS emit no
 * `act-ghost` element, so the hoist reaches nothing there. Neither
 * homepage-v30.css, tools.css nor dashboard-mockup.css mentions .btn-cta or
 * .act-ghost, so these rules collide with nothing loading earlier.
 *
 * No @media copies of either button exist in any tool sheet, so nothing here
 * is at risk from the zero-specificity media rule.
 * ==========================================================================*/
.tool .btn-cta{display:inline-flex;align-items:center;justify-content:center;gap:7px;
  padding:8px 14px;border-radius:8px;border:1px solid transparent;
  background:var(--cta);color:var(--cta-ink);
  font-size:13.5px;font-weight:600;letter-spacing:-.01em;white-space:nowrap;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18), 0 4px 14px -4px var(--accent-glow);
  transition:filter .15s,transform .1s;}
.tool .btn-cta:hover{filter:brightness(1.06)}
.tool .btn-cta:active{transform:scale(.99)}
.tool .act-ghost{display:inline-flex;align-items:center;gap:8px;padding:8.5px 14px;border-radius:8px;
  border:1px solid var(--dark-line-2);color:var(--dark-ink);font-size:13.5px;font-weight:550;
  transition:background .15s;white-space:nowrap;background:rgba(255,255,255,.03);}
.tool .act-ghost:hover{background:var(--dark-2)}
.tool .act-ghost svg{opacity:.7}

/* ---------- Step 7b · verdict zone (hoisted from 28 tool sheets) ----------
   Excluded: availability_test .verdict-in (flex two-column layout).
   .verdict-zone.bad-mode::before canonical = rgba(255,122,104,.13); the red
   group (blacklist/domain/is-it-down/ssl .18), availability+tls-version .16 and
   http-protocol/http-status .15 stay as trimmed per-tool overrides. */
.tool .verdict-zone{background:var(--dark);color:var(--dark-ink);position:relative;overflow:hidden}
.tool .verdict-zone::before{content:'';position:absolute;inset:0;pointer-events:none;background:radial-gradient(ellipse 760px 360px at 18% 145%, rgba(78,201,126,.12), transparent 62%)}
.tool .verdict-zone.warn-mode::before{background:radial-gradient(ellipse 760px 360px at 18% 145%, rgba(226,185,59,.15), transparent 62%)}
.tool .verdict-zone.bad-mode::before{background:radial-gradient(ellipse 760px 360px at 18% 145%, rgba(255,122,104,.13), transparent 62%)}
.tool .verdict-hero{display:flex;align-items:flex-start;gap:40px}
.tool .verdict-main{flex:1;min-width:0}
.tool .verdict-line{margin-top:14px;font-size:16px;color:var(--dark-muted);max-width:64ch}
.tool .verdict-line b{color:#fff;font-weight:600}
.tool .verdict-line .hl-warn{color:var(--amber-bright);font-weight:600}
.tool .verdict-line .hl-bad{color:var(--bad-bright);font-weight:600}
.tool .verdict-actions{display:flex;align-items:center;gap:9px;margin-top:24px;flex-wrap:wrap}
.tool .v-answer{font-size:44px;line-height:1.06;font-weight:700;letter-spacing:-.028em;color:#fff;max-width:640px}
.tool .v-answer em{font-family:var(--serif);font-style:italic;font-weight:500;color:var(--bad-bright)}
.tool .warn-mode .v-answer em{color:var(--amber-bright)}
.tool .v-side{flex:none;width:240px;display:flex;flex-direction:column;gap:10px}
.tool .v-chip{border:1px solid var(--dark-line-2);border-radius:var(--radius-sm);background:rgba(255,255,255,.04);padding:13px 16px}
.tool .v-chip .micro{display:block;color:var(--dark-soft);margin-bottom:5px}
.tool .v-chip .val{font-size:16px;font-weight:650;letter-spacing:-.01em;color:#fff;font-feature-settings:'tnum'}
.tool .v-chip .val.good{color:#7ee2a8}
.tool .v-chip .val.warn{color:var(--amber-bright)}
.tool .v-chip .val.bad{color:var(--bad-bright)}
.tool .v-chip .sub{font-size:11.5px;color:var(--dark-soft);margin-top:2px}
.tool .verdict-in{max-width:1120px;margin:0 auto;padding:40px 24px 40px;position:relative}

/* ---------- Step 7b · badges, pills, accent-i (hoisted from the tool sheets) ----------
   Excluded: is-it-down .upt-badge (no white-space:nowrap) and availability_test
   .badge-demo (no flex-wrap) — hoisting the canonical would have ADDED a
   declaration those two never had. .badge-img is deliberately NOT hoisted: it has
   two incompatible shapes (height:20px vs max-width:100%;height:auto).
   The .badge- and .pill shape rules keep their per-tool grouped selectors. */
.tool .accent-i{font:inherit;letter-spacing:inherit;color:var(--accent)}
.tool .on-dark .accent-i,.tool .verdict-zone .accent-i{color:var(--accent-bright)}
.tool .badge-up{background:rgba(78,201,126,.14);border:1px solid rgba(78,201,126,.38);color:#7ee2a8}
.tool .badge-warn{background:rgba(240,205,109,.13);border:1px solid rgba(240,205,109,.4);color:var(--amber-bright)}
.tool .badge-bad{background:rgba(255,122,104,.12);border:1px solid rgba(255,122,104,.38);color:var(--bad-bright)}
.tool .badge-down{background:rgba(255,122,104,.13);border:1px solid rgba(255,122,104,.4);color:#ffa093}
.tool .badge-warn .dot{background:var(--amber-bright)}
.tool .badge-bad .dot{background:var(--bad-bright)}
.tool .badge-down .dot{background:var(--bad-bright)}
.tool .badge-code{flex:1 1 180px;font-family:var(--mono);font-size:11px;color:var(--soft);background:var(--bg-3);border:1px dashed var(--line-2);border-radius:8px;padding:9px 12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tool .upt-badge .dot{width:7px;height:7px;border-radius:50%;background:var(--accent-bright)}
.tool .upt-badge .mono{font-size:11px;color:var(--dark-muted);font-weight:500}
.tool .pill{display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:3.5px 10px;font-size:11.5px;font-weight:600;white-space:nowrap}
.tool .pill i{width:6px;height:6px;border-radius:50%}
.tool .pill.ok{background:var(--accent-soft);color:var(--accent);border:1px solid var(--accent-line)}
.tool .pill.ok i{background:var(--accent)}
.tool .pill.watch{background:var(--warn-soft);color:var(--warn);border:1px solid var(--warn-line)}
.tool .pill.watch i{background:var(--warn)}
.tool .pill.down{background:var(--bad-soft);color:var(--bad);border:1px solid var(--bad-line)}
.tool .pill.down i{background:var(--bad)}
.tool .upt-badge{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--line-2);border-radius:8px;padding:7px 13px;background:var(--dark);color:#fff;font-size:12.5px;font-weight:600;white-space:nowrap}
.tool .badge-demo{display:flex;align-items:center;gap:10px;margin-top:4px;flex-wrap:wrap}
.tool .badge-up,.tool .badge-warn,.tool .badge-bad,.tool .badge-down,.tool .badge-mute{display:inline-flex;align-items:center;gap:8px;border-radius:999px;padding:6.5px 14px;
  font-size:13px;font-weight:650;letter-spacing:.02em;margin-bottom:18px;}
.tool .badge-up .dot,.tool .badge-warn .dot,.tool .badge-bad .dot,.tool .badge-down .dot,.tool .badge-mute .dot{width:8px;height:8px;border-radius:50%}
/* ==========================================================================
 * PERMALINK ROW (Step 7c)
 *
 * One canonical rule for all 29 tools. The ONLY thing that diverged across the
 * fleet was the chip's max-width (360 x21, 340 x2, 320 x4, 300 x1, plus
 * domain-checker's min(340px,100%)), so that value is exposed as the
 * --permalink-w token instead of being copied as a rule: a divergent tool sets
 * ONE declaration in its own .scope{} block (0-1-0, later file) and inherits
 * everything else. The var() keeps its 360px fallback so the rule is still
 * correct if the token block is ever unset.
 * ==========================================================================*/
.tool .permalink{display:inline-flex;align-items:center;gap:9px;max-width:min(var(--permalink-w,360px),100%);
  border:1px solid var(--dark-line-2);border-radius:8px;padding:8.5px 12px;
  font-family:var(--mono);font-size:12px;color:var(--dark-muted);background:rgba(0,0,0,.18);}
/* min-width:0 is what lets the ellipsis actually fire: as a flex item the
 * span's min-width:auto floor would otherwise prop the row up to the full
 * URL width and overflow phone viewports instead of truncating. */
.tool .permalink span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.tool .permalink button{color:var(--accent-bright);font-size:12px;font-weight:600;flex:none}
.tool .crumb{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--dark-soft);margin-bottom:20px}
.tool .crumb a:hover{color:#fff}
.tool .crumb .sep{opacity:.5}


/* ------------------------------------------------- STEP 9 · Tier 3 results
 * The result-page kit: the capture card, the card scaffold, the .kv table,
 * the .err-card grid, the .opp opportunity rows, the two meters, the terminal
 * panel and one banner leaf. Every rule here was byte-identical in 11-30 tool
 * sheets; divergent copies were trimmed to the diverging declaration only.
 *
 * DELIBERATELY NOT HOISTED - the semantic red group and its neighbours:
 *   .capture h3 em          21x var(--warn) vs 4x var(--bad) on
 *                           blacklist / domain / is-it-down / ssl. Those four
 *                           banner an actual FAILURE. Collapsing is a meaning
 *                           change; the correct fix is a .bad modifier emitted
 *                           by their JS, which is a separate change.
 *   .check-banner           5 body variants, same red group. Only its
 *                           leaf .check-banner b (20x, one body) moved.
 *   .capture.warn/.bad, .cap-form .btn-warn/.btn-bad, .kv .v.warn/.good,
 *   .opp:last-child, .opp .act, .opp p b, .term base, .budget base, .pbar i
 *                           state modifiers whose tools-without-the-rule
 *                           plausibly emit the class, or (pbar i) three
 *                           different transitions. Left per-tool.
 *
 * Neutralising declarations added rather than exclusions (Step 7b's rule -
 * excluding a tool does NOT stop a hoisted rule reaching it):
 *   .avt-page .pad-card .card-title, .iid .pad-card .card-title -> gap:normal
 *     (the CSS initial value = exactly today's rendering; canonical has 12px).
 *   .avt-page .opp keeps its `border` shorthand, which overrides the hoisted
 *     border-bottom longhand from a later file at equal specificity.
 */
.tool .capture{border:1px solid var(--accent-line);background:linear-gradient(180deg,#fff,var(--accent-soft));
  border-radius:var(--radius);padding:24px;position:relative;overflow:hidden;
  box-shadow:0 1px 2px rgba(15,23,42,.04), 0 16px 40px -22px rgba(0,126,66,.25);}
.tool .capture h3{font-size:19px;font-weight:700;letter-spacing:-.018em;line-height:1.25}
.tool .capture p{margin-top:9px;font-size:13.5px;line-height:1.6;color:var(--muted)}
.tool .capture p b{color:var(--ink-2);font-weight:600}
.tool .cap-form{display:flex;gap:8px;margin-top:16px;background:#fff;border:1px solid var(--line-2);border-radius:10px;padding:5px;box-shadow:0 4px 14px -8px rgba(15,23,42,.14)}
.tool .cap-form input{flex:1;border:0;outline:0;background:none;padding:0 12px;height:40px;font-size:14px;min-width:0}
.tool .cap-form input::placeholder{color:var(--soft)}
.tool .cap-form .btn-cta{padding:0 16px;font-size:13.5px}
.tool .cap-trust{display:flex;gap:15px;margin-top:12px;font-family:var(--mono);font-size:11px;color:var(--soft);flex-wrap:wrap}
.tool .cap-trust span{display:inline-flex;align-items:center;gap:5px;white-space:nowrap}
.tool .cap-trust svg{color:var(--accent)}
.tool .res-grid{display:grid;grid-template-columns:1.42fr 1fr;gap:14px;align-items:start}
.tool .res-col{display:flex;flex-direction:column;gap:14px;min-width:0}
.tool .res-body{max-width:1120px;margin:0 auto;padding:26px 24px 0}
.tool .card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:0 1px 2px rgba(15,23,42,.04), 0 12px 32px -18px rgba(15,23,42,.12);}
.tool .pad-card{padding:20px}
.tool .pad-card .card-title{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;gap:12px}
.tool .pad-card .card-title h3{font-size:15px;font-weight:650;letter-spacing:-.01em}
.tool .quad{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
.tool .q-card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-sm);padding:18px 18px 16px;transition:border-color .15s}
.tool .q-card:hover{border-color:var(--accent-line)}
.tool .q-card .glyph{width:36px;height:36px;border-radius:9px;display:flex;align-items:center;justify-content:center;background:var(--accent-soft);border:1px solid var(--accent-line);color:var(--accent)}
.tool .q-card h3{font-size:15px;font-weight:650;letter-spacing:-.01em;margin:12px 0 6px}
.tool .q-card p{font-size:13px;line-height:1.6;color:var(--muted)}
.tool .q-card .sym{display:inline-block;margin-top:10px;font-family:var(--mono);font-size:10.5px;color:var(--ink-3);background:var(--bg-3);border:1px solid var(--line-2);border-radius:6px;padding:2px 8px}
.tool .kv{display:grid;grid-template-columns:150px 1fr;gap:0 14px}
.tool .kv .k{padding:8.5px 0;font-size:12.5px;color:var(--soft);border-bottom:1px solid var(--bg-3)}
.tool .kv .v{padding:8.5px 0;font-family:var(--mono);font-size:12px;color:var(--ink-3);border-bottom:1px solid var(--bg-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tool .kv .k:nth-last-child(2),.tool .kv .v:last-child{border-bottom:0}
.tool .kv .v.bad{color:var(--bad);font-weight:550}
.tool .err-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.tool .err-card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-sm);padding:15px 16px}
.tool .err-card .en{display:inline-block;max-width:100%;font-family:var(--mono);font-size:11px;font-weight:600;color:var(--bad);background:var(--bad-soft);border:1px solid var(--bad-line);border-radius:6px;padding:2px 8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tool .err-card p{margin-top:9px;font-size:12.5px;line-height:1.55;color:var(--muted)}
.tool .err-card .fix{margin-top:7px;font-size:12px;color:var(--accent);font-weight:600}
.tool .err-card .en.g{color:var(--accent);background:var(--accent-soft);border-color:var(--accent-line)}
.tool .err-card .en.w{color:var(--warn);background:var(--warn-soft);border-color:var(--warn-line)}
.tool .err-card .en.n{color:var(--ink-3);background:var(--bg-3);border-color:var(--line-2)}
.tool .err-card .fix.urgent{color:var(--bad)}
.tool .opp{display:flex;gap:12px;padding:12px 0;border-bottom:1px solid var(--bg-3);align-items:flex-start}
.tool .opp .sev{flex:none;width:9px;height:9px;border-radius:50%;margin-top:6px}
.tool .opp b{display:block;font-size:13.5px;font-weight:650;letter-spacing:-.01em;color:var(--ink-2)}
.tool .opp p{margin-top:2px;font-size:12.5px;line-height:1.55;color:var(--muted)}
.tool .sev.high{background:var(--bad)}
.tool .sev.med{background:var(--amber)}
.tool .progress-wrap{margin-top:18px}
.tool .progress-meta{display:flex;justify-content:space-between;align-items:baseline;font-family:var(--mono);font-size:12px;color:var(--dark-muted);margin-bottom:8px}
.tool .progress-meta b{color:#fff;font-weight:600}
.tool .pbar{height:6px;border-radius:999px;background:rgba(255,255,255,.08);overflow:hidden}
.tool .budget-wrap{margin-top:20px}
.tool .budget-meta{display:flex;justify-content:space-between;align-items:baseline;font-family:var(--mono);font-size:12px;color:var(--dark-muted);margin-bottom:9px}
.tool .budget-meta b{color:#fff;font-weight:600}
.tool .budget-meta .cliff{color:var(--amber-bright)}
.tool .budget .seg{flex:1;height:12px;border-radius:4px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.06);transition:background .25s,border-color .25s}
.tool .budget .seg.used{background:linear-gradient(180deg,var(--accent-bright),var(--accent));border-color:transparent}
.tool .budget .seg.hot{background:linear-gradient(180deg,var(--amber-bright),#c9971c);border-color:transparent}
.tool .budget .seg.over{background:linear-gradient(180deg,var(--bad-bright),var(--bad));border-color:transparent;box-shadow:0 0 12px -2px rgba(255,122,104,.5)}
.tool .term-head{display:flex;align-items:center;gap:8px;padding:11px 16px;border-bottom:1px solid var(--dark-line);background:var(--dark-2)}
.tool .term-head .dot3{display:flex;gap:5px}
.tool .term-head .dot3 i{width:9px;height:9px;border-radius:50%;background:rgba(255,255,255,.14)}
.tool .term-head .tt{font-family:var(--mono);font-size:12px;color:var(--dark-muted)}
.tool .term-head .tc{margin-left:auto;font-family:var(--mono);font-size:12px;color:var(--dark-muted)}
.tool .term-head .tc b{color:var(--accent-bright)}
.tool .term-body{padding:14px 18px 16px;font-family:var(--mono);font-size:12.5px;line-height:1.9;color:var(--dark-muted);min-height:280px}
.tool .tl{display:flex;gap:12px;white-space:pre-wrap;animation:tool-land .3s var(--ease)}
.tool .tl .ln{flex:none;width:30px;text-align:right;color:var(--dark-soft)}
.tool .tl .ln.hit{color:var(--accent-bright);font-weight:600}
.tool .tl .ln.ovr{color:var(--bad-bright);font-weight:600}
.tool .tl .tx{flex:1;min-width:0}
.tool .tl .tx b{color:#fff;font-weight:600}
.tool .tl .tx .dim{color:var(--dark-soft)}
.tool .tl .tx .ok{color:var(--accent-bright)}
.tool .tl .tx .wr{color:var(--amber-bright)}
.tool .tl .tx .bd{color:var(--bad-bright)}
.tool .check-banner b{color:#fff}

/* ------------------------------------------------------------------ media
 * STEP 8. Media queries add ZERO specificity, so these blocks are 0-2-0/0-3-0
 * exactly like the base rules above and LOSE to any per-tool rule of equal
 * specificity, because the tool sheet loads after this file. A declaration may
 * therefore only live here once its base rule is hoisted AND every per-tool
 * full-body copy is deleted. Everything still scoped in a tool sheet keeps its
 * media override in that same sheet.
 * Blocks must stay in ascending-breakpoint order and AFTER every base rule.
 * Breakpoint ladder on a tool page: v30 980/600, tools.css 640/780/480, tools
 * 960/620. Do not invent a fourth.
 * Deliberately NOT here: .hero-in padding-top 108px (dns-checker,
 * website-from-country only, and both are excluded from the .hero hoist),
 * .verdict-in (availability_test only), and every Tier-3 grid collapse
 * (.quad/.err-grid/.tools-row/.testbar/.band-in) whose base rule is still
 * per-tool.
 */
@media (max-width:960px){
.tool .hero h1{font-size:38px}
/* align-items:stretch matters with the column flip: the base rule's
 * flex-start would size .verdict-main to fit-content, and one long
 * unbreakable child (a permalink URL) then drags the whole hero past a
 * phone viewport instead of wrapping inside it. */
.tool .verdict-hero{flex-direction:column;gap:24px;align-items:stretch}
.tool .v-answer{font-size:34px}
.tool .v-side{width:100%;flex-direction:row;flex-wrap:wrap}
.tool .v-side .v-chip{flex:1;min-width:150px}
}

@media (max-width:620px){
.tool .hero h1{font-size:30px}
}

/* ==========================================================================
 * PRINT (Step 10b) — NET-NEW. No tool sheet has a single print rule today, so
 * a result page prints the dark hero, the dark verdict zone, the dark terminal
 * panel, the nav and the footer. The result page IS the artefact people print
 * or PDF (a support ticket attachment, an audit record), so it prints as paper:
 * white ground, dark text, no chrome, no interactive affordances.
 *
 * Scoped to `.tool` (plus the two chrome wrappers) — this file loads ONLY on
 * the 32 tool templates, so nothing here can reach a marketing page.
 *
 * !important is used deliberately and for the same reason as the block below:
 * a media block adds ZERO specificity (see the note at :63), so without it
 * every surviving per-tool `.mxc .hero`-shaped rule in the later-loading tool
 * sheet would win and the page would still print dark.
 *
 * The dark-surface tokens are re-pointed rather than each rule being restated:
 * one small block flips every var()-driven dark surface, and the semantic
 * greens/ambers/reds keep their meaning because --accent-bright/--amber-bright/
 * --bad-bright are re-pointed to their ink-on-white equivalents instead of
 * being flattened to grey. Only the hard-coded #fff text needs restating.
 * ==========================================================================*/
@media print{
/* 1 · chrome and interactive affordances: not part of the artefact */
#nav-v3,.nav-v3,.footer-v3,.final-cta-outer,
.tool .capture,.tool .testbar,.tool .cap-form,
.tool .verdict-actions,.tool .btn-cta,.tool .act-ghost,
.tool .spin,.tool .permalink button{display:none!important}

/* 2 · paper: re-point the dark palette, keep the semantic hues legible */
.tool{
  --dark:#fff!important;--dark-2:#fff!important;
  --dark-ink:#0c0c0d!important;--dark-muted:#41414a!important;--dark-soft:#5a5a63!important;
  --dark-line:#e2e2e4!important;--dark-line-2:#d6d6d9!important;
  --accent-bright:#007e42!important;--amber-bright:#8a6500!important;--bad-bright:#c0382b!important;
  background:#fff!important;color:#0c0c0d!important;}
.tool .hero,.tool .verdict-zone,
.tool .term,.tool .term-head,.tool .term-body,
.tool .upt-badge,.tool .permalink{background:#fff!important;color:#1f1f22!important;box-shadow:none!important}
/* dns-checker / website-from-country renamed the shell to escape v30's global
 * `.hero` (see :202) — the token re-point above already whitens them, but their
 * gradient overlay and hard-coded white H1 need naming explicitly. */
.tool .dns-hero,.tool .wfc-hero{background:#fff!important;color:#1f1f22!important}
.tool .hero::before,.tool .verdict-zone::before,
.tool .dns-hero::before,.tool .wfc-hero::before{display:none!important}
.tool .dns-hero h1,.tool .wfc-hero h1,
.tool .hero h1,.tool .v-answer,.tool .verdict-line b,.tool .v-chip .val,
.tool .progress-meta b,.tool .budget-meta b,.tool .tl .tx b,
.tool .check-banner b,.tool .upt-badge{color:#0c0c0d!important}
.tool .v-chip .val.good,.tool .tl .tx .ok{color:#007e42!important}
.tool .term,.tool .term-head,.tool .permalink,.tool .v-chip{border:1px solid #d6d6d9!important}

/* 3 · pagination: never split a result card across two sheets */
.tool .card,.tool .pad-card,.tool .q-card,.tool .res-col,
.tool .err-card,.tool .opp,.tool .term,.tool .check-banner,
.tool .kv tr,.tool .tr-row{break-inside:avoid;page-break-inside:avoid}
.tool .term-body{min-height:0!important}
}

/* ==========================================================================
 * REDUCED MOTION (Step 10a) — NET-NEW, and this block MUST stay last.
 *
 * All 29 tool sheets ship infinite animations (pulsing dots, spinners, the
 * whois caret, the shimmer skeleton) and NOT ONE of them honours
 * prefers-reduced-motion, although the rest of the codebase does
 * (nav.css:397, homepage.css:282/535, status-page.css:574).
 *
 * `animation:none!important` — a media block adds zero specificity, and the
 * per-tool rules that DECLARE these animations live in the later-loading
 * <tool>.css, so an unweighted rule here would lose every time. This is the
 * one place in this refactor where !important is correct.
 *
 * TRANSITIONS ARE DELIBERATELY UNTOUCHED. status-page.css's blanket
 * `*{transition:none!important}` is not safe here: cookieconsent.min.css's
 * banner is dismissed on a `transitionend` handler (cookieconsent.min.js:87),
 * and killing the transition on a tool page would leave the banner stuck.
 *
 * Selector inventory (every animated rule on a tool page):
 *   tools-page  .spin · .hero-eyebrow .dot · .badge-up .dot · .tl
 *   avt         .ticker-label .dot · .avt-mk-ring · .skeleton-box::after ·
 *               .feed-row · plus its own .hero-eyebrow/.badge-up dot overrides
 *   blacklist/domain/page-speed/ssl  .step.pend .st-ico::after
 *   blacklist   .bl.pend .ic::after
 *   dns/is-it-down/ping  .rg.wait .rstat i
 *   is-it-down  .board-head .live i
 *   wfc         .mini-spin · .cr        whois  .tcur
 * `scroll-behavior` is reset too — availability_test.css:10 sets it smooth.
 * ==========================================================================*/
@media (prefers-reduced-motion:reduce){
.tool{scroll-behavior:auto!important}
.tool .spin,
.tool .hero-eyebrow .dot,
.tool .badge-up .dot,
.tool .tl,
.tool .ticker-label .dot,
.tool .avt-mk-ring,
.tool .skeleton-box::after,
.tool .feed-row,
.tool .step.pend .st-ico::after,
.tool .bl.pend .ic::after,
.tool .rg.wait .rstat i,
.tool .board-head .live i,
.tool .mini-spin,
.tool .cr,
.tool .tcur{animation:none!important}
/* Freeze, do not delete. The pulse halo on these dots is supplied ONLY by the
 * keyframe (unlike .hero-eyebrow .dot, which also carries it as a base
 * declaration), so a bare animation:none would make the halo vanish rather than
 * stand still. These are the 0%/100% frames of tool-pulse and avt-pulse. */
.tool .badge-up .dot,
.tool .step.pend .st-ico::after,
.tool .bl.pend .ic::after,
.tool .rg.wait .rstat i,
.tool .board-head .live i{box-shadow:0 0 0 3px rgba(78,201,126,.18)!important}
.tool .ticker-label .dot,
.avt-page .badge-up .dot{box-shadow:0 0 0 3px rgba(52,211,153,.18)!important}
}
