/* ============================================================================
   PathMRI site — shared styles.

   The palette and surface treatment are the console's own login screen: navy
   gradient, two soft radial glows, a drifting node mesh, glass panels over the
   top. The site and the product are meant to read as one thing, so nothing here
   invents a second visual language.
   ========================================================================== */
:root{
  --navy-0:#0D2440; --navy-1:#0A1C30; --navy-2:#081422;
  --ink:#0A3255; --blue:#305D84; --sky:#8CC0EE; --red:#E25448;
  --text:#E7EFF9; --muted:rgba(226,236,248,.68); --faint:rgba(226,236,248,.45);
  --line:rgba(255,255,255,.14); --glass:rgba(255,255,255,.06);
  --maxw:1120px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
html,body{background:var(--navy-2)}
body{
  margin:0; color:var(--text);
  font:16px/1.65 Figtree,system-ui,-apple-system,"Segoe UI",sans-serif;
  -webkit-font-smoothing:antialiased; overflow-x:hidden;
}
a{color:inherit}
.wrap{max-width:var(--maxw); margin:0 auto; padding:0 24px}
:focus-visible{outline:2px solid var(--sky); outline-offset:3px; border-radius:4px}

/* ---- animated brand backdrop ---- */
#bg{position:fixed; inset:0; z-index:0; pointer-events:none;
  background:linear-gradient(160deg,var(--navy-0) 0%,var(--navy-1) 55%,var(--navy-2) 100%)}
#mesh{position:fixed; inset:0; z-index:1; pointer-events:none}
.glow{position:fixed; z-index:0; pointer-events:none; filter:blur(80px)}
.glow.a{width:560px;height:560px; right:-170px; top:-180px; background:radial-gradient(circle,rgba(59,130,246,.40),transparent 65%)}
.glow.b{width:520px;height:520px; left:-180px; top:44vh; background:radial-gradient(circle,rgba(239,68,68,.26),transparent 65%)}
main,header,footer{position:relative; z-index:2}

/* ---- header ---- */
header{padding:22px 0}
.bar{display:flex; align-items:center; justify-content:space-between; gap:20px; flex-wrap:wrap}
.brand{display:flex; align-items:center; gap:13px; text-decoration:none}
.chip{background:#fff; border-radius:14px; padding:8px; display:inline-flex; box-shadow:0 10px 28px rgba(0,0,0,.35)}
.chip img{width:36px;height:36px;display:block}
.word{font-size:24px; letter-spacing:-.02em; font-weight:400; white-space:nowrap}
.word b{font-weight:800; color:var(--sky)}
nav{display:flex; flex-wrap:wrap; gap:8px 22px}
nav a{font-size:14.5px; color:var(--muted); text-decoration:none; font-weight:500}
nav a:hover{color:#fff}
nav a[aria-current="page"]{color:#fff; font-weight:700}

/* ---- page headings ---- */
.eyebrow{display:inline-flex; align-items:center; gap:9px; font-size:12.5px; font-weight:700;
  letter-spacing:.09em; text-transform:uppercase; color:var(--sky);
  border:1px solid var(--line); background:var(--glass); padding:7px 14px; border-radius:100px}
h1{font-size:clamp(34px,5.4vw,58px); line-height:1.06; letter-spacing:-.034em; margin:22px 0 0;
  font-weight:800; text-wrap:balance}
h1 .hl{color:var(--sky)}
.lede{font-size:clamp(16.5px,2vw,19.5px); color:var(--muted); margin:20px 0 0; max-width:68ch}
.tag{margin-top:24px; font-size:15px; font-weight:600; color:var(--faint)}
section{padding:60px 0}
/* every section on the site is also a .wrap, whose `padding:0 24px` won this
   fight and left sections touching — this restores the vertical room */
section.wrap{padding-top:60px; padding-bottom:60px}
h2{font-size:clamp(25px,3.4vw,35px); line-height:1.15; letter-spacing:-.028em; margin:0;
  font-weight:800; text-wrap:balance}
h3{text-wrap:balance}
.sub{color:var(--muted); margin:13px 0 0; max-width:66ch; font-size:16.5px}

/* ---- buttons ---- */
.cta{display:flex; gap:14px; flex-wrap:wrap; margin-top:32px}
.btn{display:inline-flex; align-items:center; gap:9px; padding:13px 24px; border-radius:11px;
  font-weight:700; font-size:15px; text-decoration:none; border:1px solid transparent;
  transition:transform .15s ease}
.btn.primary{background:linear-gradient(135deg,#1B75D0,#0C447C); color:#fff; box-shadow:0 10px 26px rgba(24,95,165,.38)}
.btn.ghost{background:var(--glass); border-color:var(--line); color:var(--text)}
.btn:hover{transform:translateY(-1px)}

/* ---- panels ---- */
.tiles{display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,258px),1fr)); gap:18px; margin-top:34px}
.tile{background:var(--glass); border:1px solid var(--line); border-radius:16px; padding:24px 22px;
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px)}
.tile .ic{width:42px;height:42px;border-radius:11px;background:rgba(255,255,255,.10);
  display:flex;align-items:center;justify-content:center;color:#BFD8F5;margin-bottom:15px}
.tile h3{margin:0 0 7px; font-size:17.5px; font-weight:700; letter-spacing:-.01em}
.tile p{margin:0; color:var(--muted); font-size:14.6px; line-height:1.6}
.tile p + p{margin-top:10px}

/* ---- definition block, the "what this is" panel ---- */
.define{background:linear-gradient(160deg,rgba(48,93,132,.30),rgba(10,50,85,.26));
  border:1px solid rgba(140,192,238,.30); border-radius:20px; padding:30px 30px 28px; margin-top:34px}
.define h2{font-size:clamp(21px,2.6vw,27px)}
.define p{color:var(--text); font-size:17px; margin:14px 0 0; max-width:74ch; opacity:.92}
.define .kv{display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,210px),1fr));
  gap:16px; margin-top:24px; padding-top:22px; border-top:1px solid rgba(255,255,255,.12)}
