:root {
  --bg: #0d1117;
  --fg: #e6e8eb;
  --muted: #8b95a1;
  --accent: #4fb3ff;
  --card: #1a212a;
  --line: #222a33;
  --border: #6b7785; /* controls: 3:1 against the page (WCAG 1.4.11) */
  --ok: #3fb950;
  --warn: #d29922;
  --bad: #ff7b72;
  --gutter: max(1rem, env(safe-area-inset-left));
  --sky: #2e3a49; /* background: stars and orbits */
  --hud: #ff8a1f; /* background: readouts */
  --orbit: #3a4858; /* background: orbits */
  --map: #f2c230; /* background: jump routes */
  color-scheme: dark;
}
/* Dark by default; light with the switch of the header (a link to /pref,
   which keeps the choice in a cookie: the server then draws the page with
   data-theme and the switch set). ?sky=demo stays dark. */
:root:not([data-sky="demo"], [data-net="demo"]):is([data-theme="light"], :not([data-theme]):has(#th-light:checked)) { --bg: #ffffff; --fg: #14181d; --muted: #5b6672; --accent: #0a6bc4; --card: #f4f6f8; --line: #e6eaee; --border: #6f7a86; --ok: #1a7f37; --warn: #9a6700; --bad: #cf222e; --sky: #cfd8e2; --hud: #d65f00; --orbit: #c5ced8; --map: #a37800; color-scheme: light; }
* { box-sizing: border-box; }
/* Background: a starry sky drifting up and readouts bottom left, painted
   through SVG masks in --sky and --hud (the rest of the sky, orbits and
   events, is in sky.css); the motion is transforms only. /clock.css (from the server) sets --bg-clock so that it
   goes on from page to page instead of starting over. */
html::before, body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  mask-repeat: no-repeat; -webkit-mask-repeat: no-repeat;
}
body::before {
  inset: -400px 0 0; background-color: var(--sky); animation: bg-rise 120s linear infinite var(--bg-clock, 0s);
  mask-image: url("bg-stars.svg?v=98776dee"); -webkit-mask-image: url("bg-stars.svg?v=98776dee"); mask-repeat: repeat; -webkit-mask-repeat: repeat;
}
html::before {
  background-color: var(--hud); opacity: .55;
  mask-image: url("bg-readouts.svg?v=e1079605"); -webkit-mask-image: url("bg-readouts.svg?v=e1079605");
  mask-position: 24px calc(100% - 24px); -webkit-mask-position: 24px calc(100% - 24px);
}
/* The sun: above the page, never hidden by it, letting clicks through. */
.sky-sun {
  position: fixed; top: 120px; right: 120px; z-index: 1; pointer-events: none; width: 24px; height: 24px; margin: -12px -12px 0 0;
  border-radius: 50%; background: radial-gradient(#fff6d6 0 18%, var(--map) 36%, color-mix(in srgb, var(--map) 30%, transparent) 52%, transparent 70%);
}
/* Its glow, always on (dimmed by sky.css while a planet passes before it). */
.sky-sun::before {
  content: ""; position: absolute; left: 50%; top: 50%; width: 56px; height: 56px; margin: -28px; border-radius: 50%; z-index: -1;
  background: radial-gradient(#fff6d6, var(--map) 30%, transparent 68%); opacity: .9;
}
.orb-ring { fill: none; stroke: var(--orbit); stroke-opacity: .85; }
.orb-p {
  position: absolute; left: var(--x); top: var(--y); width: 0; height: 0;
  transform: rotate(var(--s)) translateX(var(--r)); animation: orb-turn var(--p) linear infinite var(--bg-clock, 0s);
}
/* The bodies: each carried round with its x axis pointing away from the
   sun, so their lit side (the left, in their own frame) always faces it;
   the night side fades into the page. */
.orb-p::before {
  content: ""; position: absolute; width: var(--d); height: var(--d); margin: calc(var(--d) / -2) 0 0 calc(var(--d) / -2); border-radius: 50%; opacity: .42;
  --shade: radial-gradient(circle at 28% 50%, color-mix(in srgb, #fff 35%, transparent), transparent 38%, color-mix(in srgb, var(--bg) 75%, transparent) 78%);
  background: var(--shade), var(--c);
}
.orb-giant::before {
  background: var(--shade), repeating-linear-gradient(10deg, var(--c) 0 14%, color-mix(in srgb, var(--c) 70%, #fff) 14% 22%, color-mix(in srgb, var(--c) 75%, #000) 22% 30%);
}
.orb-ocean::before { background: var(--shade), radial-gradient(circle at 60% 35%, #6f9a5a 0 14%, transparent 15%), radial-gradient(circle at 40% 72%, #6f9a5a 0 10%, transparent 11%), var(--c); }
.orb-veil::before { background: var(--shade), repeating-linear-gradient(80deg, var(--c) 0 20%, color-mix(in srgb, var(--c) 80%, #fff) 20% 35%); }
.orb-ice::before { box-shadow: 0 0 calc(var(--d) / 2) color-mix(in srgb, var(--c) 35%, transparent); }
.orb-rock::before { background: var(--shade), radial-gradient(circle at 62% 30%, color-mix(in srgb, var(--c) 70%, #000) 0 12%, transparent 13%), radial-gradient(circle at 45% 70%, color-mix(in srgb, var(--c) 70%, #000) 0 8%, transparent 9%), var(--c); }
.orb-ringed::after {
  content: ""; position: absolute; width: calc(var(--d) * 2.3); height: calc(var(--d) * .55); margin: calc(var(--d) * -.275) 0 0 calc(var(--d) * -1.15);
  border: 2px solid color-mix(in srgb, var(--c) 70%, transparent); border-radius: 50%; transform: rotate(-20deg); opacity: .5;
}
html.sky-aim, html.sky-aim body { cursor: crosshair; }
/* A moon, going round its planet. */
.orb-moon { position: absolute; left: 0; top: 0; width: 0; height: 0; animation: orb-moon var(--m) linear infinite; }
.orb-moon::before { content: ""; position: absolute; left: calc(var(--d) / 2 + 6px); width: 3px; height: 3px; margin: -1.5px; border-radius: 50%; background: var(--muted); opacity: .4; }
@keyframes orb-moon { to { transform: rotate(-360deg); } }
@keyframes orb-turn { from { transform: rotate(var(--s)) translateX(var(--r)); } to { transform: rotate(calc(var(--s) - 360deg)) translateX(var(--r)); } }
@keyframes bg-rise { from { transform: translateY(400px); } to { transform: translateY(0); } }
@keyframes bg-rise-far { from { transform: translateY(1800px); } to { transform: translateY(0); } }
/* Narrow screens: the readouts would sit on the text. */
@media (max-width: 40rem) { html::before { display: none; } }
/* Less motion asked: everything still, the readouts too. */
@media (prefers-reduced-motion: reduce) {
  .orb-p, .orb-moon, body::before { animation: none; }
  html::before { mask-image: url("bg-readouts-still.svg?v=d5e7f9d1"); -webkit-mask-image: url("bg-readouts-still.svg?v=d5e7f9d1"); }
}
/* Events in the sky (sky.css): each at --x, --y, turned by --a; parts
   animated with transforms and opacity only. */
.ev { position: absolute; left: var(--x); top: var(--y); width: 0; height: 0; transform: rotate(var(--a, 0deg)); }
.ev div { position: absolute; }
.ev-ship { width: 9px; height: 5px; margin: -2.5px 0 0 -4.5px; background: var(--muted); clip-path: polygon(0 0, 100% 50%, 0 100%, 28% 50%); }
.ev-flash { width: 32px; height: 32px; margin: -16px 0 0 -16px; border-radius: 50%; background: radial-gradient(var(--hud), transparent 68%); opacity: 0; }
.ev-bit { width: 2px; height: 2px; background: var(--hud); opacity: 0; }
@keyframes ev-blink { 50% { opacity: .2; } }
/* Hyperspace jump: drifting, its drive charging behind it, then stretched
   out and gone in a blue flash, a flat ring where it was and a trail of
   ionized gas fading along its way. */
.ev-jglow { left: -8px; width: 22px; height: 22px; margin: -11px; border-radius: 50%; opacity: 0;
  background: radial-gradient(closest-side, #fff, color-mix(in srgb, var(--accent) 80%, transparent) 40%, transparent); animation: ev-jglow calc(3.2s * var(--slow, 1)) forwards; }
.ev-jtrail { left: 0; width: 600px; height: 1.5px; margin-top: -.75px; transform-origin: 0 50%; opacity: 0;
  background: linear-gradient(90deg, color-mix(in srgb, var(--accent) 20%, transparent), #fff 30%, color-mix(in srgb, var(--accent) 70%, transparent) 60%, transparent);
  box-shadow: 0 0 5px var(--accent); animation: ev-jtrail calc(3.2s * var(--slow, 1)) forwards; }
.ev-jring { width: 90px; height: 28px; margin: -14px 0 0 -45px; border-radius: 50%; border: 1px solid color-mix(in srgb, var(--accent) 85%, transparent);
  box-shadow: 0 0 8px color-mix(in srgb, var(--accent) 50%, transparent); opacity: 0; animation: ev-jring calc(3.2s * var(--slow, 1)) ease-out forwards; }
@keyframes ev-jglow { 0%, 15% { opacity: 0; transform: scale(.3); } 55% { opacity: .9; transform: scale(1.2); } 58% { opacity: .6; } 61% { opacity: 1; transform: scale(1.5); } 64%, 100% { opacity: 0; transform: scale(.2); } }
@keyframes ev-jtrail { 0%, 62% { opacity: 0; transform: scaleX(0); } 66% { opacity: 1; transform: scaleX(1); } 100% { opacity: 0; transform: scaleX(1); } }
@keyframes ev-jring { 0%, 62% { opacity: 0; transform: scale(.1); } 64% { opacity: 1; } 100% { opacity: 0; transform: scale(1.8); } }
.ev-jump .ev-ship { opacity: 0; animation: ev-jump calc(3.2s * var(--slow, 1)) forwards; }
.ev-jump .ev-flash { background: radial-gradient(var(--accent), transparent 68%); animation: ev-jumpflash calc(3.2s * var(--slow, 1)) forwards; }
@keyframes ev-jump {
  0% { transform: translateX(-40px); opacity: 0; } 10% { opacity: 1; }
  62% { transform: translateX(0); opacity: 1; animation-timing-function: cubic-bezier(.6, 0, 1, 1); }
  72% { transform: translateX(260px) scaleX(9); opacity: .9; } 76%, 100% { transform: translateX(600px) scaleX(14); opacity: 0; }
}
@keyframes ev-jumpflash { 0%, 60% { opacity: 0; transform: scale(.2); } 64% { opacity: .9; transform: scale(1.4); } 82%, 100% { opacity: 0; transform: scale(2.6); } }
/* Supernova: a star flaring up white-hot, its spikes, a shell of gas
   thrown off, two shock waves. */
.ev-core { width: 6px; height: 6px; margin: -3px; border-radius: 50%; background: radial-gradient(#fff 40%, var(--hud)); box-shadow: 0 0 8px 2px var(--hud), 0 0 22px 6px color-mix(in srgb, var(--hud) 30%, transparent);
  opacity: 0; animation: ev-core calc(5s * var(--slow, 1)) forwards; }
.ev-spk { width: 130px; height: 130px; margin: -65px; opacity: 0;
  background: linear-gradient(90deg, transparent 49.2%, #fff6d6 50%, transparent 50.8%), linear-gradient(0deg, transparent 49.2%, #fff6d6 50%, transparent 50.8%),
    linear-gradient(45deg, transparent 49.6%, color-mix(in srgb, #fff6d6 50%, transparent) 50%, transparent 50.4%), linear-gradient(-45deg, transparent 49.6%, color-mix(in srgb, #fff6d6 50%, transparent) 50%, transparent 50.4%);
  -webkit-mask: radial-gradient(closest-side, #000, transparent); mask: radial-gradient(closest-side, #000, transparent); animation: ev-spk calc(5s * var(--slow, 1)) forwards; }
.ev-shell { width: 190px; height: 190px; margin: -95px; border-radius: 50%; opacity: 0;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--hud) 10%, transparent) 0 55%, color-mix(in srgb, var(--hud) 45%, transparent) 78%, color-mix(in srgb, var(--bad) 55%, transparent) 88%, color-mix(in srgb, var(--accent) 35%, transparent) 95%, transparent);
  animation: ev-shell calc(5.6s * var(--slow, 1)) cubic-bezier(.15, .6, .35, 1) .9s forwards; }
@keyframes ev-spk { 0%, 18% { opacity: 0; transform: scale(.2) rotate(0deg); } 26% { opacity: 1; transform: scale(1) rotate(4deg); } 100% { opacity: 0; transform: scale(1.3) rotate(18deg); } }
@keyframes ev-shell { from { opacity: 0; transform: scale(.05); } 10% { opacity: .9; } to { opacity: 0; transform: scale(1.1); } }
.ev-ring { width: 160px; height: 160px; margin: -80px 0 0 -80px; border-radius: 50%; border: 1px solid var(--hud); opacity: 0; animation: ev-ring calc(5s * var(--slow, 1)) ease-out .9s forwards; }
.ev-ring2 { border-style: dashed; animation-delay: calc(1.6s * var(--slow, 1)); }
@keyframes ev-core { 20% { opacity: 1; transform: scale(1); } 30% { opacity: 1; transform: scale(3); } to { opacity: 0; transform: scale(.5); } }
@keyframes ev-ring { from { opacity: .8; transform: scale(0); } to { opacity: 0; transform: scale(1); } }
/* Graphs (jump routes, traceroutes, pings): plotted first, the line drawn
   from node to node and each node showing as it is reached, then the route
   flowing and a ship or a packet hopping along it. */
.ev-graph { position: absolute; inset: 0; width: 100%; height: 100%; transform: none; overflow: visible; --c: var(--map); animation: ev-graphfade var(--dur) forwards; }
.ev-net { --c: var(--accent); }
/* FTL: a green route between beacons. */
.ev-ftl { --c: var(--ok); }
.ev-decoy { fill: var(--muted); fill-opacity: .6; }
.ev-plot { fill: none; stroke: var(--c); stroke-width: 1.2; stroke-dasharray: 1; stroke-dashoffset: 1; animation: ev-plot var(--plot) linear forwards, ev-out .6s var(--plot) forwards; }
.ev-path { fill: none; stroke: var(--c); stroke-width: 1; stroke-dasharray: 5 7; opacity: 0; animation: ev-flow 1.6s linear infinite, ev-in .6s var(--plot) forwards; }
.ev-at { opacity: 0; animation: ev-in .4s ease-out forwards; }
.ev-at text { animation: ev-label .6s ease-out forwards; animation-delay: inherit; }
.ev-node { fill: var(--c); }
.ev-orb { fill: none; stroke: var(--c); stroke-opacity: .5; }
.ev-arrive { fill: none; stroke: var(--c); opacity: 0; transform-box: fill-box; transform-origin: center; animation: ev-arrive calc(1.4s * var(--slow, 1)) ease-out forwards; }
.ev-name, .ev-dist { fill: var(--c); font: 10px ui-monospace, "SF Mono", Menlo, monospace; letter-spacing: .08em; }
.ev-dist { fill-opacity: .6; }
.ev-hop { fill: var(--hud); opacity: 0; }
/* The jumps: the way lit from node to node as it is travelled. */
.ev-done { fill: none; stroke: var(--c); stroke-width: 2; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; filter: drop-shadow(0 0 3px var(--c)); }
@keyframes ev-graphfade { 0% { opacity: .8; } 90% { opacity: .8; } 100% { opacity: 0; } }
@keyframes ev-plot { to { stroke-dashoffset: 0; } }
@keyframes ev-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes ev-out { to { opacity: 0; } }
@keyframes ev-label { from { opacity: 0; transform: translateX(-6px); } to { opacity: 1; transform: none; } }
@keyframes ev-flow { to { stroke-dashoffset: -24; } }
@keyframes ev-arrive { from { opacity: .9; transform: scale(1); } to { opacity: 0; transform: scale(3); } }
/* The readouts' log: a line typed above them, blinking, then gone. */
.sky-log {
  position: absolute; left: 24px; bottom: 116px; width: calc((var(--n) + 2) * (1ch + .09em) + .2ch); overflow: hidden; white-space: nowrap;
  font: 11px ui-monospace, "SF Mono", Menlo, monospace; letter-spacing: .09em; color: var(--hud); opacity: .8;
  animation: ev-type .7s steps(var(--n)) both, ev-logout 4.8s step-end forwards;
}
.sky-log::before { content: "› "; }
@keyframes ev-type { from { width: 0; } }
@keyframes ev-logout { 0% { opacity: .9; } 8%, 16% { opacity: .35; } 12%, 20% { opacity: .9; } 85% { opacity: .8; } 100% { opacity: 0; } }
@media (max-width: 40rem) { .sky-log { display: none; } }
/* Wing: three ships in V crossing together. */
.ev-wing { opacity: 0; filter: drop-shadow(-4px 0 2px var(--accent)) drop-shadow(-9px 0 4px color-mix(in srgb, var(--accent) 40%, transparent)); animation: ev-wing calc(9s * var(--slow, 1)) linear forwards; }
.ev-wing .ev-ship { transform: translate(var(--ox), var(--oy)); }
/* In from off the left edge, out past the right one: across the whole screen. */
@keyframes ev-wing { from { transform: translateX(-40px); opacity: 0; } 3%, 99% { opacity: 1; } to { transform: translateX(calc(130vw + 400px)); opacity: 0; } }
/* Station: a Coriolis turning, a ship docking. */
.ev-coriolis { position: absolute; left: -32px; top: -32px; width: 64px; height: 64px; overflow: visible; fill: none; stroke: var(--muted); stroke-width: 1.2; opacity: 0; animation: ev-station calc(10s * var(--slow, 1)) ease-in-out forwards; }
.ev-slot { fill: var(--hud); stroke: none; animation: ev-blink 1.2s steps(1) infinite; }
.ev-station .ev-coriolis { filter: drop-shadow(0 0 3px color-mix(in srgb, var(--accent) 45%, transparent)); }
.ev-station .ev-ship { opacity: 0; animation: ev-dock calc(10s * var(--slow, 1)) forwards; }
@keyframes ev-station { from { opacity: 0; transform: scale(.7) rotate(0); } 15%, 85% { opacity: .9; } to { opacity: 0; transform: scale(1.05) rotate(80deg); } }
@keyframes ev-dock { 0%, 30% { opacity: 0; transform: translateX(-160px); } 36% { opacity: 1; transform: translateX(-140px); } 76% { opacity: 1; transform: translateX(-6px) scale(.6); } 80%, 100% { opacity: 0; transform: translateX(0) scale(.3); } }
/* Interdiction: a ship caught up, pulled out of its jump. */
.ev-intd .ev-ship { opacity: 0; }
.ev-t { animation: ev-target calc(6s * var(--slow, 1)) forwards; }
.ev-p { animation: ev-pursue calc(6s * var(--slow, 1)) forwards; }
.ev-intd .ev-flash { background: radial-gradient(var(--accent), transparent 68%); animation: ev-intflash calc(6s * var(--slow, 1)) forwards; }
@keyframes ev-target {
  0% { opacity: 0; transform: translateX(-100px); } 8% { opacity: 1; } 55% { transform: translateX(200px); }
  58% { transform: translateX(206px) rotate(25deg); } 64% { transform: translateX(210px) rotate(-15deg); } 70% { transform: translateX(212px) rotate(5deg); }
  90% { opacity: 1; transform: translateX(214px) rotate(0); } 100% { opacity: 0; transform: translateX(214px); }
}
@keyframes ev-pursue { 0% { opacity: 0; transform: translateX(-170px); } 8% { opacity: 1; } 55% { transform: translateX(160px); } 70% { transform: translateX(190px); } 90% { opacity: 1; transform: translateX(196px); } 100% { opacity: 0; transform: translateX(196px); } }
@keyframes ev-intflash { 0%, 55% { opacity: 0; transform: translateX(206px) scale(.2); } 58% { opacity: 1; transform: translateX(206px) scale(1.4); } 75%, 100% { opacity: 0; transform: translateX(206px) scale(2.4); } }
/* Comet: a head and its tails, slowly across. */
.ev-cbody { opacity: 0; animation: ev-comet calc(18s * var(--slow, 1)) linear forwards; }
.ev-head { width: 8px; height: 8px; margin: -4px; border-radius: 50%; background: radial-gradient(#fff 30%, color-mix(in srgb, var(--accent) 60%, #fff) 55%, transparent 75%);
  box-shadow: 0 0 10px 4px color-mix(in srgb, var(--accent) 45%, transparent), 0 0 28px 10px color-mix(in srgb, var(--accent) 14%, transparent); }
.ev-ctail { right: 2px; top: -1px; width: 320px; height: 2px; border-radius: 2px; background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 55%, transparent) 70%, color-mix(in srgb, #fff 80%, var(--accent))); }
.ev-ctail::before, .ev-ctail::after { content: ""; position: absolute; right: 0; top: 0; width: 250px; height: 1px; transform-origin: 100% 50%;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 45%, transparent)); animation: ev-stream 1.7s ease-in-out infinite alternate; }
.ev-ctail::before { --t: 1.4deg; }
.ev-ctail::after { --t: -1.8deg; width: 200px; animation-duration: 2.3s; }
@keyframes ev-stream { from { transform: rotate(var(--t)); opacity: .4; } to { transform: rotate(calc(var(--t) * 2.2)); opacity: .9; } }
.ev-dust { right: 0; top: -2px; width: 210px; height: 22px; border-radius: 0 0 0 100%; transform: rotate(-5deg) skewX(-25deg); transform-origin: right top;
  background: radial-gradient(ellipse 100% 60% at 100% 0, color-mix(in srgb, #fff6d6 45%, transparent), color-mix(in srgb, var(--hud) 22%, transparent) 45%, transparent 75%); }
/* In from off the left edge, its tail behind it, out past the right one. */
@keyframes ev-comet { from { opacity: 0; transform: translateX(0); } 4%, 99% { opacity: .9; } to { opacity: 0; transform: translateX(calc(130vw + 400px)); } }
/* Black hole: an accretion disc turning, stars falling in. */
.ev-hole { animation: ev-holefade calc(8s * var(--slow, 1)) forwards; }
.ev-disk { transform: rotate(-8deg) scaleY(.26); }
.ev-acc { width: 150px; height: 150px; margin: -75px; border-radius: 50%; overflow: hidden;
  -webkit-mask: radial-gradient(closest-side, transparent 22%, #000 26% 58%, transparent 100%); mask: radial-gradient(closest-side, transparent 22%, #000 26% 58%, transparent 100%); }
.ev-acc::before { content: ""; position: absolute; inset: 0; border-radius: 50%; animation: ev-spin calc(2.4s * var(--slow, 1)) linear infinite;
  background: conic-gradient(#fff6d6, var(--hud) 12%, color-mix(in srgb, var(--bad) 75%, transparent) 30%, var(--hud) 46%, #fff6d6 58%, var(--hud) 72%, color-mix(in srgb, var(--bad) 70%, transparent) 86%, #fff6d6); }
.ev-acc::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, rgba(255, 255, 255, .45), transparent 55%, rgba(0, 0, 0, .35)); }
.ev-dback .ev-acc { clip-path: inset(0 0 50% 0); }
.ev-dfront .ev-acc { clip-path: inset(50% 0 0 0); }
.ev-lens { width: 70px; height: 70px; margin: -35px; border-radius: 50%; transform: rotate(-8deg);
  background: radial-gradient(closest-side, transparent 62%, color-mix(in srgb, #fff6d6 85%, transparent) 70%, var(--hud) 80%, color-mix(in srgb, var(--bad) 50%, transparent) 90%, transparent);
  -webkit-mask: linear-gradient(#000 40%, rgba(0, 0, 0, .3) 62%); mask: linear-gradient(#000 40%, rgba(0, 0, 0, .3) 62%); }
.ev-eh { width: 26px; height: 26px; margin: -13px; border-radius: 50%; background: #030406; box-shadow: 0 0 0 1px color-mix(in srgb, #fff6d6 90%, transparent), 0 0 7px 2px color-mix(in srgb, var(--hud) 70%, transparent); }
.ev-fall { width: 2px; height: 2px; margin: -1px; border-radius: 50%; background: var(--fg); opacity: 0; animation: ev-spiral calc(5.5s * var(--slow, 1)) ease-in var(--t) forwards; }
@keyframes ev-holefade { from { opacity: 0; } 10%, 85% { opacity: 1; } to { opacity: 0; } }
@keyframes ev-spin { to { transform: rotate(360deg); } }
@keyframes ev-spiral { from { opacity: 0; transform: rotate(var(--s)) translateX(var(--r)); } 15% { opacity: .9; } 90% { opacity: .9; } to { opacity: 0; transform: rotate(calc(var(--s) + 900deg)) translateX(0); } }
/* Nebula: a veil of gas, glowing a while. */
.ev-neb {
  width: 70vmin; height: 46vmin; margin: -23vmin 0 0 -35vmin; border-radius: 50%; opacity: 0; animation: ev-neb calc(14s * var(--slow, 1)) ease-in-out forwards;
  background: radial-gradient(ellipse at 38% 50%, color-mix(in srgb, var(--accent) 55%, transparent), transparent 58%),
    radial-gradient(ellipse at 64% 42%, color-mix(in srgb, #a371f7 50%, transparent), transparent 55%),
    radial-gradient(ellipse at 52% 66%, color-mix(in srgb, var(--hud) 40%, transparent), transparent 60%);
}
@keyframes ev-neb { from { opacity: 0; transform: scale(.9) rotate(-4deg); } 40%, 60% { opacity: .28; } 60% { transform: scale(1.04) rotate(3deg); } to { opacity: 0; transform: scale(1.1) rotate(6deg); } }
.ev-neb::before, .ev-neb::after { content: ""; position: absolute; inset: 0; border-radius: 50%; }
.ev-neb::before { background: radial-gradient(ellipse 30% 22% at 30% 62%, color-mix(in srgb, var(--bad) 60%, transparent), transparent), radial-gradient(ellipse 26% 30% at 72% 32%, color-mix(in srgb, var(--ok) 35%, transparent), transparent),
    radial-gradient(ellipse 50% 12% at 50% 50%, color-mix(in srgb, #fff 18%, transparent), transparent);
  -webkit-mask: radial-gradient(ellipse 34% 22% at 40% 46%, #000, transparent), radial-gradient(ellipse 24% 34% at 63% 55%, #000, transparent), radial-gradient(ellipse 20% 14% at 30% 66%, #000, transparent), radial-gradient(ellipse 18% 26% at 74% 30%, #000, transparent);
  mask: radial-gradient(ellipse 34% 22% at 40% 46%, #000, transparent), radial-gradient(ellipse 24% 34% at 63% 55%, #000, transparent), radial-gradient(ellipse 20% 14% at 30% 66%, #000, transparent), radial-gradient(ellipse 18% 26% at 74% 30%, #000, transparent);
  animation: ev-nebd 14s ease-in-out both; }
.ev-neb::after { background: radial-gradient(2px 2px at 36% 46%, #fff, transparent), radial-gradient(1.5px 1.5px at 58% 58%, #fff, transparent), radial-gradient(2px 2px at 64% 38%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 44% 66%, #fff, transparent), radial-gradient(1.5px 1.5px at 28% 54%, #fff, transparent); animation: ev-blink 1.7s steps(2) infinite; }
@keyframes ev-nebd { from { transform: rotate(8deg) scale(.95); } to { transform: rotate(-10deg) scale(1.08); } }
/* Eclipse, on the sun (.ev-on, put on .sky-sun): a planet passes before
   it, its night side towards us, and the sun's glow dims (sky.css). */
.ev-on { position: absolute; left: 50%; top: 50%; width: 0; height: 0; transform: rotate(var(--a)); }
.ev-on div { position: absolute; }
.ev-planet {
  width: var(--d); height: var(--d); margin: calc(var(--d) / -2); border-radius: 50%; opacity: 0; animation: ev-transit calc(8s * var(--slow, 1)) linear forwards;
  background: radial-gradient(circle, color-mix(in srgb, var(--c) 18%, var(--bg)) 62%, color-mix(in srgb, var(--c) 60%, var(--bg)));
}
@keyframes ev-dim { 0%, 42% { opacity: .9; } 50% { opacity: .3; } 58%, 100% { opacity: .9; } }
@keyframes ev-transit { from { opacity: 0; transform: translateX(-70px); } 15%, 85% { opacity: 1; } to { opacity: 0; transform: translateX(70px); } }
/* Capital ship, on a planet of the orbits (.ev-kill, carried round by it):
   out of hyperspace some way off (a streak drawn back into it, a flash),
   coming in on its main engine, braking hard on its retro thrusters to hold
   92 px from the planet; charging, a
   beam, the planet blown up (a flash, a flat shock wave, a cloud, its
   pieces), the shock rocking the ship on its shield; then turning, its main
   engine lit, and away into hyperspace (a streak, a flash). All on one 10 s
   timeline; the planet is gone at 47 %. */
.ev-kill { position: absolute; left: 0; top: 0; width: 0; height: 0; transform: rotate(var(--a)); }
.ev-kill div { position: absolute; }
.ev-kbody { left: 0; top: 0; width: 0; height: 0; opacity: 0; animation: ev-kship calc(10s * var(--slow, 1)) forwards; }
.ev-kill .ev-khull { position: absolute; left: -46px; top: -22px; right: auto; bottom: auto; overflow: visible; filter: drop-shadow(0 0 3px color-mix(in srgb, var(--bg) 60%, transparent)); }
.ks-dark { fill: color-mix(in srgb, var(--fg) 22%, var(--bg)); }
.ks-mid { fill: color-mix(in srgb, var(--fg) 38%, var(--bg)); }
.ks-hull { fill: color-mix(in srgb, var(--fg) 50%, var(--bg)); }
.ks-lit { fill: color-mix(in srgb, var(--fg) 70%, var(--bg)); }
.ks-line { fill: none; stroke: color-mix(in srgb, var(--bg) 55%, transparent); stroke-width: .7; }
.ks-eng { fill: var(--accent); filter: drop-shadow(0 0 2px var(--accent)); animation: ev-kmain calc(10s * var(--slow, 1)) forwards; }
.ks-light { fill: var(--hud); animation: ev-blink 1.6s steps(1) infinite; }
.ev-kengine { left: 44px; width: 18px; height: 40px; margin: -20px 0 0 0; border-radius: 50%; background: radial-gradient(color-mix(in srgb, var(--accent) 70%, transparent), transparent 70%); opacity: 0; animation: ev-kmain calc(10s * var(--slow, 1)) forwards; }
/* Retro thrusters: their jets forward, towards the planet, pushing the ship
   back: hard while it brakes, then in short bursts to hold it there. */
.ev-kretro {
  left: -38px; top: -6px; width: 16px; height: 3px; margin-top: -1.5px; border-radius: 2px; transform-origin: right;
  background: linear-gradient(270deg, var(--fg), var(--accent) 40%, transparent); opacity: 0; animation: ev-kretro calc(10s * var(--slow, 1)) forwards;
}
.ev-kretro2 { top: 6px; animation-delay: calc(.15s * var(--slow, 1)); }
@keyframes ev-kmain { 0%, 9% { opacity: .2; } 11%, 19% { opacity: 1; transform: scale(1.3); } 22%, 73% { opacity: .2; transform: scale(1); } 76% { opacity: 1; transform: scale(1); } 84% { opacity: 1; transform: scale(1.6); } 100% { opacity: 1; transform: scale(1.6); } }
/* Side thrusters, for the turn (62 to 74 %, clockwise): a jet down at the
   nose and up at the tail to start it, the other two to stop it. The planet
   going round towards the ship's top side, they also keep up with it. */
.ev-krcs { width: 2.5px; height: 10px; margin-left: -1.25px; border-radius: 2px; opacity: 0; }
.ev-krcs-nd, .ev-krcs-td { transform-origin: top; background: linear-gradient(var(--fg), var(--accent) 40%, transparent); }
.ev-krcs-nu, .ev-krcs-tu { transform-origin: bottom; background: linear-gradient(0deg, var(--fg), var(--accent) 40%, transparent); }
.ev-krcs-nd { left: -28px; top: 4px; }
.ev-krcs-nu { left: -28px; top: -14px; }
.ev-krcs-tu { left: 36px; top: -29px; }
.ev-krcs-td { left: 36px; top: 19px; }
.ev-krcs-tu { animation: ev-krcs-go calc(10s * var(--slow, 1)) forwards; }
.ev-krcs-nu { animation: ev-krcs-stop calc(10s * var(--slow, 1)) forwards; }
.ev-krcs-nd { animation: ev-krcs-nd calc(10s * var(--slow, 1)) forwards; }
.ev-krcs-td { animation: ev-krcs-td calc(10s * var(--slow, 1)) forwards; }
@keyframes ev-krcs-go { 0%, 61% { opacity: 0; transform: scaleY(.3); } 62.5%, 66% { opacity: 1; transform: scaleY(1); } 67.5%, 100% { opacity: 0; transform: scaleY(.3); } }
@keyframes ev-krcs-stop { 0%, 70% { opacity: 0; transform: scaleY(.3); } 71.5%, 73.5% { opacity: 1; transform: scaleY(1); } 75%, 100% { opacity: 0; transform: scaleY(.3); } }
/* While it holds: the two jets down, nose and tail together, in short
   bursts, push it sideways to keep up with the planet going round. */
@keyframes ev-krcs-nd {
  0%, 28.5% { opacity: 0; transform: scaleY(.3); } 29.5%, 31% { opacity: .8; transform: scaleY(.7); } 32% { opacity: 0; transform: scaleY(.3); }
  36.5% { opacity: 0; } 37.5%, 38.5% { opacity: .8; transform: scaleY(.6); } 39.5% { opacity: 0; transform: scaleY(.3); }
  54.5% { opacity: 0; } 55.5%, 57% { opacity: .8; transform: scaleY(.7); } 58% { opacity: 0; transform: scaleY(.3); }
  61% { opacity: 0; transform: scaleY(.3); } 62.5%, 66% { opacity: 1; transform: scaleY(1); } 67.5%, 100% { opacity: 0; transform: scaleY(.3); }
}
@keyframes ev-krcs-td {
  0%, 28.5% { opacity: 0; transform: scaleY(.3); } 29.5%, 31% { opacity: .8; transform: scaleY(.7); } 32% { opacity: 0; transform: scaleY(.3); }
  36.5% { opacity: 0; } 37.5%, 38.5% { opacity: .8; transform: scaleY(.6); } 39.5% { opacity: 0; transform: scaleY(.3); }
  54.5% { opacity: 0; } 55.5%, 57% { opacity: .8; transform: scaleY(.7); } 58% { opacity: 0; transform: scaleY(.3); }
  70% { opacity: 0; transform: scaleY(.3); } 71.5%, 73.5% { opacity: 1; transform: scaleY(1); } 75%, 100% { opacity: 0; transform: scaleY(.3); }
}
@keyframes ev-kretro {
  0%, 4.5% { opacity: 0; transform: scaleX(.3); } 5.5%, 8% { opacity: 1; transform: scaleX(1.4); } 9.5%, 21% { opacity: 0; transform: scaleX(.3); }
  22.5%, 27% { opacity: 1; transform: scaleX(1.6); } 29% { opacity: .2; transform: scaleX(.4); } 30% { opacity: .7; transform: scaleX(.7); } 31.5% { opacity: 0; } 50% { opacity: 0; transform: scaleX(.4); } 52% { opacity: 1; transform: scaleX(1.2); }
  56% { opacity: .3; transform: scaleX(.5); } 58%, 100% { opacity: 0; transform: scaleX(.3); }
}
.ev-kcharge { left: -46px; width: 26px; height: 26px; margin: -13px; border-radius: 50%; background: radial-gradient(#f4fff0, #7dff6a 32%, transparent 70%); opacity: 0; animation: ev-kcharge calc(10s * var(--slow, 1)) forwards; }
.ev-kbeam {
  left: 0; width: 46px; height: 3px; margin-top: -1.5px; border-radius: 2px; transform-origin: right;
  background: linear-gradient(90deg, #f4fff0, #7dff6a); box-shadow: 0 0 6px #7dff6a; opacity: 0; animation: ev-kbeam calc(10s * var(--slow, 1)) forwards;
}
.ev-kflash { width: 70px; height: 70px; margin: -35px; border-radius: 50%; background: radial-gradient(#fff, var(--map) 30%, var(--hud) 50%, transparent 70%); opacity: 0; animation: ev-kflash calc(10s * var(--slow, 1)) forwards; }
.ev-kwave { width: 420px; height: 64px; margin: -32px 0 0 -210px; border-radius: 50%; border: 2px solid var(--hud); box-shadow: 0 0 10px var(--hud); opacity: 0; transform: rotate(-30deg) scale(0); animation: ev-kwave calc(10s * var(--slow, 1)) ease-out forwards; }
.ev-kwave2 { width: 220px; height: 220px; margin: -110px; border-radius: 50%; border: 1px dashed var(--map); opacity: 0; animation: ev-kwave2 calc(10s * var(--slow, 1)) ease-out forwards; }
.ev-kcloud { width: 140px; height: 140px; margin: -70px; border-radius: 50%; background: radial-gradient(color-mix(in srgb, var(--c) 60%, transparent), color-mix(in srgb, var(--hud) 25%, transparent) 45%, transparent 70%); opacity: 0; animation: ev-kcloud calc(10s * var(--slow, 1)) ease-out forwards; }
.ev-kill .ev-bit { width: 3px; height: 3px; animation: ev-kbits calc(10s * var(--slow, 1)) ease-out forwards; }
.ev-kill .ev-kbit { width: 4px; height: 3px; background: var(--c); }
@keyframes ev-kship {
  0%, 4.4% { opacity: 0; transform: translateX(490px) rotate(0deg) scaleX(3); }
  4.5% { opacity: 1; transform: translateX(420px) rotate(0deg) scaleX(1.7); animation-timing-function: cubic-bezier(.1, .8, .3, 1); }
  9% { transform: translateX(385px) rotate(0deg) scaleX(1); animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
  27% { transform: translateX(88px) rotate(0deg) scaleX(1); animation-timing-function: ease-in-out; }
  30%, 48% { transform: translateX(92px) rotate(0deg) scaleX(1); }
  48.6% { transform: translateX(100px) rotate(-4deg) scaleX(1); } 50.5% { transform: translateX(95px) rotate(2deg) scaleX(1); }
  53%, 62% { transform: translateX(92px) rotate(0deg) scaleX(1); animation-timing-function: ease-in-out; }
  74% { transform: translateX(96px) rotate(180deg) scaleX(1); animation-timing-function: cubic-bezier(.55, 0, .9, .5); }
  84% { opacity: 1; transform: translateX(240px) rotate(180deg) scaleX(1); animation-timing-function: cubic-bezier(.7, 0, 1, 1); }
  85.5% { opacity: .9; transform: translateX(520px) rotate(180deg) scaleX(6); }
  86.5%, 100% { opacity: 0; transform: translateX(900px) rotate(180deg) scaleX(9); }
}
/* In and out of hyperspace: a streak drawn back into the ship as it comes
   out, one drawn out of it as it goes; a flash each time, a flat ring. */
.ev-kwarp {
  left: 420px; width: 560px; height: 2px; margin-top: -1px; border-radius: 2px; transform-origin: 0 50%; opacity: 0;
  background: linear-gradient(90deg, #fff, color-mix(in srgb, var(--accent) 85%, transparent) 6%, color-mix(in srgb, var(--accent) 25%, transparent) 55%, transparent);
  box-shadow: 0 0 6px var(--accent); animation: ev-kwarp calc(10s * var(--slow, 1)) forwards;
}
.ev-kwarp2 { left: 240px; animation-name: ev-kwarp2; }
.ev-kin, .ev-kout { left: 420px; width: 90px; height: 90px; margin: -45px; border-radius: 50%; opacity: 0;
  background: radial-gradient(closest-side, #fff, color-mix(in srgb, var(--accent) 75%, transparent) 32%, color-mix(in srgb, var(--accent) 20%, transparent) 62%, transparent);
  animation: ev-kin calc(10s * var(--slow, 1)) forwards; }
.ev-kin::after, .ev-kout::after { content: ""; position: absolute; inset: -40px -10px; border-radius: 50%; border: 1px solid color-mix(in srgb, var(--accent) 80%, transparent); transform: scaleY(.35); }
.ev-kout { left: 240px; animation-name: ev-kout; }
.ev-kshield {
  left: -60px; top: -30px; width: 120px; height: 60px; border-radius: 50%; opacity: 0;
  border: 1px solid color-mix(in srgb, var(--accent) 85%, transparent); box-shadow: 0 0 10px color-mix(in srgb, var(--accent) 60%, transparent), inset 0 0 14px color-mix(in srgb, var(--accent) 45%, transparent);
  animation: ev-kshield calc(10s * var(--slow, 1)) forwards;
}
@keyframes ev-kwarp { 0% { opacity: 0; transform: scaleX(1); } 1% { opacity: 1; } 4.5% { opacity: 1; transform: scaleX(.02); } 5%, 100% { opacity: 0; transform: scaleX(0); } }
@keyframes ev-kwarp2 { 0%, 84.4% { opacity: 0; transform: scaleX(0); } 84.5% { opacity: 1; transform: scaleX(.05); } 86.5% { opacity: .9; transform: scaleX(1); } 92%, 100% { opacity: 0; transform: scaleX(1); } }
@keyframes ev-kin { 0%, 4.2% { opacity: 0; transform: scale(.2); } 4.8% { opacity: 1; transform: scale(1); } 10%, 100% { opacity: 0; transform: scale(1.9); } }
@keyframes ev-kout { 0%, 84.2% { opacity: 0; transform: scale(.2); } 84.8% { opacity: 1; transform: scale(1); } 90%, 100% { opacity: 0; transform: scale(1.9); } }
@keyframes ev-kshield { 0%, 48.2% { opacity: 0; } 48.8% { opacity: .9; } 50% { opacity: .35; } 51% { opacity: .75; } 55%, 100% { opacity: 0; } }
@keyframes ev-kcharge { 0%, 30% { opacity: 0; transform: scale(.2); } 43% { opacity: 1; transform: scale(1.2); } 45% { opacity: 1; transform: scale(.8); } 48%, 100% { opacity: 0; transform: scale(.3); } }
@keyframes ev-kbeam { 0%, 44% { opacity: 0; transform: scaleX(0); } 45.5% { opacity: 1; transform: scaleX(1); } 47.5% { opacity: 1; transform: scaleX(1); } 50%, 100% { opacity: 0; transform: scaleX(1); } }
@keyframes ev-kflash { 0%, 46.5% { opacity: 0; transform: scale(.2); } 48% { opacity: 1; transform: scale(1.6); } 52% { opacity: .9; transform: scale(2.2); } 64%, 100% { opacity: 0; transform: scale(3); } }
@keyframes ev-kwave { 0%, 47% { opacity: 0; transform: rotate(-30deg) scale(0); } 48% { opacity: .95; } 85%, 100% { opacity: 0; transform: rotate(-30deg) scale(1); } }
@keyframes ev-kwave2 { 0%, 48% { opacity: 0; transform: scale(0); } 50% { opacity: .7; } 78%, 100% { opacity: 0; transform: scale(1); } }
@keyframes ev-kcloud { 0%, 47% { opacity: 0; transform: scale(.2); } 52% { opacity: .9; transform: scale(.8); } 100% { opacity: 0; transform: scale(1.5); } }
@keyframes ev-kbits { 0%, 47% { opacity: 0; transform: rotate(var(--b)); } 48% { opacity: 1; } 90%, 100% { opacity: 0; transform: rotate(var(--b)) translateX(var(--r)) rotate(200deg); } }
/* ?sky=demo (the server sets data-sky): the sky alone, dark, the footer
   without its languages; sky.css plays the events one after the other.
   ?net=demo (data-net): the network background alone, dark. */
html[data-sky="demo"] body > :not(.nj-sky, .nj-hit, footer, .sky-music) { display: none; }
/* Its music (tools/genmusic.py): a player in a corner, faint until pointed at
   (browsers start sound only once the page has been touched). */
.sky-music { position: fixed; right: 16px; bottom: 12px; z-index: 3; width: 240px; height: 34px; opacity: .35; color-scheme: dark; transition: opacity .3s; }
.sky-music:hover, .sky-music:focus-within { opacity: .9; }
html[data-sky="demo"], html[data-sky="demo"] body { height: 100%; overflow: hidden; }
html[data-sky="demo"] footer { margin-top: auto; padding-bottom: .6rem; }
html[data-net="demo"] body > :not(.nt-bg, .nt-hit, footer) { visibility: hidden; }
:is(html[data-sky="demo"], html[data-net="demo"]) footer > small:first-of-type, :is(html[data-sky="demo"], html[data-net="demo"]) footer > small:first-of-type + br { display: none; }
@media (prefers-contrast: more), (forced-colors: active), print { html::before, body::before, .sky-sun { display: none; } }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  margin: 0; min-height: 100vh; display: flex; flex-direction: column;
  background: var(--bg); color: var(--fg);
  font: .95rem/1.45 system-ui, -apple-system, "Segoe UI", sans-serif;
}
a { color: var(--accent); }
header, footer { padding: .6rem var(--gutter); color: var(--muted); }
header { display: flex; justify-content: space-between; align-items: center; }
footer { text-align: center; font-size: .85rem; }
footer small { display: inline-block; margin-top: .1rem; }
footer .legal { font-size: .75rem; }
footer .legal a { color: var(--muted); text-decoration-color: var(--line); text-underline-offset: .15em; }
footer .legal a:hover, footer .legal a:focus-visible { color: var(--fg); text-decoration-color: currentColor; }
footer [aria-current] { color: var(--fg); }
.brand { font-weight: 700; font-size: 1.25rem; text-decoration: none; color: var(--fg); }
.brand span { color: var(--accent); }

main {
  flex: 1; width: min(40rem, 100%); margin: 0 auto;
  padding: .75rem var(--gutter) 1.25rem;
  display: flex; flex-direction: column; gap: 1.75rem;
}
h1 { text-align: center; font-size: .9rem; font-weight: 400; color: var(--muted); margin: 1.5rem 0 -1.25rem; }
h2, h3 { font-size: .8rem; font-weight: 500; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; margin: 0 0 .4rem; }
.prose ul { margin: 0; padding-left: 1.2rem; display: flex; flex-direction: column; gap: .6rem; line-height: 1.55; font-size: .95rem; }
.prose p { margin: 0; line-height: 1.55; font-size: .95rem; }
/* Privacy policy: a section per subject, the essentials first. */
.prose section h2 { margin-bottom: .6rem; }
.prose section h3 { margin: 1.1rem 0 .5rem; font-size: .9rem; font-weight: 600; color: var(--fg); text-transform: none; letter-spacing: 0; }
.privacy section { scroll-margin-top: 1rem; }
.optout { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; margin-top: .9rem; padding: .75rem 1rem; border: 1px solid var(--line); border-radius: .6rem; }
.tool .optout-state, .prose .optout-state { flex: 1 1 16rem; font-size: .9rem; }
.prose .updated { margin-top: 1rem; color: var(--muted); font-size: .85rem; }
.ai-icon { height: 1.4em; width: auto; vertical-align: -.4em; }
.ai-disc { fill: currentColor; }
.ai-glyph { fill: var(--bg); }

/* No boxes: sections are separated by space alone. */
.card { padding: 0; }
.card p { margin: 0; }

.ip {
  font: 700 clamp(1.25rem, 6.5vw, 2.25rem)/1.2 ui-monospace, "SF Mono", Menlo, monospace;
  word-break: break-all;
}
.hero { text-align: center; }
.hero-foot { display: flex; flex-direction: column; align-items: center; gap: .75rem; margin-top: .4rem; }
/* Both addresses, one under the other, IPv4 first: each with its family as a
   small spaced caption above it, a short hairline between them. An IPv6
   address is up to 39 characters against 15: it is set smaller and a little
   lighter, so it still fits one line on most screens. */
.ips { display: flex; flex-direction: column; align-items: center; margin: .4rem 0 1rem; }
.ip-row { position: relative; display: flex; flex-direction: column; align-items: center; gap: .3rem; max-width: 100%; }
.ip-row + .ip-row { margin-top: .85rem; padding-top: .85rem; }
.ip-row + .ip-row::before {
  content: ""; position: absolute; top: 0; left: 50%; width: 2.5rem; height: 1px;
  background: var(--border); opacity: .6; transform: translateX(-50%);
}
.ip-fam {
  font: 600 .68rem/1 system-ui, sans-serif; letter-spacing: .22em; text-transform: uppercase;
  color: var(--accent); padding-left: .22em; /* the spacing after the last letter, put back before the first */
}
.ip-row .ip { min-width: 0; letter-spacing: .01em; }
.ip-row.v6 .ip { font-size: clamp(.75rem, 3.1vw, 1.3rem); font-weight: 500; color: color-mix(in srgb, var(--fg) 88%, var(--muted)); }
.ips .ip-row .ip.none { font: 400 .95rem/1.2 system-ui, sans-serif; letter-spacing: 0; color: var(--muted); }
.copied { font-size: .75rem; line-height: 1.2; min-height: 1.2em; color: var(--muted); opacity: 0; transition: opacity .25s; margin-top: -.5rem; }
.copied.show { opacity: 1; }
/* An address: copied by a click on it; the address itself left as it is,
   a discreet "Copied!" under them. */
.ips .ip.copyable { cursor: copy; border-radius: .3rem; }
.ips .ip.copyable.none { cursor: default; }
.ips .ip.copyable:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The reverse name of the other family's address: its family beside it. */
.host-fam { font: 600 .68rem/1 system-ui, sans-serif; letter-spacing: .12em; color: var(--accent); white-space: nowrap; }
/* A change of address while the page is open. */
.ip-changed { margin: 0; color: var(--warn); font-size: .9rem; overflow-wrap: anywhere; }
.ip-changed:empty { display: none; }
button {
  font: inherit; padding: .3rem .8rem; border: 1px solid var(--border); border-radius: .4rem;
  background: transparent; color: var(--fg); cursor: pointer;
}
button:hover, button:focus-visible { border-color: var(--accent); color: var(--accent); }

.info { margin: 0; }
.info > div { padding: .3rem 0; }
.info > div + div { border-top: 1px solid var(--line); }
.info dt { color: var(--muted); font-size: .8rem; }
.info dd { margin: 0; overflow-wrap: anywhere; }
#search .info dd, #prop .info dd, #headers .info dd { white-space: pre-line; } /* one DNS record, one step per line */
/* TXT records: what each is for, then its value (muted when it is a token). */
#search .txt + .txt { margin-top: .4rem; }
#search .txt-key { display: block; }
#search .txt-val { color: var(--muted); }
#search .txt-more { margin-top: .4rem; padding-left: 0; }
.out dd.good { color: var(--ok); }
.out dd.bad { color: var(--bad); }
.out dd.open { font-weight: 600; }
.out dd.none { color: var(--muted); }
.headers dt { overflow-wrap: anywhere; }
.nowrap { white-space: nowrap; }
/* 404 page: a real title, then the way back. */
main.notfound h1 { font-size: 1.5rem; font-weight: 650; color: var(--fg); margin: 1rem 0 -.5rem; }
.notfound-links { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .5rem 1.25rem; }
.info .mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: .92em; }

pre { background: var(--card); padding: .55rem .8rem; border-radius: .4rem; overflow-x: auto; margin: .5rem 0 0; }

/* Terminal commands: an icon, a label, the command. */
.cli { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .9rem; }
.cli li { display: flex; gap: .75rem; align-items: flex-start; }
.cli svg { flex: none; width: 1.25rem; height: 1.25rem; margin-top: .1rem; color: var(--muted); }
.cli div { flex: 1; min-width: 0; }
.cli span { font-size: .8rem; color: var(--muted); }
.cli pre { margin: .2rem 0 0; }
/* One command per line, each with its copy button. */
.cmd-line { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
.cmd-line + .cmd-line { margin-top: .15rem; }
button.copy-cmd { flex: none; display: inline-flex; padding: .2rem .3rem; min-height: 0; border-color: transparent; color: var(--muted); line-height: 0; }
button.copy-cmd:hover, button.copy-cmd:focus-visible { border-color: var(--accent); color: var(--accent); }
button.copy-cmd.done { color: var(--ok); }
/* Help: a manual page, as man(1) sets it, with links and copy buttons. */
main.man { width: min(48rem, 100%); gap: 1.4rem; font: .875rem/1.6 ui-monospace, "SF Mono", Menlo, monospace; }
.man-head, .man-foot { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; color: var(--muted); }
.man-head { margin-top: 1.5rem; }
main.man h1 { margin: 0; font-size: inherit; color: inherit; }
main.man h2 { margin: 0 0 .2rem; font: inherit; font-weight: 700; color: var(--fg); letter-spacing: 0; text-transform: uppercase; }
main.man section > :not(h2) { margin: 0 0 0 4ch; }
main.man p { margin: 0; }
main.man section > p + p, main.man dl + p { margin-top: .6rem; }
.man var { font-style: normal; text-decoration: underline; text-underline-offset: .2em; }
.man-syn code { display: block; font: inherit; padding-left: 4ch; text-indent: -4ch; }
.man-syn b { font-weight: 700; }
.man-opts dt { font-weight: 700; }
.man-opts dt + dd { margin: 0 0 .7rem 4ch; }
.man-opts dd:last-child { margin-bottom: 0; }
.man code.cmd { font: inherit; }
.man .cmd-line { display: inline-flex; justify-content: flex-start; gap: .4rem; }
.man button.copy-cmd { padding: .1rem .25rem; }
.man-tags { display: grid; grid-template-columns: 4ch minmax(0, 1fr); gap: .3rem 2ch; }
.man-tags dt { font-weight: 700; }
.man-tags dd { margin: 0; }
.man a { font-weight: 700; }
@media (max-width: 34rem) {
  main.man section > :not(h2) { margin-left: 2ch; }
  .man-opts dt + dd { margin-left: 2ch; }
  .man-head > :last-child { display: none; }
}

/* Phones: thumb-sized buttons. */
@media (max-width: 34rem) {
  button { min-height: 2.5rem; padding-inline: 1.1rem; }
}

/* Tablets and up: label/value side by side in the info card. */
@media (min-width: 34rem) {
  .info > div { display: grid; grid-template-columns: 9rem minmax(0, 1fr); gap: 0 1rem; align-items: baseline; }
  .info dt { font-size: .9rem; }
  .headers > div { grid-template-columns: 11rem minmax(0, 1fr); }
}

/* Large screens: a little more air and type, same narrow column. */
@media (min-width: 64rem) {
  body { font-size: 1rem; }
  header, footer { padding-block: 1rem; }
  main { width: min(40rem, 100%); padding-top: 2.5rem; gap: 2.25rem; }
  h1 { margin-bottom: -1.75rem; }
  .ip { font-size: 2.5rem; }
  .ip-row.v6 .ip { font-size: 1.3rem; }
}

/* Language switch: a pill apart from the menu; the Breton one stands out. */
.lang {
  display: inline-flex; align-items: center; gap: .45rem; text-decoration: none;
  color: var(--muted); border: 1px solid var(--border); border-radius: 99rem; padding: .2rem .8rem;
}
.lang:hover, .lang:focus-visible { color: var(--fg); border-color: var(--muted); }
.lang-br { color: var(--fg); font-weight: 600; border-color: var(--accent); }
.lang-br:hover, .lang-br:focus-visible { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.flag-br { display: block; border-radius: 2px; box-shadow: 0 0 0 1px var(--line); }

/* Menu: tabs under the header, aligned with the content column. */
.tabs {
  width: min(40rem, 100%); margin: 0 auto; padding: 0 var(--gutter);
  display: flex; justify-content: center; gap: 1.75rem; border-bottom: 1px solid var(--line);
}
.tabs a {
  padding: .45rem .1rem; margin-bottom: -1px; text-decoration: none; color: var(--muted);
  border-bottom: 2px solid transparent;
}
.tabs a:hover { color: var(--fg); }
.tabs a[aria-current="page"] { color: var(--fg); font-weight: 600; border-bottom-color: var(--accent); }

/* Tools page: your connection and the tests from our servers side by side
   when there is room, stacked otherwise, the calculations below. auto-fill
   (not auto-fit) keeps the layout stable while a streamed page is only half
   received. */
main.wide { width: min(62rem, 100%); }
/* Tools and browser pages: a real page title, not the home page's quiet line. */
main.wide > h1 { font-size: 1.5rem; font-weight: 650; color: var(--fg); margin: 1rem 0 -1rem; }
.groups { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 24rem), 1fr)); gap: 2.25rem 2rem; align-items: start; }
/* Calculations: a row of their own, the two tools side by side. */
.group.calc, .group.mail { grid-column: 1 / -1; }
.calc-tools { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 24rem), 1fr)); gap: 1.25rem; align-items: start; }
/* Without ping and traceroute, the connection tests have the row to
   themselves: side by side, like the others, rather than half a row. */
.groups:not(:has(> .probes)) > .conn { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 24rem), 1fr)); gap: 1.25rem; align-items: start; }
.groups:not(:has(> .probes)) > .conn > h2 { grid-column: 1 / -1; }
/* While a probe's result is streamed, the page is sent with the probes group
   last (it holds the output); it keeps its place all the same. */
.groups.live > .calc, .groups.live > .mail { order: 1; }
.group { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }
/* The lookup, above the two groups, over the whole width: as far from them as they are from each other. */
.group.find { margin-bottom: .5rem; }
.group > h2 {
  font-size: 1.1rem; font-weight: 650; color: var(--fg); text-transform: none; letter-spacing: 0;
  margin: 0; padding-bottom: .4rem; border-bottom: 1px solid var(--line);
}
[hidden] { display: none !important; }
/* Each tool in a card of its own, its name as its title: the name reads
   first, the description under it, the form last. */
.tool {
  min-width: 0; padding: 1rem 1.1rem; border: 1px solid var(--line); border-radius: .6rem;
  background: var(--card); scroll-margin-top: 1rem;
}
.tool:target { border-color: var(--accent); }
.tool > h2, .tool > h3 { font-size: 1.05rem; font-weight: 600; color: var(--fg); text-transform: none; letter-spacing: 0; margin: 0 0 .35rem; }
.tool > h2 { font-size: 1.15rem; }
.tool p { margin: 0 0 .75rem; color: var(--muted); font-size: .92rem; }
@media (max-width: 34rem) {
  .tool { padding: .85rem .8rem; }
}
.tool form { display: flex; flex-wrap: wrap; gap: .5rem; }
.tool input, .tool select {
  flex: 1 1 12rem; min-width: 0; font: inherit; padding: .35rem .6rem;
  color: var(--fg); background: var(--bg); border: 1px solid var(--border); border-radius: .4rem;
}
.tool select { flex: 0 0 auto; color-scheme: inherit; }
.tool textarea {
  flex: 1 1 100%; min-width: 0; font: inherit; font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: .85rem;
  padding: .35rem .6rem; color: var(--fg); background: var(--bg); border: 1px solid var(--border); border-radius: .4rem; resize: vertical;
}
/* Firefox dims placeholders to half: keep them readable (WCAG 1.4.3). */
.tool ::placeholder { color: var(--muted); opacity: 1; }
/* The button that runs a tool stands out from the secondary ones. */
.tool form > button[type="submit"], #dns-start, #webrtc-start { font-weight: 600; color: var(--accent); border-color: var(--accent); }
.tool form > button[type="submit"]:hover, .tool form > button[type="submit"]:focus-visible,
#dns-start:hover, #dns-start:focus-visible, #webrtc-start:hover, #webrtc-start:focus-visible { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.tool textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.tool .sub-title { margin: 1rem 0 .25rem; font-size: .95rem; font-weight: 600; }
.tool select option { background: var(--bg); color: var(--fg); }
.tool .out { margin-top: .75rem; }
.tool #webrtc-start { margin-top: .25rem; }
.tool input:focus-visible, .tool select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.tool pre { flex: 1 1 100%; margin: 0; background: var(--bg); font-size: .85rem; white-space: pre-wrap; overflow-wrap: anywhere; }
.tool .status { margin: .5rem 0 0; }
/* Leak verdict: colour is backed by an icon and bold text, never alone. */
.tool .status.verdict { padding: .6rem .8rem; border-left: 4px solid var(--verdict); border-radius: .3rem; font-weight: 600; color: var(--fg); background: color-mix(in srgb, var(--verdict) 14%, transparent); }
.tool .status.verdict::before { content: "\2713\00a0"; color: var(--verdict); font-weight: 700; }
.tool .status.verdict-ok { --verdict: var(--ok); }
.tool .status.verdict-leak { --verdict: var(--bad); }
.tool .status.verdict-leak::before { content: "\26A0\00a0"; }
.results { list-style: none; margin: .5rem 0 0; padding: 0; }
.results li { padding: .2rem 0; overflow-wrap: anywhere; }
.mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: .92em; }
/* Expandable resolver groups: our own arrow, before the line. */
.results summary { cursor: pointer; list-style: none; }
.results summary::-webkit-details-marker { display: none; }
.results summary::before {
  content: "\25B8"; display: inline-block; width: 1.1em; color: var(--muted);
  transition: transform .15s;
}
.results details[open] > summary::before { transform: rotate(90deg); }
.results li.plain { padding-left: 1.1em; }
.results .sub { margin: .2rem 0 .3rem 1.1em; color: var(--muted); }

/* Quiet "working" dots while the DNS test runs: text color, fade only */
.dots { display: inline-flex; gap: .18rem; margin-left: .3rem; vertical-align: middle; }
.dots i {
  width: .25rem; height: .25rem; border-radius: 50%; background: currentColor;
  opacity: .25; animation: dot-fade 1.4s ease-in-out infinite;
}
.dots i:nth-child(2) { animation-delay: .2s; }
.dots i:nth-child(3) { animation-delay: .4s; }
@keyframes dot-fade { 0%, 100% { opacity: .25; } 40% { opacity: 1; } }
/* Streamed result without JS: the "done" element ends the page, which hides the indicator. */
.done { display: none; }
.running:has(~ .done) { display: none; }
@media (prefers-reduced-motion: reduce) { .dots i { animation: none; opacity: .6; } }

/* Theme switch: a quiet icon button, muted until hovered. */
.actions { display: flex; align-items: center; gap: .5rem; }
.theme-btn {
  display: inline-flex; align-items: center; justify-content: center; padding: .3rem;
  border: 0; border-radius: 50%; background: transparent; color: var(--muted);
}
.theme-btn:hover, .theme-btn:focus-visible { color: var(--fg); background: transparent; border: 0; }
.theme-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.theme-btn svg { display: block; width: 1.1rem; height: 1.1rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* The theme: a switch, the moon while dark, the sun while light; the space
   background: a checkbox. Focus shows on the label of the control. */
.theme-btn .th-sun { display: none; }
:root:not([data-sky="demo"], [data-net="demo"]):is([data-theme="light"], :not([data-theme]):has(#th-light:checked)) .theme-btn .th-sun { display: block; }
:root:not([data-sky="demo"], [data-net="demo"]):is([data-theme="light"], :not([data-theme]):has(#th-light:checked)) .theme-btn .th-moon { display: none; }
:root:has(#th-light:focus-visible) .th-btn, :root:has(.bg-r:focus-visible) .bg-l { outline: 2px solid var(--accent); outline-offset: 1px; color: var(--fg); }
/* Background switch: the planet, struck through when the sky is off. */
/* The background: space, network or none, a radio each; one label shown,
   the one for the next choice, with the icon of the current one. */
.bg-l { display: none; }
:root:is([data-sky="demo"], [data-bg="space"], :not([data-bg]):has(#bg-space:checked)) .bg-to-net, :root:is([data-net="demo"], :not([data-sky="demo"]):is([data-bg="net"], :not([data-bg]):has(#bg-net:checked))) .bg-to-off, :root:not([data-sky="demo"], [data-net="demo"]):is([data-bg="off"], :not([data-bg]):has(#bg-off:checked)) .bg-to-space { display: inline-flex; }
:root:is([data-net="demo"], :not([data-sky="demo"]):is([data-bg="net"], [data-bg="off"], :not([data-bg]):has(#bg-net:checked, #bg-off:checked))) body::before, :root:not([data-sky="demo"], [data-net="demo"]):is([data-bg="off"], :not([data-bg]):has(#bg-off:checked))::before { display: none; }
:root:is([data-net="demo"], :not([data-sky="demo"]):is([data-bg="net"], :not([data-bg]):has(#bg-net:checked)))::before { mask-image: url("net-readouts.svg?v=1c2be8d6"); -webkit-mask-image: url("net-readouts.svg?v=1c2be8d6"); }

/* Phones only: info block on one compact label/value grid (rows share the
   label column via subgrid) instead of a label stacked above every value. */
@media (max-width: 34rem) {
  .info { display: grid; grid-template-columns: max-content minmax(0, 1fr); column-gap: .75rem; }
  .info > div { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; align-items: baseline; padding: .25rem 0; }
  .info dt { font-size: .8rem; line-height: 1.4; }
  .info dd { font-size: .9rem; line-height: 1.4; }
}

/* Secondary action: quiet until hovered. */
button.quiet { border-color: transparent; color: var(--muted); font-size: .85rem; }
button.quiet:hover, button.quiet:focus-visible { border-color: var(--accent); color: var(--accent); }

/* Accessibility: skip link, keyboard focus, reduced motion. */
.skip { position: absolute; left: .5rem; top: -4rem; padding: .4rem .8rem; background: var(--bg); color: var(--fg); border: 1px solid var(--accent); border-radius: .4rem; z-index: 10; }
.skip:focus { top: .5rem; }
h1:focus { outline: none; }
a:focus-visible, summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: .2rem; }
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; scroll-behavior: auto !important; }
}

.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
button:focus-visible, .lang:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
button[aria-disabled="true"] { opacity: .6; cursor: default; }
pre:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tabs a:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: .2rem; }

/* High contrast / forced colors: keep the borders the flag and controls rely on. */
@media (forced-colors: active) {
  .flag-br { outline: 1px solid CanvasText; }
  .tabs a[aria-current="page"] { border-bottom-color: Highlight; }
  .lang-br { border-color: Highlight; }
}
@media (prefers-contrast: more) {
  :root { --muted: var(--fg); --line: var(--border); }
}

/* Text content for readers and search engines: about blurb, FAQ, tools contents. */
.about p, .faq p { line-height: 1.55; font-size: .95rem; }
.about p, .faq p { color: var(--muted); }
.faq h3 { text-transform: none; letter-spacing: 0; font-size: .95rem; font-weight: 600; color: var(--fg); margin: 1rem 0 .25rem; }
/* Contents: a row of pills, one per tool. */
.toc ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: .45rem; font-size: .85rem; }
.toc a {
  display: inline-flex; align-items: center; min-height: 1.9rem; padding: .2rem .8rem;
  color: var(--muted); text-decoration: none; border: 1px solid var(--line); border-radius: 99rem;
}
.toc a:hover { color: var(--fg); border-color: var(--border); }
/* Tools contents: the pills under the name of their group, the groups side by
   side; on phones a single row that scrolls sideways rather than a wall of pills. */
.toc-groups { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr)); gap: .9rem 1.5rem; }
.toc-groups > div > span { display: block; margin-bottom: .4rem; color: var(--muted); font-size: .75rem; }
.toc-groups ul { justify-content: flex-start; }
@media (max-width: 34rem) {
  .toc-groups {
    display: flex; gap: 1.25rem; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
    margin-inline: calc(-1 * var(--gutter)); padding-inline: var(--gutter);
    mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent);
  }
  .toc-groups::-webkit-scrollbar { display: none; }
  .toc-groups > div { flex: none; }
  .toc-groups ul { flex-wrap: nowrap; }
  .toc-groups a { white-space: nowrap; }
}
/* A tool's longer description, folded under one line. */
.hint-more { margin: 0 0 .75rem; font-size: .92rem; }
.hint-more > summary { cursor: pointer; width: fit-content; color: var(--muted); }
.hint-more > summary:hover { color: var(--fg); }
.hint-more > p { margin: .5rem 0 0; }
.more > summary { cursor: pointer; list-style: none; text-align: center; color: var(--muted); font-size: .9rem; }
.more > summary::-webkit-details-marker { display: none; }
.more > summary::before { content: "\25B8"; display: inline-block; width: 1.1em; transition: transform .15s; }
.more[open] > summary::before { transform: rotate(90deg); }
.more > summary:hover { color: var(--fg); }
.more > section { margin-top: 1rem; }
.more .faq { padding-top: .5rem; }

/* Browser page: what sites see, then the fingerprint over the whole width. */
.group > .lead { margin: 0; color: var(--muted); }
pre.ua { margin: 0; background: var(--bg); font-size: .85rem; white-space: pre-wrap; overflow-wrap: anywhere; }
.fp-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); gap: 1rem 3rem; align-items: center; margin: .75rem 0 1rem; }
.tool .fp-id, .tool .fp-meter p { margin: 0; color: var(--fg); }
.fp-id > span:first-child, .fp-meter label { display: block; color: var(--muted); font-size: .8rem; }
.fp-id .mono { font: 700 clamp(1.1rem, 4.5vw, 1.6rem)/1.3 ui-monospace, "SF Mono", Menlo, monospace; }
.fp-meter meter { display: block; width: 100%; height: 1.1rem; margin: .25rem 0 .3rem; }
.fp-meter p span { color: var(--muted); }
.fp-table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.fp-table th, .fp-table td { text-align: left; vertical-align: top; padding: .4rem .75rem .4rem 0; border-top: 1px solid var(--line); }
.fp-table thead th { border-top: 0; color: var(--muted); font-size: .8rem; font-weight: 500; }
.fp-table tbody th { font-weight: 400; color: var(--muted); width: 11rem; }
.fp-val { overflow-wrap: anywhere; }
.fp-risk { width: 9.5rem; white-space: nowrap; color: var(--muted); font-size: .8rem; }
.fp-hash { width: 5.5rem; padding-right: 0; color: var(--muted); font-size: .8rem; }
.fp-bar { display: inline-block; width: 4rem; height: .45rem; margin-right: .45rem; border-radius: 99rem; background: var(--line); overflow: hidden; vertical-align: middle; }
.fp-bar i { display: block; height: 100%; background: var(--ok); }
.fp-bar[data-level="mid"] i { background: var(--warn); }
.fp-bar[data-level="high"] i { background: var(--bad); }
.fp-canvas { display: block; max-width: 100%; height: auto; background: #fff; border-radius: .3rem; }
.fp-canvas-note { display: block; margin-top: .3rem; color: var(--muted); font-size: .8rem; }
.tool .fp-note { margin: .75rem 0 0; font-size: .85rem; }
.fp-ids { display: flex; flex-direction: column; gap: .5rem; }
/* The elements of the cross-browser identifier, to compare one by one. */
.fp-cross-detail { margin-top: .75rem; }
.fp-cross-detail summary { cursor: pointer; width: fit-content; color: var(--accent); font-size: .9rem; }
.fp-cross-detail .fp-cross-table { margin-top: .6rem; }
.fp-stable .mono, .fp-cross .mono { font-size: clamp(.95rem, 3.5vw, 1.2rem); }
/* What each element is and how to give less of it away: its name opens a
   line under it. */
.fp-name { all: unset; cursor: pointer; color: var(--muted); text-decoration: underline dotted; text-underline-offset: .2em; }
.fp-name::before { content: "\25B8"; display: inline-block; width: 1em; font-size: .8em; text-decoration: none; transition: transform .15s; }
.fp-name[aria-expanded="true"]::before { transform: rotate(90deg); }
.fp-name:hover, .fp-name[aria-expanded="true"] { color: var(--fg); }
.fp-name:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: .2rem; }
.fp-table .fp-help-row td { border-top: 0; padding-top: 0; font-size: .85rem; color: var(--muted); }
.tool .fp-help-row p { margin: 0 0 .2rem; max-width: 48rem; }
.fp-table tr[hidden] { display: none; }
.fp-elements-title { margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--line); }
/* The fingerprint over visits, kept in this browser on request. */
.fp-memory { margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.tool .fp-memory .fp-mem-out { color: var(--fg); }
.fp-mem-out:empty { display: none; }
.fp-mem-actions { display: flex; flex-wrap: wrap; gap: .5rem; }
@media (max-width: 34rem) {
  .fp-table thead { display: none; }
  .fp-table tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .15rem .75rem; padding: .45rem 0; border-top: 1px solid var(--line); }
  .fp-table th, .fp-table td { width: auto; padding: 0; border: 0; }
  .fp-table .fp-val { grid-column: 1 / -1; }
  .fp-table .fp-help-row { border-top: 0; padding-top: 0; }
  .fp-table .fp-help-row td { grid-column: 1 / -1; }
  .fp-table .fp-hash { text-align: right; }
}
/* What a site can infer: one line per check, its state as an icon and colour. */
/* The checks, by subject: leaks, VPN hints, consistency, protections. */
.check-groups { display: flex; flex-direction: column; gap: 1.1rem; margin-top: .75rem; }
.check-group h3 { margin: 0 0 .4rem; }
.check-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 26rem), 1fr)); gap: .6rem 3rem; }
.check-list li { position: relative; padding: .1rem 0 .1rem 1.6rem; line-height: 1.45; }
.check-list li::before { position: absolute; left: 0; top: .1rem; width: 1.2rem; text-align: center; font-weight: 700; }
.check-list li[data-state="ok"]::before { content: "\2713"; color: var(--ok); }
.check-list li[data-state="warn"]::before { content: "\26A0"; color: var(--warn); }
.check-list li[data-state="info"]::before { content: "\2139"; color: var(--accent); }
.check-list li[data-state="pending"]::before { content: "\25CB"; color: var(--muted); font-weight: 400; }
.check-list li[data-state="pending"] strong { color: var(--muted); font-weight: 400; }
.check-list strong { font-weight: 600; }
.check-list span { color: var(--muted); }
/* A check reached from the summary stands out for a moment. */
.check-list li { scroll-margin-top: 1rem; }
.check-list li:target { background: color-mix(in srgb, var(--accent) 12%, transparent); border-radius: .3rem; }
/* In short, at the top of the browser page: the checks done while they run,
   then what to watch and the risk of the fingerprint. */
.verdict-card { padding: 1rem 1.1rem; border: 1px solid var(--line); border-radius: .6rem; background: var(--card); display: flex; flex-direction: column; gap: .6rem; }
.verdict-card h2 { margin: 0; font-size: 1.15rem; font-weight: 600; color: var(--fg); text-transform: none; letter-spacing: 0; }
.verdict-card p { margin: 0; }
#analysis-run { align-self: flex-start; font-weight: 600; color: var(--accent); border-color: var(--accent); padding: .45rem 1.2rem; }
#analysis-run:hover, #analysis-run:focus-visible { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.verdict-progress:focus { outline: none; }
.verdict-progress { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .75rem; color: var(--muted); font-size: .9rem; }
.verdict-progress progress { flex: 1 1 12rem; max-width: 22rem; height: .55rem; accent-color: var(--accent); }
.verdict-main { font-weight: 600; font-size: 1.05rem; }
.verdict-main[data-state="ok"] { color: var(--ok); }
.verdict-main[data-state="warn"] { color: var(--fg); }
.verdict-list { margin: -.2rem 0 0; padding-left: 1.2rem; display: flex; flex-direction: column; gap: .35rem; color: var(--muted); }
.verdict-list a { font-weight: 600; color: var(--fg); text-decoration-color: var(--warn); }
.verdict-list li::marker { color: var(--warn); }
/* The identification risk in its colour, with a gauge; the words say the level. */
.verdict-fp { --level: var(--ok); display: flex; flex-direction: column; gap: .45rem; padding: .6rem .8rem; border-left: 4px solid var(--level); border-radius: .3rem; background: color-mix(in srgb, var(--level) 13%, transparent); }
.verdict-fp[data-level="mid"] { --level: var(--warn); }
.verdict-fp[data-level="high"] { --level: var(--bad); }
.verdict-fp a { font-weight: 600; }
.vfp-head { font-weight: 500; }
.vfp-gauge { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .7rem; color: var(--muted); font-size: .85rem; }
.vfp-bar { flex: 0 1 14rem; min-width: 6rem; height: .55rem; border-radius: 99rem; background: var(--line); overflow: hidden; }
.vfp-bar i { display: block; height: 100%; background: var(--level); border-radius: 99rem; }
@media (forced-colors: active) {
  .vfp-bar { border: 1px solid CanvasText; }
  .vfp-bar i { background: CanvasText; }
}
.verdict-counts { color: var(--muted); font-size: .85rem; }
/* What to do: one line per advice, after what the checks found. */
.advice { border-top: 1px solid var(--line); padding-top: .6rem; }
.advice h3 { margin: 0 0 .35rem; }
.advice ul { margin: 0; padding-left: 1.2rem; display: flex; flex-direction: column; gap: .4rem; line-height: 1.5; }
.advice li::marker { color: var(--accent); }
/* The elements the CSS demonstration styles: in the page, never seen. */
.css-probes { position: absolute; left: -10000px; top: 0; width: 1px; height: 1px; overflow: hidden; }
.css-probes span { display: block; width: 1px; height: 1px; }
.verdict-card .report { margin: .2rem 0 0; padding-top: .7rem; border-top: 1px solid var(--line); }
/* The fingerprint table while it is worked out: element names, values to come. */
#fp-out.loading .fp-summary, #fp-out.loading .fp-note, #fp-out.loading .fp-memory { visibility: hidden; }
.fp-table tr.fp-wait td { color: var(--muted); }
/* The report of the page, to copy or download. */
.report { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.report p { flex: 1 1 100%; margin: 0; color: var(--muted); font-size: .85rem; }
.report .report-status:empty { display: none; }
/* Ad-blocker bait: out of sight, 1 px tall unless a blocker hides it. */
.bait { position: absolute; left: -10000px; top: 0; width: 1px; height: 1px; }
/* Browser page: a section still to fill offers to run the analysis from there. */
.status.idle { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; }

/* Home: the kind of network of the address, in a box. An information, not a
   judgement nor a link: neutral, the same whatever the network. */
.netkind { margin: .7rem 0 0; }
.netkind span { display: inline-block; padding: .2rem .8rem; border-radius: 99rem; font-size: .85rem; color: var(--muted); border: 1px solid var(--border); }

/* Search results: titled groups in two columns side by side when there is
   room, each a stack of its own (a tall group leaves no hole beside it); one
   column under the other on a narrow screen. A group still loading shows its
   title and the running dots. */
.res-groups { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr)); gap: 1.5rem 3rem; align-items: start; }
.res-col { display: flex; flex-direction: column; gap: 1.5rem; min-width: 0; }
.res h3 { margin-bottom: .25rem; padding-bottom: .3rem; border-bottom: 1px solid var(--line); }
.res.pending h3 { color: var(--muted); }
.res.pending dl:empty { display: none; }
/* The DKIM check, under the mail of a domain. */
.tool form.dkim { margin-top: .6rem; }
.tool .hint { flex: 1 1 100%; margin: 0; font-size: .8rem; }
.dkim-out { margin-top: .4rem; }
.res .status:empty { display: none; }
/* A part of the result that failed: said in its own group. */
.res .res-note { margin: .25rem 0 0; color: var(--muted); font-size: .9rem; }
button.dkim-other { margin-top: .3rem; }
/* Port presets: quiet chips under the field. */
.presets { flex: 1 1 100%; display: flex; flex-wrap: wrap; gap: .35rem; }
button.chip { font-size: .8rem; min-height: 1.75rem; padding: .1rem .7rem; border-radius: 99rem; color: var(--muted); }
button.chip:hover, button.chip:focus-visible { color: var(--accent); }
@media (max-width: 34rem) {
  button.chip { min-height: 2.1rem; padding-inline: .8rem; }
}
/* Under a result: copy it, copy its link. */
.result-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .5rem; margin-top: .5rem; }
.result-actions button { padding-left: .4rem; padding-right: .4rem; }
.copy-note { font-size: .8rem; color: var(--muted); }
.offscreen { position: absolute; left: -10000px; top: 0; width: 1px; height: 1px; }

/* Statistics page: three figures, requests per day, what they were for. */
main.stats .lead { margin: 0; color: var(--muted); text-align: center; }
.stat-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; margin: 0; text-align: center; }
.stat-tiles dt { color: var(--muted); font-size: .8rem; }
.stat-tiles dd { margin: .2rem 0 0; font-size: clamp(1.35rem, 6vw, 2rem); font-weight: 600; font-variant-numeric: tabular-nums; }
.chart { position: relative; margin: .5rem 0 0; padding-left: 2.75rem; }
.chart svg { display: block; width: 100%; height: 11rem; overflow: visible; }
.chart .grid { stroke: var(--line); stroke-width: 1; }
.chart .col { fill: var(--accent); }
.chart .hit { fill: transparent; }
.chart .day:hover .hit { fill: color-mix(in srgb, var(--fg) 7%, transparent); }
.chart .day:hover .col, .chart .day:focus-visible .col { fill: color-mix(in srgb, var(--accent) 70%, var(--fg)); }
.chart .day:focus-visible { outline: none; }
.chart .day:focus-visible .hit { fill: color-mix(in srgb, var(--fg) 10%, transparent); }
/* A day chosen: its column stands out, the others step back. */
.chart:has(.sel) .day:not(.sel) .col { fill: color-mix(in srgb, var(--accent) 40%, var(--line)); }
.chart .day.sel .hit { fill: color-mix(in srgb, var(--fg) 7%, transparent); }
.table-view tr.sel td { font-weight: 600; }
.detail { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .25rem 1rem; scroll-margin-top: 1rem; }
.detail h2 { margin: 0; }
.detail p { margin: 0; color: var(--muted); font-size: .85rem; }
.detail a { font-size: .9rem; }
.detail-n { margin-left: .5rem; color: var(--muted); font-weight: 400; font-variant-numeric: tabular-nums; }
.ticks { position: absolute; left: 0; top: 0; width: 2.4rem; height: 11rem; }
.ticks span { position: absolute; right: 0; transform: translateY(-50%); font-size: .7rem; line-height: 1; color: var(--muted); font-variant-numeric: tabular-nums; }
.ticks .t-zero { top: 88.89%; }
.ticks .t-mid { top: 46.67%; }
.ticks .t-top { top: 4.44%; }
.chart figcaption { display: flex; justify-content: space-between; margin-top: -1rem; font-size: .75rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.table-view { margin-top: .75rem; }
.table-view summary { cursor: pointer; width: fit-content; color: var(--muted); font-size: .85rem; }
.table-view table { border-collapse: collapse; margin-top: .5rem; font-size: .85rem; }
.table-view th, .table-view td { text-align: left; padding: .15rem 2rem .15rem 0; border-top: 1px solid var(--line); }
.table-view thead th { border-top: 0; color: var(--muted); font-weight: 500; }
.table-view td:last-child, .table-view th:last-child { text-align: right; padding-right: 0; font-variant-numeric: tabular-nums; }
/* The uses in one column, the other breakdowns stacked in the second. */
.shares { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); gap: 1.75rem 3rem; align-items: start; }
.shares-col { display: flex; flex-direction: column; gap: 1.75rem; }
/* A breakdown in two or three parts: one bar split between them. */
.split-bar { display: block; width: 100%; height: .6rem; border-radius: .2rem; overflow: hidden; }
.split-bar .part { fill: color-mix(in srgb, var(--accent) 35%, var(--line)); }
.split-bar .part-0 { fill: var(--accent); }
.split-legend { list-style: none; margin: .45rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .25rem; font-size: .9rem; }
.split-legend li { display: flex; align-items: baseline; gap: .5rem; }
.split-legend i { flex: none; width: .65rem; height: .65rem; border-radius: .15rem; background: color-mix(in srgb, var(--accent) 35%, var(--line)); }
.split-legend i.part-0 { background: var(--accent); }
.split-legend .share-name { flex: 1; }
.share-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .5rem; }
.share-list li { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "name n" "bar bar"; gap: .2rem .75rem; font-size: .9rem; }
.share-name { grid-area: name; overflow-wrap: anywhere; }
.share-n { grid-area: n; font-variant-numeric: tabular-nums; }
.share-n small { color: var(--muted); }
.share-bar { grid-area: bar; display: block; width: 100%; height: .45rem; }
.share-bar .track { fill: var(--line); }
.share-bar .fill { fill: var(--accent); }
main.stats .note { margin: 0; color: var(--muted); font-size: .85rem; text-align: center; }
@media (forced-colors: active) {
  .split-bar .part { fill: GrayText; }
  .chart .col, .share-bar .fill, .split-bar .part-0 { fill: CanvasText; }
  .split-legend i { background: GrayText; forced-color-adjust: none; }
  .split-legend i.part-0 { background: CanvasText; }
}

/* Between the tabs (a swipe or a click, swipe.js): the content slides in
   from the side of the tab, the header, the tabs and the sky staying where
   they are; swipe.js skips the transition for any other link. */
@view-transition { navigation: auto; }
html:active-view-transition main { view-transition-name: page; } /* only then: its name makes it a stacking context, the controls below kept under the sky's targets */
::view-transition-group(page) { animation: none; }
html:active-view-transition-type(next)::view-transition-old(page) { animation: vt-out .28s ease-in both; --vt: -100%; }
html:active-view-transition-type(next)::view-transition-new(page) { animation: vt-in .28s ease-out both; --vt: 100%; }
html:active-view-transition-type(prev)::view-transition-old(page) { animation: vt-out .28s ease-in both; --vt: 100%; }
html:active-view-transition-type(prev)::view-transition-new(page) { animation: vt-in .28s ease-out both; --vt: -100%; }
html:active-view-transition-type(next, prev)::view-transition-old(root), html:active-view-transition-type(next, prev)::view-transition-new(root) { animation: none; }
@keyframes vt-out { to { transform: translateX(var(--vt)); opacity: 0; } }
@keyframes vt-in { from { transform: translateX(var(--vt)); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { @view-transition { navigation: none; } }
/* Without view transitions from page to page (Firefox): the new page alone
   sliding in (swipe.js). */
@media (prefers-reduced-motion: no-preference) {
  html.vt-next main { animation: vt-in .28s ease-out both; --vt: 100%; }
  html.vt-prev main { animation: vt-in .28s ease-out both; --vt: -100%; }
  html:is(.vt-next, .vt-prev) body { overflow-x: clip; }
}
/* What can be clicked in the page wins over the sky's targets behind it
   (.nj-hit, z-index 2: a planet, a constellation, what an event left); the
   header, the tabs and the footer are above them too (sky.css). */
:where(main) :where(a[href], button, input, select, textarea, summary, label) { position: relative; z-index: 3; }
/* The game (/game/): its canvas as wide as the page, space whatever the theme. */
main.game { position: relative; z-index: 3; } /* the page above the sky's targets (.nj-hit), the game not clicked through */
main.game.wide { width: min(92rem, 100%); } /* the game up to half again the field (1440 x 840) */
main.game > .lead { max-width: 62rem; margin-inline: auto; } /* the text above it as wide as the site's */
/* The field's own shape (960 x 560, game.js): as large as the window allows,
   up to half again its size, no dark bands beside it. */
.game .game-box { position: relative; width: 100%; margin: 1rem auto; max-width: calc(min(840px, 80vh) * 960 / 560); }
.game canvas { display: block; width: 100%; height: auto; aspect-ratio: 960 / 560; border-radius: 10px; background: #05080e; border: 1px solid var(--line); touch-action: none; cursor: crosshair; }
/* On a phone: no text picked by a double tap, no zoom, no grey flash; the
   canvas as tall as the screen leaves room for. */
.game .game-box { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
.game .game-box input { -webkit-user-select: text; user-select: text; }
@media (max-width: 700px) { .game canvas { height: max(260px, calc(100svh - 7rem)); } }
@media (max-height: 500px) { .game canvas { height: max(240px, calc(100svh - 1rem)); } } /* a phone on its side: the screen, once scrolled to */
/* Full screen: the box is the screen (the API's, or fixed over the page
   where there is none, as on the iPhone). */
.game .game-tools { position: absolute; top: 8px; left: 8px; z-index: 4; display: flex; gap: 6px; }
.game .game-full, .game .game-pause, .game .game-sound { display: grid; place-items: center; width: 36px; height: 36px; padding: 0;
  border-radius: 6px; border: 1px solid rgba(201, 212, 224, .35); background: rgba(5, 8, 14, .6); color: #f2f4f8; cursor: pointer; }
.game .game-full[hidden], .game .game-pause[hidden], .game .game-sound[hidden] { display: none; }
.game .game-full:hover, .game .game-full:focus-visible, .game .game-pause:hover, .game .game-pause:focus-visible, .game .game-sound:hover, .game .game-sound:focus-visible { border-color: #ff9a3c; color: #ff9a3c; }
.game .game-pause .out, .game .game-box.held .game-pause .in { display: none; }
.game .game-box.held .game-pause .out { display: inline; }
.game .game-full .out, .game .game-box.full .game-full .in { display: none; }
.game .game-box.full .game-full .out { display: inline; }
.game .game-sound .out, .game .game-box.mute .game-sound .in { display: none; }
.game .game-box.mute .game-sound .out { display: inline; }
html.game-full-on, html.game-full-on body { overflow: hidden; }
/* While a run goes on, the sky behind the game still (its animations cost
   the game its frames, in Firefox most); full screen, no sky at all (none of
   it seen). */
html.game-on :is(.nj-sky, .nj-hit, .nt-bg), html.game-on :is(.nj-sky, .nj-hit, .nt-bg) *, html.game-on :is(.nj-sky, .nj-hit, .nt-bg) *::before,
html.game-on :is(.nj-sky, .nj-hit, .nt-bg) *::after, html.game-on::before, html.game-on body::before { animation-play-state: paused !important; }
html.game-full-on :is(.nj-sky, .nj-hit, .nt-bg, .nt-hit), html.game-full-on::before, html.game-full-on body::before { display: none !important; }
html.game-full-on main.game { z-index: 1000; } /* above the header, the tabs, the footer */
.game .game-box.full { position: fixed; inset: 0; z-index: 1000; margin: 0; max-width: none; background: #05080e; }
.game .game-box:fullscreen { background: #05080e; }
/* No landscape to ask for (the iPhone) and the phone upright: the game
   turned a quarter, to be held sideways. */
@media (orientation: portrait) {
  .game .game-box.full.turn { inset: auto; top: 0; left: 100vw; width: 100vh; width: 100dvh; height: 100vw; transform-origin: 0 0; transform: rotate(90deg); }
}
.game canvas { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
.game .game-box.full canvas { width: 100%; height: 100%; border: 0; border-radius: 0; }
.game canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Its name to play under, and the board of the best. */
.game .game-name { display: none; position: absolute; left: 50%; top: calc(50% + 34px); transform: translateX(-50%); width: max-content; max-width: calc(100% - 24px);
  flex-wrap: wrap; justify-content: center; align-items: center; gap: .5rem; padding: .6rem .8rem; border-radius: 10px;
  background: rgba(5, 8, 14, .78); border: 1px solid rgba(255, 154, 60, .45); box-shadow: 0 0 24px rgba(255, 154, 60, .15); }
.game .game-box.ask .game-name { display: flex; }
.game .game-name label { color: #c9d4e0; font: 12px ui-monospace, "SF Mono", Menlo, monospace; letter-spacing: .06em; text-transform: uppercase; }
.game .game-name input { width: 11rem; padding: .45rem .6rem; border: 1px solid rgba(201, 212, 224, .35); border-radius: 6px; background: #0b1220; color: #f2f4f8; font: inherit; }
.game .game-name input:focus { outline: 2px solid #ff9a3c; outline-offset: 1px; }
.game .game-name button { padding: .45rem 1rem; border: 1px solid var(--accent); border-radius: 6px; background: var(--accent); color: #fff; font: inherit; font-weight: 600; cursor: pointer; }
/* Quitting, paused or at the end: the board drawn in the game, the name
   below it. */
.game .game-menu { display: none; position: absolute; left: 50%; bottom: 46px; transform: translateX(-50%); gap: .5rem; }
.game .game-menu button { padding: .4rem 1.1rem; border-radius: 6px; border: 1px solid rgba(201, 212, 224, .4); background: rgba(5, 8, 14, .8); color: #f2f4f8;
  font: 12px ui-monospace, "SF Mono", Menlo, monospace; letter-spacing: .08em; text-transform: uppercase; cursor: pointer; }
.game .game-menu button:hover, .game .game-menu button:focus-visible { border-color: #ff9a3c; color: #ff9a3c; }
.game .game-box.menu .game-menu { display: flex; }
.game #game-back, .game #game-again, .game .game-box.helping .game-menu button:not(#game-back) { display: none; }
/* A room (?salon=): its buttons in place of the menu (the start, or the
   next race for all, the host's; the link; leaving), the form's way in. */
.game .game-name .game-room-new { background: transparent; color: #f2f4f8; border-color: rgba(201, 212, 224, .45); font-weight: 500; }
.game .game-box.inroom .game-room-new { display: none; }
.game .game-room { display: none; position: absolute; left: 50%; bottom: 46px; transform: translateX(-50%); gap: .5rem; flex-wrap: wrap; justify-content: center; width: max-content; max-width: calc(100% - 24px); }
.game .game-box.roombar .game-room { display: flex; }
/* With the ship picker shown (drawn at the bottom left of the field), the
   buttons at the bottom over it rather than across it. */
.game .game-box.picking .game-menu, .game .game-box.picking.board .game-name { bottom: calc(114px * var(--s, 1) + 12px); } /* --s: the view's scale (game.js) */
.game .game-box.roombar .game-menu { display: none; }
.game .game-room button { padding: .4rem 1.1rem; border-radius: 6px; border: 1px solid rgba(201, 212, 224, .4); background: rgba(5, 8, 14, .8); color: #f2f4f8;
  font: 12px ui-monospace, "SF Mono", Menlo, monospace; letter-spacing: .08em; text-transform: uppercase; cursor: pointer; }
.game .game-room button:hover, .game .game-room button:focus-visible { border-color: #ff9a3c; color: #ff9a3c; }
.game #game-room-go { display: none; border-color: var(--accent); background: var(--accent); color: #fff; font-weight: 600; }
.game .game-box.roomgo #game-room-go { display: block; }
/* ?banc: the bench's buttons, above the game. */
.game-banc { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center; margin: 0 0 .6rem; }
.game-banc button { padding: .4rem .8rem; border-radius: 6px; border: 1px solid #ff9a3c; background: #1a1208; color: #ffcf8a; font: 600 .875rem system-ui, sans-serif; cursor: pointer; }
.game-banc button:hover, .game-banc button:focus-visible { background: #2a1c0c; }
/* At the end, the name already known: Play again, rather than the name. */
.game .game-box.ended #game-again { display: block; border-color: var(--accent); background: var(--accent); color: #fff; font-weight: 600; }
.game .game-box.helping #game-back { display: block; }
.game .game-box.helping .game-name { display: none; }
.game .game-box.board .game-name { top: auto; bottom: 46px; }