.define .kv div b{display:block; font-size:13px; letter-spacing:.06em; text-transform:uppercase; color:var(--sky)}
.define .kv div span{display:block; margin-top:6px; color:var(--muted); font-size:14.4px}
/* the box's last word: the two figures are two capabilities, and here are the rest */
.define .more{display:flex; align-items:center; justify-content:space-between; gap:22px; flex-wrap:wrap;
  margin-top:24px; padding-top:22px; border-top:1px solid rgba(255,255,255,.12)}
.define .more p{margin:0; font-size:15.5px; max-width:62ch; color:var(--muted)}
.define .more p b{color:var(--text)}
.define .more .btn{flex:none}

/* ---- comparison ---- */
.vs{display:grid; grid-template-columns:1fr 1fr; gap:18px; margin-top:34px}
@media(max-width:820px){ .vs{grid-template-columns:1fr} }
.col{border-radius:18px; padding:26px 24px; border:1px solid var(--line)}
.col.old{background:rgba(255,255,255,.035)}
.col.new{background:linear-gradient(160deg,rgba(48,93,132,.34),rgba(10,50,85,.30)); border-color:rgba(140,192,238,.34)}
.col h3{margin:0 0 4px; font-size:13px; font-weight:800; letter-spacing:.1em; text-transform:uppercase}
.col.old h3{color:var(--faint)} .col.new h3{color:var(--sky)}
.col .lead{margin:0 0 18px; font-size:19px; font-weight:700; letter-spacing:-.015em}
.col ul{margin:0; padding:0; list-style:none}
.col li{display:flex; gap:11px; padding:9px 0; font-size:14.8px; color:var(--muted); line-height:1.55;
  border-top:1px solid rgba(255,255,255,.07)}
.col li:first-child{border-top:0}
.col li .m{flex:0 0 auto; margin-top:2px}

/* ---- numbered method ---- */
.steps{display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr)); gap:18px; margin-top:34px}
.step{background:var(--glass); border:1px solid var(--line); border-radius:16px; padding:24px 22px}
.step .n{font-size:12px; font-weight:800; letter-spacing:.12em; color:var(--sky); text-transform:uppercase}
.step h3{margin:9px 0 7px; font-size:18px; font-weight:700}
.step p{margin:0; color:var(--muted); font-size:14.6px}

/* ---- stats ---- */
.stats{display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,180px),1fr)); gap:18px; margin-top:34px}
.stat{background:var(--glass); border:1px solid var(--line); border-radius:16px; padding:24px 22px}
.stat .k{font-size:34px; font-weight:800; letter-spacing:-.03em; color:#fff; line-height:1; font-variant-numeric:tabular-nums}
.stat .v{margin-top:8px; color:var(--muted); font-size:14.4px}

/* ---- tables (vendor coverage, package list) ---- */
.tablewrap{overflow-x:auto; margin-top:26px; border:1px solid var(--line); border-radius:16px;
  background:var(--glass)}
table{border-collapse:collapse; width:100%; min-width:560px; font-size:14.4px}
th,td{text-align:left; padding:13px 18px; border-bottom:1px solid rgba(255,255,255,.08); vertical-align:top}
th{font-size:12px; letter-spacing:.08em; text-transform:uppercase; color:var(--sky); font-weight:800;
  background:rgba(255,255,255,.04); white-space:nowrap}
tr:last-child td{border-bottom:0}
td b{color:#fff; font-weight:700}
td.mono{font:13px/1.5 ui-monospace,Consolas,monospace; color:var(--muted); white-space:nowrap}

/* ---- breadcrumb, on a feature page ---- */
.crumb{display:flex; gap:9px; align-items:center; flex-wrap:wrap; color:var(--faint);
  font-size:13.5px; font-weight:600}
.crumb a{text-decoration:none}
.crumb a:hover{color:#fff}

/* ---- read-more link, on a tile or under a section ---- */
.more{display:inline-flex; align-items:center; gap:7px; color:var(--sky); font-size:14px;
  font-weight:700; text-decoration:none}
.more:hover{color:#fff}

/* ---- link lists (docs index) ---- */
.links{display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr)); gap:14px; margin-top:26px}
.link{display:block; background:var(--glass); border:1px solid var(--line); border-radius:14px;
  padding:18px 20px; text-decoration:none; transition:border-color .15s ease, transform .15s ease}
.link:hover{border-color:rgba(140,192,238,.45); transform:translateY(-2px)}
.link b{display:block; font-size:16px; font-weight:700}
.link code{font:12.5px/1 ui-monospace,Consolas,monospace; color:var(--sky); display:block; margin-top:5px}
.link span{display:block; margin-top:8px; color:var(--muted); font-size:14.2px; line-height:1.55}

/* ---- inline code + note ---- */
code{font:0.92em/1.45 ui-monospace,Consolas,monospace; background:rgba(255,255,255,.07);
  border:1px solid rgba(255,255,255,.10); border-radius:5px; padding:1px 6px}
pre{overflow-x:auto; background:rgba(0,0,0,.28); border:1px solid var(--line); border-radius:12px;
  padding:16px 18px; margin-top:16px}
pre code{background:none; border:0; padding:0; font-size:13.2px; line-height:1.65; color:var(--text)}
.note{border-left:3px solid var(--sky); background:rgba(140,192,238,.08); border-radius:0 12px 12px 0;
  padding:16px 20px; margin-top:24px; color:var(--muted); font-size:14.8px; max-width:74ch}
.note b{color:#fff}
.warn{border-left-color:var(--red); background:rgba(226,84,72,.09)}

/* ---- footer ---- */
footer{border-top:1px solid rgba(255,255,255,.10); padding:34px 0 52px; margin-top:36px}
.fnote{color:var(--faint); font-size:13px; line-height:1.75; max-width:76ch}
.fnote code{font-size:12.4px}
.flinks{display:flex; gap:20px; flex-wrap:wrap; margin:16px 0 14px}
.flinks a{color:var(--muted); font-size:14px; text-decoration:none; font-weight:500}
.flinks a:hover{color:#fff}

@media (prefers-reduced-motion: reduce){
  #mesh{display:none}
  .btn:hover,.link:hover{transform:none}
  html{scroll-behavior:auto}
}

/* ---- the walkthrough video ---- */
.videowrap{margin-top:30px; border:1px solid var(--line); border-radius:18px; overflow:hidden;
  background:#04101d; box-shadow:0 24px 60px rgba(0,0,0,.42); line-height:0}
.videowrap video{width:100%; height:auto; display:block; background:#04101d}/* ============================================================================
   The MRI.

   Two figures share this block. The FIRST finds the firewall and the rule that
   stopped a flow, and ends red. The SECOND, right under it, crosses an IPsec
   tunnel between two sites and ends green. Same bore, same colours; the second
   figure's timing is the .mri-t section at the end, and every static rule is
   shared.

   One scanner bore travels the path and STOPS on each node to image it. Under
   the bore a node shows grey-white, the way an MRI slice does; as the bore
   leaves, the node takes its verdict — green if the flow passed it, red for the
   one that stopped it — and the wire behind the bore is painted green. Green is
   ground a real packet crossed, so it is never ahead of the bore. Each stop
   names what is read on it, in the product's own words.

   Ten- and thirteen-second loops. Pure CSS on inline SVG: no script, no canvas,
   nothing to load, nothing that can fail. Every element runs the SAME timeline
   and picks its moment with keyframe percentages, so nothing can drift the way
   chained delays do, and everything clears on the same frame.

   ONE ELEMENT, ONE ANIMATION. Two `animation` declarations on the same element
   do not add up — the later replaces the earlier — so anything that has to
   change two properties at different moments gets one keyframe set doing both.
   (A comma-separated list in ONE declaration is fine: the tunnel's traffic
   moves on one clock and changes colour on another.)

   Glyphs and colours are the console's (controller/pathmri-web: Topology.jsx,
   theme.js dark theme): three-bar host, shield firewall, source blue,
   destination magenta, steel devices, green pass, red block.

   Distances come from the figures themselves (--stop1, --stop2, --park,
   --reached-1, --reached-2, --reached-len), set on the wrapper by the
   generator, so moving a device never desynchronises this.
   ========================================================================== */

.mri{
  --t: 10s;
  --allow:#8CC0EE; --deny:#EF4444; --ok:#10B981; --fw:#8DA0BC; --src:#5AA0F2; --dst:#D946EF; --scan:#DCE5F0; --wire:rgba(226,236,248,.22);
  margin-top:26px; padding-top:24px; border-top:1px solid rgba(255,255,255,.12);
}
.mri svg{display:block; width:100%; height:auto; overflow:visible}


/* ---- one figure, two orientations ----
   Across the page on a desktop, down the page on a phone. A 1000-unit-wide
   figure at 390px scales to about 0.28, which renders a 14.5px label near 4px —
   invisible, not merely small. Only one figure is ever in the layout: the other
   is display:none, so it neither renders nor animates. */
.mri-v{display:none}
.mri .m-left{text-anchor:start}
.mri .m-left{text-anchor:start}
@media (max-width:700px){
  .mri-h{display:none}
  .mri-v{display:block}
}

/* the same choreography, down the page instead of across it */
.mri-v .m-scanner{animation-name:m-travel-v}
@keyframes m-travel-v{
  0%     {transform:translateY(0);            opacity:0}
  2%     {transform:translateY(0);            opacity:1}
  13%    {transform:translateY(0);            opacity:1}
  21%,35%{transform:translateY(var(--stop1)); opacity:1}
  44%,96%{transform:translateY(var(--park));  opacity:1}
  100%   {transform:translateY(var(--park));  opacity:0}
}

/* ---- the path, and the devices on it ---- */
.m-wire{stroke:var(--wire); stroke-width:2; stroke-linecap:round}
/* a device is its own shape — no ring, no plate, nothing around it */
.m-dev{fill:none; stroke:var(--src); color:var(--src); stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}
.m-fw{stroke:var(--fw); color:var(--fw)}
.m-dst{stroke:var(--dst); color:var(--dst)}
.m-dev-found{animation:m-dev-found var(--t) ease-out infinite}
.m-dev-ok-0{animation:m-dev-ok-0 var(--t) ease-out infinite}
@keyframes m-dev-ok-0{
  0%,1%  {stroke:var(--src);  color:var(--src)}
  3%,8%  {stroke:var(--scan); color:var(--scan)}   /* being imaged */
  11%    {stroke:var(--ok);   color:var(--ok)}
  96%    {stroke:var(--ok);   color:var(--ok)}
  100%   {stroke:var(--src);  color:var(--src)}
}
.m-dev-ok-1{animation:m-dev-ok-1 var(--t) ease-out infinite}
@keyframes m-dev-ok-1{
  0%,20% {stroke:var(--fw)}
  22%,30%{stroke:var(--scan)}
  33%    {stroke:var(--ok)}
  96%    {stroke:var(--ok)}
  100%   {stroke:var(--fw)}
}
@keyframes m-dev-found{
  0%,43% {stroke:var(--fw)}
  45%,52%{stroke:var(--scan)}
  56%    {stroke:var(--deny)}
  96%    {stroke:var(--deny)}
  100%   {stroke:var(--fw)}
}
.m-chk{fill:rgba(140,192,238,.72); font:600 10.5px ui-monospace,Consolas,monospace;
  text-anchor:middle; letter-spacing:.02em; opacity:0}
.m-chk-0{animation:m-chk-0 var(--t) ease-out infinite}
.m-chk-1{animation:m-chk-1 var(--t) ease-out infinite}
.m-chk-2{animation:m-chk-2 var(--t) ease-out infinite}
@keyframes m-chk-0{
  0%,4% {opacity:0; transform:translateY(3px)}
  7%    {opacity:1; transform:translateY(0)}
  96%   {opacity:1; transform:translateY(0)}
  100%  {opacity:0; transform:translateY(0)}
}
@keyframes m-chk-1{
  0%,23%{opacity:0; transform:translateY(3px)}
  26%   {opacity:1; transform:translateY(0)}
  96%   {opacity:1; transform:translateY(0)}
  100%  {opacity:0; transform:translateY(0)}
}
@keyframes m-chk-2{
  0%,46%{opacity:0; transform:translateY(3px)}
  49%   {opacity:1; transform:translateY(0)}
  96%   {opacity:1; transform:translateY(0)}
  100%  {opacity:0; transform:translateY(0)}
}
.m-port{fill:rgba(226,236,248,.42); font:600 11.5px ui-monospace,Consolas,monospace;
  text-anchor:middle; letter-spacing:.04em}
.m-name{fill:#E7EFF9; font:700 14.5px Figtree,system-ui,sans-serif; text-anchor:middle}
.m-sub{fill:rgba(226,236,248,.5); font:500 12px ui-monospace,Consolas,monospace; text-anchor:middle}
/* "not reached" is a FINDING — it appears when the scan finds it, not before */
.m-late{opacity:0; animation:m-read-2 var(--t) ease-out infinite}
.m-role{fill:var(--allow); font:800 10.5px Figtree,system-ui,sans-serif; letter-spacing:.14em;
  text-anchor:middle; text-transform:uppercase}
.m-role-source{fill:var(--src)}
.m-role-destination{fill:var(--dst)}


/* ---- the stretch the packet actually crossed ----
   Drawn under the packet as it travels, and it STOPS at the device that
   stopped it. Green here means measured, not assumed: this much of the path is
   proven, and the rest was never reached. The two colours are the two halves of
   the answer, so they must never blur into one another. */
.m-reached{stroke:var(--ok); stroke-width:2.6; stroke-linecap:round; stroke-dasharray:var(--reached-len);
  stroke-dashoffset:var(--reached-len); animation:m-reached var(--t) cubic-bezier(.65,0,.35,1) infinite}
.m-reached-glow{stroke:var(--ok); stroke-width:9; stroke-linecap:round; opacity:.5;
  filter:url(#m-soft); stroke-dasharray:var(--reached-len); stroke-dashoffset:var(--reached-len);
  animation:m-reached var(--t) cubic-bezier(.65,0,.35,1) infinite}
@keyframes m-reached{
  0%,13% {stroke-dashoffset:var(--reached-len); opacity:1}
  21%,35%{stroke-dashoffset:var(--reached-1);   opacity:1}
  44%    {stroke-dashoffset:0;                  opacity:1}
  96%    {stroke-dashoffset:0;                  opacity:1}
  100%   {stroke-dashoffset:0;                  opacity:0}
}
/* ---- the scanner: one bore, travelling the whole path ---- */
.m-scanner{animation:m-travel var(--t) cubic-bezier(.65,0,.35,1) infinite}
@keyframes m-travel{
  0%     {transform:translateX(0);            opacity:0}
  2%     {transform:translateX(0);            opacity:1}
  13%    {transform:translateX(0);            opacity:1}
  21%,35%{transform:translateX(var(--stop1)); opacity:1}
  44%,96%{transform:translateX(var(--park));  opacity:1}
  100%   {transform:translateX(var(--park));  opacity:0}
}
.m-band{fill:none; stroke:rgba(226,236,248,.13); stroke-width:13}
.m-ticks line{stroke:rgba(226,236,248,.20); stroke-width:1.2}
.m-lip{fill:none; stroke:rgba(226,236,248,.20); stroke-width:1.1}

/* the band lights while imaging, and goes red once parked on the deny */
.m-band-on{fill:none; stroke:var(--allow); stroke-width:13; opacity:.26;
  animation:m-band-on var(--t) ease-out infinite}
@keyframes m-band-on{
  0%  {opacity:.26; stroke:var(--allow)}
  50% {opacity:.42; stroke:var(--allow)}
  56% {opacity:.52; stroke:var(--deny)}
  96% {opacity:.44; stroke:var(--deny)}
  100%{opacity:.26; stroke:var(--allow)}
}

/* the segments travelling round the band — a bore spins while it images */
.m-segments{fill:none; stroke:rgba(226,236,248,.5); stroke-width:13;
  stroke-dasharray:7 21; animation:m-spin 2.6s linear infinite}
@keyframes m-spin{ to{stroke-dashoffset:-56} }

/* where the beam meets the wire: a hot spot, and two thin rays across the bore */
.m-hot{fill:url(#m-hot); animation:m-hot var(--t) ease-out infinite}
@keyframes m-hot{
  0%,50%{opacity:1}
  56%,100%{opacity:0}
}
.m-hot-deny{fill:url(#m-hot-deny); opacity:0; animation:m-bore-deny var(--t) ease-out infinite}
.m-ray{stroke:rgba(220,235,250,.30); stroke-width:1; stroke-dasharray:3 6;
  animation:m-ray 1.9s linear infinite}
@keyframes m-ray{ to{stroke-dashoffset:-18} }

/* the light inside the bore, kept faint so the path stays visible through it */
.m-bore-glow{fill:url(#m-bore-light)}
.m-bore-glow-deny{fill:url(#m-bore-deny); opacity:0; animation:m-bore-deny var(--t) ease-out infinite}
@keyframes m-bore-deny{
  0%,51%{opacity:0}
  56%   {opacity:1}
  96%   {opacity:1}
  100%  {opacity:0}
}

/* ---- what the scan reads as each device passes through the bore ---- */
.m-read{opacity:0}
.m-read-1{animation:m-read-1 var(--t) ease-out infinite}
@keyframes m-read-1{
  0%,28%{opacity:0; transform:translateY(4px)}
  31%   {opacity:1; transform:translateY(0)}
  96%   {opacity:1; transform:translateY(0)}
  100%  {opacity:0; transform:translateY(0)}
}
.m-read-2{animation:m-read-2 var(--t) ease-out infinite}
@keyframes m-read-2{
  0%,51%{opacity:0; transform:translateY(4px)}
  54%   {opacity:1; transform:translateY(0)}
  96%   {opacity:1; transform:translateY(0)}
  100%  {opacity:0; transform:translateY(0)}
}
@keyframes m-dead{
  0%,56% {stroke:var(--wire);        stroke-dasharray:600 0}
  62%,96%{stroke:rgba(239,68,68,.5); stroke-dasharray:5 7}
  100%   {stroke:var(--wire);        stroke-dasharray:600 0}
}


/* ---- reconcile: the two answers side by side, and whether they agree ---- */
/* This is the step the picture used to leave out. The scan predicts, the packet
   observes, and the product is the COMPARISON — so the comparison is drawn. */
.m-chip{fill:rgba(255,255,255,.05); stroke:var(--line); stroke-width:1}
.m-chip-k{fill:var(--sky); font:800 9.5px Figtree,system-ui,sans-serif; letter-spacing:.14em;
  text-anchor:middle; text-transform:uppercase}
.m-chip-v{font:700 12px ui-monospace,Consolas,monospace; text-anchor:middle}
.m-chip-no{fill:var(--deny)}
.m-match{fill:rgba(140,192,238,.16); stroke:var(--sky); stroke-width:1.5}
.m-tick{fill:none; stroke:var(--sky); stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round}
.m-match-tx{fill:var(--sky); font:800 9.5px Figtree,system-ui,sans-serif; letter-spacing:.14em;
  text-anchor:middle; text-transform:uppercase}

/* predicted appears the moment the scan reads the deny — before any packet */
.m-rec-a{opacity:0; animation:m-rec-a var(--t) ease-out infinite}
@keyframes m-rec-a{
  0%,62%{opacity:0; transform:translateY(5px)}
  66%   {opacity:1; transform:translateY(0)}
  96%   {opacity:1; transform:translateY(0)}
  100%  {opacity:0; transform:translateY(0)}
}
/* observed appears when the packet dies */
.m-rec-b{opacity:0; animation:m-rec-b var(--t) ease-out infinite}
@keyframes m-rec-b{
  0%,66%{opacity:0; transform:translateY(5px)}
  70%   {opacity:1; transform:translateY(0)}
  96%   {opacity:1; transform:translateY(0)}
  100%  {opacity:0; transform:translateY(0)}
}
/* and only then can they be compared */
.m-rec-c{opacity:0; animation:m-rec-c var(--t) ease-out infinite}
@keyframes m-rec-c{
  0%,72%{opacity:0; transform:scale(.7)}
  76%   {opacity:1; transform:scale(1)}
  96%   {opacity:1; transform:scale(1)}
  100%  {opacity:0; transform:scale(1)}
}
/* ---- the verdict, which is the point ---- */
.m-verdict{opacity:0; animation:m-verdict var(--t) ease-out infinite}
@keyframes m-verdict{
  0%,78%{opacity:0; transform:translateY(6px)}
  83%   {opacity:1; transform:translateY(0)}
  96%   {opacity:1; transform:translateY(0)}
  100%  {opacity:0; transform:translateY(0)}
}
.m-v-label{fill:rgba(226,236,248,.62); font:600 13px Figtree,system-ui,sans-serif}
.m-v-strong{fill:#fff; font:800 13px Figtree,system-ui,sans-serif}
.m-v-rule{fill:var(--deny); font:700 12.5px ui-monospace,Consolas,monospace}
.m-rule-ok{fill:var(--ok); font:600 11.5px ui-monospace,Consolas,monospace; text-anchor:middle}
.m-rule-no{fill:var(--deny); font:700 11.5px ui-monospace,Consolas,monospace; text-anchor:middle}

/* Someone who asked for less motion gets the ANSWER, not the journey: the bore
   parked on the device that stopped the flow, every rule read, the verdict
   shown, and nothing moving. */
@media (prefers-reduced-motion: reduce){
  .mri *{animation:none !important}
  .mri-h .m-scanner{opacity:1; transform:translateX(var(--park))}
  .mri-v .m-scanner{opacity:1; transform:translateY(var(--park))}
  .m-band-on{stroke:var(--deny); opacity:.44}
  .m-segments{stroke:rgba(226,236,248,.34)}
  .m-bore-glow-deny{opacity:1}
  .m-dev-found{stroke:var(--deny)}
  .m-dev-ok-0,.m-dev-ok-1{stroke:var(--ok); color:var(--ok)}
  .m-chk,.m-late,.m-read,.m-verdict,.m-rec-a,.m-rec-b,.m-rec-c{opacity:1}
  .m-reached,.m-reached-glow{stroke-dashoffset:0}
  .m-hot{opacity:0}
  .m-hot-deny{opacity:1}
  .m-dead{stroke:rgba(239,68,68,.5); stroke-dasharray:5 7}
}


/* ==========================================================================
   The second figure: two sites, one tunnel, verified end to end.

   Same bore, same dwell, same colours. Four stops instead of three, one leg
   runs through the tube, and the ending is green: ring, hot spot and verdict
   all say "reachable — through the tunnel, encrypted". Only the timing and
   the ending differ, so only those are redefined here; every static rule
   above applies unchanged.

     0-2    appear on app-01           2-11   dwell: routing, host firewall
     11-17  travel                     17-27  dwell fw-site-a: phase 1, 2, route, rules
     27-40  through the tunnel         40-50  dwell fw-aws-b
     50-56  travel                     56-65  dwell db-02: host firewall, listener
     66-85  the two answers, the tick, the verdict     85-96 hold, 96-100 clear
   ========================================================================== */
.mri-t{--t:13s}
.mri-t .m-scanner{animation-name:t-travel}
.mri-t.mri-v .m-scanner{animation-name:t-travel-v}
@keyframes t-travel{
  0%     {transform:translateX(0);            opacity:0}
  2%,11% {transform:translateX(0);            opacity:1}
  17%,27%{transform:translateX(var(--stop1)); opacity:1}
  40%,50%{transform:translateX(var(--stop2)); opacity:1}
  56%,96%{transform:translateX(var(--park));  opacity:1}
  100%   {transform:translateX(var(--park));  opacity:0}
}
@keyframes t-travel-v{
  0%     {transform:translateY(0);            opacity:0}
  2%,11% {transform:translateY(0);            opacity:1}
  17%,27%{transform:translateY(var(--stop1)); opacity:1}
  40%,50%{transform:translateY(var(--stop2)); opacity:1}
  56%,96%{transform:translateY(var(--park));  opacity:1}
  100%   {transform:translateY(var(--park));  opacity:0}
}
.mri-t .m-reached,.mri-t .m-reached-glow{animation-name:t-reached}
@keyframes t-reached{
  0%,11% {stroke-dashoffset:var(--reached-len); opacity:1}
  17%,27%{stroke-dashoffset:var(--reached-1);   opacity:1}
  40%,50%{stroke-dashoffset:var(--reached-2);   opacity:1}
  56%,96%{stroke-dashoffset:0;                  opacity:1}
  100%   {stroke-dashoffset:0;                  opacity:0}
}

/* the pipe stays steel until the bore has come out the other end of it */
.m-tube{fill:none; stroke:var(--fw); stroke-width:1.3; stroke-linecap:round; opacity:.75;
  animation:t-tube var(--t) ease-out infinite}
.m-tube-mouth{fill:rgba(255,255,255,.035)}
.m-tube-sheath{stroke-width:30; opacity:.09}
@keyframes t-tube{
  0%,38%{stroke:var(--fw)}
  41%   {stroke:var(--ok)}
  96%   {stroke:var(--ok)}
  100%  {stroke:var(--fw)}
}
/* the traffic inside it: always moving, faint until the bore has proved the
   stretch, then bright green — motion that never claims more than was measured */
.m-tube-flow{fill:none; stroke:var(--fw); stroke-width:3; stroke-linecap:round; stroke-dasharray:9 15; opacity:.22;
  animation:t-flow 1.6s linear infinite, t-flow-on var(--t) ease-out infinite}
@keyframes t-flow{ to{stroke-dashoffset:-48} }
@keyframes t-flow-on{
  0%,38%{stroke:var(--fw); opacity:.22}
  41%   {stroke:var(--ok); opacity:.6}
  96%   {stroke:var(--ok); opacity:.6}
  100%  {stroke:var(--fw); opacity:.22}
}
.m-tube-lbl{fill:rgba(226,236,248,.55); font:600 10.5px ui-monospace,Consolas,monospace;
  text-anchor:middle; letter-spacing:.04em}

/* the ring finishes green, not red */
.mri-t .m-band-on{animation-name:t-band}
@keyframes t-band{
  0%,60%{opacity:.26; stroke:var(--allow)}
  64%   {opacity:.5;  stroke:var(--ok)}
  96%   {opacity:.44; stroke:var(--ok)}
  100%  {opacity:.26; stroke:var(--allow)}
}
.mri-t .m-hot{animation-name:t-hot}
@keyframes t-hot{ 0%,60%{opacity:1} 64%,100%{opacity:0} }
.m-hot-ok{fill:url(#m-hot-ok); opacity:0; animation:t-bore-ok var(--t) ease-out infinite}
.m-bore-glow-ok{fill:url(#m-bore-ok); opacity:0; animation:t-bore-ok var(--t) ease-out infinite}
@keyframes t-bore-ok{ 0%,60%{opacity:0} 64%,96%{opacity:1} 100%{opacity:0} }
.mri-t .m-hot-deny,.mri-t .m-bore-glow-deny{animation:none; opacity:0}

/* four stops, each greening at the END of its dwell */
.mri-t .m-dev-ok-0{animation:t-dev-0 var(--t) ease-out infinite}
.mri-t .m-dev-ok-1{animation:t-dev-1 var(--t) ease-out infinite}
.mri-t .m-dev-ok-2{animation:t-dev-2 var(--t) ease-out infinite}
.mri-t .m-dev-ok-3{animation:t-dev-3 var(--t) ease-out infinite}
@keyframes t-dev-0{
  0%,1%  {stroke:var(--src);  color:var(--src)}
  3%,8%  {stroke:var(--scan); color:var(--scan)}
  11%    {stroke:var(--ok);   color:var(--ok)}
  96%    {stroke:var(--ok);   color:var(--ok)}
  100%   {stroke:var(--src);  color:var(--src)}
}
@keyframes t-dev-1{
  0%,16% {stroke:var(--fw)}
  18%,23%{stroke:var(--scan)}
  26%    {stroke:var(--ok)}
  96%    {stroke:var(--ok)}
  100%   {stroke:var(--fw)}
}
@keyframes t-dev-2{
  0%,39% {stroke:var(--fw)}
  41%,46%{stroke:var(--scan)}
  49%    {stroke:var(--ok)}
  96%    {stroke:var(--ok)}
  100%   {stroke:var(--fw)}
}
@keyframes t-dev-3{
  0%,55% {stroke:var(--dst);  color:var(--dst)}
  57%,61%{stroke:var(--scan); color:var(--scan)}
  64%    {stroke:var(--ok);   color:var(--ok)}
  96%    {stroke:var(--ok);   color:var(--ok)}
  100%   {stroke:var(--dst);  color:var(--dst)}
}

/* what is read at each stop, then what that reading produced */
.mri-t .m-chk-0{animation:t-chk-0 var(--t) ease-out infinite}
.mri-t .m-chk-1{animation:t-chk-1 var(--t) ease-out infinite}
.mri-t .m-chk-2{animation:t-chk-2 var(--t) ease-out infinite}
.mri-t .m-chk-3{animation:t-chk-3 var(--t) ease-out infinite}
@keyframes t-chk-0{ 0%,3% {opacity:0; transform:translateY(3px)} 6% {opacity:1; transform:translateY(0)} 96%{opacity:1; transform:translateY(0)} 100%{opacity:0; transform:translateY(0)} }
@keyframes t-chk-1{ 0%,18%{opacity:0; transform:translateY(3px)} 21%{opacity:1; transform:translateY(0)} 96%{opacity:1; transform:translateY(0)} 100%{opacity:0; transform:translateY(0)} }
@keyframes t-chk-2{ 0%,41%{opacity:0; transform:translateY(3px)} 44%{opacity:1; transform:translateY(0)} 96%{opacity:1; transform:translateY(0)} 100%{opacity:0; transform:translateY(0)} }
@keyframes t-chk-3{ 0%,57%{opacity:0; transform:translateY(3px)} 60%{opacity:1; transform:translateY(0)} 96%{opacity:1; transform:translateY(0)} 100%{opacity:0; transform:translateY(0)} }
.mri-t .m-read-1{animation:t-read-1 var(--t) ease-out infinite}
.mri-t .m-read-2{animation:t-read-2 var(--t) ease-out infinite}
@keyframes t-read-1{ 0%,22%{opacity:0; transform:translateY(4px)} 25%{opacity:1; transform:translateY(0)} 96%{opacity:1; transform:translateY(0)} 100%{opacity:0; transform:translateY(0)} }
@keyframes t-read-2{ 0%,45%{opacity:0; transform:translateY(4px)} 48%{opacity:1; transform:translateY(0)} 96%{opacity:1; transform:translateY(0)} 100%{opacity:0; transform:translateY(0)} }

/* the two answers, the tick, the verdict */
.m-chip-ok{fill:var(--ok)}
.mri-t .m-rec-a{animation:t-rec-a var(--t) ease-out infinite}
.mri-t .m-rec-b{animation:t-rec-b var(--t) ease-out infinite}
.mri-t .m-rec-c{animation:t-rec-c var(--t) ease-out infinite}
.mri-t .m-verdict{animation:t-verdict var(--t) ease-out infinite}
@keyframes t-rec-a{ 0%,66%{opacity:0; transform:translateY(5px)} 70%{opacity:1; transform:translateY(0)} 96%{opacity:1; transform:translateY(0)} 100%{opacity:0; transform:translateY(0)} }
@keyframes t-rec-b{ 0%,70%{opacity:0; transform:translateY(5px)} 74%{opacity:1; transform:translateY(0)} 96%{opacity:1; transform:translateY(0)} 100%{opacity:0; transform:translateY(0)} }
@keyframes t-rec-c{ 0%,75%{opacity:0; transform:scale(.7)} 79%{opacity:1; transform:scale(1)} 96%{opacity:1; transform:scale(1)} 100%{opacity:0; transform:scale(1)} }
@keyframes t-verdict{ 0%,80%{opacity:0; transform:translateY(6px)} 85%{opacity:1; transform:translateY(0)} 96%{opacity:1; transform:translateY(0)} 100%{opacity:0; transform:translateY(0)} }

/* reduced motion: the finished, green state */
@media (prefers-reduced-motion: reduce){
  .mri-t .m-band-on{stroke:var(--ok)}
  .mri-t .m-hot-ok,.mri-t .m-bore-glow-ok{opacity:1}
  .mri-t .m-hot-deny,.mri-t .m-bore-glow-deny{opacity:0}
  .mri-t .m-dev-ok-2,.mri-t .m-dev-ok-3,.mri-t .m-tube,.mri-t .m-tube-flow{stroke:var(--ok); color:var(--ok)}
  .mri-t .m-tube-flow{opacity:.6}
}
